http://forbot.pl/blog/wiadomosci/robot-szybki-jak-usain-bolt-motywuje-do-biegania-id15017
Monthly Archives: maj 2016
Arduino: Przerwania + TCRT5000 do wykrywania szybkości obrotowej koła (04-05-2016)
Warto poczytać: https://www.arduino.cc/en/Reference/AttachInterrupt
oraz zapamiętać:
Płytka | Piny cyfrowe pod które możemy podpiąć przerwania |
Uno, Nano, Mini, other 328-based | 2, 3 |
Mega, Mega2560, MegaADK | 2, 3, 18, 19, 20, 21 |
Micro, Leonardo, other 32u4-based | 0, 1, 2, 3, 7 |
Zero | wszystkie, za wyjątkiem 4 |
MKR1000 Rev.1 0 | 0, 1, 4, 5, 6, 7, 8, 9, A1, A2 |
Due | wszystkie |
oraz ,,zdarzenia”, podczas których uaktywni się funkcja przypisana pod dane przerwanie: LOW, CHANGE, RISING, FALLING (HIGH – tylko płytka Due). Krótko: funkcja „podpięta” do przerwania wywoła się wówczas, gdy na tym pinie (tym = zdefiniowanym podczas attachInterrupt) zajdzie konkretne „zdarzenie”, np. LOW. Oczywiście taka funkcja ma być szybka: ustalenie flagi, sterowanie napięciem na pinach – digitalWrite – ale nie delay(ileś-tam).
Przykład: Arduino + przycisk do błyskania diodą #13. Hardware: przycisk (mikroswicz podłączamy do GND a drugą nóżką do pinu #2 w Arduino).
#define PIN 2 bool stan=false; void setup() { pinMode(13, OUTPUT); digitalWrite(13, 0); pinMode(PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(PIN), blysk, LOW); } void loop() { delay(10000); } void blysk(){ stan=!stan; digitalWrite(13, stan); }
Gdy nic nie wiemy o przerwaniach, to przyglądając się funkcji loop() można by powiedzieć, że program NIC NIE ROBI! Tylko czeka 10s, a potem znowu czeka 10s, i tak w kółko… Więc skąd się bierze błyskanie diody #13 w momencie klikania przycisku? Otóż wywołanie delay() zatrzymuje działanie programu, ale przerwania ciągle działają. Skoro więc „podpięliśmy” naszą funkcję (o nazwie blysk()) do przerwania, to właśnie ona się wywoła (gdy stan pinu #2 zmieni się na LOW – to wszystko zostało powiedziane w funkcji setup()). Właśnie taki mechanizm wykorzystałem do wykrycia kolizji przez zderzak naszego pojazdu – pisałem o tym w poprzednim poście. UWAGA: powyższy program działa dość dynamicznie, „nerwowo” reagując na wciśnięcie przycisku – oczywiście jest to zjawisko drgania styków (ang. bouncing), o czym mówiliśmy na naszych poprzednich spotkaniach (tutaj, dla przejrzystości kodu nic z tym nie robię, brak jest debouncing-u).
Dodatkowo: zliczanie obrotów koła.
podłączyliśmy czujnik optyczny odbiciowy TCRT5000 do obudowy silniczka, a następnie wewnątrz koła umieściliśmy białą kartkę z czarną krechą. Czytamy wartości rejestrowane przez czujnik ale nie na Serial monitorze, ale GRAFICZNIE, za pomocą Processinga.
Widzimy wyraźnie moment, gdy czujka mija czarną kreskę. Widać też, że piki zdecydowanie różnią się od „tła”, choć często mają różną wartość w maksimum. Łatwo wykombinować prosty algorytm (czy skuteczny? niedługo się o tym przekonamy) liczący szybkość obrotową koła:
- zapisujemy t1, czyli czas pojawienia się maksimum (funkcja millis())
- czekamy na kolejne maksimum, gdy je złapiemy to
- zapisujemy t2, czyli czas pojawienia się kolejnego maksimum- wówczas różnica czasów t2 i t1 daje właśnie czas jednego, pełnego obrotu.
Pewnie „diabeł tkwi w szczegółach” ale powinno działać. Jak powiedziałem na zajęciach – więcej kresek (ale z umiarem! powiedzmy 4 na początek) powinny zwiększyć rozdzielczość zliczania liczby obrotów koła.
Będziemy to programować na kolejnych zajęciach…
Arduino: software do zderzaków – przerwania
Zmodyfikowana wersja softu ze zderzakami – tym razem użyłem przerwań i w przypadku kliknięcia przeszkody – w przerwaniu zmieniam pomocniczą zmienną informującą o konieczności cofnięcia i zmiany kierunku ruchu. Działa nieźle.
Poprzednia wersja softu prowadziła pojazd w danym kierunku z wykorzystaniem funkcji delay(ileś-tam), a dopiero potem sprawdzała przyciski (mikrostyki) – to powodowało, że gdy zderzenie nastąpiło w czasie jazdy, to takie zdarzenie mogło nie być zarejestrowane (nie zawsze się zdarzało, że przycisk pozostawał wciśnięty po zakończenia delay). Tutaj rozwiązałem to za pomocą dwóch przerwań… wiem – za dużo, już w głowie mam lepszy algorytm, bez przerwań, ale to w następnym odcinku.
Dla bardziej dociekliwych:
#define LEFT_BTN 2 #define RIGHT_BTN 3
(w przypadku Arduino UNO przerwania tylko dla pinów 2 i 3), dalej:
pinMode(LEFT_BTN, INPUT_PULLUP); pinMode(RIGHT_BTN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(LEFT_BTN), turn_right, LOW); attachInterrupt(digitalPinToInterrupt(RIGHT_BTN), turn_left, LOW);
to w setup()ie,
a dwie funkcje turn_left() i turn_right() zmieniają pomocnicze zmienne nakazujące zmianę kierunku ruchu (w funkcji loop).