Marina
projekt Roboloď
Projekt „Roboloď” pro mne začal na vánočním večírku 2015, tj. skoro před třemi lety. Bývalý kolega z práce říkal, že jeho kamarád shání někoho, kdo by dokázal zrobotizovat lodičku zavážející krmení do sádek na rybníce. Projekt byl (a stále je) takový „tajuplný”, ale nakonec jsme se se dvěma dalšími kamarády rozhodli do toho jít. Když nic, tak ověříme, jak se nám spolupracuje a na vodě jsme s robotama ještě nebyli … Blog update: 8/9 — Vodní test 3
Historické pozadí
Po několika iteracích se ukázalo, že to je vlastně kamarád kamaráda, který
to poptává pro svého dobrého zákazníka a ten to možná dělá ještě pro někoho
dalšího. První domluva, o co přesně jde, nějaký čas trvala.
Asi první zklamání (setkání s realitou) bylo, když se ukázalo, že „zavážková
lodička” je fakticky malý RC model. Do té doby jsem měl představu pramice
nebo nějakého motorového člunu, který uveze člověka, který by zavážel návnadu
na uživatelem zadanou GPS souřadnici. Zatímco u velké lodě bychom se s
elektronikou a i nějakým vývojem do základní ceny možná nějak schovali, u
plastové čínské hračky to už tehdy (kdybychom si to přiznali) nepřipadalo v úvahu.
Komerčně jsme to v tento okamžik měli vzdát, což jsme neudělali. „Vždyť pro to
všechno máme a v Číně se dají součástky pořídit za pár drobných!” Jo, jo,
kolikrát v životě člověk ještě podobnou chybu udělá
Na druhou stranu výhodou malé lodičky bylo, že nám ji jednoho dne mohla kamarádka kamaráda v
krabici přivézt, a následně nebyl velký problém jít testovat „k lachtanovi” na Petřín
nebo na Vltavu.
Technologie
PPM řízení serv
Ona to vlastně byla celkem pěkná hračka a holt jsme (obávám se, že nemůžu
použít minulého času) jak děti a tak jsme ji vyzkoušeli a obratem rozebrali.
Řízení lodi je diferenciální, tj. dva motory a dva vodní šrouby. Dálkově je možné
ještě zapínat LEDky (hodí se v noci nebo za šera) a vysypávat náklad. Celkově
čtyřkanálová vysílačka s přijímačem. Komunikace je jednosměrná, i
když je možné dokoupit např. sonarový modul pro detekci ryb, a ten by
pravděpodobně obsahoval i posílání dat zpět uživateli.
Připojení přijímače do řídící jednotky (časem pracovně nazývaná „čínská hlava”) je
pomocí trojžilového kabelu. Zem, napájení a „nějaký” signál. Pulzy pro řízení
serv již léta znám, ale jak je až 8 kanálů kombinovaných do
jednoho signálu byla pro mne novinka. Jedná se o takzvané PPM kódování, co
používá Futaba: jednotlivé 1.5ms dlouhé pulzy definují náběžnou hranou
jednotlivé kanály a hlavní cyklus zachovává 20ms periodu (tj. 50Hz).
Před pár měsíci si Šimi pořídil digitální sondu a z ní lze vyčíst a nakreslit
obrázek výše (kéž bychom toto měli na začátku).
A další plán? Napíchneme si na tento kabel „štěnici”, která bude signál
odposlouchávat a podle typu navigace buď přijímaný signál přepošle dál nebo
vygeneruje vlastní pro autonomní řízení. Snadné, není-liž pravda?
Zavařené čínské hlavy
U čínských výrobků jde hlavně o cenu, takže je očekávané (teď už to vím), že
součástky nebudou nijak předimenzované, spíše naopak. Pro řízení motoru nebyl
použit žádný H-můstek, jak je známe z našich robotů, ale kombinace relátek a
tranzistorů, které na některé signální sekvence reagovaly vyhořením :-(. Trošku
nás uklidnila (možná nás měla naopak více znervóznit!) zpráva od dodavatele,
že se to občas děje i při normálním
používání (?!), ale stavte nad tím autonomii!
Nakonec jsme používali pouze tři příkazy vlevo, rovně a vpravo a dávali si
pozor ať z příkazu vlevo nepřecházíme do příkazu vpravo. Stejně tak jsme
eliminovali couvání a tedy změnu směru otáčení motorů.
Senzory pro navigaci
Je až neuvěřitelné, jak za ta léta klesla cena GPS a IMU jednotek. Tento trend je jistě
spojen s integrací senzorů do telefonů, ale možná i nejrůznějších hraček. Šimi poměrně
dost brblal, když jsem chtěl nahradit 2D kompas z první dávky 3D kompasem s
gyrem … přeci jenom to zdvojnásobilo cenu součástek (!). Poučení? U prvních
prototypů neřešte cenu součástek, stejně nakonec budou v produkci jiné!
Komunikace
Automonmí řízení mělo být realizováno pomocí WiFi připojení. Šimi si již delší
dobu hrál s oblíbeným ESP8266, zase v ceně pár dolarů v jednokusech a stačilo
„jen to zapojit”.
Arduino
Pro odposlech přijímaného signálu a generování nového jsme chtěli použít
Arduino. Zase je to o ceně - to ani obyčejnou destičku vám nevyrobí za cenu již
připravené a osazené varianty s Arduinem. Arduino jsem již jednou programoval
(viz FireAnt), ale stejně mne to párkrát dostalo (detaily
viz dále).
Android aplikace a celkové schema
Aby byl obrázek kompletní, je třeba ještě zmínit hlavní řídící aplikaci, která
běžela na Android telefonu (telefon nebyl součástí dodávky). Uživatel se k lodičce
připojil pomocí WiFi, realizované ESP8266 čipem. Ten se dále postaral o sběr a
přeposílání dat z GPS přes seriový port a IMU a Arduino přes I2C.
Komunikační protokol
Vše to začalo přeposíláním dat ze seriáku přes WiFi (je na to možná i nějaký
vzorový příklad, ze kterého Šimi vycházel?). A jelikož na seriáku byla GPS,
která mluvila NMEA protokolem, tak i výsledný komunikační protokol tomu zůstal
hodně podobný, tj. textový, '$' na začátku a '*' s kontrolním součtem na
konci.
TCP vs. UDP
Co je lepší používat na řízení lodičky, TCP nebo UDP protokol? Na první pohled
by se zdálo, že samozřejmě TCP, tam je přece zaručený přenos, neztrácí se pakety a o
vše se stará systém. Myslím, že i důvod pro první použití TCP byl právě
příklad sériová linka-WiFi, který TCP používal (přeci jenom nechcete, aby se vám
ztrácely bajty).
A jak to fungovalo? No zvláštně. S ultrastarým notebookem to
šlo celkem dobře, ale s mým (teď už asi jenom 10 let starým) notebookem
nikoliv. Detaily si teď už moc nepamatuji, ale pokud jsem po každém přijatém
paketu něco poslal, tak to začalo fungovat lépe. Důvod? Ukázalo se, že TCP
na straně ESP8266 úplně dobře nepodporuje okénko pro potvrzení přijetí, nebo to
bylo špatně nakonfigurované, a novější OS jako default počítal s potvrzením až
po několika zprávách. ESP8266 však udrželo jenom jeden TCP paket.
UDP s upraveným protokolem byla lepší volba. Co dělat
při ztrátě paketu? Poslat ho znova nebo raději již poslat další s novějšími
daty? Je to podobné jako u streamování videa - pokud něco vypadne, tak je to
hloupé, ale pokud toho není moc, tak to skoro nepoznáte. Do UDP paketů tedy
přibyl čítač (index paketu), aby bylo možné výpadky snadno detekovat. Přibyla i
časová známka pro měření latence. Konečně lodička posílala i poslední
akceptovaný příkaz, podle kterého momentálně naviguje.
Navigační smyčka
Klasicky verze 0 byla nejtriviálnější varianta, která by mohla fungovat:
- zjisti GPS pozici
- zjisti úhel z kompasu
- spočítej úhel k cílovému bodu
- je-li absolutní rozdíl úhlu (vezme-li se v úvahu 360 stupňů perioda) větší než daný limit, proveď korekci vlevo nebo vpravo, jinak jeď rovně
- je-li vzdálenost menší než 2m, tak na chvíli zastav a pak naviguj na další bod
Prostě takový „vodní” RoboOrienteering
. A kupodivu to nebylo až tak zlé! Resp. začaly vylézat úplně jiné problémy,
než, které jsme rešili na začátku. Např. se ukázalo, že nutný požadavek je, aby
se lodička autonomně navigovala do cílů vzdálených až 300m. Jako on tam občas
nějaký WiFi packet doletí, ale na nějakou spolehlivou navigaci zapomeňte.
S tím byl spojen i problém ultra dlouhé zpětné vazby (navíc s vypadáváním
paketů). Pošlete-li příkaz: „zatáčej doprava” a následných 10 příkazových
paketů se ztratí, co myslíte, že se stane? HW byl poddimenzovaný, tak jsme to
dál flikovali rozšířením příkazů o dobu jejich trvání (de-facto počet 20ms period)
Po jejím vypršení se přešlo na defaultní
příkaz, který byl „jeď rovně”.
Dobré, resp. lepší než předtím, ale … s novým přesnějším nástrojem se
ukázalo, že „čínská hlava” na korekce občas vůbec nereaguje!? Pokud zatočíte
volantem doprava a jen někdy na to stroj zareaguje opravdovým zatočením, tak
to je skoro … těžké. Bylo by třeba posílat daný přikaz a rovnou nějak
ověřovat, že je realizovaný. Asi vás nemusím 2x přesvědčovat, že to už je pak
jednodušší si tam dát vlastní H-můstek a ty motory si prostě řídit sám.
Druhá limitace HW, tentokrát našeho, byl výkon. Pokud chcete nějak rozumně
zpracovávat gyra, kompas a nedej bože akcelerometry, tak potřebujete vyšší
vzorkovací frekvenci, ať můžete průměrovat/filtrovat. My se horkotěžko dostali
na 8Hz.
Gyro vs. kompas
Jak jsem psal výše, verze 0 používala pouze kompas pro určení aktuálního směru
lodi. Co je ale dobré mít na pozoru, že kompas je typicky hodně filtrovaný a má
tedy relativně pomalou odezvu. Pokud se lodička točí jak blázen, tak získané
měření z kompasu moc relevantní nebude … to jsem chytrý, co? … to víte,
generál po boji.
Ve zkratce to byl jeden ze zdrojů kmitání … prostě lodička si myslela, že
kouká špatným směrem, ale fakticky už měla jet rovně. Pro rychlé korekce úhlu
je rozhodně lepší použít čistě integraci úhlové rychlosti z gyra.
Android aplikace
Android verzi uživatelské aplikace nám naprogramoval PetrS. Ano, klasicky se
ukázalo, že i ta nejtriviálnější verze není jen tak a hned. A pak „drobnosti”
typu: „vy určitě chcete být na internetu, ale ten přes lodičku nějak
nefunguje, tak více to, já vás raději přepojím na jinou wifinu ...”
Výsledné řešení se mi svoji jednoduchostí libilo . Jelikož manualní řízení
přes RC vysílačku stále fungovalo (v libovolný okamžik tak uživatel může
převzít řízení automatu), tak na jednotlivé cílove body člověk najel ručně. V
Android aplikaci pak pouze zmáčnul plus jako přidej bod. První a
automaticky i poslední bod byl HOME, kam se lodička po skončení úkolu
vrací.
Autonomní jízda byla pak podobně jako u přehrávání muziky: tlačítko Play,
Pause, Stop.
Drobnou vadou na kráse byla nutnost kalibrace kompasu, ale tato akce byla
schovaná v nastavení společně s před-výběrem WiFi spotu.
Závěr a „Matrix reloaded”?
Jednou z mých (skoro tajných) motivací v tomto projektu bylo vytvoření „černé
krabičky”, kterou dáte do libovolné RC hračky a získáte tím autonomního
robota se znalosti GPS pozice a WiFi komunikací. Ono se ale ukazuje, že
zmíněný Futaba PPM protokol zas tak běžný v levných RC hračkách není, což je
asi ale teprve první problém.
Teď bych šel Šimiho cestou, který si to celé vedle postavil znova, jen místo
Arduina použil Raspberry Pi Zero W
a to řízení si naprogramoval v Pythonu. Vše to jelo
rovnou na lodi, tj. žádné problémy s výpadky paketů. Ano, je to o trošku dražší, ale
jestli jsme to definitivně nevzdali (já myslím, že jo), tak toto je cesta
(možná).
Appendix — Arduino digitalWrite()
Asi první zrada s Arduino programováním bylo debugování pomocí
LEDky. Co jsem si z programování AVRka pamatoval, že dané makra, jako např.
sei(), se přímo překládají na 1:1 asemblerovské instrukce. A zápis na port
by měl proběhnout v jednom taktu. Toto ale rozhodně neplatí pro funkci
digitalWrite() a volat tuto funkci v interruptu rozhodně není dobrý
nápad.
Co se vám v podobném případě může hodit je znalost, jak generovat assembler
výstup? Odpověď naleznete na
Arduino fóru:
m:\arduino-nightly\hardware\tools\avr\bin\avr-objdump.exe Files > Preferences > verbose compilation
Zde je pro představu dekompilace celé funkce digitalWrite() (no vlastně
není celá, protože v některých případech volá ještě další pod-funkce):
void digitalWrite(uint8_t pin, uint8_t val) { 99e: 0f 93 push r16 9a0: 1f 93 push r17 9a2: cf 93 push r28 9a4: df 93 push r29 9a6: 1f 92 push r1 9a8: cd b7 in r28, 0x3d ; 61 9aa: de b7 in r29, 0x3e ; 62 uint8_t timer = digitalPinToTimer(pin); 9ac: 28 2f mov r18, r24 9ae: 30 e0 ldi r19, 0x00 ; 0 9b0: f9 01 movw r30, r18 9b2: e8 59 subi r30, 0x98 ; 152 9b4: ff 4f sbci r31, 0xFF ; 255 9b6: 84 91 lpm r24, Z uint8_t bit = digitalPinToBitMask(pin); 9b8: f9 01 movw r30, r18 9ba: e4 58 subi r30, 0x84 ; 132 9bc: ff 4f sbci r31, 0xFF ; 255 9be: 14 91 lpm r17, Z uint8_t port = digitalPinToPort(pin); 9c0: f9 01 movw r30, r18 9c2: e0 57 subi r30, 0x70 ; 112 9c4: ff 4f sbci r31, 0xFF ; 255 9c6: 04 91 lpm r16, Z volatile uint8_t *out; if (port == NOT_A_PIN) return; 9c8: 00 23 and r16, r16 9ca: c9 f0 breq .+50 ; 0x9fe// If the pin that support PWM output, we need to turn it off // before doing a digital write. if (timer != NOT_ON_TIMER) turnOffPWM(timer); 9cc: 88 23 and r24, r24 9ce: 21 f0 breq .+8 ; 0x9d8 9d0: 69 83 std Y+1, r22 ; 0x01 9d2: 0e 94 6d 04 call 0x8da ; 0x8da 9d6: 69 81 ldd r22, Y+1 ; 0x01 out = portOutputRegister(port); 9d8: e0 2f mov r30, r16 9da: f0 e0 ldi r31, 0x00 ; 0 9dc: ee 0f add r30, r30 9de: ff 1f adc r31, r31 9e0: ec 55 subi r30, 0x5C ; 92 9e2: ff 4f sbci r31, 0xFF ; 255 9e4: a5 91 lpm r26, Z+ 9e6: b4 91 lpm r27, Z uint8_t oldSREG = SREG; 9e8: 9f b7 in r25, 0x3f ; 63 cli(); 9ea: f8 94 cli if (val == LOW) { *out &= ~bit; 9ec: 8c 91 ld r24, X out = portOutputRegister(port); uint8_t oldSREG = SREG; cli(); if (val == LOW) { 9ee: 61 11 cpse r22, r1 9f0: 03 c0 rjmp .+6 ; 0x9f8 *out &= ~bit; 9f2: 10 95 com r17 9f4: 81 23 and r24, r17 9f6: 01 c0 rjmp .+2 ; 0x9fa } else { *out |= bit; 9f8: 81 2b or r24, r17 9fa: 8c 93 st X, r24 } SREG = oldSREG; 9fc: 9f bf out 0x3f, r25 ; 63 } 9fe: 0f 90 pop r0 a00: df 91 pop r29 a02: cf 91 pop r28 a04: 1f 91 pop r17 a06: 0f 91 pop r16 a08: 08 95 ret 00000a0a <_ZN6StringD1Ev>: *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); }
Pokud ale potřebujete rychlou verzi (tak, jak jsem to naivně předpokládal), tak
je třeba použít přímo bitovou konstrukci:
ARDUINO_LED_PORT |= ARDUINO_LED_BIT; // faster digitalWrite(ARDUINO_LED, HIGH); ARDUINO_LED_PORT &= ~ARDUINO_LED_BIT; // faster digitalWrite(ARDUINO_LED, LOW);
Blog / Marina 2.0
15. srpen 2018 — Marina 2.0
Šimi to nechce vzdát. Je to marný, je to marný, je to marný. Jsem teď na
krátké dovolené u Lipenského jezera a to je přeci ideální příležitost pro
testovaní nové konfigurace, není-liž pravda? No asi jsem to měl spíše nechat
doma …
Včera jsem chtěl psát, proč to musí být vždy tak komplikované — proč nestačí
to jenom pustit a jede to? Je tu dost omezený internet a lodička není přepnuta
do Access Point režimu. Ale mám adaptér na micro SD kartu a dokonce jednu
náhradní … takže nějaká cesta existuje, snad.
První pozorování bylo, že když jsem SD kartu dal do Win7 počítače, tak jednak
ji chtěl hned opravovat (to jsem mu raději zakázal), ale pak jediné co bylo
čitelné byl nějaký boot disk. Karta má 2GB, ale ten boot disk má pouze 42MB??
Sebral jsem manželce USB kabel na telefon a postupoval podle článku
Connect
To A Raspberry Pi Zero With A USB Cable And SSH (současně jsem koukal do
desertbot.io SSH into Pi
Zero over USB). Vlastně to vypadá jednoduše:
- USB kabel zapojit do „prostředního” konektoru s názvem USB (tj. ignorovat krajní POW konektor)
- na micro SD kartě vytvořit prázdný soubor se jménem ssh
- editovat config.txt a přidat na konec souboru řádek dtoverlay=dwc2
- editovat cmdline.txt a rozšířit příkazový řádek o modules-load=dwc2,g_ether (má tam být pouze jedna oddělující mezera a vše je na jediném příkazovém řádku)
Pak jsem USB zapojil do počítače a po chvíli se objevilo:
RNDIS/Ethernet Gadget - No driver found |
V článku
How
to install Microsoft RNDIS driver for Windows 7 to bylo celkem přímočaré a až
na poslední varování, že driver nebude možná fungovat to prošlo.
V ipconfigu jsem viděl další vytvořené spojení:
Ethernet adapter Local Area Connection 3: Connection-specific DNS Suffix . : Link-local IPv6 Address . . . . . : fe80::24c1:bf2:aee1:ce8e%67 Autoconfiguration IPv4 Address. . : 169.254.206.142 Subnet Mask . . . . . . . . . . . : 255.255.0.0 Default Gateway . . . . . . . . . :
ale jakou adresu má RasPi? Ono to vlastně píšou i v tom článku … stačí se
připojit pomocí ssh pi@raspberrypi.local:
RasPi konzole přes USB |
Ještě jsem nezmínil jeden detail: po připojení ke zdroji napájení (přes USB) se
objevila WiFi lodičky?! Po překonfigurování na Access Point WiFi od RasPi
zmizela a další experimenty jsem odložil až na další reboot. No a to se
pomalu dostáváme ke dnešku … zase vidím WiFi (možná je ze starého ESP8266,
který je tam stále někde schovaný??) a zase se nemůžu připojit. Horší je, že se
nemůžu připojit ani přes to USB :-(. Napadá mne pouze restart Windows …
Dnes asi žádné spojení nebude ... |
16. srpen 2018 — WARNING Socket timeout!
Tak reboot Windows nepomohl ani reinstalace RNDIS/Ethernet Gadget driveru.
Sigh. A tak jsem udělal další krok, za který bych ostatní v lepším případě
peskoval v horším rovnou fackoval. Modifikoval jsem záložní micro SD kartu. A
to stejným způsobem, co jsem popisoval včera, tj. zpřístupnění ssh konzole přes
USB. Tentokrát jsem se ale vyvaroval jakýchkoliv zásahů do
/etc/network/interfaces, který mohl být zdrojem problému …
Také psal Šimi: Na SD kartě jsou 2 partitions /boot je FAT32 (50MB) a velká
/rootfs je ext4. Ale filesystem ext4 zase není vidět ve Win7 :-( Našel jsem, že
snad číst i zapisovat Ext4 ve Win by měl umět http://www.ext2fsd.com/
Ne, ESP tam není, je tam nainstalováno hostapd, které se má starat o
vytvoření AP, ale myslel jsem, ze je vypnuté, nebo se to chová tak, že když v
módu station nenajde v nějakém timeoutu známý AP, tak zapne hostapd?
Mě se to do AP nikdy nepřepnulo, ale zkoušel jsem to jen v dosahu našeho AP.
Jestli se ti objeví v seznamu WiFi, tak to tak musí být. Dá se na něj přihlásit?
Mělo by to být bez hesla. Jestli to nepůjde, tak ještě musí být správně
nastavené /etc/dnsmasq.conf? Ale teď, když se do Rasp nedostaneš ani kabelem
kvůli driveru, ani wifi kvůli nastavení, ani na SD kvůli filesystemu... Ani
tady to bez boje nepůjde :-/ Držím palce.
Stav je teď ale trošku jiný. S druhou kartou se mi opět podařilo přihlásit přes
USB kabel. Stejně tak se objevilo SSID lodičky. Znova jsem koukal do
originálního /etc/network/interfaces a vše je tam zakomentované. Cvičně
jsem i zkoušel přímo pustit kód python3 marina.py, který selhal na
pi@raspberrypi:~/marina $ python3 marina.py Socket created Traceback (most recent call last): File "marina.py", line 33, in __init__ self.skt.bind((self.UDP_IP, self.UDP_PORT)) OSError: [Errno 98] Address already in use During handling of the above exception, another exception occurred: Traceback (most recent call last): File "marina.py", line 207, inmain() File "marina.py", line 183, in main net = Net(ppm_switcher) File "marina.py", line 34, in __init__ except (socket.error, msg): NameError: name 'msg' is not defined
… a on důvod byl, že marina.py se pouští automaticky. Z ps axuf
vybírám:
pi@raspberrypi:~/marina $ ps axuf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND … avahi 252 0.0 0.7 6388 3132 ? Ss 21:35 0:00 avahi-daemon: running [raspberrypi.local] avahi 261 0.0 0.3 6388 1608 ? S 21:35 0:00 \_ avahi-daemon: chroot helper root 320 0.1 0.6 10128 3060 ? Ss 21:35 0:01 wpa_supplicant -B -c/etc/wpa_supplicant/wpa_supplicant.conf -iwla root 414 0.0 0.4 2920 1812 ? Ss 21:35 0:00 /sbin/dhcpcd -q -w root 425 30.7 1.9 55412 8832 ? Sl 21:35 5:30 python3 /home/pi/marina/marina.py root 474 0.0 0.5 6160 2624 ? Ss 21:35 0:00 /usr/sbin/hostapd -B -P /run/hostapd.pid /etc/hostapd/hostapd.con dnsmasq 477 0.1 0.5 9068 2424 ? S 21:35 0:01 /usr/sbin/dnsmasq -x /run/dnsmasq/dnsmasq.pid -u dnsmasq -r /run/ …
Systém jsem shodil a znova zapnul, tentokrát ale přes PWR konektor a šlo se
připojit na WiFi! … ano IP adresu jsem si pamatoval z minulého běhu. I to
zalogovalo několik sekund „jízdy” všech senzorů. OK
Krabičku s RasPi, senzory a Arduinem jsem tedy zase sešrouboval, přepojil
napájecí konektor z lodi a do třetice zapnul. Připojit přes WiFi šlo, ping
fungoval, ale … řízení lodičky stávkuje. Nekomunikuje a jenom to hází:
m:\git\robolod\robolod\python>c:\Python27\python.exe boat.py 169.254.88.144 9999 "WiFi only … boat battery" METALOG: logs/meta_180816_125343.log Arduino RESET None 2018-08-16 12:53:45,012 WARNING Socket timeout! ERR: 1 2018-08-16 12:53:47,026 WARNING Socket timeout! 2018-08-16 12:53:49,026 WARNING Socket timeout! 2018-08-16 12:53:51,028 WARNING Socket timeout! 2018-08-16 12:53:53,029 WARNING Socket timeout! 2018-08-16 12:53:55,030 WARNING Socket timeout! …
a žádná data nechodí (ani po několika opakováních). Divné … asi mne čeká
další rozborka-sborka''.
17. srpen 2018 — Test Ext2Fsd-0.69 + problém s napájením?
Zatím žádná sláva. Sice jsem si vytvořil teorii, čeho by mohl být WARNING
Socket timeout! důsledkem: marina.py je náš kód, který nemusí být úplně
na vše připravený a pokud nějak částečně spadne, tak může být následně
problém se připojit. No jo, ale ono se to postupně ještě zhoršovalo. V první
fázi jsem mohl Marinu přes WiFi spojení stále pingnout, ale již se k ní
nešlo připojit pomocí ssh:
problém s ssh připojením |
Nezbylo mi, než „roboloď” natvrdo vypnout. Ale po zapnutí už se neobjevila
ani její WiFina :-(.
Dnes jsem řídicí krabičku zase rozdělal, odpojil napájení z lodi a zkusil
nejprve připojeni (a napájení) přes USB a v druhém kroku pouze napájení přes
POW konektor. Oboje fungovalo bez problémů! Tak mne jenom napadá, jestli loď
nemá nějaký problém s napájením??
Ext2Fsd-0.69
Druhá řada neúspěchů byla na poli micro SD karty a Ext4 partition. Po přečtení
úvodní stránky Ext2Fsd projektu, kde autor píše:
Don't use Ext2Fsd 0.68 or earlier versions with latest Ubuntu or Debian
systems. Ext2Fsd 0.68 cannot process EXT4 with 64-BIT mode enabled, then it
could corrupt your data. Very sorry for this disaster issue, I'm working on an
improvement. jsem byl „lehce” nervozní to vůbec instalovat, ale … moc
času nezbývá, sigh.
Po vložení SD karty a puštění Ext2 Volume Manageru to vypadalo celkem dobře:
Ext2 Volume Manager |
tj. u DISK 2 je vidět Linux Partition type. No jo, ale když jsem ji
chtěl připojit nebo přiřadit disk, tak celý program spadnul :-(
Mount Linux partition |
Pád programu |
No nic. Je možné, že ta karta je opravdu nějak poničená a proto si ji nemůžu
přečíst, ale … vlastně i s tou druhou kartou lodička naběhla a byla vidět
její WiFina (jen jsem ji přestal používat, protože se nedalo připojit přes USB
a vlastně asi ani přes tu WiFi).
Zbývá necelých 24h … začínám být pomalu pesimistický …
19. srpen 2018 — Prohra - skóre 0:1
Tak Marina 2.0 nakonec opouštěla Lipno, aniž by si zaplavala :(. Ještě jsem
ověřoval variantu, že to není „duchařina”, tj. jestli náhodou neruší RC
vysílačka WiFinu, ale vypadá to, že ne — po odpojení konektoru a napájení
přes POW konektor s běžící lodičkou vše fungovalo OK. Předpokládám rušení na
napájení??
Šimi teď přepnul na prioritní dlouhodobý projekt „Ondra”, ale snad do září
připraví mini-revizi HW. Ještě info: Marina.py se spouští v souboru
/etc/rc.local., ale jestli se výstupy automaticky logují netuším??
raspi-gpio set 14 ip python3 /home/pi/marina/marina.py & iptables-restore < /etc/iptables.ipv4.nat
Předpokládám, že první řádek je „tajuplný hack” s GPS I/O, ale jistý si
nejsem. Stejně tak proč je třeba nastavovat iptables??
Nasucho si asi můžu hrát s upgrade řídícího boat.py a testovat logování UDP
packetů na OSGARovi.
25. srpen 2018 — OSGAR UDP Logging
To byla zase jednou výživná lekce :-(. Dnes jsem se pokoušel rozchodit logování
UDP pomocí OSGAR knihovny. A nefungovalo
to. Raspberry mám připojené přes USB, tj. spojení přes kabel. Starý
boat.py kód funguje, nový logsocket.py nikoliv. Prošel jsem snad
všechny rozdíly v kódu a nic …
A pak mi došel jeden detail — starý kód pouštím pod Python2, ale nový již
běží v Python3, že by tam něco změnili?! Upravil jsem si marina.py na
lodičce, aby vypisovala debug hlášky a v obou případech přijde první paket a to
ze stejné IP adresy a portu. Následně lodička začne chrlit tuny zpráv o stavu
senzoru. Pak už jsem to nevydržel a minimalistickou verzi zkusil rovnou v
konzoli:
M:\git\osgar>python Python 3.6.2 (v3.6.2:5fd33b5, Jul 8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import socket >>> soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) >>> soc.bind(('', 9999)) >>> soc.recvfrom(1024) ^C m:\git\robolod\robolod\python>c:\Python27\python.exe Python 2.7.5 (default, May 15 2013, 22:43:36) [MSC v.1500 32 bit (Intel)] on win 32 Type "help", "copyright", "credits" or "license" for more information. >>> import socket >>> soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) >>> soc.bind(('', 9999)) >>> soc.recvfrom(1024) ('93191615643CHV,1000,1001,1000,1000,A*31\r\n', ('169.254.91.207', 9999)) >>> soc.recvfrom(1024) ('93201615731MAG,-139,-364,481,252.00*67\r\n', ('169.254.91.207', 9999))
A důvod, proč Python 2.7 jede, ale Python 3.6 nikoliv? No jak se dostanete až
na dno problému, tak je to vlastně jednoduché …
Přes
Firewall
for dummies jsem se dostal k obrázku výše a potvrdil konečnou domněnku —
pro starší Python jsem měl porty otevřené, ale pro nový nikoliv. Sigh.
M:\git\osgar>python Python 3.6.2 (v3.6.2:5fd33b5, Jul 8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import socket >>> soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) >>> soc.bind(('', 9999)) >>> soc.recvfrom(1024) (b'40511175634CHV,1000,1022,1000,1000,A*30\r\n', ('169.254.198.186', 9999)) >>> soc.recvfrom(1024) (b'40521175718MAG,-221,-458,425,248.00*60\r\n', ('169.254.198.186', 9999))
Tak teď už jenom uklidit ty hromady hnoje, co jsem tam tam přidal, abych
zjistil rozdíl, a připravit
pull request na logování UDP.
Ano, teď už to jede … viz boat-180825_182317.log.
30. srpen 2018 — Powerbanka
Dobrá zpráva — lodička jede a lze se na ní připojit. Provizorní řešení je
trošku obskurní, ale … účel světí prostředky. Vypojil jsem 5V napájecí
pin a půjčil si od Pavla z Short Circuits Prague powerbanku (resp. půjčil mi
rovnou dvě ).
První pokus se sice WiFi lodičky objevilo, ale lodička neposílala žádná data.
Proč? Program vůbec neběžel a když jsem svoji debug verzi pustil ručně, tak
pi@raspberrypi:~/marina $ python3 md_marina.py Socket created Traceback (most recent call last): File "md_marina.py", line 208, inmain() File "md_marina.py", line 188, in main sensors = Sensors() File "md_marina.py", line 115, in __init__ self.hmc5883l = i2c_hmc5883l.i2c_hmc5883l(1) File "/home/pi/marina/i2c_hmc5883l.py", line 36, in __init__ self.setScale(gauss) File "/home/pi/marina/i2c_hmc5883l.py", line 85, in setScale self.setOption(self.ConfigurationRegisterB, self.scale_reg) File "/home/pi/marina/i2c_hmc5883l.py", line 96, in setOption self.bus.write_byte_data(self.addr, register, options) OSError: [Errno 121] Remote I/O error
… tj. kompas neodpovídá a položilo to hlavní program. A neodpovídá, protože
nebyl napájený … zatím OK. Zapnul jsem tedy napájení lodičky a vše jede, jen
data z GPS zatím moc zajímavá nejsou:
$GPRMC,,V,,,,,,,,,,N*53 $GPRMC,192355.80,V,,,,,,,300818,,,N*7E
ale jsem pod střechou a signál je tu slabý (i když se mi tu dříve GPS již
mnohokrát chytla). No jestli jsem to nezakřikl — teď mi jede jenom GPS, která
je připojena přes RS232. Ostatní senzory a Arduino na I2C se odmlčely.
p.s. vlastně i ta teorie s Remote I/O error je možná pochybná! Nepustil
jsem to jako sudo, ale možná to není nutné??
Další chybka:
File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner self.run() File "/usr/lib/python3.5/threading.py", line 1180, in run self.function(*self.args, self.kwargs) File "/home/pi/marina/scheduler.py", line 16, in _run self.function(*self.args, self.kwargs) File "md_marina.py", line 191, in states_update sensors.update() File "md_marina.py", line 143, in update self.mag = self.hmc5883l.getAxes() + self.hmc5883l.getHeading() File "/home/pi/marina/i2c_hmc5883l.py", line 123, in getHeading headingRad = math.atan2(scaled_y, scaled_x) TypeError: a float is required
Přidal jsem si další debug výpis pro (scaled_x, scaled_y, scaled_z) a
-235.52 None -197.8 nevypadá dobře … TODO (tady by se opravdu hodilo
logování I2C rovnou na lodičce).
3. září 2018 — SMBus a I2CLibraries
Koukám teď na chybu, co jsem reportoval posledně, a ona je vlastně v původní
knihovně. Šimi nakonec volil SMBus, což není
sado-maso, ale The System Management Bus postavený na I2C. V čem se liší
zatím nevím (mám offline stránku
i2c-bus.org, kde mluví o kontrole paketů
(PEC), timeout pro přenosy, standardizované typy, max. bitrate 100kHz/s … ale
to bych jenom papouškoval, aniž bych tomu zatím moc rozuměl).
I2CLibraries je pak už Python
knihovna pro práci s akcelerometrem i2c_adxl345.py, gyrem
i2c_itg3205.py a kompasem i2c_hmc5883l.py. Je zvláštní, že původní
autor přešel od SMBusu k I2C knihovně, ale zase neznám detaily. My jdeme opačným
směrem.
Tak zpět k té chybě — z None se špatně počítá úhel, OK. Knihovna
nahrazuje hodnotu -4096 za None, proč? V HMC5883L.pdf píší: In the
event the ADC reading overflows or underflows for the given channel, or if
there is a math overflow during the bias measurement, this data register
will contain the value -4096. This register value will clear when
after the next valid measurement is made. OK, takže -4096 reprezentuje
nevalidní hodnotu přetečení nebo podtečení …
… pak by i heading měl být nevalidní. Ale také všichni uživatelé musí být
připravení, že možná dostanou None. Uvidíme. Teď nastává ten okamžik, kdy
plně využívám přehrávání z logu 1:1 … stejný kód pustím na notebooku, stejně
mi spadne, opravím, spadne to nejspíše o patro výše nebo na nějakém překlepu
atd. dokud to neprojde. Ale chyba lávky — tady logování aktivity na SMBusu
nemám :-(. Unittesty pro rozšíření také nejsou (teď se odvolávám na zdrojovou
knihovnu I2CLibraries). Zbyněk
by určitě řekl, tak si ten test napiš sám a měl by pravdu …
Hmm, třída pojmenovaná i2c_hmc5883l, nevěřil bych, že mne PEP8 tak nakazí.
No zatím si mne ten wrapper pro kompas moc nezískal. Když jsem udělal
MagicMock na všechno možné:
class HMC5883lTest(unittest.TestCase): def test_overflow(self): with patch('i2c_hmc5883l.smbus') as mock: hmc = i2c_hmc5883l(port=1) hmc.bus = MagicMock() hmc.bus.read_i2c_block_data = MagicMock(return_value=b'001122') hmc.getHeading()
tak to padlo na
M:\git\robolod\robolod\raspberry\python>python -m unittest E ============== ERROR: test_overflow (test_i2c_hmc5883l.HMC5883lTest)--------------Traceback (most recent call last): File "M:\git\robolod\robolod\raspberry\python\test_i2c_hmc5883l.py", line 15, in test_overflow hmc.getHeading() File "M:\git\robolod\robolod\raspberry\python\i2c_hmc5883l.py", line 124, in g etHeading headingRad += self.declination AttributeError: 'i2c_hmc5883l' object has no attribute 'declination'--------------Ran 1 test in 0.018s FAILED (errors=1)
… přemýšlím, kdo ty moje „nářky” bude číst. Možná Šimi, ale nejspíše tím
„zahluším” původní článek :-( … komentáře vítány. Prostě je třeba nejprve
zavolat setDeclination() než použiji getHeading(). Sigh. Nedivím se, že
se do unittestů netestovaných tříd nikdo nehrne …
Tak ještě jednou jsem si „natloukl” aneb testy mají smysl v okamžiku, když
očekáváte jiný výsledek. Tento test by měl přeci již selhat, není-liž
pravda?!
data = struct.pack('>3h', 10, -4096, 30) hmc.bus.read_i2c_block_data = MagicMock(return_value=data) hmc.getHeading()
Neselhal. Proč? Někdo tam, určitě v dobré víře, prohodil Y a Z osu:
(magno_x, magno_z, magno_y) = struct.unpack('>3h', bytes(b))
(toto je již střelba do vlastních řad)
============== ERROR: test_overflow (test_i2c_hmc5883l.HMC5883lTest)--------------Traceback (most recent call last): File "M:\git\robolod\robolod\raspberry\python\test_i2c_hmc5883l.py", line 24, in test_overflow hmc.getHeading() File "M:\git\robolod\robolod\raspberry\python\i2c_hmc5883l.py", line 124, in g etHeading headingRad = math.atan2(scaled_y, scaled_x) TypeError: must be real number, not NoneType--------------Ran 1 test in 0.003s FAILED (errors=1)
Konečně! Asi je na čase to opravit a zatočit s lodičkou, jak je to tedy s
těma osama … pokračování příště.
4. září 2018 — SMBus review
V rámci včerejšího syncu jsem si stáhl
System Management Bus
(SMBus) Specification 3.0. Jednak bych se o tom rád dozvěděl více než
„štěky” typu The System Management Bus (SMBus) is more or less a
derivative of the I2C bus. (src) nebo
SMBus (System Management Bus) is a subset from the I2C protocol
(src)
a pak jsem zvědavý.
Jako programátor se až tak netrápím rozdíly elektrické specifikace (zatím), ale
zajímá mne hlavně komunikační protokol a rozdíly vůči I2C, čemuž je věnován
Appendix B. U I2C není žádná „minimální komunikační rychlost” — pokud
master nebo slave uzemní SCL linku, tak je vše blokované. U SMBusu je
vyžadována minimální frekvence 10kHz s různými časovými limity. Ty
předpokládám všechny tři senzory (kompas, gyro a akcelerometr) splňují a
Arduino s HW řešením I2C je snad také OK, ale raději časem ověřím.
Co se mi nelíbilo, ale teď se to vyjasnilo, bylo naše použití
read_i2c_block_data() se specifikací počtu bajtů ke čtení. SMBus
specifikace totiž popisuje Block Read, kde slave v prvním bajtu
odpovědi říká, kolik bajtů má master přečíst. Ale třeba u kompasu HMC5883
píšou:
To minimize the communication between the master and this device, the
address pointer updated automatically without master intervention. The
register pointer will be incremented by 1 automatically after the current
register has been read successfully.
To move the address pointer to a random register location, first issue a
“write” to that register location with no data byte following the commend. For
example, to move the address pointer to register 10, send 0x3C 0x0A.
Tj. žádné extra bajty o délce bloku! A rozuzlení? Ono i v tom
SMBus Python bindingu je ještě druhá
funkce read_block_data(), která délku jako parametr nedostává, takže snad
OK.
Rozmyslel jsem si i svůj další plán. Lodička musí být nakonec plně autonomní,
tj. chci logovat vše co se tam děje. Plánuji tedy udělat OSGAR I2C wrapper,
takže se mi budete moci smát v přímém přenosu … . A OSGAR tak začne
podporovat i levné senzory na I2C, což se může časem hodit.
p.s. Šimi píše, že Y a Z jsou prohozené jak v původních
I2CLibraries, tak v
HMC5883L
specifikaci … ve zkratce je to tak správně, i když za mne ne úplně
očekávané a jen to dokazuje, že neumím číst … možná je to kompatibilita 2D a
3D kompasů?
5. září 2018 — OSGAR Marina 2.1
Nemůžu spát. Měl jsem přeci jenom poznámky sepsat ještě včera večer a
nenechávat to až na ráno, no nic …
Začal jsem do
feature/marina2-i2c
větve rozcházet Marinu s OSGAR knihovnou. A vlastně to byla po delší době
zase radost — neřeším jen lodičku, ale potenciálně i X dalších robotů.
Klasicky to nebylo bez problémů. Na lodičce není git, ale čert to vem,
kopíruji to tam jak za starých časů. Není tam ani screen, což mne v případě
vypadávajícího spojení bude na vodě určitě mrzet. A pak tam nejsou Pythonovské
balíčky jako numpy nebo msgpack,
který používáme pro serializaci zpráv u OSGARa. Podle všeho tam ale není ani
pip (píp) a setuptools … a v té chvíli jsem to chtěl vzdát.
Vyhození numpy bylo celkem jednoduché — byl to nějaký zbytkový kód v
gps.py, který si zaslouží promazat. Horší to bylo s msgpack. Dobrá
zpráva je, že se používá jenom na jednom místě a to
serialize.py.
Hack byl brutální, ale není čas „řešit třísky” …
Další dílek do skládanky byly specifikace jednotlivých senzorů a návrh
„protokolu”. Naštěstí to mají všechny tři senzory stejné a podobně je i
přiohnutý Arduino kód. Pro zápis je první bajt číslo registru a následují data
pro zapsání. U čtení se nejprve pošle číslo registru ve write režimu a pak
master přepne do read a čte kolik chce bajtů. V kódu to nevypadá 2x
krásně, ale tento výsek specifikuje čtení kompasu, gyra i akcelerometru:
self.i2c_loop = [ [0x1E, 'R', 0x03, 6], # compass HMC5883L [0x68, 'R', 0x1B, 8], # gyro ITG-3205 [0x53, 'R', 0x32, 6], # acc ADXL345 ]
Je to tedy I2C adresa, 'R'/'W', číslo registru a počet bajtu k přečtení resp.
pole bajtu pro zápis. Až mne zaskočilo, když to hned na poprvé fungovalo!
Čtení všech senzorů na I2C vycházel na 40Hz update, což je pěkné (a po pravdě
si nejsem teď jistý, jaká rychlost I2C je momentálně nastavená).
Přidal jsem vyčítání jednotlivých RC kanálů z Arduina a pak už se to začalo
chovat „podle očekávání”:
pi@raspberrypi:~/osgar $ python3 osgar/boat.py run config/test-i2c.json –note "serialized by str(), test new OSGAR marina.py, read Arduino channel 0" Exception in thread Thread-2: Traceback (most recent call last): File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner self.run() File "/home/pi/osgar/osgar/drivers/logi2c.py", line 39, in run received = self.com.read_i2c_block_data(addr, reg, len_or_data) OSError: [Errno 121] Remote I/O error
Pak ještě asi 4x a ve všech případech (s logy je to celkem triviální
záležitost) to bylo čtení gyra:
0:00:06.504589 1 [30, 'R', 3, 6] 0:00:06.505638 1 [104, 'R', 27, 8] 0:00:06.506624 1 [83, 'R', 50, 6] 0:00:06.507602 1 [8, 'R', 0, 2] 0:00:06.513724 3 [30, 3, [2, 249, 4, 251, 251, 219]] 0:00:07.148480 2 [30, 'R', 3, 6] 0:00:08.150481 2 [30, 'R', 3, 6] 0:00:09.152503 2 [30, 'R', 3, 6] 0:00:10.154548 2 [30, 'R', 3, 6]
… toto je výpis z logu, kde první je čas v sekundách, číslo uloženého kanálu
(zde je 1 zápis na I2C, 2 je aplikační cyklus a 3 je čtení z I2C) a na 104 už
nedošlo. Předpokládám, že je to tím, že z gyra čtu nejvíce bajtů v jednom bloku
(8), tak to asi zkusím rozdělit na dva dotazy: teplota a jednotlivé osy. Nebo
to spíše použiji jako testovací příklad na zotavení z chyby. A také bych ověřil
tu rychlost a nastavil ji na 100kbps, pokud není.
Jak jsem říkal, že teď už neřeším jenom lodičku, ale i jiné roboty, tak jsem
např. narazil na chybu, resp. neočekávané chování, kdy pořadí kanálů se měnilo
mezi jednotlivými běhy:
0:00:00.018215 0 b"{'names': ['app.raw', 'boat.cmd', 'i2c.i2c']}" vs. 0:00:00.018767 0 b"{'names': ['i2c.i2c', 'app.raw', 'boat.cmd']}"
Správně bych k nim měl přistupovat přes jména, ale myslel jsem, že se to
nejprve vše nakonfiguruje a až v druhém kroku nastartuje, ale … další TODO k
ověření.
Ještě pozorování, že po vyčtení všech šesti Arduino kanálů (opravdu má ta
vysílačka tolik kanálů??) a stavu, zda je či není vysílačka zapnutá klesla
frekvence na 16.6Hz … ale zatím bych to neřešil. Chybí ještě posílání příkazů
na motory, tj. ještě se to o něco zpomalí.
Konečně jsem přilepil i konfiguraci GPS driveru (pár řádek v konfiguraci), ale
pod střechou se mi nechytá (to dobou venku celkem lilo, takže test jsem
odložil).
0:00:00.028329 0 b"{'names': ['i2c.i2c', 'boat.cmd', 'gps_serial.raw', 'gps.position', 'gps.rel_position', 'app.raw']}" … 0:00:00.330516 3 b'GPGGA,,,,,,0,00,99.' … 0:00:00.356955 3 b'99,,,,,,*48\r\n' 0:00:00.359239 4 [None, None]
Kostelní hodiny odbily 4am … možná vhodný okamžik na změnu modu …
p.s. teď jsem ve fázi sběru dat a funkční autonomní celek je ještě daleko.
Uvědomuji si, co práce musel Šimi investovat na rozchození celé lodičky
„postaru”. Pokud to vyjde, tak vyrazím na vodu nasbírat alespoň nějaká data v
manuálním režimu.
6. září 2018 — Vodní test
Dnes večer jsem vyrazil k vodě. Zbývá poslední den možná dva a tak mi lehce
„teče do bot”. Naštěstí ale neteče do lodičky. To bylo první pozorování,
kdy zadek se dost naklonil a voda se dostala do komory pro krmení. Ale v
prostorách s elektronikou naštěstí zůstalo sucho.
Udělal jsem tři testy a všechny dopadly stejně: lodička se zuřivě točila 10s
vlevo a hlásila, že je cca 20 metrů od cíle. Tipoval bych to na problém s
kalibrací kompasu, ale to uvidíme …
Pokud se podíváte na
poslední
commity, tak uvidíte celkem nepěkné „zářezy”, se kterými bych se moc
nechlubil. Zkopíroval jsem experimentální verzi ze starého captain.py,
upravil print pro Python3, line.py a route.py přesunul do
osgar/lib a rozšířil konfiguraci, aby řídící aplikace dostávala pozici od
GPS a směr lodi z kompasu.
Výpadky I2C při komunikaci s gyrem jsem zatím ošetřil jedním odchycením výjimky
OSError, zapsání do logu a jedno zopakovaní čtení. V logu to pak vypadá:
0:00:04.042995 5 [30, 3, [2, 149, 5, 117, 249, 173]] 0:00:04.050689 0 b'[Errno 121] Remote I/O error' 0:00:04.058167 5 [104, 27, [198, 96, 255, 250, 255, 164, 255, 253]] 0:00:04.063915 5 [83, 50, [247, 255, 1, 0, 225, 255]]
takže snad dobré.
Z nasbíraných dat zatím dekóduji pouze kompas. Kalibraci jsem udělal první na
stole (zatím hardcoded) a po dvou otáčkách lodičky ve vzduchu vypadala celkem
rozumně:
Upravil jsem také řízení motorů — zatím i horní vrstva používá šířky pulzu,
kde 1000 odpovídá středové poloze. Původní kód bral v úvahu aktuální úhlovou
rychlost lodičky, což momentálně chybí.
Z nepříjemností zatím vadí posílání float hodnoty (podle očekávání).
M:\git\osgar>python osgar\replay.py d:\md\osgar\logs\boat\boat-180906_174543.log –module boat … Exception in thread Thread-1: Traceback (most recent call last): File "D:\WinPython-64bit-3.6.2.0Qt5\python-3.6.2.amd64\lib\threading.py", line 916, in _bootstrap_inner self.run() File "M:\git\osgar\osgar\drivers\marina.py", line 53, in run self.bus.publish('heading', heading) File "M:\git\osgar\osgar\bus.py", line 72, in publish assert data == ref_data, (data, ref_data) AssertionError: (0.42291981964892333, 0.4229198196489234)
Tj. pokud ten float zapíšete pomocí str() a pak přečtete, tak přijdete
o rozlišení (zde zcela zbytečné). Byl bych zvědav, zda msgpack by toto
řešil?? V plánu bylo v OSGARovi používat obecně zlomková čísla, co jsou běžná
např. v autech na CAN sběrnici.
Tak proč Marina na vodě tak tancovala? Výpis proměnné heading pro poslední
log naznačuje, že to není dobré :-( … co obrázek? A jaj, jaj … výpis x, y,
z:
422 -4096 1350 422 -4096 1355 424 -4096 1354 418 -4096 1359 425 -4096 1349 422 -4096 1354 …
Je vám to nějaké povědomé? … tak jo, je třeba snížit citlivost kompasu.
7. září 2018 — Vodní test 2
Včera večer mne pobavil Šimi: Takhle to vypadá, jako bys hrál hru "kdybyste
si mohli vzít na pustý ostrov tři pythonovské knihovny, které by to byly?"
… tak alespoň jednoho čtenáře mám
Před dnešním testem jsem opravil (snad) orientaci kompasu, posílám si úhlovou
rychlost (i když se ještě nepoužívá), ale na vodě to vypadalo dost jako včera
:-(. Lodička občas pár metrů popojela, ale skončila snad pokaždé v zuřivém
točení na místě. Důvod? Podle všeho manuální kalibrace kompasu, viz obrázky
níže (uznávám, že by bylo vhodnější je dát přes sebe … prostě střed
cx, cy = 900, -1300 z prvního obrázku je na druhém mimo „mísu” resp. elipsu).
Ve staré verzi bylo vždy nutné nejprve provést kalibraci na vodě … je na čase
to tam zase zapojit, sigh.
Znova koukám na ty obrázky a ten střed je mimo jak v x-ové tak y-ové
souřadnici … možná to tam ručně (červené kolečko) dokreslím, ať je to
zřejmé.
Jinak asi nic extra zajímavého. Powerbanka svítí už pouze třema LEDkama — na
to kolik hodin byla lodička zapnutá (zatím jedu celý týden bez nabíjení) myslím
dost dobré … jsem zvědavý, jak moc je pokles lineární, ale asi bych to neměl
riskovat.
p.s. přemýšlím nad dalším krokem (teď je tma, navíc venku prší, tj. další test
až zítra ráno), který by nebyl těžký a snad vedl ke kýženému výsledku. Přidal
jsem do JSON konfigurace offsety kompasu — tam to patří, s každým logem se to
ukládá a na tom základě pak loď naviguje. Nemělo by se mi tedy již stávat:
M:\git\osgar>python osgar\replay.py –module boat d:\md\osgar\logs\boat\boat-180 907_110047.log … Exception in thread Thread-1: Traceback (most recent call last): File "D:\WinPython-64bit-3.6.2.0Qt5\python-3.6.2.amd64\lib\threading.py", line 916, in _bootstrap_inner self.run() File "M:\git\osgar\osgar\drivers\marina.py", line 65, in run self.bus.publish('heading', heading) File "M:\git\osgar\osgar\bus.py", line 72, in publish assert data == ref_data, (data, ref_data) AssertionError: (-2625, 9893)
… po změně kalibrace, když chci přehrát starší log (pokud chci, tak i na
starší log můžu vynutit jinou konfiguraci). Mimochodem změnil jsem ty float
na setiny stupně v int — bez 100% jistoty přehrávání logu jsem úplně
ztracený!
OK, tak jsem přidal ještě jednoduchý nástroj na parsování I2C logů s výpisem
doporučené kalibrace (střed (min+max)/2).
M:\git\osgar>python osgar\compass_calib.py d:\md\osgar\logs\boat\boat-180907_110047.log (924, -1263, [731, 1117, -1483, -1042]) M:\git\osgar>python osgar\compass_calib.py d:\md\osgar\logs\boat\boat-180907_115152.log (658, -1591, [444, 872, -1823, -1358])
8. září 2018 — Vodní test 3
Uznávám, že vymýšlením titulků jsem se poslední dny moc nevěnoval … no prostě
dnes byl třetí a nejspíš i poslední test na jezeře. Přidal jsem si parametr
duration a tak z příkazové řádky mohu říci jak dlouho se má lodička snažit
něco dělat. Nastavil jsem to na 10s, přepnul vysílačku do manuálního režimu,
páčkou uvedl lodičku do zuřivého otáčení na místě a nasbíraná data rovnou „na
lodi” analyzoval:
pi@raspberrypi:~/osgar $ python3 osgar/compass_calib.py boat-180908_093323.log (659, -1571, [443, 875, -1811, -1331])
Pak jsem pustil lodičku v normálním režimu a ona jela na břeh. Další pokus
znova atd. Kód jsem upravil, aby vedle konfigurace kompasu a gyra šly snadno
prohazovat kontrolní body (waypoints), vybral zase nějaké 2 roky (?) staré
a jelo to pěkně. Dnes mírně fouká západní vítr, takže na datech z gyra asi
budou v 3D vidět i vlnky … možná.
V závěrečné fázi jsem ještě zakomentoval korekce s úhlovou rychlostí a kupodivu
to nebylo tak zlé. Zase 3x opakování, kde cílový waypoint je na „útesech” …
nejspíše je hladina Lipenského jezera o dost níž než v roce 2016??
A co dál? No, žena začala balit věci, tak bych se asi měl věnovat jiným
záležitostem :-(. Chtěl jsem ještě párkrát lodičkou objet přístavní molo,
nasbírat GPS data a definovat nové testovací body, ale … možná až příště,
bude-li.
Skóre druhého výletu bych asi označil remízou 1:1 — lodička nakonec sama
autonomně jela, ale vlastně stejným kódem jako před lety (a se stejnými
problémy). Nově má plnou autonomii a vyrovná se s výpadky WiFi sítě. Data ze
senzorů sbírá rychleji a pravidelněji, takže je otevřen prostor pro lepší
navigaci!