Czech English

Rocker

terénní robot

Robota s nezávislým pohonem a řízením všech kol jsem si chtěl postavit již dávno. Konečně jsem objevil vhodné pohony - robotická serva (WaveShare ST3215), která splnila téměř všechny požadavky (a za rozumnou cenu). A tak vznikl robot se čtyřkolovým podvozkem typu rocker-bogie.

Aktualizace: 5.5.2024 Uživatelské rozhraní pro robota


Základní údaje

Autor
  • Martin Locker
Řídicí počítače
  • low level - STM32F103
  • high level - Raspberry Pi 3B
Senzory
  • IMU
  • GPS
  • Lidar LDrobot LD-06
  • hloubková kamera RealSense D455
Pohon
  • 8x digitální robotické servo WaveShare ST3215
Napájení
  • pohony LiPol 3s 5Ah
  • elektronika power banka 20Ah
Koncepce
  • čtyřkolový podvozek typu Rocker-bogie (výkyvné uložení kol)
  • každé kolo má nezávislý pohon a nezávislé natočení směru

Charakteristika robota

Podvozek

Podvozek robota je postaven z hliníkových profilů, plexi a dílů vyrobených 3D tiskem z PLA. Snahou bylo udělat konstrukci co nejčistší (aby nikde nic nepřekáželo, nekoukaly dráty, ...). Takže některé části jsou nakonec celkem komplikované - převodovka s pohonem uvnitř kola, vidlice kol, jejímž vnitřkem vedou vodiče k servům (viz. fotky).

Řízení pohybu

Podvozek je navržen tak, že osy zatáčení kol jsou ve vrcholech čtverce (robot má stejný rozchod i rozvor kol).
Díky nezávislému natáčení každého kola lze realizovat dva základní způsoby řízené:
  • "automobilové" řízení s (ackermannovým) řízením všech čtyř kol a samostatným řízením rychlosti každého kola
  • synchrodrive (všesměrové řízení) - všechna kola natáčena do stejného směru a otáčejí se stejnou rychlostí
    + otáčení na místě (kola se natočí ve směru kružnice procházející osami natáčení kol)

Vlastní řízení (výpočty natočení kol a jejich rychlosti) řídí mikrokontroler na základě povelů z nadřízeného systému
(1. dopředná rychlost + úhlová rychlost, 2. rychlost + směr).

Video


První jízda - dálkově řízeno

28. ledna 2024 - Odladěn driver pro komunikaci se servy

Po postrčení Martinem D. jsem (po delší době) vytáhl robota a pustil se konečně do napsání rozumného rozhraní pro komunikaci s digitálními servy.
Snažil jsem se to napsat tak, aby to bylo použitelné na různých platformách (zatím tedy AVR, STM32 a ESP32). Nejnižší vrstvu implementující jednodrátovou sériovou komunikaci jsem oddělil od vyšších vrstev a pro STM32 vyzkoušel tři varianty realizace - standardní využití knihovní obsluhy uartu (s možností využití hw řešení single wire half duplex na STM32), vlastní obsluha uartu přes přerušení (zatím nevyzkoušeno) a využití dma přenosu (to by měla být cílová varianta). Bohužel zatím DMA přenos nepůjde použít, protože na použité desce zrovna UART3 sdílí stejné kanály s rozhraním SPI1, které bude sloužit pro komunikaci s RPi a tam je dma nutností.
Low level mikrokontroler by měl být v budoucnu schopen obsloužit všechny periferie (kromě kamery), tj. pohony, imu, gps a lidar. Z hlediska pohonů bude zajišťovat výpočet natočení jednotlivých kol a jejich rychlosti dle povelů z nadřízeného systému a zpětné čtení enkodérů. U dalších periferií bude zajišťovat periodické vyčítání dat. Proto se snažím napsat obsluhu tak, aby co nejméně zatěžovala mikrokontroler. Použití dma pro uart jsem už zvládl (po větším úsilí) při vyčítání lidaru. Proto to u komunikace se servy už celkem šlo (jen se museli použít dva kanály - pro vysílání a příjem).
Závěr
  • hotovo: vyčítání dat z lidaru, komunikace se servy
  • k řešení: doladit řízení pohonů (výpočty natočení a rychlostí), komunikace s imu (třetí uart po fyzické vrstvě can), komunikace s RPi (spi)

5. května 2024 - Uživatelské rozhraní pro robota

Po posouzení možností jak realizovat na robotovi uživatelské rozhraní (GUI), tj. lehkého prozkoumání jak to naprogramovat v Qt, wxWidgets, ... a zhodnocení času potřebného k jejich zvládnutí s dostupným výkonem na Raspberry Pi 3B, jsem došel k závěru, že tudy cesta nevede. Při povídání s Martinem D. jsem nadhodil možnost realizovat GUI jako webovou stránku, což bylo ohodnoceno, že to není tak špatný nápad.
Trošku problém je, že je potřeba obousměrná komunikace - zobrazování, ovládání. Což se na webu realizuje obvykle různými oklikami. Před nedávnem jsem však toto zkoušel na ESP32, kde je dostupná knihovna pro komunikaci pomocí websocketů. Celkem to fungovalo, takže jsem očekával, že něco podobného najdu i pro Raspberry Pi, resp. linux. Určitě nechci na RPi provozovat webserver (toho výkonu není na rozdávání).
Bohužel jsem nic vhodného nenašel. Tak jsem začal z různých zdrojů zkoumat komunikaci pomocí socketů, není to až taková věda. Takže z nějakých příkladů upravit socket server nebyl problém. Horší je, že jsem nenašel žádný příklad, kde by to bylo řešeno neblokujícím způsobem. Všude používali blokující volání, tj. nebylo možné posílat a přijímat data současně (předpokládali pouze komunikaci - dotaz/odpověď). Nakonec jsem to tedy snad nějak zvládl přepsat.
Poslední krok bylo upravit to na websockety, aby to fungovalo s webovým prohlížečem. O tom jsem neměl vůbec povědomost. Takže jsem opět začal hledat nějakou knihovnu, výběr byl velmi omezený. Nakonec jsem vybral libwebsocket. Než jsem začal zkoumat zdrojáky, tak jsem raději nejprve nastudoval příslušné RFC (a bylo to dobrá volba, celkem jsem pochopil jak to celé funguje). S drobnými úpravami se mi podařilo ukázkový příklad přeložit, spustit a kupodivu se to tvářilo, že to funguje. Opět to ale bylo napsáno s využitím blokujicího volání funkcí socketu. Takže s přechozí zkušeností jsem to přepsal a vypadalo to, že je hotovo (pátek po 8. večer).
V sobotu chci poslat na webovou stránku nejen text, ale i obrázek. Ale ouha, nějak to nejde poslat, resp. zjišťuji, že přijde jen kus dat a následně socket spadne. Z těch dat přijde jen malý kousek, řádově desítky bytů (u přenosu textu to stačilo). Tak zkoumám, kde se to "rozbije" a nakonec zjišťuju, že to je v přípravě rámce. V té knihovně je obrovská bota, parametr udávající délku dat se ukládá do proměnné o velikosti "7 bitů". Výsledkem je, že nejde poslat více než 125 B. Ono to kódování packetů je trochu složitější (do 125 B je základní, pro delší se to kóduje jinak). Takže po úpravě velikosti proměnné na int se to rozbíhá a přenáším celý obrázek o velikosti cca 20 KB.
Chvíli bojuji s překódováním dat do base64 v javascriptu, aby se to dalo zobrazit jako obrázek. A opět to vypadá, že to funguje. Ale nejásejme předčasně. Zkouším trošku větší obrázek, a to pro změnu shodí socket ihned. Už jdu téměř na jistotu a kontroluju vygenerovanou hlavičku packetu. Druhý limit pro odlišné kódování je 64 KB a opravdu tentokrát to uloží do hlavičky jen první byte délky zprávy (ostatní zahodí) = druhá zásadní chyba. Ještě, že jsem si prozíravě nastudoval to RFC (jinak bych to těžko hledal). Po opravě přenáším i ten 100 KB obrázek. Že nikdo u doporučované knihovny, která je téměř 10 let na githubu, nezkusí přenášet více než 125 B dat, jsem opravdu nečekal. Proč si já vždycky vyberu špatně.
Dalším testováním odhaluji, že to ještě není ono. Sice socket otevřený při připojení clienta beží jako neblokující, ale socket serveru je stále blokující. V principu by to nevadilo, ale pokud to pustím ve zvláštním vláknu, tak to nejde shodit (visí to na funkci čekající na připojení klienta). Upravuju i serverovou stranu na neblokující. Zase to vypadá dobře, ale jen než zkusím opět ten velký obrázek. Bohužel je teď neblokující i zápis do streamu, a když se to nevejde do bufferu (64 KB), resp. ještě není vyprázdněný, tak to spadne. Takže ještě upravit volání write, aby zkontrolovalo kolik dat se předalo k odeslání a postupně to odeslat po částech.
Už dlouho jsem se do programování takhle nezakousl. Ale po třech "dnech" to snad funguje.
Závěr
  • hotovo (snad, je třeba to řádně otestovat): odesílání dat na webovou stránku (text, obrázek) a příjem dat z webu (pouze text)