Med Asbjørn, Christer og Jesper

fredag den 9. november 2007

NXT programmering, lesson 8

Tidsforbrug: 3 timer. Deltagere: Asbjørn, Christer og Jesper.
Målet med dagens er, at eksperimentere med flere forskellige simultane adfærdsmønstre.

Vi vil gennemgå disse skridt et for et:
  • Ombygning af bilen.
    • Der skal monteres en ultrasonisk sensor.
  • Eksperimenter med den udleverede kode.
    • Først med et enkelt adfærdsmønster, derefter flere.
  • Diskussion af klasserne Behavior og Locomotion
    • Besvarelse af konkrete spørgsmål i opgaveformuleringen.
  • Tilføjelse af nyt adfærdsmønster: "kør mod lyset"
Ombygning af bilen.
Tidsforbrug: 15 minutter.

Vi har valgt at genbruge LEGO-modellen, vi brugte som sidste uges Braitenberg vehicle. Herpå har vi så monteret den ultrasoniske sensor ovenpå.

Eksperimenter med den udleverede kode.
Tidsforbrug: 45 minutter.

Først kørte vi kun med RandomDrive. Denne ændrede vi hurtigere og uden pauser. Dette gjorde vi fordi den kørte så langsomt, at den kun meget sjældent kørte ind i ting.
Herefter aktiverede vi AvoidFront klassen. Denne virkede dog ikke umiddelbart og gav en konstant måling på 255. Løsningen var at flytte sensoren fra port 4 til port 3. Nu virkede den, men den kørte stadig ind i ting. Problemet løste vi ved at sætte threshold op fra 20 cm til 40 cm. Dette bevirkede at den herefter stoppede i god tid før kollision. Til sidst aktiverede vi PlaySounds og observerede at alle tre adfærdsmønstre kørte.

Under vores gennemgang af koden opdagede vi et par småfejl. Et par steder (AvoidFront og PlaySounds) fandt vi en række drawString() inde i en løkke. Dette er ikke noget problem i sig selv, men når den opretter et nyt String-objekt hver gang og VM'en ikke har en garbage collector, bliver det et problem med memory leaks. Vi løste problemet ved at ændre disse til drawChar(), da det alligevel kun var et enkelt bogstav den udskrev hver gang.

Diskussion af klasserne Behavior og Locomotion.
Tidsforbrug: 30 minutter.

Hvad er formålet med daemon threads?
En daemon thread kan ikke holde Java VM'en kørende hvis programmet afsluttes.

Hvordan bruges undertrykkelses booleanvariablen i LocoMotion.java?
Hvis en klasse har sin undertrykkelsesboolean sat, vil LocoMotion ikke adlyde den. Dens adfærd bliver da undertrykt.

Hvordan vil vi beskrive delay metoden i Behavior?
Det er en metode der busywaiter til en af to ting sker:
  • Den når sin timeout værdi.
  • Den er undertrykt.
Formålet er at være en slags adfærds-reset.

Hvordan bruges undertrykkelsesmekanismen i Behavior til kontrolleret adgang til motorerne?
Som udgangspunkt skiftes adfærdsmønstrene til at tilgå motorerne. Hvis en adfærd er undertrykt, vil delay-metoden afslutte med det samme og adfærden vil ikke kunne komme til udtryk.

Er der situationer hvor denne model fejler?
Når den bliver undertrykt, vil en adfærden løkke bare stå og loope. I det øjeblik den ikke er undertrykt mere, vil den stoppe et sted i løkken. Vi kan ikke være sikre på hvor dette sker, men kun håbe på at det er et "godt" sted.

Tilføjelse af nyt adfærdsmønster: "kør mod lyset"
Tidsforbrug: 1 time og 30 minutter.

Det første vi gjorde var en mindre refaktorering af den udleverede kode. I den udleverede kode skal en behaviour eksplicit kende alle behaviours den vil undertrykke. Dette gør det besværligt at tilføje nye behaviours eller ændre rækkefølgen af eksisterende behaviours. Vi udvidede Behaviour super-klassen med to feltvariable: child og childSuppressed, hvor child er en Behaviour og childSuppressed er en boolean. Desuden udvidede vi koden i Behaviour med:

private void updateChildSuppressed()
{

if(child != null)
child.setSuppressed(suppressed || childSuppressed);
}

Et child er altså suppressed hvis enten dens ane er suppressed eller dens ane eksplicit har bedt om at barnet er suppressed. På denne måde får vi en kæde af behaviours hvor den enkelte behaviour kun behøves at kende til den umiddelbart foregående.

Til denne delopgave udvidede vi bilen med en lyssensor. For at kunne observere den nye adfærd i detalje, måtte vi ændre et par af de andre adfærdsmønstre:
  • RandomDrive blev ændret til at køre mere i cirkler og mindre lige ud. Hermed ville det være nemmere for den at "få øje på" lyskilden.
  • Threshold for AvoidFront blev sat ned til 30 cm. Igen pga det lille testrum.
Vi havde sidste gang eksperimenteret med en robot der kan søge lyset ved at kigge på forskellen mellem to lyssensorer. Vi var dog kun i stand til at anskaffe to RCX lyssensorer, disse var dog ikke gode nok til at skelne små forskelle i lys så det kom aldrig til at virke særligt god. Denne gang valgte vi derfor en simplere metode der kun kræver en enkelt lyssensor og derfor kunne vi bruge NXT sensoren. Algoritmen var simpel: Vi beregner et vægtet løbende gennemsnit (som beskrevet i teksten her) af de lysværdier vi har set og hvis den værdi vi måler nu er større end gennemsnittet antager vi at robotten peger mod lys, suppreser barnet til vores Behaviour og sætter bilen til at køre fremad:

avg.addValue(val);
if(val > avg.get())
{
setChildSuppressed(true);
Locomotion.forward(300, 300);
delay(300);
}

Denne behaviour blev indsat mellem DriveRandom og AvoidFront:

RandomDrive rd = new RandomDrive("Drive", 1);
GoTowardsTheLight gl = new GoTowardsTheLight("Light", 2, SensorPort.S4, rd);
AvoidFront af = new AvoidFront("Avoid", 3, SensorPort.S3, gl);
PlaySounds ps = new PlaySounds("Play", 4, af);

Ideen er at hvis vi ikke ser lys kører vi tilfældigt rundt. Når vi så (tilfældigvis) peger i retningen af lys kører vi fremad. På den måde burde vi i længden nærme os eventuelle lyskilder.

Nedenstående billede er taget med lang lukketid i et møkelagt rum. Kameraet var indstillet til først at tage et billede med blitz og derefter holde sig åbent i 15 sekunder. Da det er håndholdt, er der en vist mængde af rysten, hvilket kan ses på, at lyskilden øverst til venstre i billedet har flyttet sig undervejs. Det ændrer dog ikke på billedets centrale budskab.
Til at begynde med stod bilen hvor den ses på billedet. Efter lyset blev slukket ses det, at den først drejer rundt om sig selv. Da får den øje på lyskilden og kører hen mod denne. Lige før den når frem, træder AvoidFront adfærden i kraft og den bakker tilbage. Til sidst kører den tilfældigt og taber lyset af syne, hvorefter de 15 sekunder er gået.

Ingen kommentarer: