torsdag den 27. november 2008

week 10

Deltagere: Peter, Michael, Asger
Varighed: 3 timer
Mål: Undersøg Behaviour programmering med nxj klasser

Plan:
* Kør BumperCar på NXT'en
* Undersøg koden for NXJ's behaviors
* Tilføj exit behavior
* Tilføj play behavior

Bemærk, vi bruger lejos 0.7, som har en forbedret Behavior og Abritrator

BumperCar på NXT


NXT'en kører fremad til touchsensoren bliver aktiveret, når det sker
kører den lidt tilbage, og dreje en smule til venstre. Derefter
starter den forfra. Hvis man holder touchsensoren nede bliver den ved
med at bakke og dreje gentagende gange, uden at køre fremad.

Koden


I Abritrator finder man en Monitor med følgende kode.

//FIND HIGHEST PRIORITY BEHAVIOR THAT WANTS CONTROL
highestPriority = NONE;
for( int i = maxPriority; i >= 0; i--)
{
if(_behavior[i].takeControl())
{
_highestPriority = i;
break;
}
}
if(_highestPriority > _current && _current != NONE)
{
_behavior[_current].suppress();
}
Thread.yield();


Det den gør er at gennemløbe alle behaviors startende med den der har
højst priotet, når den finder en som ønsker kontrol stopper den
gennemløbet og vælger den behavior.

Dvs. at DriveForward.takeControl kun bliver kaldt når HitWall retunere
false i sin takeControl.


Exit Behavior


At implementere en exitbehavior "burde" være simpelt. Desværre ser det
ud til at de ellers gode ændringer der er kommet i version 0.7 af NXJ
har tilføjet nogle nye problemer. Fx starter Abritrator en monitor
tråd, som ikke er sat til daemon, derfor kan ens program ikke afslutte
så længe den tråd kører, hvilket den bliver ved med så længe, at der
er en Behavior der vil have kontrol. Derfor, for at lave en
exitbehavior, så skal den have kendskab til alle andre behaviors, som
have mulighed for at slå dem alle fra.

Opdatering:


Ved at Kalde Abritrator med false som andet argument, så den ikke ikke
retunere ved inaktivitet, så fungere det hele meget bedre. Dog er
semantiken for action og suppress ændret lidt, så suppress bliver kun
kaldt, hvis action ikke har retuneret før en anden Behavior skal
afvikles. Derfor lavede vi om i DriveForward, så den har en whileløkke
der bliver ved med at kalde Thread.yield() indtil suppress bliver
kaldt, på den måde er vi sikret at suppress bliver kaldt.

Play sound


Når alle behaviors er sat ind, og man aktivere hitwall og sound
samtidig, så ignorers sound da hitwall har højere priotet. Hvis man
derefter aktivere exit, så afslutter programmet.

torsdag den 20. november 2008

Legolab week 9


Legolab week9

Dato: 20/11 2008
Tidsforbrug: 3 timer
Deltagere: Michael, Asger, Peter

Plan:
* Teste præcisionen af relativ positionering.


=== Teste præcisionen af relativ positionering.
Vi bruger en standard robot lavet fra byggevejledningen i LEGO 9797
sættet s. 8-22.

-- Kalibrering.
Vi kalibrerer både omkredsen af hjulene og hjulafstanden. For at
kalibrere omkredsen lader vi robotten køre en meter frem og stoppe. Så
kan vi teste om de præcist er 56mm i diameter som der står påtrykt på
hjulene.

Kalibrering af hjul:
Vi kalibrerede robottens hjuldiameter ved at bruge programmet
CalHjul.java
.

Da vi satte robotten igang så vi straks at den drejede en smule til
den ene side, fordi hjulene ikke var præcist lige store. Vi satte en
whiteboard marker på robotten for at den kunne tegne den vej den
faktisk kørte. Det viste sig at den kørte vej, afveg 1cm fra en lige
streg over en afstand på en meter. Vi løste problemet ved at prøve
forskellige hjul, indtil vi fandt 2 ens hjul, der kun gav en afgivelse
på 2mm over afstanden på 1m.

Med en hjuldiameter på 56mm kører robotten 1cm forkort
på 1m, så den faktiske hjuldiameter for robotten er en smule mindre
nemlig 55,44mm.

Vi kørte 3 test med den nye hjuldiameter. Alle gav en afvigelse på
under 1mm, over afstanden på 1m.

--- Kalibrering af hjulafstand.

For at kunne dreje præcist med TachoNavigator klassen, skal man kende
den diameter robotten drejer om. Vi har målt den til at være 110mm,
for at eftertjekke dette har vi lavet et lille program

CalDistance.java
som drejer 2 gange rundt om sig selv i step af
45 grader.

Vi ser at robotten faktisk drejer præcist med en hjulafstand på 110mm.

--- Test af kalibrering.

Vi tester præcisionen af robotten ved at lade den køre samme rute som
i Brian Bagnall's bog, kapitel 12, men vi lader vores robot køre turen
2 gange så vi bedre kan se effekten af akkumuleret fejl. Programmet vi
har brugt er TestCal .

Resultat:

Det viser sig at robotten er omtrent 40cm fra origo når den slutter
sin anden runde. Vores første tanke var at det skyldes at
TachoNavigators goTo metode var upræcis, så vi udregnede selv de
vinkler og afstande der skulle bruges. Resultatet var det samme. Ved
at montere en whiteboard marker på robotten kunne vi se hvilken sti
den kørte på gulvet. Det viser sig at robotten slet ikke kører lige
selvom vi kalibrede den til at kunne køre ligeud. Over 2m afviger
banen robotten kørte, 2 cm fra en lige linje, dvs den har en afvigelse
på 2,26 grader pr meter den kører. Det betyder at hvis vi kører 10m
har vi en akkumuleret afvigelse af vinklen på 22,6 grader. Det passer
godt med den observerede slutafvigelse for vinklen i vores test.

Men da vi havde slet ikke så store afvigelser i den kliniske test vi
kørte. Konklusionen må hermed være at batteriniveauet eller overfladen
der køres på spiller en rolle for præcisionen af robotten. Når denne
styres vha.

Week 8 - Prioriteret opførsel

Date: 20/11-08
Duration of activity: 3hours
Group members: 20051770, 20051866 og 20052051




LEGO car that exhibits several behaviors



Goal:
Beskrive hvordan Jack opfører sig når vi kører programmet
SoundCar.java
på ham og tolke det output han giver.

Plan:
Oploade programmet og lade Jack gøre det han gør bedst. Excekverer det.

Robot:
Vi brugte samme robot som til øvelserne i uge 7.

Code:
SoundCar
er det primære program.

Hjælpeklasserne er:
AvoidFront
Behavior
Car
PlaySound
RandomDrive

Resultater:
Vi så at hvis Jack blev overladt til sig selv, kørte han glad rundt på
må og få og spillede lyde engang imellem. Hvis vi så stak en hånd ned
foran ham, så vi at han bakkede bagud og drejede mod venstre for at
kunne køre i en anden retning end der hvor noet blokerede hans vej.

Vi så også at hans opførelser kunne blokere hinanden, da vi kunne
sætte en hånd ned foran ham mens han kørte rundt og han ville straks
stoppe og bakke væk. Dog stoppede han helt op selvom der var en hånd
foran ham, hvis han skulle til at spille en melodi, da denne opførsel
blokerer for alle andre.

På LED'et havde de forskellige opførsler fået en linje hvor de kunne
printe deres opførsel. 'f' hvis de kørte fremad, 'b' hvis de kørte
bagud og 's' hvis de stoppede Jack. Her kunne man igen se hvordan de
forskellige opførsler blokerer hinanden.

Konklusion:
SoundCar ser ud til at give Jack flere forskellige opførsler, to han
kan bruge til at bevæge sig rundt i verdenen og "fløjte" og én til at
køre væk fra objekter han ellers vill være kørt ind i. Vi kan se at
implementationen virker, da Jack stopper med at køre rundt på må og få
hvis han skal fløjte eller undgå en hånd.


Class Behavior



Hvis vi kigger i SoundCar klassen kan vi se at der bliver oprettet 3
tråde, en RandomDrive tråd, en AvoidFront tråd og en
PlaySoundTråd. Hver ny tråd får de foregående givet med i sin
konstruktor, således at den kun undertrykke deres opførsel.

Formålet med at gøre de tre ovennævnte tråde til daemons er så vidt vi
kan se udelukkende at man så slipper for at "holde styr på dem". Dvs
vi behøver ikke vente på at de lukker ned før vi stopper programmet.

Opførslen i SoundCar er implementeret ud fra Subsumption Architecture idéen.

Idéen baserer sig på at opførelserne er strukturet i lag, hvor
"reflekserne" ligger i bunden og "overvejede" handlinger ligger
øverst. En opførsel kan så blokere de ovenliggende opførsler, således
at disse ikke udføres.

Et eksempel vil være en overvejet handling som at bevæge sig mod en
dør og refleksen at flytte sig fra det søm man lige har trådt på. Her
skal refleksen naturligvis blokere for at man bevæger sig videre mod
døren indtil sømmet er ude.

Implementationen af Behavior klassen virker ved at hver underliggende
handling kender til alle de ovenstående og så blokerer hver eneste af
dem når dens egen opførsel skal udføres.

Dette er en udemærket implementation så længe vi ikke har mange
forskellige behaviors. Hvis vi derimod havde mange behaviors ville en
anden implementation mæske være bedre. Vi forestiller os et array af
opførsler med et blokerings indeks, der kan fortælle hvorfra og
opefter opførsler er blokeret. Dette ville forhindre at alle
ovenliggende opførsler skulle tilføjes i konstruktoren som det gøres
nu, se bl.a PlaySound, men istedet skulle opførslen bare tilmelde sig selv til en
BehaviorController klasse og tilgå motore gennem denne klasse.

Dette ville bl.a gøre det muligt at udkommentere AvoidFront tråden
uden at ændre for meget i koden. Pt. hvis man vil af med AvoidFront,
skal man også rette i PlaySound Klassen, da denne kræver to Behavior
objekter, men nu kun skal blokerer RandomDrive. (Alternativt kunne man
give RandomDrive med to gange til PlaySound, men dette er heller ikke
synderligt kønt)


Added "Drive Towards Light" behavior



Goal:
Vi skal tilføje en opførsel til Jack, således at han sammen med de tre
tidligere opførsler nu også vil søge mod lyset. Denne nye opførsel
skal spille sammen med de tre tidligere og undertrykke dem hvor det mening.

Plan:
Planen er ganske simpel. Vi skal med udgangspunkt i
vores SensorBot
klasse fra uge 7 bygge en FollowLight klasse, som nedarver fra
Behavior klassen og bruger denne til at arbejde sammen med de andre behaviors.

Måden vi har tænkt os at gøre dette på er ved at bygge en FollowLight
klasse, der nedarver fra Behavior og i run implementerer en algoritme
til at køre mod lys.

For ikke at skulle ændre alt for meget på opførsels rækkefølgen,
behavior stakken, vælger vi at lægge FollowLight ovenpå og lade den
blokerer alt andet hvis Jack ser et lys han kan køre
mod. Dvs. prioriteringsrækkefølgen er RandomDrive, AvoidFront,
PlaySound og FollowLight. Besynerligt nok vil Jack dermed hellere
følge efter et lys end at undgå en lavthængende bro lige foran ham.

Da måden Jack "ser" lys på er ved at observerer forskelle i lyset til
venstre og lyset til højre for ham. Vi antager at disse godt kan
varierer uden at Jack faktisk har set et lys og vælger derfor at
FollowLight først skal sætte ind hvis hvis forskellen kommer over et
threshold, som vi finder ved trial and error.

Kode:
Koden for den nye main klasse kan ses i
LightSoundCar

Selve koden der får robotten til at følge efter lys er implementeret i
en do-while løkke der bliver ved med at køre indtil lysforskellen
kommer under thresholdet. Når dette sker holder klassen op med at
undertrykke de "højere" opførsler.

Den modificerede SensorBot ligger i
FollowLight

Resultater:
Robotten reagerer fint på lys og vi kan se på displayet at den
undertrykker de andre.

Desværre har vi også set PlaySound klassen afspille lyd og "låse op"
for AvoidFront og RandomDrive.

Konklusion:
Behavior implementationen har vist nogle kraftige mangler i disse
forsøg. Vi har observeret at selvom opførsler ikke selv er i stand til
at overtage styringen fordi de bør være undertrykte, kan de godt låse
op for højereliggende opførsler.

Et hotfix til dette ville være at suppress alle andre opførsler inde i
vores løkke i, så det ville se således ud.


do {

b1.setSuppress(true);
b2.setSuppress(true);
b3.setSuppress(true);
int rightSpeed = rightLight * SPEED_GAIN;
int leftSpeed = leftLight * SPEED_GAIN;
forward(rightSpeed, leftSpeed);

rightLight = rightLS.readPercent();
leftLight = leftLS.readPercent();

} while (threshold < (rightLight - leftLight));


En anden og bedre er at hver klasse i deres while-loop som det første
checker om de er suppressed og hvis de er så ikke gør noget derfra.

En helt tredje er at man som nævnt ovenfor implementerer en behavior
stack, der som et minimum ikke tillader undertrykte opførsler at
ændre på om andre opførsler er undertrykte. En lidt udvidet
implementation ville endda selv schedule opførselstrådene og ikke køre
de undertrykte.

Vores konklusion er at Behavior klassen virker, men den kræver at man
har tiltro til de klasser der extender den, da det er alt for nemt at
implementere en klasse som låser op for sig selv eller andre uden at
"have tilladelse til det".

mandag den 3. november 2008

Week 7 - Braitenberg vehicles

Deltagere: Asger, Michael og Peter
Varighed: 4 timer.
Målet er at se hvordan Braitenberg køretøjer reagerer ved påvirkninger udefra.

Plan:
  1. Se at køretøj 2a kører mod lyset, hvis den ser lys.
  2. Se at køretøj 2b vil afvige fra en lyskilde.
  3. Gøre koden adaptiv overfor ændringer i omgivelsens lysstyrke.



Robotten:
Da vi skulle bruge en robot trukket ved 2 uafhængige hjul, har vi bygget den "oprindelige" lego robot. Denne har vi udstyret med 2 lyssensorer, som peger fremad. Derudover er robotten udstyret med 2 fremadrettede lydsensorer.





Teori:
Teorien kan findes her.


Forsøg 1:
Det første forsøg vi har lavet med robotten var at forbinde sensorer til motorerne, som i køretøj 2a.
Ideen med dette køretøj er at det vil forsøge at køre mod sensorernes stimuli. Da vi har bruge lys sensorer, valgte testede vi køretøjet ved brug af lyset fra en lighter. Vores test viser at robotten kører mod flammen, hvis den er mindre end 30 cm. fra lighteren, er den længere væk er lyset fra flammen for svagt (I dagslys).

Forsøg 2:
I dette forsøg er højre/venstre sensor forbundet til venstre/højre motor, som på køretøj 2b.
Teorien er at køretøjet vil dreje væk fra den sensor der får et stimuli. Igen har vi brugt en lighter som lyskilde, robotten drejer væk fra ilden, hvilket er meget smart, så den ikke bliver brændt af :)

Forsøg 3:
Formålet med forsøget er at få robotten til at ændre opfattelsen af hvad der er gennemsnitlige lysværdi.

For at gøre det laver vi et løbende gennemsnit.
Lad A være det løbende gennemsnit, v være den nuværende lysværdi og N er antallet af målinger der udregnes over.
Formlen for det løbende gennemsnit er så:
A := v/N + (1 - 1 / N) * A

Denne formel gør at vores gennemsnit vil konvergere mod vores målinger over tid, således at vores robot vil kunne begå sig i et foranderligt miljø.

Robottens gennemsnitlige lysværdi er adaptiv overfor ændringer i lysforholdene. Med de nuværende konstanter der bliver brugt i koden tager det ca. 20 sekunder fra der sker en markant ændring i lysforholdene, til der er en ny stabil gennemsnitlig værdi.

** snip
Vores normalize funktion er ganske simpel.
Den lader kun lys og lyd værdier på over average påvirke jack, da average ses som værende baggrundsstøj.
Den returnerer så lysværdien minus lydværdien og bruger denne som power til motorene. Ideen er at jo mere lys der er jo hurtigere kører jack og jo mere lyd jo langsommere.

Tests:
Succeskriteriet for vores robot er at dens threshold værdier kan ændre sig løbende alt efter dens miljø og at den vil reagerer veldefineret når den ser stærkt lys.

Det første succeskriterie blev opfyldt da vi kunne se vores robots average værdi ændre sig alt afhængig af om vi slukkede eller tændte lyset.
** snip