Gridi the Bot - RC Mode
Modyfikacja platformy Gridi the Robot do wersji zdanie serwowanej
Supplies
- 1 x Arduino Pro Micro
- 2 x nRF24L01
- 2 x HW-200
- 1 x joystick
- 2 x dystanser M3x10+6
- 2 x dystanser M3x20
- 2 x nakrętka M3
- 6 x śrubka M3x6
Wydruk Elementów
Materiał: PLA
Dysza: 0,4 mm
Wysokość warstwy: 0,2 mm
Wypełnienie: Gyroid 30%
Modyfikacja Robota
L298N
Podpięcie w Arduino przesunąć o 1 w lewo:
- ENA - 10
- IN1 - 9
- IN2 - 8
- IN3 - 7
- IN4 - 6
- ENB - 5
nRF24L01
- CE -> 2
- CSN -> 4
- SCK -> 13
- MO -> 11
- MI -> 12
- GND -> GND
- VCC -> 5V
Pilot
joystick
- GND -> GND
- +5V -> 5V
- VRX -> A1
- VRY -> A0
- SW -> 10
nRF24L01
- CE -> 9
- CSN -> 8
- SCK -> 15
- MO -> 16
- MI -> 14
- GND -> GND
- VCC -> RAW (nie powinno się tak podpinać, ale ze względu na brak dodatkowego pinu 5V wykorzystamy go)
Komunikacja Bezprzwodowa
Proces komunikacji
Moduł nRF24L01 jest niewielkim układem elektronicznym służącym do bezprzewodowej komunikacji między urządzeniami elektronicznymi, np. między dwoma mikrokontrolerami Arduino. Dzięki niemu urządzenia mogą przesyłać informacje bez użycia kabli, wykorzystując fale radiowe.
Proces komunikacji zaczyna się w mikrokontrolerze. Program działający na Arduino przygotowuje dane, które mają zostać wysłane. Mogą to być na przykład liczby z czujnika, polecenia sterujące lub inne informacje. Dane te są przekazywane do modułu nRF24L01 za pomocą cyfrowej komunikacji SPI (Serial Peripheral Interface).
Po otrzymaniu danych moduł nRF24L01 przygotowuje je do transmisji radiowej. Najpierw tworzy tak zwany pakiet danych. Pakiet jest niewielką strukturą informacji, która zawiera kilka elementów:
- adres odbiorcy - identyfikator urządzenia, do którego wiadomość jest przeznaczona
- dane właściwe (payload) - czyli informacje, które chcemy przesłać
- informacje kontrolne - służące do sprawdzenia poprawności transmisji
Dzięki temu odbiornik może sprawdzić, czy wiadomość jest kompletna i czy nie została uszkodzona podczas transmisji.
Następnie moduł przekształca dane cyfrowe na sygnał radiowy. W praktyce polega to na modulowaniu fal elektromagnetycznych. Oznacza to, że informacja jest zakodowana w zmianach parametrów fali radiowej (np. jej częstotliwości lub fazy). W przypadku nRF24L01 stosowana jest cyfrowa transmisja radiowa przeznaczona do przesyłania małych pakietów danych.
Po przygotowaniu sygnału moduł wysyła go przez swoją antenę. Antena jest elementem, który zamienia sygnał elektryczny na fale elektromagnetyczne rozchodzące się w przestrzeni.
Te fale radiowe:
- rozchodzą się w powietrzu we wszystkich kierunkach
- przenikają przez większość materiałów, takich jak plastik czy drewno
- poruszają się z bardzo dużą prędkością, zbliżoną do prędkości światła (około 300 000 km/s)
Moduł nRF24L01 pracuje w paśmie częstotliwości około 2,4 GHz. Jest to popularne pasmo używane przez wiele technologii bezprzewodowych, między innymi:
- Wi-Fi
- Bluetooth
- niektóre bezprzewodowe myszy i klawiatury
Ponieważ w tym paśmie działa bardzo wiele urządzeń, przestrzeń radiowa jest podzielona na kanały. Kanał można porównać do numeru częstotliwości, na której pracuje urządzenie. Jeśli dwa moduły są ustawione na ten sam kanał, mogą się ze sobą komunikować. Jeśli pracują na różnych kanałach, nie będą się "słyszeć".
Jednak sam kanał nie wystarcza. W powietrzu może być wiele urządzeń pracujących na tej samej częstotliwości. Dlatego każdy pakiet danych zawiera także adres odbiorcy. Moduł odbiorczy porównuje adres w odebranym pakiecie ze swoim własnym adresem. Jeśli adres się zgadza, dane zostają przyjęte. Jeśli nie pakiet jest ignorowany.
Drugie urządzenie również posiada moduł nRF24L01, który w tym czasie pracuje w trybie odbiornika. Jego zadaniem jest:
- ciągłe nasłuchiwanie fal radiowych na wybranym kanale
- wykrycie sygnału radiowego zawierającego pakiet danych
- sprawdzenie adresu odbiorcy
- odebranie i zapisanie danych
Gdy pakiet zostanie odebrany, moduł zamienia sygnał radiowy z powrotem na dane cyfrowe. Następnie przekazuje je do mikrokontrolera (np. Arduino), który może je dalej przetwarzać w programie.
Podczas transmisji radiowej mogą pojawić się różne problemy, takie jak:
- zakłócenia od innych urządzeń radiowych
- osłabienie sygnału przez ściany lub przeszkody
- chwilowa utrata pakietu danych
Dlatego nRF24L01 posiada wbudowane mechanizmy zwiększające niezawodność komunikacji. Należą do nich między innymi:
- sprawdzanie poprawności danych (CRC) - moduł sprawdza, czy pakiet nie został uszkodzony
- automatyczne potwierdzenie odbioru (ACK) - odbiornik wysyła informację, że pakiet dotarł poprawnie
- automatyczne ponowne wysyłanie (Auto Retransmit) - jeśli potwierdzenie nie nadejdzie, nadajnik wysyła pakiet ponownie
Ważne jest również to, że dane nie są przesyłane jako ciąg pojedynczych bitów przez długi czas. Zamiast tego są dzielone na pakiety. Każdy pakiet jest niewielką wiadomością zawierającą komplet informacji potrzebnych do jego poprawnego przesłania i odebrania.
Wysyłanie informacji
Na początku programu dodajemy biblioteki. Każda z tych bibliotek ma inne zadanie:
- SPI - pozwala płytce komunikować się z innymi urządzeniami przez protokół przesyłania danych (SPI). Moduł radiowy korzysta właśnie z tego sposobu.
- nRF24L01 - zawiera podstawowe informacje potrzebne do obsługi modułu radiowego nRF24L01.
- RF24 - udostępnia gotowe polecenia do łatwego wysyłania i odbierania danych przez ten moduł.
W naszym przypadku konieczne jest zainstalowanie jedynie RF24 by TMRh20.
Następnie programu tworzymy obiekt, który będzie reprezentował moduł radiowy nRF24L01 w naszym kodzie. Dzięki temu program wie, z którego urządzenia korzysta i przez jakie piny będzie się z nim komunikować. Ten zapis tworzy obiekt o nazwie radio, który korzysta z biblioteki RF24 do obsługi modułu radiowego. Wartość 9 oznacza pin CE (Chip Enable). Służy on do włączania i wyłączania trybu nadawania lub odbierania. 10 oznacza pin CSN (Chip Select Not). Odpowiada on za komunikację przez interfejs SPI.
Teraz tworzymy coś, co nazywa się struct (czyli struktura). Struktura to typ danych, który pozwala przechowywać kilka różnych wartości razem w jednym pakiecie. Można to porównać do pudełka z przegródkami, w którym każda przegródka przechowuje inną informację. W naszym przypadku takie „pudełko” ma dwie przegródki: x oraz y. Każda z nich przechowuje liczbę typu int, czyli liczbę całkowitą (na przykład 1, 10 lub -5).
Teraz tworzymy zmienną, która będzie przechowywać konkretne wartości. Można to porównać do planu pudełka i prawdziwego pudełka. struct Data to plan, który mówi jak wygląda pudełko, natomiast Data data; to już konkretne pudełko, które możemy wypełnić danymi. Ta zmienna będzie przechowywać wartości x i y, które później zostaną wysłane.
Następnym krokiem jest uruchomienie modułu. Polecenie radio.begin() przygotowuje moduł do pracy. Płytka zaczyna komunikować się z modułem przez interfejs SPI i sprawdza, czy wszystko działa poprawnie.
Każdy moduł radiowy musi wiedzieć, dokąd wysłać dane. Jeśli dwa moduły mają ustawiony ten sam adres, mogą się ze sobą komunikować. Funkcja openWritingPipe() otwiera kanał do wysyłania danych, a address oznacza adres odbiornika.
Moduł nRF24L01 może wysyłać sygnał z różną mocą. W tym przykładzie ustawiona jest niska moc, aby oszczędzać energię i zmniejszyć możliwość zakłóceń. Funkcja setPALevel() ustawia poziom mocy sygnału, a RF24_PA_LOW oznacza niski poziom mocy.
nRF24L01 może działać w dwóch trybach: nasłuchiwania (czyli odbierania danych) oraz wysyłania danych. Ponieważ najpierw zajmiemy się nadajnikiem wyłączamy tryb nasłuchiwania. Funkcja stopListening() zatrzymuje odbieranie danych i przełącza moduł w tryb wysyłania. Jeśli chcemy, aby moduł odbierał dane zamiast je wysyłać, używamy funkcji startListening(). Ta funkcja przełącza moduł radiowy w tryb nasłuchiwania, czyli oczekiwania na dane od innego urządzenia.
Mając juz skonfiguruwany i uruchomiony modół możemy wysłać dane. Polecenie radio.write() wysyła zawartość zmiennej data. Funkcja write() odpowiada za wysłanie danych. Zapis &data oznacza adres miejsca w pamięci, w którym znajdują się dane. Natomiast sizeof(data) określa, ile bajtów danych należy wysłać. Dzięki temu moduł radiowy wysyła dokładnie tyle danych, ile zajmuje nasza struktura.
Na końcu programu robimy krótką przerwę. Dzięki temu dane nie są wysyłane zbyt szybko, co mogłoby powodować błędy w komunikacji. Funkcja delay() zatrzymuje program na chwilę.
Kod Nadajnika
Pierwsza część kodu odpowiada za przygotowanie potrzebnych zmiennych i bibliotek. Najpierw dołączane są biblioteki (SPI, nRF24L01, RF24). Następnie tworzony jest obiekt radio, który określa piny używane do komunikacji z modułem. Dalej definiowany jest adres komunikacyjny oraz struktura Data, która określa jakie dane będą przesyłane (dwie wartości analogowe x i y). Na końcu tworzony jest obiekt data, który będzie przechowywał dane do wysłania.
Funkcja setup() wykonuje się tylko raz po uruchomieniu i odpowiada za konfigurację modułu radiowego. Funkcja radio.begin() inicjalizuje komunikację, openWritingPipe(address) ustawia adres odbiornika, setPALevel() określa moc nadawania, a stopListening() przełącza moduł w tryb nadawania.
Funkcja loop() wykonuje się w nieskończonej pętli podczas działania mikrokontrolera. Najpierw odczytywane są wartości z wejść analogowych A0 i A1, które mogą pochodzą z joysticka. Następnie dane są zapisywane w strukturze data i wysyłane przez moduł radiowy przy użyciu radio.write(). Na końcu dodane jest opóźnienie delay(50), aby ograniczyć częstotliwość wysyłania danych.
Downloads
Przypomnienie O Warunkach Logicznyhc I Mapowaniu Wartości
W programie używana jest instrukcja warunkowa if / else if / else, która pozwala programowi podejmować decyzje na podstawie określonych warunków. Program sprawdza warunki od góry do dołu. Gdy znajdzie pierwszy prawdziwy warunek, wykonuje przypisany do niego blok kodu i pomija pozostałe. Ogólny schemat działania wygląda następująco:
Map()
W programie używana jest funkcja map(), która służy do przeliczania wartości z jednego zakresu liczbowego na inny zakres. Ogólna postać funkcji wygląda następująco:
gdzie:
- wartość - liczba, którą chcemy przeliczyć
- od_min - dolna granica starego zakresu
- od_max - górna granica starego zakresu
- do_min - dolna granica nowego zakresu
- do_max - górna granica nowego zakresu
Jazda Przód Tył
Pierwsza część kodu odpowiada za przygotowanie bibliotek, pinów oraz zmiennych potrzebnych do działania programu. Najpierw dołączane są biblioteki SPI, nRF24L01 oraz RF24. Następnie definiowane są piny sterujące mostkiem H. Dalej tworzony jest obiekt radio, który określa piny używane do komunikacji z modułem radiowym (CE i CSN). Po nim definiowany jest adres komunikacyjny, który musi być taki sam jak w nadajniku. Następnie tworzona jest struktura Data, która określa jakie dane będą odbierane (dwie wartości analogowe x i y). Na końcu tworzony jest obiekt data, który będzie przechowywał odebrane dane.
Funkcja setup() wykonuje się tylko raz po uruchomieniu mikrokontrolera i ponownie odpowiada za konfigurację pinów oraz modułu radiowego. Na początku piny sterujące silnikami ustawiane są jako wyjścia przy użyciu funkcji pinMode(). Następnie inicjalizowana jest komunikacja z modułem radiowym funkcją radio.begin(). Funkcja openReadingPipe(0, address) ustawia adres, z którego będą odbierane dane. Kolejna funkcja setPALevel() ustawia moc sygnału radiowego (w tym przypadku niski poziom). Na końcu startListening() przełącza moduł w tryb odbioru danych.
Funkcja loop() wykonuje się w nieskończonej pętli podczas działania mikrokontrolera. Na początku program sprawdza, czy moduł radiowy odebrał nowe dane przy pomocy funkcji radio.available(). Jeśli dane są dostępne, zostają odczytane funkcją radio.read() i zapisane w strukturze data. Następnie pobierana jest wartość y, która odpowiada za ruch przód-tył robota.
W zależności od wartości joysticka wykonywane są instrukcje warunkowe if / else if / else. Jeśli wartość jest większa niż 540, robot jedzie do przodu. Jeśli jest mniejsza niż 480, robot jedzie do tyłu. Jeśli wartość znajduje się pomiędzy tymi zakresami, robot zatrzymuje się. Taki zakres wokół środka joysticka tworzy tzw. „martwą strefę”, dzięki której robot nie porusza się samoczynnie gdy joystick znajduje się blisko środka.
Funkcja map() oblicza proporcjonalną wartość w nowym zakresie. W przypadku odczytów analogowych zwracane są wartości analogowe w zakresie 0-1023. Natomiast prędkość silników sterowana sygnałem PWM działa w zakresie 0-255. Dlatego konieczne jest przeliczenie wartości joysticka na zakres używany do sterowania silnikami.
Przykład użyty w kodzie:
Oznacza to, że:
- wartość 540 zostanie zamieniona na 0
- wartość 1023 zostanie zamieniona na 255
Wszystkie wartości pomiędzy nimi zostaną przeliczone proporcjonalnie. Dzięki temu im bardziej joystick jest wychylony do przodu, tym większa jest prędkość silników. Podobna operacja wykonywana jest podczas jazdy do tyłu:
W tym przypadku zakres joysticka od 480 do 0 jest przeliczany na zakres prędkości 0–255, co pozwala zwiększać prędkość jazdy w tył wraz z większym wychyleniem joysticka.
Dzięki zastosowaniu funkcji map() sterowanie prędkością robota staje się płynne i proporcjonalne do wychylenia joysticka. Na końcu funkcja analogWrite() ustawia prędkość silników.
Downloads
Skręcanie
Aby umożliwić skręcanie konieczne jest dodatnie odczytu zmiennej x, która przechowuje poziome wychylenie joysticka:
Dzięki niej program wie, w którą stronę użytkownik chce skręcić robotem. Pozwala to nie tylko jechać przód lub tył, ale też reagować na wychylenie joysticka w lewo i w prawo. Aby kontrolować prędkość każdego silnika osobno, wprowadzono dwie zmienne speedLeft i speedRight. Na początku przyjmują one wartość bazową odczytaną z osi Y joysticka. Umożliwia to niezależną regulację prędkości lewego i prawego silnika, dzięki czemu robot może skręcać, zwalniając jeden z silników, a drugi utrzymując na pełnej prędkości.
Skręt realizowany jest poprzez warunki sprawdzające wychylenie osi X. Gdy joystick jest przesunięty w prawo, prędkość prawego silnika zostaje zmniejszona o połowę:
Analogicznie, gdy joystick jest przesunięty w lewo, zwalniany jest lewy silnik:
Na końcu wartości prędkości są wysyłane do silników przy użyciu funkcji analogWrite(), przy czym każdy silnik otrzymuje swoją indywidualną prędkość:
To pozwala na dokładną kontrolę ruchu robota. Możliwe jest jednoczesne przyspieszanie, zwalnianie lub skręcanie, w zależności od położenia joysticka w osi X i Y. Zmiany te sprawiają, że robot staje się znacznie bardziej elastyczny w sterowaniu i pozwala na naturalną jazdę oraz manewrowanie w miejscu, co było niemożliwe przy użyciu jednej wspólnej prędkości dla obu kół.
Downloads
Kontrola Prędkości Skrętu
W poprzedniej wersji programu skręcanie polegało na zmniejszeniu prędkości jednego z silników o połowę. W nowej wersji wprowadzono zmienną turnFactor, która pozwala płynnie regulować różnicę prędkości pomiędzy silnikami w zależności od wychylenia joysticka. Fragment kodu odpowiedzialny za skręt w prawo wygląda następująco:
Funkcja map() przelicza wartość osi X joysticka z zakresu 512-1023 na zakres 0-255. Oznacza to, że im bardziej joystick zostanie wychylony w prawo, tym większa będzie wartość zmiennej turnFactor. Następnie wartość ta zostaje dodana do prędkości lewego silnika oraz odjęta od prędkości prawego silnika. Dzięki temu lewy silnik zaczyna obracać się szybciej, a prawy wolniej, co powoduje skręt robota w prawo. Analogicznie działa skręt w lewo:
W tym przypadku wychylenie joysticka w lewo powoduje zmniejszenie prędkości lewego silnika i zwiększenie prędkości prawego silnika. Dzięki temu robot skręca w lewo. Kolejną zmianą jest zastosowanie funkcji constrain(), która ogranicza wartości prędkości silników do dopuszczalnego zakresu.
Funkcja ta sprawdza, czy wartość zmiennej mieści się w określonym zakresie. Jeśli wartość przekroczy górną granicę 255, zostanie ustawiona na 255, natomiast jeśli spadnie poniżej 0, zostanie ustawiona na 0. Jest to konieczne, ponieważ podczas dodawania lub odejmowania wartości turnFactor prędkość silników mogłaby wyjść poza zakres obsługiwany przez funkcję analogWrite(), który wynosi 0-255. Ostatni fragment programu odpowiada za wysłanie obliczonych prędkości do silników:
W odróżnieniu od wcześniejszej wersji programu każdy silnik otrzymuje teraz własną prędkość. Dzięki temu możliwe jest jednoczesne poruszanie się robota do przodu lub do tyłu oraz skręcanie poprzez różnicę prędkości pomiędzy kołami.
Downloads
Gwałtowne Manwry
W stosunku do poprzednich wersji programu należy wprowadzić zmianę w sposobie przetwarzania sygnału z joysticka, aby osiągnąć bardziej płynne i intuicyjne sterowanie robotem. Głównym celem tej zmiany jest przeliczenie wartości osi joysticka do wspólnego zakresu -255 do 255, który będzie jednocześnie określał kierunek oraz prędkość ruchu. Aby to osiągnąć, należy wprowadzić nowe zmienne przechowujące przeliczone wartości osi joysticka:
Zmienne te będą przechowywać wartości odpowiadające ruchowi przód-tył oraz lewo-prawo, przeliczone do zakresu używanego przez sterowanie silnikami. Kolejną zmianą jest przeliczenie osi Y joysticka do zakresu -255 do 255, aby jedna zmienna mogła określać zarówno jazdę do przodu, jak i do tyłu.
Dzięki temu wartości dodatnie oznaczają jazdę do przodu, a wartości ujemne jazdę do tyłu. Zakres pomiędzy 480 a 540 tworzy martwą strefę joysticka, która zapobiega przypadkowemu poruszaniu się robota, gdy joystick znajduje się blisko środka. Podobną zmianę należy wprowadzić dla osi X, która odpowiada za skręcanie robota.
Aby umożliwić jednoczesne sterowanie ruchem oraz skrętem, należy zastosować mikser napędu różnicowego (tank drive), który oblicza prędkość każdego silnika na podstawie obu osi joysticka.
W tym rozwiązaniu oś Y odpowiada za ruch przód-tył, natomiast oś X wprowadza różnicę prędkości pomiędzy silnikami, co powoduje skręcanie robota. Aby zapobiec przekroczeniu dopuszczalnego zakresu prędkości, należy zastosować funkcję constrain(), która ogranicza wartości do zakresu -255 do 255.
Ostatnią zmianą jest uzależnienie kierunku obrotów silników od znaku obliczonej prędkości.
Jeśli wartość prędkości jest dodatnia, silnik obraca się w kierunku jazdy do przodu. Natomiast gdy wartość jest ujemna, kierunek obrotów zostaje odwrócony, a do funkcji analogWrite() przekazywana jest dodatnia wartość prędkości.
Downloads
Kontrola Ruszania
Przy gwałtownym zwiększeniu prędkości robot może wpadać w poślizg, szczególnie gdy silniki otrzymują natychmiast maksymalną wartość sygnału PWM. Dlatego wprowadzono rozwiązanie, które powoduje stopniowe zwiększanie prędkości, zamiast natychmiastowej zmiany.
Aby to osiągnąć, należy wprowadzić zmienne przechowujące aktualną prędkość silników, które będą stopniowo zmieniane w kierunku prędkości docelowej.
Zmienne te przechowują rzeczywistą prędkość lewego i prawego silnika w danym momencie działania programu. Dzięki temu możliwe jest kontrolowanie tempa przyspieszania robota. Kolejną zmianą jest wprowadzenie stałych określających maksymalne tempo przyspieszania.
Stała ACCEL_LIMIT określa maksymalną zmianę prędkości w jednym cyklu programu. Oznacza to, że prędkość silnika może zwiększyć się lub zmniejszyć tylko o niewielką wartość w każdej iteracji pętli, co powoduje płynne przyspieszanie.
Natomiast INSTANT_LIMIT określa próg prędkości, do którego robot może przyspieszać natychmiast. Dzięki temu przy małych prędkościach robot reaguje szybko na ruch joysticka, natomiast przy większych prędkościach przyspieszanie jest już ograniczone.
Następnie zamiast bezpośredniego ustawiania prędkości silników należy wprowadzić zmienne określające docelową prędkość silników.
Wartości te określają prędkość, którą robot powinien osiągnąć na podstawie położenia joysticka.
Aby stopniowo zmieniać prędkość, należy zastosować funkcję:
Funkcja ta oblicza nową prędkość silnika na podstawie aktualnej prędkości oraz prędkości docelowej.
W tym celu wprowadzono funkcję:
Jej zadaniem jest kontrolowanie zmiany prędkości w taki sposób, aby robot nie przyspieszał zbyt gwałtownie.
Na początku funkcja sprawdza, czy robot hamuje lub zmienia kierunek ruchu. W takiej sytuacji zmiana prędkości następuje natychmiast, ponieważ szybkie hamowanie poprawia kontrolę nad robotem.
Jeżeli natomiast robot przyspiesza, funkcja sprawdza czy aktualna prędkość znajduje się poniżej progu INSTANT_LIMIT. Jeśli prędkość jest niewielka, robot może przyspieszyć szybciej, ponieważ ryzyko poślizgu jest wtedy małe. Natomiast gdy prędkość przekroczy określony próg, dalsze przyspieszanie odbywa się już stopniowo przy użyciu ograniczenia ACCEL_LIMIT.
Dzięki temu prędkość silników zwiększa się stopniowo w kolejnych iteracjach programu. Wprowadzenie kontroli przyspieszenia sprawia, że robot porusza się płynniej i stabilniej, ponieważ nagłe zmiany prędkości nie powodują już utraty przyczepności kół.
Downloads
Przełącznik Trybu Jazdy
W stosunku do poprzedniej wersji programu można wprowadzić możliwość chwilowego wyłączenia ograniczenia przyspieszenia, aby robot mógł natychmiast osiągnąć zadaną prędkość. Funkcja ta działa jako tryb boost, który pozwala na szybkie przyspieszenie w sytuacjach wymagających dynamicznej reakcji robota. Aby to osiągnąć, należy rozszerzyć strukturę przesyłanych danych o informację o stanie przycisku w nadajniku.
Nowe pole button przechowuje informację, czy przycisk na nadajniku jest wciśnięty. Dzięki temu odbiornik może reagować na dodatkową komendę wysyłaną razem z danymi z joysticka. W programie odbiornika należy następnie odczytać stan przycisku:
Zmienna boost określa, czy tryb szybkiego przyspieszenia jest aktywny. Kolejna zmiana polega na dodaniu warunku, który decyduje o sposobie obliczania prędkości silników.
Jeżeli przycisk jest wciśnięty, ograniczenie przyspieszenia zostaje pominięte i prędkość silników zostaje natychmiast ustawiona na wartość docelową. W przeciwnym przypadku nadal stosowana jest funkcja calculateNewSpeed(), która ogranicza tempo przyspieszania, aby zapobiec poślizgowi robota.
Aby umożliwić przesyłanie informacji o przycisku, należy również wprowadzić zmiany w programie nadajnika. Struktura danych musi zostać rozszerzona o dodatkowe pole:
Następnie należy skonfigurować pin przycisku jako wejście z wewnętrznym rezystorem podciągającym:
Zastosowanie trybu INPUT_PULLUP powoduje, że pin ma stan wysoki, gdy przycisk nie jest wciśnięty, oraz stan niski po jego naciśnięciu. Dlatego podczas zapisywania stanu przycisku do struktury danych należy odwrócić odczytaną wartość:
Dzięki temu zmienna button przyjmuje wartość true, gdy przycisk jest wciśnięty, oraz false, gdy pozostaje zwolniony. Wprowadzenie tej zmiany pozwala na włączenie trybu szybkiego przyspieszenia tylko w momencie naciśnięcia przycisku, natomiast w normalnej pracy robot nadal korzysta z mechanizmu kontroli przyspieszenia, który zapobiega utracie przyczepności kół.