czech english

Paula

mini-drone proti trudomyslnosti

Paula je loňský model malé drony do dlaně. Je to hračka na doma za necelých 3kkč od DJI a Intelu. Oficiální jméno zní Ryze Tello. Standardní použití je řízení pres WiFi z mobilního telefonu, ale výrobce podporuje i oficiální SDK. Tento blog je pro podobně praštěné, na které již to „domácí vězení” trošku padá a potřebují rozptýlit. Blog update: 8/2 — cv2.Stitcher_create



Blog / Paula

2. únor 2021 — Základní info

Na Tello dronu jsem narazil před pár dny, kdy mi na YouTube vyskočilo 3 hodinové video Drone Programming With Python Course (2021). Jednak mne zaujalo, že je někdo schopen v tomto prostoru vysvětlit základy létání s dronou, programování v Pythonu, OpenCV a pod. + i ta malá drona vypadala zajímavě. Autor videa sice píše, že s DJI a Intel nemá nic společného, ale za mne jim reklamu rozhodně dělá. Mne zviklal, že jsem si dronu objednal a dnes by měla dorazit (možná je to i motivace začít sepisovat poznámky, než budu realitou nemile překvapen). Evidentně se nemohu dočkat/dospat, protože bylo 3:45, když jsem prvně koukl na hodiny.
Co je na té droně tak zajímavého? No připomíná mi to kombinaci staré Parrot ARDrone2 (Heidi) s SDK a možností řízení přes WiFi a o něco novější mini-drony Parrot Rolling Spider (Jessica). Reklama slibuje 13 minut letu, streaming HD videa a snadné ovldádání. Je fakt, že Tello SDK 1.3 (pdf) má pouhých 8 stránek a projdete to za pár minut.

Řízení

Drona se ovládá pomocí UDP paketů, kde na první pohled vidím tři kanály pro tři porty:
  • 8889 — posílání příkazů
  • 8890 — příjem stavů
  • 11111 — příjem videa
Defaultní IP adresa je 192.168.10.1 a předpokládám, že drona má DHCP s nastavitelným zabezpečením.
Příkazy jsou textové, jako takeoff, land, streamon, streamoff, tj. vlet, přistání, zapnutí a vypnutí posílání videa. Dále emergency vypne všechny motory, up 20-500 vzlétne nahoru 20cm až 5m, podobně down, left, right, forward, back … a to už jsme na čtvrté stránce dokumentace SDK. Zbývá otočení ccw 1-3600 (conterclockwise/proti směru hodinových ručiček), tj. až 10 otáček, podobně cw ve směru hodinových ručiček. S flip a go x y z speed už máte všechny jednoduché stavební bloky „pro děti” (ano, těm je tato hračka primárně určena).
Drsněji vypadá curve x1 y1 z1 x2 y2 z2 speed což by měl být oblouk. Rychlost se pak nastavuje pomocí speed 10-100 v cm/s, tj. do 1m/s. No a kdyby někomu nestačily tyto základní příkazy tak ještě existuje rc a b c d, který nastavuje podobně jako u ARDrone2 RC kanály left/right, forward/backward, up/down, yaw, vše s hodnotami -100100.

Čtení stavu

Průběžně se můžete dotazovat na stav jednotlivých parametrů jako: speed?, battery?, height?, temp? (teplota), attitude? (IMU data pitch, roll, yaw), baro? (barometer v metrech?), acceleration? (ve všech osách x, y, z), tof? (time of flight, předpokládám sonar dolu), wifi? (SRN … seriové číslo?). A to je všechno.
Konečně se lze zeptat na Tello State, což by měl být string a jako příklad uvádí:
"pitch:%d;roll:%d;yaw:%d;vgx:%d;vgy%d;vgz:%d;templ:%d;temph:%d;tof:%d;h:%d;bat:%d;baro:%.2f;
  time:%d;agx:%.2f;agy:%.2f;agz:%.2f;\r\n"
… hmm, to vypadá spíše jako print příkaz do Pythonu nebo C … tj. asi se lze zeptat na vše najednou?? To by asi byl i můj případ ale otázka, jak často se člověk může ptát?

Závěr

O videu se v SDK PDFku nic nepraví, tak doufám, že to bude nějaký standardní video stream nebo JPEG obrázky. Stejně tak očekávám ještě nějaký „druhý protokol”, binární, pro interní účely. No možná to byly vyhozené peníze, ale to se člověk nedozví, dokud to nezkusí (ano, nebo dokud nebude více sledovat internet, ale to už mne pomalu přestává bavit). Tak uvidíme — držte mi palce.
p.s. pokud dronu máte a už s ní máte i nějaké zkušenosti, tak napište … díky!

3. únor 2021 — Google Play 2.8

Včera jsem si ještě před vyzvednutím balíčku nainstaloval Google Play aplikaci Tello. Co mne ale „trošku” vyděsilo bylo její hodnocení:
Možná jsem měl zrovna smůlu, ale vzhledem k tomu, že nejčastější hodnocení byla pouze jedna hvězdička, to bylo asi očekávané.
Tello drones are garbage. Ordered 1 new for my son for christmas and came with a dud battery. Returned and replaced with a 2nd and it worked for 1 day, tho never stable and always floated to the side banging into objects. Then day 2 the back propellers began going haywire, outspinning the front making the piece junk flip over every takeoff. Returned a 2nd time for full refund, no replacements. We're done. Our worst experience ever on Amazon was this garbage. … no hned jsem se těšil více (ironie).
Dronu a extra ochrannou klec jsem si včera večer vyzvedl. Pro referenci jsem kupoval:
První, co mne překvapilo, jak je to hrozně malinké. Balíček je jak malá svačinka. Těch by se opravdu bez problému vešlo 10 do komínkui i na Kloubáka K2.
Druhé pozorování bylo, že jsem udělal dobře a koupil combo. V praxi to znamená dvě baterky navíc a malá nabíječka. V opačném případě by totiž člověk chvíli lítal a pak musel dronu použít jako nabíječku a za hodinu by mohl udělat další mini-pokus. Baterky se nabíjí postupně s tím, že u každé svítí, zda je nabitá (zelená), právě se nabíjí (blikající zelená) nebo je ve frontě na nabíjení (žlutá). Předpokládám, že jsou ještě nějaké chybové stavy, ale ty snad hned tak neuvidím.
Baterky jsem nechal nabíjet přes noc, tj. teď mám „tři dávky”, jenom to bude muset počkat (pes, snídaně, práce, Robotour webinář, SubT středeční call …), takže report z prvního pokusu o navázání komunikace až zítra.
p.s. ještě jsem se dozvěděl, že EDU verze podporuje SDK 2.x a swarm dronů, což základní (moje) verze nepodporuje, ale tím se nechám znervózňovat až zítra …
p.s.2 přiložený český manuál říká „revidovaná verze 1.2 z roku 2018”, takže tyto mini-drony žádná novinka nejsou

4. únor 2021 — command "command"

… aby k tomu nedošlo, prozradím vám konec celé detektivky:
první úspěšný pohovor
první úspěšný pohovor
(Cimrman)
No nechtěla se se mnou mrcha bavit. Stáhl jsem si příklad Tello3.py odkazovaný z SDK a ani to nefungovalo. Aplikace na Android byla také taková „zvláštní”. Obraz z kamery byl rozbitý, ale když jsem si uložil obrázek, tak pak v galerii vypadal OK. Když jsem ale přepnul na nahrávání videa, tak aplikace po chvíli napsala Overheet, shutting down?!
A rozuzlení? No ono je to vlastně v tom SDK v úvodu napsané: Remark2: Send “command” command to Tello via UDP PORT 8889 to initiate Tello’s SDK mode, before sending all other commands, prostě je nejprve třeba poslat příkaz/commnad "command", aby se zapnul SDK mód.
A vlastně mi už funguje i první pokus v OSGARovi:
python -m osgar.logger tello-210203_225017.log
 k           name bytes | count | freq Hz
- - - - - - - - -  - - - - - - - - - - - - - -
 0            sys   916 |   6 |   0.6Hz
 1      tello.cmd     9 |   1 |   0.1Hz
 2    udp_cmd.raw     0 |   0 |   0.0Hz
 3 udp_status.raw 13343 | 101 |   9.9Hz
 4  udp_video.raw     0 |   0 |   0.0Hz

Total time 0:00:10.163582
… tj. po odeslání command už chodí stavové data na 10Hz.
Data pak vypadají takto:
0:00:00.110007 3 b'pitch:0;roll:0;yaw:-2;vgx:0;vgy:0;vgz:0;templ:92;temph:94;tof
:10;h:0;bat:27;baro:358.34;time:0;agx:-2.00;agy:6.00;agz:-999.00;\r\n'
0:00:00.213012 3 b'pitch:0;roll:0;yaw:-2;vgx:0;vgy:0;vgz:0;templ:92;temph:94;tof
:10;h:0;bat:27;baro:358.35;time:0;agx:-3.00;agy:7.00;agz:-998.00;\r\n'
0:00:00.314018 3 b'pitch:0;roll:0;yaw:-2;vgx:0;vgy:0;vgz:0;templ:92;temph:94;tof
:10;h:0;bat:27;baro:358.39;time:0;agx:-4.00;agy:4.00;agz:-1000.00;\r\n'
…
… tj. baterky jsou asi skoro vybité (27%). Na večer experimentování z jedné baterky OK. Tak první krůček snad učiněn.

5. únor 2021 — H.264 video

Včera jsem se kousek posunul i s nahráváním videa, ale bohužel skoro o zanedbatelný kousek:
python -m osgar.logger tello-210204_154413.log
 k           name   bytes | count | freq Hz
- - - - - - - - - - - - - - - - - - - - - - - - -
 0            sys     918 |    6 |   0.6Hz
 1      tello.cmd      30 |    3 |   0.3Hz
 2    udp_cmd.raw      12 |    3 |   0.3Hz
 3 udp_status.raw   13737 |  101 |  10.0Hz
 4  udp_video.raw 2494746 | 1801 | 178.6Hz

Total time 0:00:10.085510
Tj. vidíte tam zhruba 2.5MB video UDP paketů. Přidal jsem i jednoduchou sekvenci:
python -m osgar.logger tello-210204_154413.log –stream tello.cmd
0:00:00.017842 1 b'command'
0:00:02.009850 1 b'streamon'
0:00:05.010625 1 b'streamoff'
tj. v čase 0 zapni SDK protokol mód, v čase 2s spusť nahrávání a v čase 5s ho zase vypni. Datově cca 1MB/s myslím zní celkem rozumně.
Listen to the data stream with the port number 11111 through UDP. The data stream is encoded with the format of h264. Because size of encoded data of one frame image in this stream is larger than the maximum load for a single udp transmission, every segment of one frame encoded picture’data are divided into different blocks, with the unit size of 1460bytes. And the last block of a image data is smaller than 1460 bytes.
… toto zní celkem rozumně. Jeden frame může být (typicky je) veliký a tak se rozdělí na několik o velikosti 1460 bajtů
So by detecting the size of the block, it can be determined whether the data block is the end of the data of the current single image. Splicing the last block in sequence with the data blocks previously listened to, you can get the complete encoded data of a single image.
… toto ale už je divočina! Pokud vám přijde kratší paket, tak je to konec frame?! A co výpadky?
python -m osgar.logger tello-210204_154413.log –format "{timestamp} {len(data)}" 
    –stream udp_video.raw | head -n 25
0:00:00.036130 1460
0:00:00.036936 1460
0:00:00.037336 1460
0:00:00.038663 1460
0:00:00.038781 1460
0:00:00.039000 1460
0:00:00.039154 1460
0:00:00.041383 1460
0:00:00.041505 1460
0:00:00.041573 1460
0:00:00.041779 1460
0:00:00.041900 552
0:00:00.070896 1460
0:00:00.071040 1460
0:00:00.071232 1460
0:00:00.071323 1460
0:00:00.073455 1460
0:00:00.073628 1460
0:00:00.073719 1460
0:00:00.073964 1460
0:00:00.075897 1460
0:00:00.076018 1460
0:00:00.076285 1460
0:00:00.076400 729
0:00:00.105331 1460
Takto to vypadá skoro rozumně, časově jsou si ty bloky blízko a pak začíná nový, ale dekódovat to jako H.264 frame se mi zatím nedaří. Parrot u každého paketu měl jeho index a délku, tak možná něco podobného je i zde?? Z nostalgie bych se po letech mohl podívat zase dovnitř, viz starý článek H.264 pro vidění dravce.

6. únor 2021 — Takeoff!

První vzlet je vždycky drama, obzvláště pokud se jedná o start autonomní mise. A ani Paula nezklamala.
Sekvence byla poměrně minimalistická:
self.tasks = [
            [2, b'streamon'],
            [3, b'takeoff'],
            [5, b'land'],
            [8, b'streamoff']
        ]
tj. zapni nahrávání videa, odstartuj a po dvou sekundách zase raději přistaň a následně vypni nahrávání videa. A jak to dopadlo?
Program skončil, ale drona stále visela ve vzduchu (necelý metr nad zemí). Byl jsem rád, že jsem použil ochrannou klec, ale stejně, jak jí sundat dolů?!
Nenapadlo mne nic lepšího, než ten jediný program, co jsem dosud měl, pustit znova:
Home, sweet home! Předpokládám, že u vzletu drona neakceptuje další příkazy nebo se něco porouchalo. Mám pocit, že podobné chování měla i Jessica — což bylo extrémně nepříjemné, pokud se na startu vymkla kontrole, prostě neakceptovala ani příkaz přistaň.
python -m osgar.logger tello-210205_190125.log –stream tello.cmd udp_cmd.raw
0:00:00.032778 1 b'command'
0:00:00.046018 2 b'ok'
0:00:02.086795 1 b'streamon'
0:00:02.137147 2 b'ok'
0:00:03.002316 1 b'takeoff'
0:00:05.000937 1 b'land'
0:00:08.001190 1 b'streamoff'
0:00:08.003700 2 b'ok'
… no nevypadá to, že by "takeoff" byl potvrzený!
A v druhém pokusu, začínaje ve vzduchu, na "takeoff" odpověděla "error":
python -m osgar.logger tello-210205_190142.log –stream tello.cmd udp_cmd.raw
0:00:00.032203 1 b'command'
0:00:00.076145 2 b'ok'
0:00:02.065302 1 b'streamon'
0:00:02.115965 2 b'ok'
0:00:03.024324 1 b'takeoff'
0:00:03.036509 2 b'error'
0:00:05.026166 1 b'land'
0:00:08.023093 1 b'streamoff'
0:00:08.034631 2 b'ok'
0:00:09.106121 2 b'ok'
… a to potvrzení přistání vypadá také jako až po jeho skončení. Byla by pěkná nějaká stavová proměnná, nebo holt na ten start musím počkat o něco déle.

7. únor 2021 — Selfie

Další cíl dosažen a vypadá takto:
To řešení je brutální, ale šlo o „prokopnutí cesty” a stačí náznak světla na konci tunelu. Prostě video jsem nahrával už předevčírem, ale nebyl jsem schopen ho dekókovat. Potvrdil jsem si, že je to H264 kodek, dokonce upravený starší kód vylámal počty makrobloků, tj. zjistil jsem, že výsledný obrázek je menší než u ARDrone2 … ano, marketingový klam 720p … jen to není 16:9, ale 4:3, tj. rozlišení je 960x720. Ale pokusy dekódovat I-frame (jestli to nepletu) selhal.
Když už jsem propadl malomyslnosti, tak jsem koukal dále na to 3h video. Říkal jsem si, že on to také musí nějak řešit?! Pro řízení drony používá DJITelloPy a tam je čtení videa řešeno přes cv2.VideoCapture() a jako parametr dostává address_schema = 'udp://@{ip}:{port}'. Prostě pustí pomocné vlákno a to přímo čte UDP pakety a OpenCV to i rovnou dekóduje do numpy obrázků. Pěkné! Ale funguje to? Jako první jsem zkusil jsem take-picture.py
Napůl mne vlastně potěšila záplava hlášek:
(osgar) md@md-ThinkPad-P50:~/git/DJITelloPy/examples$ python take-picture.py 
[INFO] tello.py - 104 - Tello instance was initialized. Host: '192.168.10.1'. Port: '8889'.
[INFO] tello.py - 418 - Send command: 'command'
[INFO] tello.py - 443 - Response command: 'ok'
[INFO] tello.py - 418 - Send command: 'streamon'
[INFO] tello.py - 443 - Response streamon: 'ok'
[h264 @ 0x153f740] non-existing PPS 0 referenced
[h264 @ 0x153f740] non-existing PPS 0 referenced
[h264 @ 0x153f740] decode_slice_header error
[h264 @ 0x153f740] no frame!
[h264 @ 0x153f740] non-existing PPS 0 referenced
[h264 @ 0x153f740] non-existing PPS 0 referenced
[h264 @ 0x153f740] decode_slice_header error
[h264 @ 0x153f740] no frame!
[h264 @ 0x153f740] non-existing PPS 0 referenced
[h264 @ 0x153f740] non-existing PPS 0 referenced
[h264 @ 0x153f740] decode_slice_header error
[h264 @ 0x153f740] no frame!
[h264 @ 0x153f740] non-existing PPS 0 referenced
[h264 @ 0x153f740] non-existing PPS 0 referenced
[h264 @ 0x153f740] decode_slice_header error
[h264 @ 0x153f740] no frame!
[h264 @ 0x153f740] non-existing PPS 0 referenced
…
… ale drona vzlétla, opravdu jeden snímek udělala a přistála. Dveře do „tajemné komnaty” jsou tímto pootevřeny.
V druhém pokusu, kdy jsem zkoušel příklad nahrávání videa, už to bylo divočejší, protože drona se zamotala do věšáku — ochranná klec byla dobrá investice. Ono to trošku vypadá jak míč, tak jsem to zkusil vzít do ruky a po vzoru starých ARDrone2 to otočit vzhůru nohama a motory se zastavily. To se také může někdy hodit.
Problém je tedy množství nevalidních snímků v úvodu nahrávání videa a zatím nevím, jak ty nástroje přesvědčit, aby to ignorovaly. Alternativa byla vytvořit fiktivní Tello dronu, předstírat, že vysílá UDP pakety s daným časováním a výsledek vypadá takto (po spojení obou kousků pomocí ffmpeg -i "concat:video1.avi|video2.avi" -c copy video.avi).

8. únor 2021 — cv2.Stitcher_create

Přemýšlel jsem, co by nejlépe vystihlo dnešní pokusy s dronou (neděle 7/2 … je to takové posunuté) a je to pokus o poskládání panoramatu z videa drony. Nejprve jsem trošku ladil kód, abych droně posílal další příkazy až když předešlé vykoná (hlavně takeoff) a když toto začalo celkem rozumně fungovat, tak jsem chtěl udělat panoramatický snímek, resp. video 360 stupňů dokola. Asi rovnou naznačím co je další cíl — udělat dva panoramatické snímky nad sebou. Drona má totiž senzor na měření vzdálenosti od země a tak bych mohl udělat panoramatické stereo.
Příkaz pro dronu:
command
streamon
takeoff
cw 360
land
streamoff
cw 360 je „otoč se o 360 stupňů po směru hodinových ručiček”. Samozřejmě jsem tam měl překlep, což je ve vzduchu vždy „komické”:
0:00:01.069556 SEND b'streamon'
0:00:01.119955 — b'streamon' b'ok'
0:00:02.004058 SEND b'takeoff'
0:00:03.263466 Battery: 78 -> 77
0:00:07.193178 Battery: 77 -> 76
0:00:08.315170 — b'takeoff' b'ok'
0:00:09.183728 Battery: 76 -> 75
0:00:10.010189 SEND b'cv 360'
0:00:10.050536 — b'cv 360' b'unknown command: cv'
… ale pak to správně přistálo, takže OK.
No a teď to skládání obrázků. Je to na dva řádky (!):
stitcher = cv2.Stitcher_create()
status, result_img = stitcher.stitch(images)
Drsné, nemyslíte? Uplně se mi nechce sdílet panoramatický snímek pracovno-ložnice, ale …
První pokus je jen pár snímků „obrazu” (takové to černé je ochranný kryt drony).
Druhý pokus skončil Killed (pravděpodobně na nedostatek paměti) a tak místo všech obrázků z 360 stupňové otočky jsem tomu podhodil jenom každý pátý snímek. A dopadlo to takto: