Przedstawię tu jak można zrobić własny bezprzewodowy gamepad w oparciu o Arduino R4 WiFi i Joystick shield. Nasz kontroler będzie łączył się z naszą siecią WiFi i wysyłał na nasz serwer dane o wciśniętych klawiszach poprzez protokół bezpołączeniowy UDP, co zapewni nam szybką reakcję na wciskane klawisze.
Potrzebne nam będzie zasadniczo tylko tytułowe Arduino R4 WiFi i tytułowy joystick shield, do kupienia za jakieś kilkanaście złotych:
Tu już trzeba zaznaczyć, że ten shield oferuje dwa rodzaje sterowania:
- sam joystick pozwala sterować analogowo, mam przez to na myśli, że odczytana z jego potencjometrów wartość wiernie odzwierciedla wychylenie gałki
- przyciski, jak to przyciski, dają nam tylko informacje booleowską, true lub false, wciśnięte lub nie
Możliwość sterowania analogowego joystickiem pozwala nam na lepszą precyzję w poruszaniu tym, czym akurat sterujemy.
Joystick shield pasuje na Arduino R4, gdyż ma ono tę samą formę co poprzednie Uno R3:
Uruchomienie joystick shield
Zacznijmy od samego uruchomienia shielda. Na szczęście, tak jak to w środowisku Arduino bywa, mamy już gotowy do tego sketch.
Klasa JoystickShield sprytnie ukrywa odczyt przycisków i ADC za ładnymi, dobrze opisanymi funkcjami.
Kod: C / C++
Wgrywamy, testujemy:
Wszystko działa, a wychylenia mamy w zakresie od -100 do 100, czyli nie są to zwykłe przyciski - o to właśnie chodziło, to pozwala sterować danym urządzeniem w precyzyjny sposób.
Upakowujemy we własną strukturę
Tak zebrane dane trzeba jakoś przekazać dalej. W tym celu warto upakować jest je w strukturę. Przyciski mogą być w jednym polu typu integer (a nawet może się zmieszczą w bajcie) jako poszczególne bity. Tak oszczędzamy miejsce. Natomiast wychylenie musi być już jako liczba całkowita ze znakiem. Dodatkowo dodałem sobie ID pakietu, które jest jego zasadniczo kolejnym indeksem, zwiększanym z każdą wysyłką danych.
Kod: C / C++
Tak wygląda wypełnianie struktury. Zmienna globalna odlicza kolejne pakiety.
Kod: C / C++
Jeszcze trzeba wypełnić przyciski. W tym celu dodałem enumerację określającą, który indeks bitu odpowiada za który przycisk:
Kod: C / C++
Potem trzeba zapalać odpowiedni bit, gdy dany przycisk jest wciśnięty. Aby zamienić indeks bitu na maskę trzeba użyć przesunięcia bitowego, a aby zapalić ten bit, używamy OR.
Kod: C / C++
Wysyłamy dane przez UDP
Teraz trzeba wysłać naszą strukturę przez sieć. Zdecydowałem się na protokół bezpołączeniowy UDP. On co prawda może gubić pakiety, ale przynajmniej przesyłać je będzie szybko. Uznałem, że to ważniejsze, niż rzetelność połączenia, którą oferuje TCP.
Przeanalizujmy zatem demko z samego Arduino R4, klienta UDP usługi NTP:
Kod: C / C++
Zasadniczo musimy wykorzystać pokazane powyżej wysyłanie:
Kod: C / C++
Należy pamiętać, że wysyłamy dane na konkretny adres IP i port. Na tym adresie IP i porcie musi nasłuchiwać serwer.
Modyfikacja powyższego kodu jest bardzo prosta. Po prostu usuwamy wysyłanie wedle protokołu NTP i zamiast tego wysyłamy naszą strukturę. Gotowe.
Odbiór danych na komputerze
Teraz trzeba jeszcze odebrać wysłane dane. Posłuży nam do tego serwer UDP. Serwer UDP można bardzo prosto utworzyć w C# przy użyciu klasy UdpClient.
Ważne, by nasłuchiwać na tym samym porcie na który wysyłamy dane.
Potem możemy odbierać w pętli pakiety i je przetwarzać za pomocą BinaryReader. Nie musimy się tu martwić o fragmentację, tak małe pakiety nie są dzielone, mieszczą się w całości w jednej ramce:
Kod: C / C++
Odpalamy oba programy, zarówno joystick jak i serwer.... upewniamy się, czy są w tej samej sieci WiFi i... sukces:
Nasz program poprawnie odbiera dane z kontrolera.
Podsumowanie
Prosty i przyjemny projekt. Już zasadniczo można czymś sterować na PC.
Analogicznie można postawić serwer UDP na drugim Arduino, ESP bądź czymkolwiek innym i tam odbierać pakiety z inputem użytkownika.
Również można by rozwinąć moją aplikację napisaną w C# tak by wysyłała Windowsowe wciśnięcia klawiszy czy tam ruszała myszką, wtedy nasz Arduino gamepad pozwoliłby nawet nam sterować naszym PC.
Możliwości są bardzo duże.
Czy widzicie jakieś zastosowanie dla takiego DIY?
Na koniec przypomnę też mój wcześniejszy gamepad, który realizowałem na PIC:
Gamepad USB/HID na PIC18F45K50 (z dodatkowym trybem myszki oraz CDC)
PS: Jeśli nie zależy nam na szybkiej reakcji sterowanego urządzenia, ale zależy nam na tym, by każdy pakiet docierał do celu, należy przerobić przykład tak by korzystał z rzetelnego, połączeniowego TCP. TCP gwarantuje, wysłane pakiety dotrą (chyba, że całkiem zostanie zerwane połączenie) i w razie problemu je wysyła ponownie, a UDP wysyła je na ślepo bez sprawdzania odbioru)
Fajne? Ranking DIY Pomogłem? Kup mi kawę.