Zmieniam godziny naszych cotygodniowych spotkań – od najbliższych zajęć (wtorek, 6 marzec) widzimy się w godzinach 14:15-15:45 (plus/minus ewentualne przedłużenia do 16-tej). Jak zawsze zajęcia we wtorki w sali 1064. Do zobaczenia!
KG
Zmieniam godziny naszych cotygodniowych spotkań – od najbliższych zajęć (wtorek, 6 marzec) widzimy się w godzinach 14:15-15:45 (plus/minus ewentualne przedłużenia do 16-tej). Jak zawsze zajęcia we wtorki w sali 1064. Do zobaczenia!
KG
Na zajęciach wykorzystaliśmy proste elementy do zbudowania prototypu maszyny badającej nasz refleks. Ale od początku.
Moduł posiada trzy piny – GND oraz Vcc to zalsilanie, S to stygnał wysyłany przez płytkę (na innych płytkach często oznaczony OUT). My używamy modułów firmy RobotDyn (o nazwie Button Switch module) i trzeba przyznać im dobrą jakość wykonania. Na dodatek układy te mają wbudowanego LED-a informującego o wciśnięciu przycisku.
Najpierw sprawdzamy, czy po wciśnięciu przycisku Arduino „zobaczy” jedynkę (stan HIGH) czy „zero” (stan LOW). Prosty programik poniżej:
#define gdzie 7 void setup(){ pinMode(gdzie, INPUT); Serial.begin(9600); } void loop(){ Serial.println(digitalRead(gdzie)); delay(100); }
Bibliotyki Arduino wyposażone są w funkcje pseudo losowe – czyli takie, które generują liczby „udające” prawdziwe liczby losowe. Mowa tu o funkcji rand() – aby to sprawdzić piszemy poniższy kod:
void setup(){ Serial.begin(9600); } void loop(){ Serial.print("czas= "); Serial.print(millis()); Serial.print(" los="); Serial.printtln(rand()); delay(100); }
Widzimy więc duuuuuże (i losowe!) liczby całkowite, które wyświetlają się co 100ms. Aby z takich liczb zbudować coś konkretnego, np. typowy rzut kostki do gry – trzeba to lekko zmodyfikować przez użycie funkcji reszta z dzielenia całkowitego (tzw. modulo, symbol % w języku C/C++):
void setup(){ Serial.begin(9600); } void loop(){ Serial.print("czas= "); Serial.print(millis()); Serial.print(" kostka="); Serial.printtln(1 + rand()%6); delay(100); }
Jak to działa? Reszta z dzielenia całkowitego przez 6 zwraca liczby z przedziału 0..5, ale my dodajemy jeszcze jedynkę – otrzymujemy liczby 1…6 – czyli naszą kostkę do gry. W ten właśnie sposób możemy modyfikować wynik funkcji rand() i dopasowywać ją do naszych potrzeb.
Podłączyliśmy niebieskiego LED-a bezpośrednio do pinu 13 Arduino i GND – bez dodatkowego, wymaganego opornika. Nie jest to poprawne połączenie (brak opornika = uszkodzenie LED-a), ALE niebieskie LEDy mają (wysokie) napięcie przewodzenia, około 3V. Arduino zasili je jednak 5V – co jest za dużo – i uszkadzamy naszego LED-a, ale go nie zniszczymy (celowo wybrałem niebieski LED, a nie inny – inne LEDy pracuą na napięciu ~2V, więc 5V by je zniszczyło). Zależy mi tutaj na prostocie budowy układu więc darowałem sobie niezbędny opornik (no i nie chiałem korzystać z wbudowanego LEDa #13 – bo jest mały i niewyraźny).
Chwilowo odłożyliśmy moduł z przyciskiem i zaprogramowaliśmy włączenei LED-a po losowym czasie od 5s, do 15s:
#define LED 13 void setup(){ pinMode(LED, OUTPUT); } int i; void loop(){ //odczekanie 5..15 sekund delay(5000+ rand()%10000); //wlaczenie LED-a digitalWrite(LED, HIGH); delay(1000); digitalWrite(LED, LOW); //miganie - znak, ze za chwile powtarzamy zabawe for (i=0; i<4; i++){ digitalWrite(LED, HIGH); delay(200); digitalWrite(LED, LOW); delay(200); }//miganie }
Warto pobawić się z tym programem, uzupełniając go o dodatkowe informacje wyświetlane przez monitor portu szeregowego – informujące, że trwa losowe czekanie, a potem, że włączono LEDa i na koniec – że zabawa od początku się zaczyna.
Wracamy do przycisku – rozbudowujemy poprzedni program o odczytanie momentu wciśnięcia przycisku. Użytkownik ma to zrobić w momencie zapalenia się niebieskiego LEDa — tylko, że nie wiadomo, kiedy to dokładnie nastąpi (losowy czas z poprzedniego programu). Na koniec wyświetlimy czas jego reakcji – jego refleksu 😉
#define LED 13 #define gdzie 7 void setup(){ pinMode(gdzie, INPUT); pinMode(LED, OUTPUT); Serial.begin(9600); } int i; unsigned long int t1,t2; void loop(){ Serial.println("START!"); //odczekanie 5..15 sekund delay(5000+ rand()%10000); t1=millis(); //wlaczenie LED-a digitalWrite(LED, HIGH); while (digitalRead(gdzie)== HIGH); t2=millis(); digitalWrite(LED, LOW); Serial.print("Rekacja (refleks)="); Serial.print(t2-t1); Serial.println(" ms"); delay(500); //miganie - znak, ze za chwile powtarzamy zabawe for (i=0; i<4; i++){ digitalWrite(LED, HIGH); delay(200); digitalWrite(LED, LOW); delay(200); }//miganie }
Kluczowa jest linia #17 – to w niej następuje zatrzymanie działania programu i oczekiwanie na rekację użytkownika. Zrealizowałem to za pomocą pętli podczytującej przycisk – w moim module naciśnięcie przycisku powoduje odczyt stanu LOW, natomiast stan HIGH oznacza brak wciśnięcia. Jak widać ta pętla NIC nie robi. Właśnie o to mi tu chodziło – pętla nic nie robi, więc ponownie wracamy do sprawdzenia warunku pętli while – bez straty czasu. I tak w kółko, aż w końcu naciśnięty zostanie przycisk.
A jak mierzę czas? Za pomocą funkcji millis() – która zwraca czas (w milisekundach) od uruchomienia Arduino. Robię to dwukrotnie – przed odczytaniem przycisku zapisuję do zmiennej t1, a po naciśnięciu przycisku – do zmiennej t2. Różnica tych czasów jest właśnie Twoim czesem reakcji – Twoim refleksem.
Program należy rozbudować – o dwa przyciski, dwa LEDy. To wzbogaci zabawę, bo losowo zapali się albo jeden LED, albo drugi. Warto wybrać dwa kolory LED-ów i dwa kolory przycisków. To będzie dodatkowe utrudnienie dla użytkownika – ma on bowiem wcisnąć odpowiedni przycisk (np. LED żółty – to i przycisk żółty, a nie niebieski. Niebieski to dyskwalifikacja! I na odwrót).
Inna modyfikacja polega na wychwyceniu falstartu – zapobiegnięciu sytuacji, że użytkownik bezmyślnie „klika” przyciskiem w nadziei, że gdy LED się zaświeci – on właśnie wcisnął przycisk i otrzymał bardzo krótki czas reakcji. Trzeba tak zrobić, aby wciśnięcie przycisku PRZED zaświeceniem kończyło zabawę. Podpowiedź: zamiast funkcji delay() w linii #13 trzeba sprytnie wykorzystać pętlę while…
(c) KG 2018
Przedłużamy przerwę w spotkaniach Fi-BOTa ze względu na „walkę o zaliczenia” w ramach sesji poprawkowej. Widzimy się 27-go lutego (wtorek, jak zawsze 16:00).
KG