torsdag den 15. november 2007

NXT Programming, Lesson 9

Varighed: 4 1/2 timer, Deltagere: Rolf og Janus

Målet med dagens øvelser er at prøve at navigere ved hjælp af den indbyggede tacho-tæller i NXT motorerne og se hvordan to motorer i lejOS-systemet kan benyttes med lejOS klassen TachoNavigator til at styre så præcist som muligt - og hvor præcist systemet kan holde styr på position og retning.

Eftersom vi har været venlige at udlåne bilen fra sidste uge til en anden gruppe er planen følgende:

  • Genbyg standardbilen fra 9797 instruktionshæftet
  • Test af TachoNavigator-klassen fra lejOS omkring navigation
  • Undersøgelse af hvordan dette kan kombineres med et avoiding-system
  • Konklusion baseret på resultaterne

Navigation

For at undersøge TachoNavigator-klassen har vi lavet klassen Navigator som laver en instans af TachoNavigator og bruger denne. Den første test er at udføre en række bevægelser og så returnere til start-punktet:

  resetAndWait();
  nav.goTo(100, 0);
  nav.goTo(50, 50);
  nav.goTo(50,-25);
  nav.goTo(0,0);

TachoNavigator-klassen benytter hjul-diameteren og afstanden mellem de 2 hjul til at bedømme hvor den er, det er derfor vigtigt at få de korrekte målinger af disse for at få så korrekt en navigation som muligt. Først havde vi fejlmålt afstanden mellem hjulene til 13cm, hvilket gav en helt forkert positionering i testen. Da vi målte efter til 11,3cm var testen stadig en smule forkert. Vi kiggede derfor nærmere på hvor hjulene havde kontakt med jorden (omdrejningspunkterne) og brugte en afstand på 11cm. Dette gjorde at testen nu blev udført med stor nøjagtighed, robotten stoppede indenfor omkring 2cm af oprindelsespunktet, hvilket kan siges at være meget præcist givet de tekniske begrænsninger i NXT'en.

Vores anden test var et forsøg på at bedømme TachoNavigatorens evne til at måle afstand. I Brian Bagnall's noter skriver han at "Blightbot does a good job of measuring distance but his weekness arises when he rotates". Vi vil derfor se præcist hvor god Tacho-controlleren er til at måle afstand:

  // Test 2
  resetAndWait();
  nav.goTo(200, 0);

I denne test kører vi 2 meter fremad. Vi gentog testen 3 gange og selv om det var svært at få robotten til at køre i præcis samme retning (når vi sætter robotten ned kan der være en grads forskel på retningen) stoppede den på præcist den samme afstand hver gang.
Men hvad så hvis man vil køre den samme afstand men i mindre stræk af gangen?

Vores tredje test var en afstandstest, hvor navigatoren blev sat til at teste en kørsel på 200cm men i træk af 20cm:

  resetAndWait();
  for (int i=1; i<11; i++){
   nav.goTo(20*i,0);
  }

Robotten holder en synlig pause imellem hver kommando, hvor det er tydeligt at lejOS laver små korrektioner (f.eks. for at undgå at motoren overskyder og kommer for langt). I et enkelt af forsøgende var denne korrektion forskellig på de to motorer, hvilket resulterede i at robotten drejede en lille smule til venstre - hvilket klart ikke er intentionen. Ud over dette problem var den tilbagelagte afstand den samme som før.

Den fjerde test testede rotation. Det viste sig dog at hvis man kalder rotate(360) bevæger robotten sig ikke ud af stedet idet den automatisk ser at den allerede har den korrekte placering. Vi lavede derfor en ny test, hvor robotten drejede 360 grader rundt om sig selv i træk af 45 grader:

  resetAndWait();
  for (int i = 0; i<8; i++){
   nav.rotate(45);
  }

Resultatet var rimeligt præcist, men der var en lille fravigelse på omkring 8 grader. Dette passer fint med antagelsen om at drejning er en smule upræcist mens afstandsmåling er ganske præcist. Dette skyldes muligvist at "trædepuden" for hjulet er næsten en centimeter bredt og det derfor kan være svært at beregne den korrekte hjulafstand i alle situationer (små ujævnheder i overfladen der køres på kan også have indvirkning). Legos egen tacho-meter har en usikkerhed på omkring 1 grad pr roterings-kommando, hvilket med 2 hjul giver en større (omend fast) usikkerhed.

At finde vej uden om objekter

For igen at afprøve suppression-idéen fra sidste uge har vi valgt at lave et robot-styrings-system, der ved hjælp af forskellige behaviours finder vej uden om forhindringer i sin søgning efter målet (et forudbestemt punkt i koordinat-systemet fra TachoNavigoteren).

Som udgangspunkt forsøger NavigateCourse at bevæge sig imod destinationspunktet, denne opførsel kan dog undertrykkes af AvoidObject, som vil forsøge at forhindre kollision med forhindringer (baseret på input fra ultralydssensoren).

AvoidObject vil først forsøge at se (ved at dreje robotten) om det er muligt at køre til venstre rundt om objektet, og derefter om det er muligt at køre til højre rundt om objektet. Der er ikke nogen grund til at vælge denne rækkefølge frem for omvendt - i grunden kan valget være tilfældigt, men for at kunne genskabe fejl har vi valgt at fastlåse det.

En af de ting vi tidligere observerede omkring ultralydssensoren var at den har svært ved at "se" ting når lyden reflekteres fra en vinkel. Af denne grund har vi forsøgt at designe NavigateCourse således at vinklen når der måles så vidt muligt altid er 90 grader. Her antages det at robotten starter således at den står orthogonalt eller parallelt med alle flader i forhindringsbanen og at alle forhindringer er udformet som kasser af forskellige størrelser. Begge behaviours "forsøger at holde robotten langs linierne i koordinatsystemet" - dvs. alle drejninger er 90 grader. Et interessant problem er her muligheden for en større og større akkummuleret fejlprocent på grund af de mange drejninger.

En observation vi lavede var at det også er nødvendigt at NavigateCourse can suppresse inputet til AvoidObject når der drejes, således at målingerne kun foretages når NavigateCourse har positioneret robotten så den bevæger sig langs en af de imaginære linier - og ikke f.eks. imens der drejes.

En anden observation er at getAngle()-funktionen selv forsøger at korrigere for evt. fejl i forbindelse med sidste drejning, således at hvis der blev drejet for meget eller for lidt vil den på en 90-graders drejning ende med at returnere f.eks. 89 eller 91. Dette giver problemer i vores system, da modellen kun kan arbejde i hele drejninger. Vi har derfor valgt at kategorisere alt som er tæt på hele drejninger som værende præcis en hel drejning. Med andre ord vil robotten betragte et sving som "godt" hvis den tilnærmelsesvis ramte 90 grader i den rigtige retning.

Vores NavigateCourse-klasse bruger den udgave af goTo(), som returnerer med det samme (alternativet var at vente indtil kommandoen var udført). Det sidste problem vi løb ind i var at hver gang man kalder goTo(...) sker der en kalibrering af den sidst kørte afstand. Det betyder at hvis man konstant kalder goTo(...) vil robotten næsten stå stille. Som løsning lod vi derfor NavigateCourse se om robotten var i bevægelse i forvejen og i så fald vil den ikke kalde en ny goTo(...) blot for at sætte den samme destination.

Kildekode, billeder og film

Kildekoden til Navigator, NavigateCourse og AvoidObject kan findes her.

Test-banen, som ses på nedenstående billede var en samling papkasser spredt ud på gulvet. Opgaven var at bevæge sig 2 meter frem (målet er markeret på gulvet og robotten skal starte fra blyanten):
Følgende film viser et par forskellige forsøg på gennemløb.

Konklusion

Alt i alt virkede det ganske godt. Men det er lidt ærgeligt at den har den lille fejlmargen når den roterer, det betyder desværre at vores Avoidrobot ikke altid kommer helt pænt frem når den drejer meget. Selvom det i de fleste tilfælde (Som set på videoen) virker ret godt. Det trick som fik den til at virke til sidst var at korrigere for den forskel, der var i det vi ville rotere i forhold til det den troede den var roteret - hvis denne forskel kom over 2 grader lavede vi en korrigering. Bilen havde nemlig svært med at dreje bare 1 grad, hvilket også passer med den unøjagtighed som der er på grad tælleren på motorerne.

Ingen kommentarer: