Skocz do zawartości

Tablica liderów


Popularna zawartość

Pokazuje zawartość z najwyższą reputacją 28.03.2019 we wszystkich miejscach

  1. 2 punkty
    Co to jest timelapse? W razie, gdyby ktoś nie wiedział, co mało prawdopodobne, ale jednak - jest to przeciwieństwo slow-motion, czyli film, który jest kilka albo kilkanaście razy przyspieszony. Filmy takie pozwalają obejrzeć zjawiska, które ze swojej natury są bardzo wolne, na przykład wyrastanie ciasta, płynięcie chmur na niebie, rośnięcie roślin i tak dalej. Nagranie timelapse nie jest jakimś wielkim wyczynem, bo większość aparatów i kamerek sportowych ma taki tryb wbudowany, a na telefony komórkowe istnieją tysiące aplikacji realizujących takie właśnie nagranie. Do czego więc może służyć maszyna do timelapse? Najbardziej podstawową wersją timelapse jest oczywiście nieruchomy kadr - ustawiamy kamerę na statywie, uruchamiamy proces nagrywania i zostawiamy wszystko na odpowiedni czas. Filmy takie same w sobie robią już wrażenie, ale znacznie ciekawiej jest, gdy kadr jest zmienny, na przykład gdy zastosujemy panoramowanie (czyli powolny obrót) albo liniowe przesunięcie. Kłopot polega na tym, że obrót taki musi być realizowany bardzo wolno - w tempie dopasowanym do tempa robienia zdjęć. 45 stopni to być może dużo, ale jeżeli kamera ma zarejestrować, powiedzmy, 40 minut materiału przy 30 klatkach na sekundę, to mamy prędkość obrotu rzędu 45/(40*60) = 0,01875 stopnia na sekundę. Żeby było trudniej, kamera musi obracać się płynnie, bo timelapse będzie wyraźnie poszarpany. Do czegoś takiego trzeba już dedykowanego urządzenia: kupionego albo - co znacznie ciekawsze - zrobionego samodzielnie. Komponenty Tym razem kontrolerem stało się Arduino Uno, między innymi dlatego, że razem z shieldem z wyświetlaczem i klawiaturą zapewniło dosyć niskim kosztem interfejs użytkownika. Płynny i w pełni kontrolowany obrót zapewni silnik krokowy, a ten konkretny, czyli SY35ST26-0284A wybrałem w dużej mierze dlatego, że można go zasilić bezpośrednio dwucelowym akumulatorem LiPo. Do silnika należało oczywiście również kupić odpowiedni sterownik. Oprócz tego wyposażyłem się też w obudowę - być może efekt końcowy nie powala estetyką, ale bardzo nie lubię kończyć projektów z gmatwaniną sterczących przewodów i po ukończeniu jeżdżącego robota stwierdziłem, że będę dbał również o wygląd moich projektów. To nie był koniec zakupów - silnik krokowy oferuje 200 kroków na obrót, co daje 1,8 stopnia na krok. Tymczasem ja potrzebowałem stukrotnie większej dokładności, dlatego konieczne było zbudowanie przekładni zębatej. Zębatki Z przekonaniem, że w Internecie można znaleźć wszystko zacząłem szukać zębatek i okazało się, że wcale nie tak łatwo jest znaleźć zębatki do takiego projektu. Byłem ograniczony ich rozmiarem oraz sposobem montażu - nie posiadając wtedy drukarki 3D (na której pewnie sam wydrukowałbym potrzebne koła), miałem też ograniczone możliwości związane z montażem komponentów. W akcie desperacji napisałem email z zapytaniem ofertowym do krakowskiej firmy, która specjalizuje się w produkcji kół zębatych, ale koszty rzędu (o ile dobrze pamiętam) 800 PLN za cztery koła zębate przekraczały wielokrotnie mój budżet na ten projekt. Wróciłem więc do poszukiwań i w końcu znalazłem odpowiednie koła zębate w sklepie conrad.pl. Kupiłem dwa czterdziestozębowe i dwa trzydziestozębowe - w przypadku, gdyby te pierwsze nie zmieściły się wewnątrz obudowy. Oprócz tego kupiłem jedną piętnastkę oraz dwunastkę - ta ostatnia miała otwór na oś pasujący do kupionego przeze mnie silnika krokowego. Przekładnia Teraz musiałem zaprojektować przekładnię - skorzystałem w tym celu z darmowego Solid Edge Drafting - świetnego dwuwymiarowego cada. Pomierzyłem wszystkie przestrzenie suwmiarką i wyszło na to, że przekładnia zmieści się w całości w przedniej, podwyższonej części obudowy. Nie dysponuję żadną maszyną CNC, ale otwory w aluminiowych płytkach musiałem zrobić bardzo dokładnie, bo inaczej zębatki nie zazębiłyby się (w jedną albo drugą stronę) albo obracały ze zbyt dużym oporem. Wpadłem więc na pomysł - wydrukowałem układ otworków w obu płytkach przygotowany wcześniej w cadzie na papierze samoprzylepnym i przykleiłem go na obrabianym aluminium. Potem dociąłem płytki zgodnie z ramkami i wywierciłem otwory w oznaczonych miejscach - okazało się, że taka dokładność była wystarczająca i wszystko ładnie wskoczyło na swoje miejsca. Montaż Po zbudowaniu przekładni nie zostało już zbyt dużo do roboty - zamontowałem wewnątrz obudowy Uno z shieldem LCD, podłączyłem do przygotowanej wcześniej płytki prototypowej ze sterownikiem silnika, a do niej sam silnik. Potem skręciłem wszystko i dostałem (w miarę) zgrabne urządzenie. Programowanie Na potrzeby tego projektu napisałem specjalnie własny zestaw bibliotek, które ułatwiają budowanie wielopoziomowych menu na shieldzie LCD. Programik jest stosunkowo prosty - należy obrócić silnik w położenie źródłowe i docelowe, ustalić czas obrotu - i uruchomić. Program oblicza o jaki kąt obrócić silnik w jakim czasie i powolutku obraca oś z jednego położenia do drugiego. Ponieważ program z bibliotekami jest dosyć duży, nie będę go tu zamieszczał, ale można go ściągnąć z mojego repozytorium na gitlabie. Efekty Czy cel został osiągnięty? Definitywnie tak - nagrane filmy poddaję niewielkiej obróbce w VirtualDub (korzystam z plugina o nazwie deshaker), żeby odrobinę poprawić ich jakość, ale nawet i bez tej obróbki filmiki wyglądają całkiem przyzwoicie. Przykładowy poniżej: Wnioski Po pierwsze, maszyna jest niestety przeraźliwie głośna. Obracanie (przynajmniej na początku, podczas ustawiania zakresów) osi generuje dźwięk przypominający skrzyżowanie kosiarki do trawy i piły łańcuchowej. Winne są najprawdopodobniej pancerne zębatki oraz luzy na osiach - teraz, mając już drukarkę 3D, wydrukowałbym sobie wszystko z PLA spasowane do dziesiątych milimetra, podczas budowy tego urządzenia skazany byłem jednak tylko na własne ręce i montaż przekładni na pewno nie jest tak dokładny jaki mógłby być. Poza tym warto byłoby rozważyć również zastosowanie mniejszych, plastikowych zębatek, tylko obawiałem się trochę, czy będę w stanie zamontować je pewnie do osi - tak, by nie wyrobiły się i nie zaczęły obracać w miejscu. Plusem tej przekładni jest natomiast fakt, że jest po prostu pancerna - myślę, że spokojnie mógłbym zamontować na niej lustrzankę z solidnym obiektywem i ani przekładnia ani silnik nawet by nie sapnęły. Zdecydowanie warto było zainwestować w obudowę - kosztowała mnie raptem 15 złotych, a znacząco podniosła estetykę projektu (i przynajmniej w pewnym stopniu chroni elektronikę przed warunkami atmosferycznymi i kurzem. Wbrew pozorom dosyć wygodne okazało się zasilenie urządzenia z zewnątrz - wyprowadziłem sobie ze środka kabelek zakończony wtyczką T-Dean i gdy chcę uruchomić narzędzie, po prostu łapię jeden z dwucelowych akumulatorów LiPo walających się gdzieś po domu i maszyna może na nim działać naprawdę długo. Choć urządzenie powstało już jakiś czas temu, nie użyłem go jeszcze zbyt wiele razy; tak naprawdę zbudowałem je pod kątem filmowego projektu, który mam zamiar nakręcić, ale wymaga on dosyć dużo czasu w plenerze, a tego zasobu od jakiegoś czasu niestety trochę mi brakuje. Ale też nie tracę nadziei - być może za kilka lat zrealizujemy go razem z córką? Czas pokaże...
  2. 2 punkty
    Trudne początki Tak naprawdę to jest chyba mój pierwszy projekt w świecie Arduino! Zamarzyłem sobie zbudowanie własnego, terenowego pojazdu zdalnie sterowanego - takiego, na którym można potem zamontować jakiś chwytak, ramię albo kamerkę z przekaźnikiem FPV. Kontroler Tu akurat nie miałem większego wyboru, bo wtedy pod ręką miałem akurat Arduino Leonardo. Zaletą tej płytki jest kompatybilność z popularnymi shieldami do Uno a także złącze microUSB typu B (zamiast mało popularnego złącza "drukarkowego" w Uno). Na potrzeby tego niezbyt skomplikowanego projektu moc obliczeniowa tej płytki jest również całkowicie wystarczająca. Podwozie Moim planem było zbudowanie definitywnego i niepokonanego łazika marsjańskiego, więc zwykłe podwozie nie wchodziło w grę - koniecznie musiało być terenowe. Przegrzebałem naprawdę połowę Internetu w poszukiwaniu tego idealnego podwozia (ale - nie ukrywajmy - mieszczącego się również w moim budżecie) i w końcu mój wybór padł na podwozie Dagu DG012-ATV z napędem na cztery koła. Nieco podwyższony prześwit w stosunku do innych podwozi (dający nadzieję na pokonywanie niewielkich przeszkód), napęd na cztery koła - wszystko to brzmiało bardzo zachęcająco. Czterema silnikami coś oczywiście musi obracać, razem z podwoziem nabyłem więc również czterokanałowy sterownik silników DFRobota (w postaci shieldu dla Arduino). Serwo i czujnik Żeby urozmaicić nieco projekt, dodałem do niego serwo modelarskie, na którym zamontowałem ultradźwiękowy czujnik odległości z założeniem, że spróbuję kiedyś napisać program do autonomicznego poruszania się. RC Od długiego czasu używam do zdalnego sterowania aparatury FrSky Taranis, więc oczywiście musiałem skorzystać z kompatybilnego odbiornika - w tym przypadku X8R. Zasilanie Projekt oczywiście musiał być mobilny, więc zdecydowałem się na zasilenie go dwucelowym akumulatorem Lipo; konieczne okazało się też zastosowanie układu BEC, który obniżył napięcie akumulatora do 5V. Teraz pozostało już tylko zmontować wszystko w całość. Montaż podwozia Tu obyło się bez niespodzianek i problemów, po prostu skręciłem wszystko zgodnie z instrukcją i wyprowadziłem na zewnątrz przewody, którymi zasilane miały być silniki. Potem sprawy nieco się skomplikowały. Wszystko rozbiło się generalnie o to, że jak bym nie ułożył elementów na podwoziu, po prostu nie było takiego ułożenia, żeby wszystko się zmieściło. Sprawy utrudniał również fakt zastosowania Leonardo, które - umówmy się - jest raczej kobylaste i znacznie lepiej sprawdziłoby się tu kompatybilne z tą płytką Arduino Micro. Do tego dochodził BEC, odbiornik, serwo (którego nota bene nie miałem jak zamocować, bo w wersji 4WD podwozia miejsce na serwo zajmowane było przez dwa dodatkowe silniki) no i oczywiście akumulator. Dlatego zdecydowałem się na umieszczenie wszystkiego ponad podwoziem, pozostawiając na dole sam akumulator. Przykleiłem więc na dolnym pokładzie rzep, na którym mocowany jest akumulator - przeciążenia podczas poruszania robota są tak znikome, że jest to naprawdę pewny i sprawdzony sposób montażu (pozwalający też szybko zamontować albo zdemontować akumulator w razie potrzeby). Oprócz tego przykręciłem w narożnikach podwozia długie dystanse (kupione kiedyś w Chinach na potrzeby projektu quadrokoptera) i zabrałem się za przygotowywanie górnej części pojazdu. Górne podwozie wykonałem z fragmentu płytki aluminiowej, którą dociąłem tak, by znalazła się dokładnie ponad górną częścią podwozia - i jednocześnie dzięki temu przykryła koła, z których pył mógł się dostawać do elektroniki. W płytce wyciąłem otwór na serwo; ponieważ nie dysponuję żadnym sprzętem CNC, który pomógłby mi wyciąć równy, parametryczny otwór, rad nierad wziąłem do ręki wiertarkę, najpierw nawierciłem otwory, potem zamontowałem w niej frez i zacząłem ręcznie wycinać aluminium, a na końcu doszlifowałem wszystko pilnikami o zmniejszającej się ziarnistości. Cały proces poniżej: Teraz można było powoli przystąpić do montażu. Na pierwszy ogień poszło serwo, które na szczęście wpasowało się w wycięty przeze mnie otwór po prostu idealnie. Następnym krokiem było zamontowanie BECa, którego umieściłem pod górnym pokładem. Przewód zasilający (zakończony złączem T-Dean) musiałem rozgałęzić, ponieważ jedna para przewodów musiała zostać połączona z BECem, który obniży napięcie do 5V dla części elektroniki, zaś druga para - do sterownika silników, który będzie potem je zasilał. Szczęśliwie silniki akceptują napięcie dwucelowego akumulatora LiPo - trzeba to koniecznie sprawdzić przed zakupem/montażem! Arduino Leonardo można zasilić bezpośrednio z akumulatora, natomiast konieczne było przylutowanie odpowiedniej wtyczki (na zdjęciu po prawej stronie). Na koniec pozostało podłączenie wszystkich komponentów i otrzymujemy następujący efekt: Programowanie Pierwszym programikiem, który napisałem, był tester silników, który uruchamiał każdy z nich na pół sekundy. Kod wygląda następująco: const int E1 = 3; // Motor1 Speed const int E2 = 11; // Motor2 Speed const int E3 = 5; // Motor3 Speed const int E4 = 6; // Motor4 Speed const int M1 = 4; // Motor1 Direction const int M2 = 12; // Motor2 Direction const int M3 = 8; // Motor3 Direction const int M4 = 7; // Motor4 Direction void M1_advance(char Speed) { digitalWrite(M1, HIGH); analogWrite(E1, Speed); } void M2_advance(char Speed) { digitalWrite(M2, LOW); analogWrite(E2, Speed); } void M3_advance(char Speed) { digitalWrite(M3, LOW); analogWrite(E3, Speed); } void M4_advance(char Speed) { digitalWrite(M4, HIGH); analogWrite(E4, Speed); } void M1_back(char Speed) { digitalWrite(M1, LOW); analogWrite(E1, Speed); } void M2_back(char Speed) { digitalWrite(M2, HIGH); analogWrite(E2, Speed); } void M3_back(char Speed) { digitalWrite(M3, HIGH); analogWrite(E3, Speed); } void M4_back(char Speed) { digitalWrite(M4, LOW); analogWrite(E4, Speed); } void setup() { for (int i = 3; i < 9; i++) pinMode(i, OUTPUT); for (int i = 11; i < 13; i++) pinMode(i, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); } void loop() { digitalWrite(LED_BUILTIN, HIGH); M1_advance(100); delay(500); M1_advance(0); M2_advance(100); delay(500); M2_advance(0); M3_advance(100); delay(500); M3_advance(0); M4_advance(100); delay(500); M4_advance(0); digitalWrite(LED_BUILTIN, LOW); delay(2000); // Delay 2S } Jak widać, sterowanie silnikami odbywa się poprzez podawanie kierunku poprzez piny cyfrowe i prędkości poprzez piny analogowe - proste, jak konstrukcja cepa. Teraz przyszła kolej na odbiornik RC i tu zaczęły się schody. Odbiorniki klasycznie podają stan każdego kanału poprzez sygnał PWM. W praktyce jest to seria naprzemiennych zer i jedynek, z których każda para 1+0 trwa 1/55 sekundy. Wartość możemy odczytać mierząc czas trwania sygnału 1: jeżeli jest to 1 milisekunda, przyjmujemy wartość minimalną ("-1"), jeżeli 1.5 milisekundy, to wartość środkową ("0"), zaś jeśli 2 milisekundy, to wartość maksymalną ("1"). Niektóre odbiorniki pozwalają na nieco szerszy zakres - od 0.5ms do 2.5ms, X8R domyślnie podaje wartości z tego pierwszego zakresu. Ponieważ musiałem mierzyć wartości na dwóch różnych kanałach, zdecydowałem się skorzystać z mechanizmu przerwań. Działa on mniej więcej następująco: gdy zajdzie wybrane zdarzenie (na przykład zmiana stanu danego pinu z niskiego na wysoki), wykonanie programu jest przerywane, zostaje wykonana funkcja oznaczona jako tzw. handler przerwania, a po jej zakończeniu program wznawia wykonanie w miejscu, w którym został przerwany. Na Arduino można znaleźć bardzo wygodną bibliotekę EnableInterrupt, która uogólnia sposób dodawania i usuwania handlerów przerwań pomiędzy różnymi wersjami Arduino, a korzysta się z niej w następujący sposób: #include "EnableInterrupt.h" volatile int microsStart = 0; void pin0Rising() { microsStart = micros(); disableInterrupt(0); enableInterrupt(0, pin0Falling, FALLING); } void pin0Falling() { int microsEnd = micros(); int diff = microsEnd - microsStart; if (diff > 1500) { digitalWrite(LED_BUILTIN, HIGH); } else { digitalWrite(LED_BUILTIN, LOW); } disableInterrupt(0); enableInterrupt(0, pin0Rising, RISING); } void setup() { enableInterrupt(0, pin0Rising, RISING); pinMode(LED_BUILTIN, OUTPUT); } void loop() { } Po wpięciu przewodu sygnałowego do pinu 0 i uruchomieniu programiku na kontrolerze, wbudowana dioda powinna się zapalić w momencie, gdy ustawimy drążek w położeniu większym niż połowa. Zwrócę jeszcze uwagę na magiczne słówko "volatile" przy deklaracji zmiennej - informuje ono kompilator, że zmienna ta nie może zostać zoptymalizowana (kompilator, a dokładniej optymalizator w niektórych przypadkach może w locie usunąć zmienną, na przykład jeżeli nie jest ona używana lub przez cały czas trwania programu ma zawsze tę samą wartość). Dodam tu jeszcze jedną ważną informację: program obsługi przerwania powinien być tak krótki, jak to tylko możliwe! Ma to sporo sensu jeżeli się nad tym nieco dłużej zastanowić, ale ja na to nie wpadłem i w pierwotnej wersji programu cała obsługa silników umieszczona była właśnie w programie obsługi przerwania. I ku mojemu zdziwieniu, po uruchomieniu programu, pomimo tego, że drążki były w położeniu zerowym, dwa silniki zaczęły się obracać. Okazało się, że obsługa przerwania obliczającego czas trwania PWM na pierwszym kanale trwała tak długo, że sztucznie opóźniała wywołanie drugiego przerwania wykonującego te same obliczenia dla drugiego kanału, przez co podawało ono zawyżone wartości. Wystarczyło przebudować program w taki sposób, by obsługa silników znalazła się poza programami obsługi przerwań i wszystko wróciło do normy. Pamiętajmy - to może oczywiste, ale mimo wszystko warto to powiedzieć - że mikrokontrolery nie są wielowątkowe, a przerwania nie są wątkami: wykonują się tylko jedno na raz. Drugie przerwanie musi czekać, aż pierwsze zostanie do końca obsłużone. Przed napisaniem końcowego programu pozostało mi już tylko przetestować obsługę czujnika ruchu, programik wygląda następująco: #include <NewPing.h> #define ULTRASONIC_TRIGGER_PIN 9 #define ULTRASONIC_ECHO_PIN 10 #define MAX_DISTANCE 400 NewPing sonar(ULTRASONIC_TRIGGER_PIN, ULTRASONIC_ECHO_PIN, MAX_DISTANCE); void setup() { pinMode(LED_BUILTIN, OUTPUT); } void loop() { digitalWrite(LED_BUILTIN, HIGH); delay(50); digitalWrite(LED_BUILTIN, LOW); delay(50); int ping = sonar.ping_cm(); if (ping < 30) digitalWrite(LED_BUILTIN, HIGH); else digitalWrite(LED_BUILTIN, LOW); delay(200); } Również i tu korzystam z wbudowanej diody, która powinna zapalić się, gdy zmierzona przez czujnik odległość będzie mniejsza niż 30 cm. Wreszcie program obsługujący całego robota: #include <NewPing.h> #include "EnableInterrupt.h" #include "NewPing.h" // Motor constants // Motor1 Speed #define MOTOR_1_SPEED_PIN 3 // Motor2 Speed #define MOTOR_2_SPEED_PIN 11 // Motor3 Speed #define MOTOR_3_SPEED_PIN 5 // Motor4 Speed #define MOTOR_4_SPEED_PIN 6 // Motor1 Direction #define MOTOR_1_DIR_PIN 4 // Motor2 Direction #define MOTOR_2_DIR_PIN 12 // Motor3 Direction #define MOTOR_3_DIR_PIN 8 // Motor4 Direction #define MOTOR_4_DIR_PIN 7 // Ultrasonic constants #define ULTRASONIC_TRIGGER_PIN 9 #define ULTRASONIC_ECHO_PIN 10 #define MAX_DISTANCE 400 // Servo constants #define SERVO_PIN 13 // AI constants #define DISTANCE_THRESHOLD_2 80 #define DISTANCE_THRESHOLD_1 40 // Ultrasonic control NewPing sonar(ULTRASONIC_TRIGGER_PIN, ULTRASONIC_ECHO_PIN, MAX_DISTANCE); // Motor control functions void M1_advance(byte Speed) ///<Motor1 Advance { digitalWrite(MOTOR_1_DIR_PIN, HIGH); analogWrite(MOTOR_1_SPEED_PIN, Speed); } void M2_advance(byte Speed) ///<Motor2 Advance { digitalWrite(MOTOR_2_DIR_PIN, LOW); analogWrite(MOTOR_2_SPEED_PIN, Speed); } void M3_advance(byte Speed) ///<Motor3 Advance { digitalWrite(MOTOR_3_DIR_PIN, LOW); analogWrite(MOTOR_3_SPEED_PIN, Speed); } void M4_advance(byte Speed) ///<Motor4 Advance { digitalWrite(MOTOR_4_DIR_PIN, HIGH); analogWrite(MOTOR_4_SPEED_PIN, Speed); } void M1_back(byte Speed) ///<Motor1 Back off { digitalWrite(MOTOR_1_DIR_PIN, LOW); analogWrite(MOTOR_1_SPEED_PIN, Speed); } void M2_back(byte Speed) ///<Motor2 Back off { digitalWrite(MOTOR_2_DIR_PIN, HIGH); analogWrite(MOTOR_2_SPEED_PIN, Speed); } void M3_back(byte Speed) ///<Motor3 Back off { digitalWrite(MOTOR_3_DIR_PIN, HIGH); analogWrite(MOTOR_3_SPEED_PIN, Speed); } void M4_back(byte Speed) ///<Motor4 Back off { digitalWrite(MOTOR_4_DIR_PIN, LOW); analogWrite(MOTOR_4_SPEED_PIN, Speed); } // PWM control volatile int microsYStart = 0; volatile int microsXStart = 0; volatile int microsZStart = 0; volatile int yMicros = 0; volatile int xMicros = 0; volatile int zMicros = 0; int UScounter = 0; int USlock = 0; // Pin 0 interrupt handling void pin0Rising() { microsYStart = micros(); disableInterrupt(0); enableInterrupt(0, pin0Falling, FALLING); } void pin0Falling() { yMicros = micros() - microsYStart; disableInterrupt(0); enableInterrupt(0, pin0Rising, RISING); } // Pin 1 interrupt handling void pin1Rising() { microsXStart = micros(); disableInterrupt(1); enableInterrupt(1, pin1Falling, FALLING); } void pin1Falling() { xMicros = micros() - microsXStart; disableInterrupt(1); enableInterrupt(1, pin1Rising, RISING); } // Pin2 interrupt handling void pin2Rising() { microsZStart = micros(); disableInterrupt(2); enableInterrupt(2, pin2Falling, FALLING); } void pin2Falling() { zMicros = micros() - microsZStart; disableInterrupt(2); enableInterrupt(2, pin2Rising, RISING); } void setup() { for (int i = 3; i < 9; i++) pinMode(i, OUTPUT); for (int i = 11; i < 13; i++) pinMode(i, OUTPUT); pinMode(ULTRASONIC_TRIGGER_PIN, OUTPUT); pinMode(ULTRASONIC_ECHO_PIN, INPUT); pinMode(SERVO_PIN, OUTPUT); enableInterrupt(0, pin0Rising, RISING); enableInterrupt(1, pin1Rising, RISING); enableInterrupt(2, pin2Rising, RISING); } void loop() { // Eval motor signals int yValue = (yMicros - 1500) / 2; int xValue = (xMicros - 1500) / 2; if (yValue > 260 || yValue < -260) yValue = 0; if (xValue > 260 || xValue < -260) xValue = 0; int leftEngines = constrain(xValue + yValue, -250, 250); int rightEngines = constrain(yValue - xValue, -250, 250); // Check for obstacles every 10th iteration UScounter++; if (UScounter >= 10) { UScounter = 0; int frontDistance = sonar.convert_cm(sonar.ping_median(5)); if (frontDistance != 0 && frontDistance < DISTANCE_THRESHOLD_2) { if (frontDistance > DISTANCE_THRESHOLD_1) USlock = 1; else USlock = 2; } else USlock = 0; } if (USlock == 1) { leftEngines = constrain(leftEngines, -250, 128); rightEngines = constrain(rightEngines, -250, 128); } if (USlock == 2) { leftEngines = constrain(leftEngines, -250, 0); rightEngines = constrain(rightEngines, -250, 0); } if (abs(leftEngines) < 20) { M3_advance(0); M4_advance(0); } else if (leftEngines > 0) { M3_advance(leftEngines); M4_advance(leftEngines); } else { M3_back(-leftEngines); M4_back(-leftEngines); } if (abs(rightEngines) < 20) { M1_advance(0); M2_advance(0); } else if (rightEngines > 0) { M1_advance(rightEngines); M2_advance(rightEngines); } else { M1_back(-rightEngines); M2_back(-rightEngines); } } Pozwala on na kontrolowanie robota przy pomocy jednego drążka aparatury (dwóch kanałów). Oprócz tego program cyklicznie sprawdza odległość przed robotem i zabezpiecza przed wjechaniem w ścianę: w przypadku przeszkody znajdującej się bliżej niż 80 cm od robota, zostanie ograniczona jego maksymalna prędkość, natomiast jeżeli odległość ta będzie mniejsza niż 40cm, robot zatrzyma się całkowicie i niemożliwe będzie ruszenie nim do przodu. Wnioski To była prawdziwa frajda zobaczyć, jak robot rusza i jeździ zgodnie z instrukcjami z aparatury! Pierwszy skończony projekt. Nauczyłem się na nim dużo, bo okazało się, że w trakcie pracy podjąłem bardzo dużo nietrafnych decyzji. Robot tak naprawdę nigdy nie wyjechał z domu, ma bardzo otwartą konstrukcję, która sprzyja dostawaniu się do obudowy pyłu i piachu. W domowych warunkach wystarczyłby natomiast napęd na dwa koła - w ten sposób miałbym też trochę miejsca wewnątrz obudowy. Arduino Leonardo jest świetne, ale wielkie. Znacznie lepiej sprawdziłoby się Arduino Micro albo Teensy. To drugie nawet bardziej, bo shield do sterowania silnikami pożera dużo pinów i niewiele zostaje na odbiór sygnału z odbiornika RC. Udało mi się jeszcze podłączyć czujnik odległości, ale serwo wpiąłem już bezpośrednio w odbiornik, bo po prostu zabrakło mi pinów. Nie ma większego sensu robić żadnych projektów (innych niż wstępne prototypy) na przewodzikach połączeniowych. Lepiej kupić sobie płytkę prototypową, złącza goldpinowe, przewodziki kydexowe i polutować wszystko na płytce - układ zajmuje znacznie mniej miejsce i jest znacznie mniej podatny np. na przypadkowe wyjęcie przewodu. Chodzi mi po głowie wskrzeszenie projektu - właśnie przy pomocy Teensy oraz drukarki 3D, przy pomocy której mogę wydrukować całe nadwozie szyte na miarę. Ale podejrzewam, że zajmę się tym dopiero za jakiś czas...
  3. 2 punkty
    Przy kołach 26" masz około 2m na jeden obrót koła. To przy 2750 obrotach na minutę daje ci prędkość 5500m/minutę, czyli jakieś 3300km/h. Zakładając oczywiście brak oporów powietrza i toczenia, oraz dowolnie długi czas na pokonanie bezwładności tych twoich 100kg. I brak bariery dźwięku.
  4. 2 punkty
    To co robiłem jak najbardziej było testami jednostkowymi. A logika biznesowa to miejsce, gdzie takie testy dają najwięcej wartości i są najłatwiejsze do napisania.
  5. 2 punkty
  6. 2 punkty
  7. 2 punkty
    Raport mniejszości Oglądaliście kiedyś ten film? Główny bohater posługiwał się tam futurystycznym (przynajmniej jak na tamte czasy) interfejsem, którym sterował przy pomocy gestów. Fragment, który mam na myśli, możecie obejrzeć na Youtube. Osiągnięcie takiego poziomu zaawansowania wymaga oczywiście lat pracy, ale możemy spróbować skonstruować urządzenie, które będzie namiastką opisanego powyżej interfejsu. Koncepcja Zbudujemy urządzenie typu pan-tilt, czyli platformę obracającą się w dwóch osiach, sterowaną serwami. Sterowanie odbywać się będzie zdalnie, poprzez przechylanie telefonu komórkowego - platforma będzie próbowała naśladować gesty wykonywane przy pomocy telefonu. Platforma Na początku sama platforma - zdecydowałem się zaprojektować własną od zera, bazując na projekcie znalezionym na Thingiverse. Obrót w osi poziomej jest zmniejszony przez zębatkę - pozwala ona mniej więcej na 1/3 oryginalnego zakresu ruchu, ale za to jest on bardziej płynny. Obrót wokół osi pionowej jest natomiast nieograniczony. Pewnym kłopotem okazały się zębatki - przygotowanie dobrego koła zębatego wbrew pozorom wcale nie jest tak prostym zadaniem, jakim mogłoby się wydawać. Co więcej, nie ma również zbyt dużo narzędzi pozwalających na wygenerowanie prawidłowych kół zębatych. Po długich poszukiwaniach udało mi się jednak odnaleźć odpowiednie narzędzie - umożliwia ono konstruowanie kół zewnętrznych, wewnętrznych oraz listew zębatych: Gear Bakery. Wygenerowane koła zębate zapisywane są jako pliki .dxf, a te można już bez problemu wciągnąć do Fusion 360. Założyłem, że platforma będzie obracana zwykłymi, małymi serwami modelarskimi. Docelowo planowałem postawić na niej co najwyżej sportową kamerkę, więc moment rzędu 1.8 kg*cm jest tu całkowicie wystarczający. Pozostało wymodelowanie i wydrukowanie części, z których złożyłem potem platformę. Kontroler Tym razem potrzebowałem trochę więcej mocy obliczeniowej niż w wypadku prostszych projektów - w końcu musiałem postawić serwer odbierający dane po UDP - zdecydowałem się więc na Raspberry Pi. Serwer napisałem w Pythonie, bo język ten jest stosunkowo wysokopoziomowy i mocno separuje programistę od warstwy systemu i sprzętu: mogłem dzięki temu skupić się na istocie zadania, a nie na detalach implementacyjnych. Raspberry ma jednak pewną wadę - nie za dobrze radzi sobie z generowaniem sygnału PWM - sprzętowo może robić to tylko na jednym pinie. Co gorsza, standardowa biblioteka RPi.GPIO pozwala jedynie na programowe generowanie PWM - nie dawało to zbyt dobrych efektów. Na szczęście problem ten można bardzo elegancko obejść. Firma Adafruit przygotowała bowiem cwany układzik, który pozwala na sterowanie przy pomocy PWM aż dwunastoma niezależnymi urządzeniami, natomiast komunikacja tego układu z Raspberry odbywa się już po moim ulubionym protokole, czyli I2C. Układ ten rozwiązał jeszcze jeden problem, którego istnienie uświadomiłem sobie tak naprawdę w momencie, gdy właśnie zniknął. Serwa trzeba przecież jakoś zasilić, a nie można podłączyć ich do pinu 5V Raspberry - mają przecież znacznie większe zapotrzebowanie prądowe. PCA9685 w tym celu wyprowadza jednak szybkozłączkę, do której można podpiąć zewnętrzne zasilanie. Za każdym razem, gdy potrzebuję gdzieś 5V, zwykle robię mały przekręt: korzystam z kontrolera silnika bezszczotkowego, do którego przylutowałem wtyczkę T-Dean. Oprócz tego - co oczywiste - że ESC służy do sterowania silnikiem, obniża on również napięcie do 5V i przekazuje przewodami, które normalnie podłącza się do odbiornika RC. W pierwotnym zamyśle mechanizm ten nosił nazwę BEC - Battery Eliminator Circuit - i pozwalał w łatwy sposób zasilić odbiornik RC bez użycia dodatkowego akumulatora. Tymczasem wystarczy ominąć pin sterowania i mamy mały, wygodny, mobilny zasilacz na 5V. Konfiguracja Raspberry Aby mój skrypt w Pythonie uruchomił się, konieczne jest doinstalowanie biblioteki Adafruit pozwalającej na sterowanie kontrolerem PCA9685. Na początku trzeba oczywiście włączyć szynę I2C; robimy to w oknie konfiguracji Raspberry. Potem upewniamy się, że zainstalowane są następujące pakiety: sudo apt-get install python-smbus sudo apt-get install i2c-tools Po zainstalowaniu i2c-tools możemy użyć programiku i2cdetect, żeby sprawdzić, czy Raspberry prawidłowo wykrył kontroler PCA9685: ~ $ sudo ic2detect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: 70 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Teraz możemy ściągnąć i zainstalować bibliotekę do Pythona. sudo apt-get install build-essential python-dev cd ~ git clone https://github.com/adafruit/Adafruit_Python_PCA9685.git cd Adafruit_Python_PCA9685 sudo python setup.py install Uruchamiamy Do uruchomienia całego urządzenia potrzebujemy dwóch kawałków kodu, jednego mniejszego, drugiego większego. Tym mniejszym jest serwer w Pythonie, który steruje serwami. Możecie go ściągnąć z mojego repozytorium albo po prostu przekleić, bo jego kod jest stosunkowo krótki: # -*- coding: utf-8 -*- import socket import sys import time import Adafruit_PCA9685 # Częstotliwość sterowania PWM FREQUENCY = 50 # Czas jednego cyklu CYCLE_TIME = 1 / float(FREQUENCY) # Procentowy czas cyklu dla położenia minimalnego SERVO_MIN_PERCENT = 0.00055 / CYCLE_TIME # Procentowy czas cyklu dla położenia maksymalnego SERVO_MAX_PERCENT = 0.00245 / CYCLE_TIME # Wartość minimalna dla 4096 kroków SERVO_MIN = int(4096 * SERVO_MIN_PERCENT) # Wartość maksymalna dla 4096 kroków SERVO_MAX = int(4096 * SERVO_MAX_PERCENT) # Tworzymy obiekt pwm (przyjmie domyślnie adres 0x40) pwm = Adafruit_PCA9685.PCA9685() pwm.set_pwm_freq(FREQUENCY) def setAngle(channel, angle): pwm.set_pwm(channel, 0, int(SERVO_MIN + (float(angle) / 180.0) * (SERVO_MAX - SERVO_MIN))) def processCommand(command): angles = command.split("|") angles = list(map(lambda x: max(-90, min(90, -int(x.strip()))) + 90, angles)) print("P: {0}, Y: {1}".format(angles[0], angles[2])) setAngle(14, int(angles[0] / 10) * 10) setAngle(15, int(angles[2] / 10) * 10) def main(): # Create TCP/IP socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Bind the socket to the port server_address = ('', 10000) sock.bind(server_address) print("Waiting for data...") buffer = "" try: while True: data, addr = sock.recvfrom(32); buffer = buffer + data commandEnd = buffer.find(";") if (commandEnd != -1): command = buffer[0:commandEnd] buffer = buffer[commandEnd+1:] processCommand(command) except KeyboardInterrupt: print('Ctrl+C received, closing...') # Start program main() Drugi program jest już większy - to aplikacja na Androida, która pozwala na podłączenie się do serwera i przesyłanie informacji o orientacji telefonu. Ta również dostępna jest w moim repozytorium, tylko tym razem trzeba kod już ściągnąć i przebudować w Android Studio. Efekt Końcowy efekt na zdjęciu będzie wyglądał marnie, dlatego przygotowałem krótki filmik prezentujący, jak uruchomić cały projekt i jakie są efekty jego działania: Wnioski Serwa są bardzo wygodne w montażu i obsłudze, ale niestety również mało precyzyjne. Do takiego prostego projektu nadają się świetnie, ale w warunkach produkcyjnych trzeba byłoby wymienić je na ciche i dokładne silniki bezszczotkowe - takie, jakie są używane w gimbalach. Platforma reaguje na specyficzne ułożenie komórki; dzieje się tak dlatego, że komórka obrót wokół osi pionowej wysyła jako odchylenie od północy (0 stopni to północ). Tymczasem platforma "nie wie", w którą stronę jest zwrócona. Aby projekt był bardziej uniwersalny, można zastosować jedno z dwóch rozwiązań: dodać czujnik orientacji do platformy i kompensować różnice albo zapamiętać ułożenie komórki podczas łączenia do serwera i uznać je za pozycję "zerową". Mojemu projektowi daleko oczywiście do zaprezentowanego rozwiązania w "Raporcie mniejszości", ale nie ukrywam, że dał mi sporo frajdy. Można wykorzystać go jako bazę do zdalnego sterowania położeniem kamery lub na przykład ramienia robota.
  8. 2 punkty
  9. 2 punkty
  10. 1 punkt
    Nazwa RoChN - Robot o Chwytliwej Nazwie obejmuje trzy wersje robota (V1 - V3), które zbudowaliśmy z kolegą paor na początku w ramach eksperymentu, a następnie już jako pełnoprawna szkolna drużyna robotyczna KRÓL. Jest to jedna z ostatnich tego typu (procesor, brak enkoderów) konstrukcji na dużych zawodach w Polsce. Pomimo tego osiąga całkiem przyzwoite wyniki, zdarzyło mu się też powalczyć o podium, którego jednak nigdy nie zdobył. Opiszę po kolei wszystkie wersje, ponieważ nie różnią się na tyle, aby można było je uznać za osobne konstrukcje. Elektronika: Zastosowaliśmy mikrokontroler ATmega324 taktowany 16MHz kwarcem, 12 czujników linii KTIR0711s podłączone do trzech poczwórnych komparatorów LM339 i mostek H - TB6612FNG. Do komunikacji wykorzystaliśmy HC-05. Sekcja zasilania od wersji trzeciej składa się z dwóch stabilizatorów na 5V - osobnych dla czujników i logiki. Silniki są zasilane bezpośrednio z akumulatora 2s. Z akumulatorem 150mAh waży około 70g. Mechanika: Zastosowane silniki to Pololu HP 10:1. Sprawdziły się dobrze, chociaż za względu na dość znaczny przebieg szczotki są mocno zużyte. Robot składa się z dwóch dwustronnych płytek drukowanych połączonych aluminiowymi listewkami i taśmą ffc. Z tyłu znajduje się dodatkowa podpórka wykonana z kawałka drutu, która zapobiega odwracaniu się robota przy starcie z dużą prędkością. Przednia płytka posiada ślizgacze wykonane z rezystorów THT - sprawują się lepiej, niż stosowane do tego przedtem LEDy. Oprogramowanie: Program do robota został napisany w języku C. Realizuje on regulator PD, z którym było sporo problemów ze względu na brak wiedzy teoretycznej oraz doświadczenia w strojeniu. Powstał też program na komputer ułatwiający komunikację z robotem poprzez bluetooth i umożliwiający zmiany w konfiguracji, ręczne sterowanie i trochę innych "bajerów". Krótki opis zmian w kolejnych wersjach: -V1 Pierwsze podejście do zbudowania linefollowera na zawody. Wykonana domowymi metodami płytka okazała się być bardzo wadliwa i ostatecznie robot ten nigdy nie ruszył z miejsca - przód nie został nawet wyczyszczony z tonera. Większość elementów z płytki głównej została później wylutowana. Wyciągnęliśmy z tej porażki wiele wniosków, w końcu człowiek najlepiej uczy się na błędach. -V2 W przeciwieństwie do poprzednika robot posiada płytkę drukowaną wykonaną na zamówienie. Problemy spowodowały części projektu, które nie zostały przetestowanie przy okazji wersji pierwszej - stabilizator napięcia przegrzewał się i trzeba było dodać mu radiator w postaci kawałka drutu. Już na zawodach okazało się, że robot jest za szeroki, w wyniku czego miewał problemy z ciasnymi zakrętami. Pojawiły się też kłopoty z modułem bluetooth - legendarnym HC-05, który po jakimś czasie odmówił współpracy i trzeba było go wymienić. W międzyczasie zmieniliśmy też kształt przedniej płytki, jak się później okazało z kiepskiego na jeszcze gorszy. Wyciągnęliśmy z tej konstrukcji dużo wniosków, które wpłynęły na wersję trzecią. Na zdjęciach widać, że część elementów została wylutowana do ponownego użycia. -V3 Prawdopodobnie ostatnia wersja z tej serii, praktycznie pozbawiona błędów projektowych. Węższa i lżejsza. Oddzieliliśmy zasilanie czujników linii od reszty, a do połączenie przedniej płytki z tylną zastosowaliśmy taśmę o rasterze 0.5 mm. Również ta konstrukcja miała kilka przodów w ramach eksperymentów z ułożeniem czujników. Przez jakiś czas używaliśmy opon odlewanych z silikonu, jednak okazały się mniej przyczepne niż mini-z - może to kwestia braku doświadczenia w doborze proporcji. Podczas początkowych testów udało nam się dwa razy spalić mikrokontroler i zepsuć rezonator kwarcowy, który niezbyt umiejętnie wymieniłem - wydać to na zdjęciach. Osiągnięcia: 6. miejsce Robotic Arena 2019 4. miejsce Robomaicon 2019 Zdjęcia i filmy z zawodów: Wersja 2 na starcie lf drag na BBR 2018
  11. 1 punkt
    Dostępne na rynku oczyszczacze powietrza nie kosztują mało. Sam filtr, który wydaje się najważniejszym elementem kosztuje najczęściej nie więcej niż 1/3 oczyszczacza. Postanowiłem więc zbudować własny oczyszczacz. Oczywiście czas poświęcony na budowę też ma wartość, ale nie traktuje tego jako roboczogodziny a po prostu zabawę . W moim przypadku, koszt całości wyniósł około 300zł. Dla porównania, gotowy oczyszczacz Xiaomi to wydatek około 500zł, jesienią było to minimum ~650zł . Kupiłem filtr Xiaomi z wkładem węglowym, który jest nieco droższy niż zwykły, który montowany w fabrycznych oczyszczaczach. Użyty przeze mnie wentylator posiada według producenta wydajność 150m³/h co jest wartością 2x mniejszą niż fabryczny oczyszczacz. Jest to jednak w zupełności wystarczające. Mechanika Oczyszczacz składa się z filtra powietrza, wentylatora 200mm, łącznika filtra z wentylatorem i sterownika. Łącznik został wydrukowany na drukarce 3D. Wentylator to najtańszy wentylator 200mm jaki znalazłem w sklepie komputerowym. Elektronika Całość bazuje na płytce z ESP32. Na niej znajduje się shield prototypowy Arduino, a do niego są zamontowane kolejne elementy. Używałem głównie gotowych modułów. Starałem się w miarę możliwości nie lutować ich bezpośrednio do PCB tylko umieszczać na listwach kołkowych. Schematu niestety nie mam. Wszystko było lutowane na bieżąco w przypływach weny Planuje jeszcze wyprowadzić drugą szynę I2C i podłączyć do niej drugi barometr który będzie umieszczony w wewnętrznej części filtra. Będę mógł w ten sposób zbadać zależność różnicy ciśnień od obrotów wentylatora. Czujniki Jako czujnik pyłu zastosowałem GP2Y1010AU0F. Kluczem była niska cena. Niestety wymaga on dość dokładnego synchronizowania w czasie załączania diody LED i pomiaru napięcia wyjściowego. Z czym miałem duże problemy o czym napiszę niżej. Dodatkowo, jako że jest to czujnik analogowy, jego wyjście skaluje się względem napięcia zasilania. A tak się składa że o ile ESP32 jest zasilane ze stabilnych 3.3V, to czujnik jest zasilany z szyny 5V. Tutaj występuje wyraźny rozstrzał między zasilaniem z zasilacza (wtedy szyna 5V jest zasilana przez diodę która powoduje spadek napięcia) a zasilaniem przez USB. Staram się to kompensować dodatkowym pomiarem napięcia szyny 5V. Nie jest to idealnie, choć daje dużo. Prawdopodobnie czujnik nie skaluje swojego wyjścia idealnie liniowo z napięciem zasilania, stąd ten problem. Oprócz tego na płytce znajduje się czujnik wilgotności HDC1080 oraz ciśnienia BMP280. Oba mają wbudowane termometry, więc nie potrzeba dodatkowego. Teraz prawdopodobnie użyłbym BME280. Interfejs W sterowniku użyłem wyświetlacza OLED. Wyświetlane są na nim aktualne parametry, takie jak: temperatura, wilgotność, poziom zanieczyszczeń, moc wentylatora i inne. Wyświetlacz jest sterowany za pomocą interfejsu I2C. Obok wyświetlacz znajduje się enkoder. Użyłem gotowego modułu bo akurat nie miałem pod ręką tego typu enkodera z przyciskiem. Można nim regulować moc oczyszczacza oraz przełączać między trybami: "auto" i "manual". Oczywiście jak na 2019 rok przystało, oczyszczaczem można sterować też po WiFi :) Na ESP32 jest uruchomiony webserver. Panel webowy wygląda tak: W kodzie znajdują się funkcje które utrzymują stałą łączność WiFi z routerem. Dane dostępowe do znanych nam WiFi należy umieścić w pliku "wifi_credentials.json" i wgrać wraz z innymi plikami. Niestety hasła należy umieścić w formie tekstowej. Biblioteka micropythona do obsługi WiFi nie obsługuje haseł w wersji zahashowanej (PSK). W przyszłości może dopiszę bardziej ludzką formie wprowadzania haseł Sterowanie wentylatorem Z racji tego że użyłem najtańszego wentylatora o tej średnicy, posiada on tylko 3 pinową wtyczkę. Taki wentylator można sterować jedynie napięciowo. Wymyśliłem więc sposób na regulację PWMem napięcia wyjściowego przetwornicy impulsowej. Polega to na podkradaniu lub wprowadzaniu dodatkowego prądu do wyjściowego dzielnika napięcia. Schemat tego wygląda następująco: Zauważyłem że im mniejsza częstotliwość sygnału PWM, tym bardziej nieliniowa jest zależność Vout=f(PWM). Dlatego częstotliwość PWM została ustawiona na 312kHz. Aproksymacje tej funkcji stworzyłem robiąc pomiary Vout w zależności od danego wypełnienia PWM, a następnie w arkuszu kalkulacyjnym wyznaczyłem współczynniki funkcji liniowej. Współczynniki te są na sztywno zapisane w kodzie. Micropython Zdecydowałem się użyć micropythona ze względu na chęć nauki czegoś nowego. Niestety, jak okazało się w trakcie, posiada on wiele ograniczeń. Największą wadą jest używanie blokującego dostępu do interfejsów komunikacyjnych. Przez co np.: w trakcie odświeżania wyświetlacza nie można dokonywać pomiarów czujnika pyłu czy obsługiwać żądań serwera. Ne można też używać drugiego rdzenia ESP32. Przez co interfejs użytkownika chodzi wyraźnie wolno, i nie wygląda na uruchomiony na czymś tak mocnym Cały kod jest dostępny na GitHubie: https://github.com/Harnas/ESP32_Airpurifier
  12. 1 punkt
    Bardzo fajne wykonanie. Jakieś 2 lata temu zrobiłem podobny feeder. Ale Twój wygląda o wiele lepiej. Kotki widzę że również zadowolone. Świetna robota !
  13. 1 punkt
  14. 1 punkt
    Dziękuję za głosy na Cukiereczka oraz za przesłany zestaw gadżetów!
  15. 1 punkt
    @adusn86 Wszystko co ma efekt "wow" kosztuje. Żyroskop do mojego robota kosztował z 5 zł, ale podejrzewam że w Segwayach są dokładniejsze. Cały mój robot nie jest zbyt dokładny co widać po tym jak się trzęsie, choć to pewnie głównie zasługa silników. Są to drogie pojazdy, ale jak się doda wszystko razem to koszt części niski nie jest, a że ich główne zastosowanie jest w specjalistycznej branży to i marżę można dodać sobie większą. @ethanak Zgaduję że dzięki temu taka noga będzie się sama naturalnie zginać w kolanie, tak jak to robi ludzka noga. Nogi mam swoje i nigdy nie miałem do czynienia z protezami, ale tak zgaduję. Drugą opcją która przychodzi mi do głowy to balansowanie tej nogi. Zauważ że jak stoisz, pomimo że się nie ruszasz to mięśnie w nodze cały czas pracują aby utrzymać cię w pionie, a szczególnie palce u stopy. Z tego co słyszałem, osobom które straciły palce u nóg ciężej jest utrzymać stabilność. Bardzo dobrze to widać na robocie, który pomimo że ma za zadanie stać prosto, cały czas musi korygować swoją pozycję i silniki cały czas pracują, w przeciwnym wypadku od razu się wywala. Osoby z protezą nogi często chodzą o kulach, chociaż teoretycznie ilość kończyn jest taka sama. Sztuczna noga nie zapewnia jednak tego balansu który zapewnia prawdziwa. To wszystko moje domysł, poczekajmy aż Adusn się wypowie
  16. 1 punkt
    W sumie Arduino to taka zabawka... edukacyjna co prawda ale jednak zabawka. Co w tym dziwnego, że większość projektów powstałych na bazie zabawki to po prostu zabawki następnej generacji? Pokaż przykłady projektów które były: bajerami duperelami aby potwierdzić swoją opinię. Twierdzenie że "coś tam to większość" to nie to forum - tu siedzą ludzie przyzwyczajeni (abo tacy, którzy powinni się przyzwyczaić) do ścisłych sformułowań
  17. 1 punkt
    @roger_z >"Założę się, że to były po prostu testy dlatego, że miały jakieś być." Nie, było to TDD. I w dodatku prowadzący z którymi to było są na co dzień seniorami w pewnej dużej firmie IT, jeśli ma to tu jakieś większe znaczenie. >"warto mieć testy, żeby przy refactoringach czegoś nie popsuć." Jeśli zmienia się również interfejsy to trzeba wtedy pisać od nowa testy. Przy takim dynamicznym kodzie chyba lepiej pisać testy po napisaniu kodu.
  18. 1 punkt
    #2 Klawiatura na Arduino to dość przydatna sprawa. Tylko że jak ma się podobne komercyjne rozwiązania to własne DIY odchodzą na drugi plan. Ale jest w tym trochę prawdy, że ciężko wymyślić coś naprawdę praktycznego. Ostatnio zainteresowało mnie modelarstwo (modele HO lokomotyw, semafory itp...) jest to temat, w którym za prosty sterownik diody świecącej płaci się po kilkadziesiąt $. Myślę, że to jest obszar, w którym znajomość Arduino i podstaw elektroniki pozwala zaoszczędzić sporo pieniędzy.
  19. 1 punkt
    To jakiego typu projekty chciałbyś widzieć w wykonaniu hobbystów? Ludzie budują głównie to na co mają ochotę i to, co sprawia im frajdę. Takie kolorowe gadżety buduje się najprzyjemniej
  20. 1 punkt
    Wszystkie osoby, których projekty zostały zgłoszone w tym temacie powinny właśnie otrzymać prywatną wiadomość z kodami rabatowymi Wyjątkiem są jedynie te osoby, które poprosiły o wygenerowanie zsumowanych kodów na koniec akcji. Jeśli ktoś nie otrzymał kodu to jest to jedynie moje przeoczenie, proszę wtedy o wysłanie prywatnej wiadomości. Kody będę otrzymywał w tej chwili już znacznie szybciej, więc autorzy wszystkich nowych DIY otrzymają swoje rabaty na początku następnego tygodnia. PS Ukryłem wcześniejsze wiadomości dotyczące ręcznego przydzielania rabatów, aby nie wprowadzać nikogo w błąd.
  21. 1 punkt
    Nie zdążyłem edytować postu, żeby to dopisać Odnośnie tego linku Elvisa - można znaleźć też wiele prób "polemizowania" z nim np to: https://dmerej.info/blog/post/my-thoughts-on-why-most-unit-testing-is-waste/ I pokazuje te opisane rzeczy z innych stron. Też warte przeczytania jako uzupełnienie. Co do postu wyżej - przykład z testowaniem rzeczy, które wiemy, że byłoby ciężko wywołać w sesji debugowania - to mógłbyś nawet umieścić w artykule w sekcji "Problemy typowe dla systemów embedded" - wydaje mi się to bardzo ważnym argumentem za testami - w wielu przypadkach "unhappy path"e są jakoś pomijane bo ciężko je wywołać/wymusić na zewnętrznym układzie, żeby nam przesłał "zepsutą" ramkę.
  22. 1 punkt
    TDD sprawdza się tam, gdzie masz do napisania jakąś logikę aplikacji. Z przykładów mogę podać np. protokoły komunikacyjne. Pisałem ich już trochę i TDD jest świetne do sprawdzania przekłamania pól w ramkach, retransmisji, timeoutów, handshakeów i innych tego typu procedur, które ciężko jest dobrze napisać, a debugowanie jest problematyczne, bo czasem ciężko wywołać te błędy. Poza tym później jak się na przykład zmieni się długość i kolejność pól to bez unit testów nawet mała zmiana może oznaczać całe dni debugowania. Pisałem też w ten sposób różne sterowniki z logiką typu wyłącz awaryjnie, jeżeli przez określony czas sygnał jest powyżej progu. Poza tym obliczenia zawierające logikę, obsługa błędów, triggerowanie eventów. W tych wszystkich zastosowaniach TDD po prostu pomaga. Owszem, pracowałem też ze źle napisanymi testami i faktycznie jest to udręka. Jednak często wystarczą proste refactoringi typu podzielenie ogromnego testu, w którym nie wiadomo o co chodzi na wiele małych skupionych na jednym zadaniu. Wtedy jak taki test nie przechodzi, od razu nazwa daje wskazówkę co jest nie tak. Inna sprawa, że zwykle trudność w testowaniu pokazuje problemy z implementacją np. wielka funkcja robiąca wiele rzeczy na raz. Sformułowania takie jak: w stosunku do TDD są bardzo niesprawiedliwe. Zwykle jest właśnie w drugą stronę - duże projekty bez testów jednostkowych też czasem przez przypadek mogą działać poprawnie, ale jest to raczej wyjątek od reguły.
  23. 1 punkt
  24. 1 punkt
    Mało wiadomo o całym napędzie w tym rowerze. Jeżeli to nie jest silnik typu hub (a wnioskuję, że nie jest) to musisz dodać przekładnię zmniejszającą obroty. Pomyśl jaką prędkość chcesz osiągnąć (np 20km/h), oblicz obwód Twojego koła i policz jakie przełożenie potrzebujesz między silnikiem a kołem do osiągnięcia takiej prędkości. Pomijasz tutaj sprawności, opory toczenia, moce itd.
  25. 1 punkt
  26. 1 punkt
    poszukaj bibliotek mających w nazwie "button" - co najmniej jedna (nie pamiętam teraz która a nie mam jak sprawdzić) obsługuje długie i krótkie przyciśnięcia.
  27. 1 punkt
    Może zamiast jechać po bandzie, zapomnij o tabelce ABSOLUTE MAXIMUM RATINGS i trzymaj się wartości z tabelki ELECTRICAL CHARACTERISTICS. Będzie zdrowiej dla mostka.
  28. 1 punkt
  29. 1 punkt
  30. 1 punkt
  31. 1 punkt
  32. 1 punkt
    Ankieta w artykule była ważna do niedzieli. Swoje głosy oddały łącznie 62 osoby, wszystkim głosującym dziękuję za wskazanie swoich faworytów. Za najlepszą konstrukcję tego zestawienia uznaliście Cukiereczka, czyli robota typu linefollower. Gratulacje dla autora, który zgodnie z wcześniejszym ogłoszeniem wygrywa zestaw gadżetów Forbota. @mice.co, czekam na kontakt w wiadomości prywatnej - podaj adres do wysyłki
  33. 1 punkt
  34. 1 punkt
  35. 1 punkt
  36. 1 punkt
  37. 1 punkt
  38. 1 punkt
  39. 1 punkt
  40. 1 punkt
  41. 1 punkt
    https://forbot.pl/forum/topic/13529-lernek-zabawka-edukacyjna-dla-mlodszego-brata/
  42. 1 punkt
  43. 1 punkt
  44. 1 punkt
    Witam serdecznie To mój pierwszy wpis na tym forum. Na wstępie chciałbym podziękować za kurs arduino. Mając 32 lata i będąc humanistą zainteresowałem się tą małą, ale jakże ciekawą płytką. Wasz kurs bardzo pomaga w zrozumieniu o co chodzi w tym "tajemnym programowaniu". Jestem na początku drogi i pewnie jeszcze długo będę się czuł jak dziecko we mgle, ale postanowiłem podzielić się rozwiązaniem zadania nr 2.4. Program zdaje się działać prawidłowo, ale wolałbym by ktoś mądrzejszy to ocenił. #define zielona 8 #define czerwona 9 String odebraneDane = ""; // pusty ciag odebranych danych void setup () { Serial.begin(9600); // inicjalizacja połaczenia z pc pinMode(zielona, OUTPUT); // konfiguracja wyjsc pinMode(czerwona, OUTPUT); digitalWrite(zielona, LOW); // wyłaczamy diody na starcie digitalWrite(czerwona, LOW); } void loop () { if(Serial.available() > 0) { //czy arduino odebrało dane //jesli tak, to odczytaj je do znaku konca linii i zapisz w zmiennej odebraneDane odebraneDane = Serial.readStringUntil('\n'); if (odebraneDane == "zielona"){ // jesli odebrano słowo "zielona" digitalWrite(zielona, HIGH); //to włączamy diode zielona delay(1000); digitalWrite(zielona, LOW); } if (odebraneDane == "czerwona") { digitalWrite(czerwona, HIGH); // to włącz diodę czerwoną delay(1000); digitalWrite(czerwona, LOW); } if (odebraneDane !="czerwona" and odebraneDane!="zielona") { Serial.println("Podales zly kolor!"); } }}
  45. 1 punkt
    W końcu zabrałem się za kurs i tydzień temu w sobotę odebrałem paczkę z elementami. Dzisiaj można powiedzieć, go że ukończyłem . Wykonałem wszystkie zadania i trochę eksperymentowałem. Bardzo dziękuje za stworzenie kursu, wszystko bardzo fajnie opisane i pokazane. Wkrótce zabieram się za część drugą. Dziękuje raz jeszcze za włożoną pracę w napisanie ciekawych artykułów i przygotowania tego wszystkiego. Dodam jeszcze, pewnie przez niektórym znaną, stronę na której można zobaczyć działanie układów, które robimy. Lepiej zrozumiałem dzięki niej ostatni układ i polecam jej przejrzenie, choć oczywiście nie zastąpi ona samego składania układów . W linku zrobiony przerzutnik bistabilny z ostatniego artykułu na stronie o której pisałem:Link
  46. 1 punkt
    Robicie świetną robotę na blogu, kursy obejmują wiele poziomów trudności. Lutowany układ posłużył mojej dziewczynie jako oświetlenie w tle małego drzewka, nie schowałem go do szafki. Zostałem Waszym patronem z wielką przyjemnością! Dzięki kursowi lutowania dużo się już nauczyłem, czekam na więcej
  47. 1 punkt
    Wielkie dzięki za długo wyczekiwany rozdział kursu! Rewelacyjna narracja pozwala mi na bezproblemową przesiadkę ze środowiska Arduino do dużo bardziej skomplikowanego kodowania STM32 przy użyciu Cube. Opis jest prosty, systematyczny i treściwy. Z niecierpliwością czekam na dalsze odcinki (m.in. USB host)!
  48. 1 punkt
  49. 1 punkt
    Dziękuję serdecznie za ten kurs! Dla takich początkujących jak ja jest idealny! A jako sumienny uczeń również pozwolę sobie pokazać swoją "pracę domową" Najwięcej czasu zajęło mi dobieranie rezystora dla czerwonej diody, by ją całkiem wygasić. Ostatecznie wpadłem na pomysł, by na chwilę podłączyć potencjometr, ustawić odpowiednią do wygaszenia wartość, następnie zmierzyć opór potencjometru i wstawić właściwy opornik - w moim przypadku 390 Ohm. Na zdjęciach nie bardzo widać, że te diody na prawdę świecą, więc dla porządności jeszcze "filmik": Serdecznie pozdrawiam i biorę się za następne zadania!
  50. 1 punkt
    Kozacki kurs, naprawdę dawno nie widziałem w sieci tak pożytecznego materiału... Ja wiem, że trochę wazelina, ale co tam Trzymajcie tak dalej...
Tablica liderów jest ustawiona na Warszawa/GMT+02:00
×
×
  • Utwórz nowe...