Table of Contents

Príprava na turnaj

Analýza

Turnaj predstavuje akciu „RoboCup at FIIT“, ktorá pozostáva z viacerých presne zadefinovaných disciplín. Pravidlá pre jednotlivé disciplíny, zhľadom na ktoré sme analyzovali a pripravovali Test Framework pre turnaj je možné nájsť na stránke http://www2.fiit.stuba.sk/robocup/2012/turnaj_pravidla_3D.htm.
Po spustení meraní jednotlivých disciplín v Test Frameworku (disciplíny sú v ňom nazvané ako „test case“), skúšaní rôznych situácií ako splniť alebo nesplniť disciplíny, sledovaní vyhodnotení disciplín a porovnaní tohto všetkého s pravidlami sme usúdili, že momentálny stav Test Frameworku nebol vyhovujúci pre použitie na oficiálnom turnaji.

Implementácia

V ďalších podkapitolách uvádzame jednotlivé disciplíny a zmeny, ktoré sme v nich vykonali.

Vstávanie

Pri disciplíne vstávanie má hráč v pravidlách udanú počiatočnú pozíciu, na ktorej má disciplínu vykonávať. Táto pozícia (-3; 0) bola nastavená tak, aby sa pri inicializácii disciplíny na ňu hráč teleportoval.
Podľa pravidiel disciplíny sa meranie zastaví buď po 20 sekundách alebo 1 sekundu po tom, ako sa robot dostane do vzpriamenej polohy (vstane) a prestane sa hýbať. Vtedajší stav bol taký, že sa meranie zastavilo buď po 20 sekundách alebo hneď ak je hráč vo vzpriamenej polohe. Do metódy „isStopCriterionMet“, ktorá sleduje hráča a na základe istých podmienok zastavuje disciplínu, bola pridaná kontrola, ktorá sledovala presné hodnoty súradníc hráčovej hlavy a meranie zastavilo vtedy, ak bolo hráčovo telo vo vzpriamenej polohe a jeho hodnoty ostali nezmenené počas 1 sekundy. Zabezpečil to nasledujúci kód:

TransformationMatrix currentBodyState = p.getBody().getHead().getTransformation();

if (standing) { // is standing
   if ((elapsedTime - lastIsStandingTime) <0) {    // first standed up
        lastIsStandingTime = elapsedTime;
        lastBodyState = currentBodyState;
    } else if (currentBodyState.compareWith(lastBodyState)) {
        if ((elapsedTime - lastIsStandingTime)>= 1) {
            successTime = (elapsedTime - startTime);
            return true;<br />
        }
    } else {
        lastBodyState = currentBodyState;
        lastIsStandingTime = elapsedTime;
    }
} else {
    lastBodyState = currentBodyState;
    lastIsStandingTime = 5000;
}

Chôdza (stabilita)

Cieľom tejto disciplíny je prejsť na vzdialenejšiu polovicu ihriska. Počas nej sa pripočítavajú trestné sekundy, teda 10 sekúnd za dotyk počas 1 sekundy inou časťou tela ako chodidlom.
Vtedajší kód mal znova zadané nesprávne počiatočné súradnice hráča a preto ich bolo potrebné zmeniť podľa pravidiel na (-5; 1).
V prípade, že hráč spadne a nebude sa vedieť postaviť, server automaticky premiestňuje hráča za hranice ihriska. V pravidlách je zadefinované, že ak tento prípad nastane, disciplína má byť vyhodnotená ako keby hráč ostal ležať na zemi do uplynutia časového limitu disciplíny. Vtedajší kód tejto disciplíny toto neošetroval, preto sme to zapracovali nasledujúcou metódou, ktorá kontroluje, či sa hráč nenachádza mimo ihriska:

private boolean playerBehindBorder(Player player) {
    double playerLocationX = player.getLocation().getX();
    double playerLocationY = player.getLocation().getY();

    if (Math.abs(playerLocationX)> (fieldLength / 2)
   || Math.abs(playerLocationY)> (fieldWidth / 2)) {
        return true;
    }
    return false;
}


V metóde „evaluate“ bola chybne počítaná lineárna aproximácia výsledného času podľa prejdenej vzdialenosti, ktorá sa využíva vtedy keď hráč nestihne v stanovenom limite prejsť za polku ihriska. Táto metóda bola nami viac-menej celá prerobená a bolo v nej aj sprehľadnené vypisovanie výsledkov. Bol ošetrený aj stav, keď hráč prešiel nulovú dĺžku a hrozilo delenie nulou pri vyhodnocovaní. Lineárna aproximácia bola urobená nasledovne:

double maxTime = 180;
double traveled = Math.abs(initPos.getX()) - Math.abs(currentPlayerLocationX);
if (Math.abs(playerLocationXBeforePutBehindBorder) <= (fieldLength / 2)) {
    traveled = Math.abs(initPos.getX()) - Math.abs(playerLocationXBeforePutBehindBorder);
}
double result = -5000;
if (traveled != 0) {
result = (Math.abs(initPos.getX()) * maxTime) / traveled;
}

Chôdza (rýchlosť)

Cieľ tejto disciplíny je podobne ako v predchádzajúcej dostať sa na druhú stranu ihriska, avšak podstatnejšia ako stabilita je rýchlosť hráča a preto tu hráč nedostáva trestné sekundy.
Ako v predchádzajúcom prípade tu bola zadefinované nesprávna počiatočná pozícia hráča a tiež neexistovala kontrola prípadu, keď server premiestni spadnutého hráča za hranice ihriska. Taktiež sme tu našli chybné počítanie lineárnej aproximácie času pre prípad, keď hráč nestihne prejsť na druhú stranu ihriska v časovom limite. Opravili sme to podobne ako v predošlej disciplíne.

Kopanie do lopty (vzdialenosť)

Cieľom tejto disciplíny je kopnúť loptu čo najďalej v rozmedzí piatich pokusov. Disciplíny, kde sa vyžaduje kopanie hráča do lopty sa od ostatných odlišujú, že ich merania sú odštartované v hracom režime „KickOff_Left“ namiesto „PlayOn“. Vo vtedajšom kóde sme to podľa tohto upravili.
Znova sme pridali kontrolu premiestnenia hráča serverom za hranice ihriska.
Pravidlá k disciplíne udávajú aj to, že pokiaľ hráč počas kopnutia spadne, vydelí sa výsledná vzdialenosť dvomi. Pridali sme kontrolu pádu hráča a ak sa tak stane, je to zaznamenané v premennej:

if(!playerFalled && ss.getScene().getPlayers().get(0).isOnGround()){
    playerFalled = true;
}

Starý kód zastavoval meranie kopu vtedy, keď lopta prešla určitú malú vzdialenosť. Toto však nebolo výhodné a nahradili sme tým, že meranie sa zastaví vtedy, keď sa lopta prestane hýbať po tom, čo sa už hýbala:

if(ballMoved && !ss.getScene().isBallMoving()){
return true;
}

Starý kód vyhodnocoval disciplínu tak, že sa až na konci pozrel, či je hráč na zemi a vtedy delil výsledok dvomi. Tento stav bol nevyhovujúci, pretože hráč mohol počas disciplíny padnúť, vstať a potom kopnúť do lopty a skončiť na konci disciplíny vo vzpriamenej polohe. Toto sme nahradili podmienkou, v ktorej figuruje už spomínaná premenná, v ktorej je uložené, či hráč niekedy počas kopu padol na zem.

Kopanie do lopty (presnosť)

Podobne ako v predošlej disciplíne sme potrebovali upraviť štart merania do fázy „KickOff_Left“. Znova sme pridali kontrolu premiestnenia hráča serverom za hranice ihriska.
Ďalšie pravidlá sú kopnutie lopty smerom k niektorému rohy ihriska, penalizácia pádu násobením odchýlky kopu od rohu ihriska dvomi a prejdenie lopty minimálne 1,5 metra.
V tomto prípade už kód obsahoval zastavenie merania v prípade, že sa lopta hýbala a prestala sa hýbať. Ostatné veci boli taktiež v poriadku.

Otočenie hráča

Cieľom tejto disciplíny je otočenie sa o 180 stupňov s toleranciou 5 stupňov, pričom sa z dvoch pokusov započíta ten rýchlejší.
Znova bolo potrebné pridať iniciálnu pozíciu hráča. Znova sme pridali kontrolu premiestnenia hráča serverom za hranice ihriska.
Kontrola toho, kedy sa hráč úspešne otočil bola vo vtedajšom kóde robená veľmi komplikovane a vo veľa prípadoch vyhodnocovala disciplínu nesprávne. My sme si na začiatku určili hodnoty uhlov natočení, medzi ktorými je možné vyhodnotiť, že sa hráč úspešne otočil. Jednoduchými podmienkami sme to potom v metóde „isStopCriterionMet“ kontrolovali spolu s tým, či je hráč zároveň aj v stojacej polohe:

boolean standing = false;
if (p.getBody().getHead().getTransformation().getValues()[14]>= 0.45) {
    standing = true;
}
boolean turned = false;
if (exptectedRotation1 <exptectedRotation2) {
    if (actualPlayerRotation>= exptectedRotation1 && actualPlayerRotation <= exptectedRotation2) {
   turned = true;
    }
} else {
    if (actualPlayerRotation>= exptectedRotation2 && actualPlayerRotation <= exptectedRotation1) {
        turned = true;
    }
}
if (standing && turned) {
    return true;
}

Bolo potrebné ošetriť aj vyhodnotenie nesplnenia disciplíny, ktoré sme vykonali vrátením veľmi veľkej hodnoty 5000s.

Zmeny spoločné pre všetky disciplíny

Vo všetkých disciplínach sme rozumne upravili ich výpisy. Nechali sme iba tie najdôležitejšie, teda tie, ktoré hovoria o začiatku, konci, vyhodnotení disciplíny s vypisovaním penalizácií a podobne. Zmenili sme level výpisov na INFO, čo znamená, že Test Framework ich zobrazuje používateľovi v jeho spodnej časti bez nutnosti nastavovať level výpisov. Pretým bola väčšina výpisov levelu FINE a na ich zobrazovanie bolo potrebné Test Framework dodatočne nastavovať.