VertiCar to zdalnie sterowana platforma jezdna. Robota zaprojektowano tak aby poruszał się w pozycji pionowej balansując na dwóch kołach.
- Mikrokontroler (wykorzystano esp32-s3),
- Hoverboard z stm32 lub dwa silniki o dużym momencie (ze sterownikami),
- IMU (np. 10dof imu od waveshare),
- Zasilanie (tu wykorzystano oryginalną baterię z hoverboarda lion 10s i osobny pakiet 3s do zasilania mikrokontrolera ze stabilizatorem na 5v)
- Breadbord i przewody z goldpinami,
- Tablet/telefon + gamepad (opcjonalnie),
- Profile do wykonania konstrukcji
- Lutownica,
- drukarka 3D,
- piła do metalu
- komputer
- VS code + platformio
VertiCar - balansująca baza jezdna UGV
Wprowadzenie i ewolucja platformy
VertiCar przeszedł długą drogę rozwojową, zanim osiągnął obecną formę. Pierwszym etapem było przeprogramowanie oryginalnego sterownika pochodzącego z elektrycznej deskorolki (hoverboarda) z wykorzystaniem otwartoźródłowego projektu hoverboard-hack-FOC. Równolegle zbudowano ramę z profili aluminiowych v-slot, do których przymocowano koła ze zintegrowanymi silnikami bezszczotkowymi typu hub motor. Po początkowym zaprogramowaniu układu jako zdalnie sterowanego samochodu i przystąpieniu do testów, oryginalny sterownik uległ spaleniu. Po trzech dniach nieudanych prób diagnozy i naprawy uszkodzonych elementów, podjęto decyzję o zmianie strategii i zainwestowaniu w profesjonalne kontrolery VESC. Kolejne kroki obejmowały zaprogramowanie obsługi MEMSowego IMU od waveshare.
Architektura systemu i moduł główny (main.cpp)
Sercem całego układu jest mikrokontroler z rodziny ESP32-S3, którego główna pętla programu koordynuje pracę wszystkich modułów ze średnią częstotliwością 200 Hz. W pliku głównym zdefiniowano obiekty reprezentujące najważniejsze peryferia: jednostkę inercyjną imu (komunikującą się przez magistralę I2C za pomocą biblioteki Wire), panel kontrolny panel oraz kontroler sieciowy wificontroler. Pętla loop() precyzyjnie mierzy czas trwania każdego cyklu (dt), co jest kluczowe dla poprawnych obliczeń całkujących i różniczkujących w stabilizacji. Telemetria, obejmująca aktualny kąt pochylenia pojazdu, sumaryczny prąd silników oraz czas pętli, jest zbierana i wysyłana do interfejsu sieciowego co 50 milisekund aby nie obciążać magistrali szeregowych.
Integracja ze sterownikami VESC (VescDriver.cpp)
Za wysterowanie silników odpowiada dedykowana klasa VescDriver, która komunikuje się ze sterownikami VESC przy użyciu sprzętowego interfejsu szeregowego Serial. Algorytm napędowy wykorzystuje miksowanie sygnałów w celu jednoczesnego balansowania i skręcania – komenda dla lewego koła to suma zadanej prędkości i skrętu (cmd.speed + cmd.steer), natomiast dla prawego koła to ich różnica (cmd.speed - cmd.steer). Sterownik posiada również mechanizm zabezpieczający: prąd zadawany silnikom jest odcinany, jeśli aktualny współczynnik wypełnienia PWM (Duty Cycle) przekroczy bezpieczny limit zdefiniowany w parametrze maxOnCurrentDuty. W przypadku zatrzymania maszyny lub przekroczenia krytycznego kąta, do silników wysyłana jest komenda zerowego prądu lub aktywowany jest wbudowany hamulec.
Algorytm stabilizacji: Autorski regulator PID i obsługa IMU (PidControler.cpp)
Utrzymanie pionowej orientacji pojazdu realizowane jest w oparciu o odczyty kąta pochylenia (pitch) z układu MPU9250. Na podstawie tych danych działa stworzona od podstaw klasa PidControler. Kod regulatora wprowadza kilka zaawansowanych rozwiązań technicznych mających na celu poprawę stabilności:
- Różniczkowanie po pomiarze (Derivative on Measurement): Zamiast liczyć pochodną z błędu (co mogłoby powodować gwałtowne szarpnięcia tzw. "derivative kick" przy zmianie wartości zadanej), człon D reaguje wyłącznie na fizyczną zmianę położenia odczytanego z czujnika.
- Filtr dolnoprzepustowy (LPF): Sygnał różniczkujący jest silnie zaszumiony przez wibracje napędu, dlatego zastosowano algorytm wygładzania z wykorzystaniem stałej czasowej _tau, która odfiltrowuje nagłe, błędne skoki.
- Anti-Windup (Dynamiczne bindowanie): Zjawisko nasycenia całki zablokowano mechanizmem, który pozwala na dalszy wzrost członu sumującego _integralSum jedynie wtedy, gdy błąd ma znak przeciwny do osiągniętego limitu siłownika (co oznacza, że całka będzie malała w kierunku zera).
Łączność i interfejs: Serwer WWW i WebSockets (WifiControler.cpp oraz index.html)
Pojazd może być konfigurowany i sterowany całkowicie bezprzewodowo. Kod mikrokontrolera uruchamia lokalny punkt dostępowy WiFi (softAP) oraz korzysta z systemu plików w pamięci flash (LittleFS), aby serwować bezpośrednio do przeglądarki stronę internetową index.html. Komunikacja dwukierunkowa o niskich opóźnieniach bazuje na protokole WebSockets. Po stronie przeglądarki zaimplementowano skrypt JavaScript wykorzystujący natywne API navigator.getGamepads(), które w czasie rzeczywistym odczytuje fizyczne osie podłączonego po bluetooth pada i wysyła rozkazy sterowania w formacie JSON (zawierające wartości x, y oraz stan przycisku uzbrajania) do ESP32. Interfejs webowy pozwala także na dynamiczne strojenie regulatora (wysyłając JSON z nowymi nastawami Kp, Ki, Kd) oraz wyświetla na żywo telemetrię i parametry łącza sieciowego.
Mechanizmy bezpieczeństwa
System wyposażony jest w procedury awaryjne:
- Programowy Watchdog: Klasa WifiControler stale monitoruje czas nadejścia ostatniego pakietu sterującego. Jeśli łączność WebSockets zostanie zerwana lub opóźnienie przekroczy 500 milisekund, wartości zadane prędkości i skrętu są natychmiast resetowane do bezpiecznego poziomu zera.
- Ping / Pong: Skrypt webowy co 200 milisekund wysyła ramkę testową "ping", a serwer odpowiada "pong", co pozwala na bieżąco monitorować jakość połączenia radiowego w interfejsie użytkownika.
- Zabezpieczenie przed utratą kontroli: Wyjście na silniki uruchamiane jest tylko pod warunkiem trzymania przycisku zezwalającego na ruch (wificontroler.getButton0()) oraz gdy bezwzględny kąt pochylenia maszyny nie przekracza zdefiniowanej wartości granicznej (MAX_ANGLE). Po jej przekroczeniu regulatory PID resetują swoją pamięć stanu wewnętrznego (PIDangle.reset()), a napęd jest całkowicie odłączany.
zip poniżej
https://youtube.com/shorts/pOIL8b8veV4?si=UTe3X6FdxB3bdIib