Reportáž z Istrobot 2016 (trochu nevážná, ale s poučeními)

23.4.2016 jsem se v Bratislavě zúčastnil soutěže Istrobot 2016.
Původně jsem se chtěl zúčastnit jen jako divák a rozhodčí soutěže Voľná jazda, ale osud tomu chtěl, že jsem i soutěžil v disciplíně V sklade kečupu. Jak se to mohlo stát a jak to dopadlo?

Do Bratislavy na soutěž Istrobot jezdím rád. Domácké prostředí, příjemná atmosféra atd., prostě pohoda. Posledních několik let tam i jako člen poroty hodnotím roboty, přihlášené do soutěže Voľná jazda. Tato soutěž je pro stavitele robotů, kteří se nechtějí svazovat pravidly, protože kromě základní bezpečnosti mají zcela volné ruce a mohou vytvořit cokoli, co nespadá do ostatních kategorií. To je vždycky zajímavé – např. letos se tak sešel robot vysokoškolského studenta pro mapování prostředí, robot řízený neuronovou sítí a Legomodel robota na výrobu pizzy z Legových kostiček:


Ale o tom tenhle příspěvek nebude. Tenhle příspěvek je o soutěži Ketchup House a mé účasti v ní na poslední chvíli.

Soutěž se mi už roky líbí, dokonce tak, že jsem se s bratislavským organizátorem Rišem Baloghem dohodl, že ji smíme v Praze taky pořádat. Jde v ní o to, aby robot ve skladu posbíral co nejvíc plechovek a dovezl je na místo, odkud startuje. Plechovky jsou zčásti předurčeně a zčásti náhodně umístěné někde ve skladu na průsečících čar, které robotům pomáhají v orientaci. Ve skladu ale jezdí roboti dva a oba se snaží získat plechovek co nejvíc.
Letos se mi přihlásili dva naši studenti, že by do téhle soutěže postavili robota plně z Lega a navíc, že nebudou jezdit po čarách jako ostatní, ale volně prostorem. Pravidla to nijak neupravují (postavit je možné z čehokoli a jezdit taky může, jak chce, i když většina ostatních jezdí po čarách, protože to je snadnější), ale jednak to pojali trochu jako výzvu, jestli to vůbec jde, a navíc účast v dubnové soutěži chtěli mít jako test před červnovým nasazením na našem Robotickém dni. To by bylo príma. Jenže práce jaksi nepostupovaly tak, jak by bylo dobré a dva týdny před soutěží stále nejezdili. Domluvili jsme se tedy na plánu 0 (pevná procházka po čarách a úklid jen toho, co cestou náhodou potká) a i na plánu -1 (dojeď pro plechovku přímo před sebou a dovez ji zpět, nezkoumaje jestli tam je nebo není), ale v úterý před pátečním odjezdem ani verze -1 nebyla (problémy se senzory a s psaním diplomky) a svou účast odvolali. Takže smůla, ani letos MFF na Istrobotu robota mít nebude…

V pátek 22.4. ráno se mi to nějak při snídani zželelo, takže jsem zauvažoval, co by se dalo podniknout. A vymyslel jsem Plán. Něco spíchnu. Bude mi stačit, když robot bude splňovat pravidla a i když samozřejmě prohraje, něco dělat bude a aspoň dám jednomu účastníkovi skvělý pocit, že není poslední. V dílně jsem proto vzal robota, co ho normálně využívám pro své studenty na jízdu po čáře (Parallax BoeBot), vyrobil radlici na tlačení plechovek (asi 30cm něčeho jako tohle), a přidal zásadní věc – kousek plexi a vypínač, že to dám nahoru jako kryt a nouzový vypínač (BoeBot žádný vypínač buhvíproč nemá, vypíná se vytažením konektoru od napájení). To jsem hodil do krabice, přidal hrst vázacích pásků, dávno prošlé plechovky s kečupem (motivují k opatrné manipulaci…), nějaký senzor na detekci soupeře a hurá na soutěž. Docela to nakonec klaplo, až na nějaké ty zádrhele. Pro poučení (nebo výstrahu?) se pokusím popsat některé problémy a jejich řešení, případně se i přiznat k nepravostem.

Cestou autem jsem se pustil do programování (neřídil jsem). Jako základ jsem využil kód, který jsem už měl pár let hotový z předváděčky těchhle malých robůtků (tancují na hřišti z téhle soutěže, čili základní ježdění je hotové). Zbývalo dořešit jen několik drobností:
a) jak vyhledávat plechovky;
b) jak je vozit na správné místo (čára, odkud robot startuje);
c) jak je tam dobře odložit a umístit;
a d) jak se vyhýbat soupeři.

„Několik drobností“ jsem snadno vyřešil následovně:
a) nijak, prostě se projedu po hřišti a když potkám plechovku, fajn;
b) nijak, prostě jedu, a když nějaká plechovka pojede se mnou, fajn;
c) když je tlačím před sebou, tak bude stačit kousek couvnout a jet jinam;
d) tohle už metodou a) řešit nešlo, přece jen pravidla vyžadují jistou opatrnost (Je však pritom zakázané poškodzovať súperovho robota a brániť mu v pohybe.). Čili bude potřeba se nějak vyhýbat nárazu. Pro zjednodušení jsem se rozhodl zastavit, pokud by se přede mnou soupeř objevil (pozn.1). K detekci soupeře jsem v krabici něco měl, konkrétně dálkoměrný senzor: vzal jsem s sebou Sharp GP2D12, budu tedy moct zastavit, kdyby na mě soupeř jel. Jenže z GP2D12 se v autě vyklubal GP2D120, který má místo dosahu 10-80cm dosah jen 4-30cm (одна буква – и какая разница…). No, neuvidí ho moc dopředu, ale aspoň se v autě při ladění nemusím moc rozmachovat, říkám si. Ale připadal jsem si trochu jako telefonista kupující vycházkové hole.

Co se týče projížďky po hřišti, zvolil jsem jistotu a naprogramoval pevnou cestu. To šlo snadno, protože robot už uměl jezdit na zadaná místa, takže stačilo vymyslet, kam. Zvolil jsem několik souřadnic, občas dojet domů, vyložit plechovky a tak pořád dokola, dokud nevyprší čas (pozn.2). Původní kód byl skoro to, co jsem potřeboval, stačilo udělat pár „hacků“: ošetřit vykládání a ošetřit zastavení před soupeřem. Vykládání jsem chtěl udělat jen občas a na správném místě. Kdybych plechovky ale vyložil na nějaké souřadnici – křižovatce, tak by mi tam překážely v další jízdě, musel bych couvnout o čtvereček zpátky a s tím algoritmus jízdy po čáře nepočítal. Takže jsem zvolil „ruční“ popojetí kousek dopředu a kousek dozadu, přičemž „kousek“ byl definován časem. Jako nejlepší se ukázalo jet 1s dopředu a 0.85s dozadu, čímž jsem se dostal skoro na původní místo (pozn.3). Paráda. Jak ale poznat, že mám vykládat? To si do nějak poznamenám u souřadnic postupných cílů. „Nějak“ nakonec dopadlo tak, že když bych měl na místě čekat 11ms, je to pokyn k vyložení (pozn.4).

Detekci soupeře jsem udělal tak, aby v případě, že se přede mnou objeví nějaká překážka, robot zastavil. Senzor jsem umístil tak, aby viděl i plechovky a napsal k němu rozhodovací systém, který rozhodne, jestli vidím plechovku nebo soupeře (snadno: pokud se překážka hýbe, je to soupeř, pokud se to nehýbe, je to plechovka (pozn.5)). Měl jsem totiž v úmyslu plechovky vyhledávat aktivněji a jezdit si pro ně najisto. Ale když se ukázalo, že senzor beztak vidí jen těsně před robota, tak jsem se na hledání plechovek vyignoroval, senzor dal do vyšší letové hladiny a detekoval jen soupeře – když je blíž než v nekonečnu, tak zastavím (pozn.6). Nicméně ani to moc nefungovalo, protože jsem ho stejně v reálu viděl, jen když byl těsně před radlici a někdy ani to ne (pozn.7)

Po dojetí do Bratislavy jsem robota vyzkoušel, nějak jezdil, a tak jsem další ladění nechal až na den soutěže. Tam se ukázalo několik problémů:
– Cestou se povolily šroubky. Problém: původní BoeBot má imperiální závity, já potřeboval delší. Řešení: vzal jsem M3 i s vědomím, že to nejsou ty správné. M3 do 3/8″ chytit taky jde, pěkný to vůči nim ale fakt není.
– Když tlačím víc plechovek, prokluzují mi kolečka. Řešení: jednu plechovku (svoji) si naložím na robota a zvýším tak přítlak koleček.
– Moje radlice (hranaté otevřené U) je schopná vzít tolik plechovek, že už je robot nezvládne tlačit a zastaví se jimi, obzvláště při zatáčení (což je logické, tlačí jen jedním motorem). Řešení: kleštěmi jsem radlici „upravil tvar“, aby se jich nevešlo tolik. Že občas nějakou ztratí, mi nevadí, aspoň ty zbylé utlačím.
– Když při otáčení brnknu o právě vyloženou plechovku, nějak se to celé rozhodí a robot se ztratí. Řešení: kleště a ohnout radlici, aby nebrnkala + upravit vykládací manévr, viz pozn. 4.
– V prvním zápasu jsem umístil jednu plechovku, ale poněkud nepřesně, takže se nepočítala. Řešení: kleště a ohnout radlici, aby vozila plechovky víc uprostřed.
– Když s takhle šikovně ohnutou radlicí najedu do Legosoupeře, spolehlivě se k němu zaháknu. Řešení: zase kleště a ohnout konce líp.

V průběhu kvalifikačního kola jsem ještě vymyslel několik pěkných cest, které se daly do robota dodatečně nahrát. Jednu měl přednastavenou v programu, ale před startem bylo možné ji přes seriovou linku přehrát jinou, kterou si pamatoval až do resetu (to byla zadaná vlastnost tanečního algoritmu). Doplnil jsem si navíc „soft reset“, který mi umožnil při přípravě na start vyzkoušet, jestli se robot po odstartování rozjede. Soft resetem jsem ho tím samým startovacím tlačítkem zase připravil ke startu (pozn.8), ale věděl jsem, že jsem třeba nezapomněl zapnout motory apod. (pozn.9)

K mému velkému úžasu jsem postoupil do finále. V kvalifikaci totiž nakonec skórovali jen tři roboti, na prvním místě loňský vítěz „VeterRobot“ s 21 body, na druhém „LNX transBot“ s 11 body a na třetím já se 3 body. Ostatní buď nejezdili vůbec, nebo žádnou plechovku ze skladu nedovezli na správné místo. Už v kvalifikaci se ukázalo, že VeterRobot jezdí také pevnou trasu, ale nemá, jak by soupeře poznal. Byl sice z Lega, ale „bylo ho víc“, takže když se potkal s mým drobečkem, ani si málem nevšiml a můj robot se totálně dezorientoval (pozn.10). Proto jsem vymyslel i další cestu, abych se s ním prostě nepotkával. Bohužel to byl jen odhad a ke kolizi stejně nakonec došlo a můj chudák se na hřišti ztratil. Škoda, měl jsem pro soupeře připravené překvápko – projet mu jeho domácí lajnu a odvézt mu poťouchle všechny jeho plechovky (to je v pravidlech explicitně povolené). Zvlášť VeterRobot by si to zasloužil – nekouká napravo nalevo a bourá do čehokoli, ale nakonec navozí na domácí čáru klidně i 10 plechovek (pozn.11).

No, nakonec můj robot, podle vzniku nazvaný „MART Friday Bot“, po zásluze skončil jako poslední bodovaný. Jenže to bylo třetí místo ve finále – ale když se to vezme kolem a kolem, tak vlastně co? Jezdil? Ano. Bodoval? Ano. Skončil jsem líp než nějaký lepší robot? Ne. Takže třetí místo je vlastně úplně přiměřené. Jen je z toho závěrečné pozorování, které se zdráhám nazvat poučením:

I za den se dá připravit robot na soutěž… 😆


Doplnění:

… teda aspoň když máte po ruce robota, který tak nějak jezdí a k tomu pár let zkušeností, abyste si troufli provizorně ošulit, co bude třeba (pozn.12).

A pro ty, co to nemají, přidávám ještě pár (teď už vážně míněných) rad:

Není potřeba mít všechno tip ťop. Vylepšovat je možné postupně, nechtějte všechno najednou. Dávejte si jednoduché cíle a ono to přijde.

Nebojte se použít / ukázat robota, který ještě není dokonalý. Jednak si to sami užijete i tak, a navíc na tom budete líp než ti, kdo pořád jen staví a vylepšují a staví a …

Robota, který něco dělá, nepředělávejte totálně. Stane se, že se vám bude narychlo hodit mít ve skříni něco, co funguje.

PS: Kdyby měl někdo zájem, s potěšením mu robota ukážu, vysvětlím, přidám další rady atd., třeba na některém z dalších Robodoupat.


Poznámky:

Pozn. 1: To není dobrá metoda. Jednak neřeší couvání ani otáčení, a navíc, kdyby tohle udělali oba roboti, tak se oba zastaví a čekají až do konce. Ale pro mě to bylo „aspoň něco“. Jak jsem později zjistil, byl jsem dokonce jediný, kdo měl „tak propracovanou metodu předcházení srážek“ — ostatní totiž neměli nic. Trága.
Pozn. 2: Robot se měl po skončení tříminutového zápasu vypnout, takže stačilo občas zkontrolovat čas a když vypršel, vypnout motory.
Pozn. 3: 1 a 0.85 byly empiricky stanovené konstanty: plechovky byly vůči robotovi docela těžké, takže když je tlačil, jel o něco pomaleji než když couval. Zároveň to bylo tak akorát, že když nic netlačil, tak sice jel dopředu o něco víc než zpátky, ale to se vzápětí samo srovnalo díky správnému algoritmu pro jízdu po čáře a otáčení.
Pozn. 4: Protože tancující robot občas potřeboval čekat, tak dostával v rámci pokynů i čas čekání, resp. čas, kdy má z nějakého místa vyjet. Tady nikdy čekat nemusel, takže všechny časy byly 0, ale využil (čti zneužil) jsem tento údaj jinak. Do programu jsem doplnil obezličku (čti ukrutnou prasárnu): if(waittime==11)unload();
Pozn. 5: To samozřejmě není správně, protože to může být soupeř, který také čeká, až se já pohnu.
Pozn. 6: Vzdálenost, na kterou jsem soupeře detekoval, jsem určil od oka pohledem na ladící výpis, jaké hodnoty přibližně v tom místě senzor vrací. Dále, senzor vrací hodnotu, která je vzdálenosti nepřímo úměrná, takže ve výsledku způsob kontroly vypadal celkem zábavně:
#define infinity 28
if(distance > infinity) stop();

Pozn. 7: Holt směrový senzor občas snad viděl skrz soupeře, nebo ten nebyl přesně uprostřed, případně mu viděl do útrob ale neviděl postranní konstrukci, takže jsem stejně narážel. Mnohem lepší by byl nějaký ultrazvuk.
Pozn. 8: Nezapomeňte na debouncing. Mně se prvně po přidání soft resetu robot nějak nerozjížděl a bylo to proto, že odstartování čekalo jen na zmáčknutí tlačítka, ale už ne na jeho puštění. Takže se hned ujal Soft reset, který sice kulturně čekal na zmáčknutí a pak na puštění, no jo, jenže ten start ne…
Pozn. 9: To je velmi typický důvod nerozjetí robota, vidím to na soutěžích velmi často. Člověk v minulém zápase robota zastaví nouzákem a pak na to zapomene. Já doporučuji napsat si na papírek „checklist“ a před startem podle něj robota připravit: Postav robota na start. Zapni hlavní vypínač. Zapni motory. Odmáčkni nouzový vypínač. atd.
Pozn. 10: Bodejť by ne, když neměl žádnou globální lokalizaci. Když ho nabral soupeř zboku, ani o kolizi nevěděl, takže když ho přitom soupeř někam popostrčil, prostě pokračoval dál a hledal čáru, jakoby se nic nestalo. To ale obvykle znamenalo, že byl jinde a pak jezdil úplně blbě – vykládal plechovky uprostřed hřiště, občas vypadl ven…
Pozn. 11: Děvčata navíc přiznala, že na robotovi od loňska nic nezměnila. To také asi vysvětluje, proč v zápase vždycky vyjeli na stejném místě ven z hřiště – vloni byl Veter Team v Praze na Robotickém dni a naše pražské hřiště je o dvě čáry větší.
Pozn. 12: Úmyslně jsem napsal „připravit“ a ne „postavit“. Robota jsem už měl, jen jsem ho upravil a doplnil, aby se mohl zúčastnit (viz také poslední rada v rámečku). A přitom jsem jeho původní funkčnost nezmenšil, vše, co uměl předtím, zůstalo zachováno.