torsdag den 20. november 2008

Uge 11; 'Behavior and Arbitrator'

Deltagere:
Morten, Lars og Thomas.

Goal:
At undersøge opførsel-baseret arkitektur, implementeret ved hjælp af klasserne lejos.subsumption.Behavior og lejos.subsumption.Arbitrator.
Samt at lave en alternativ implementation af Arbitrator-klassen.

Plan:
(1) Uploade samples/BumberCar/BumberCar.java til NXT-robotten.
(2) Indse at hvis en Behavior's takeControl metode returnerer sand, efter denne lige har kørt, får den ikke lov igen før en anden behavior har kørt.
(3) Undersøge om takeControl i klassen DriveForward kaldes, hvis den overliggende HitWall er aktiv.
(4) Implementere en tredie Behavior Exit, der reagerer ved tryk på ESCAPE-knappen ved kald af System.exit(0). Exit skal have højeste prioritet.
(5) Undersøg hvad der sker ved tryk på ESCAPE samme tid med at HitWall er aktiveret.
(6) Undersøge om det er muligt, for HitWall-behavioren fortsat at kontrollere motorerne efter suppress metoden er kaldt fra Arbitrator.
(7) Implementere en fjerde Behavior PlaySound, der reagerer ved tryk på ENTER knappen og afspiller en lyd. PlaySound skal indsættes i prioritetsarrayet mellem DriveForward og HitWall.
(8) Forklare hvad der sker når robotten kører og Hitwall aktiveres, hvorefter PlaySound aktiveres mens Hitwall stadig er aktiv (og dernæst escape-behavioren).
(9) Implementere en alternativ Arbitrator, hvor takeControl kaldes for alle Behaviors hver gang løkken gennemløbes. Undersøg betydningen af at metoder kan lave busy-wait og dets indflydelse på action metoden.

Activities:

(1)
Overførslen af BumperCar.java til NXT'en gik uden problemer som forventet.

(2)
Ved udførsel af programmet observeres den forventede opførsel, således at robotten stopper helt når tryksensoren holdes inde. Efter at have studeret kildekoden til Arbitrator, er det klart at en behavior maksimalt må udføres en gang i træk(det står endda kommenteret i koden), derudover er koden struktureret således at en behavior med højere prioritet stadig suppresser andre behaviors selvom den ikke selv er i stand til at køre.

(3)
Ved at studere Arbitratorkoden ser vi, at det kun er muligt for en behavior der ligger over den nuværende, at preempte en allerede kørende behavior. Derfor vil den lavere liggende behavior aldrig blive udført, dette betyder dog ikke at den lavere rangerende behaviors takeControl() metode ikke bliver kaldt, behavioren bliver blot sat til at vente, indtil den overliggende er færdig med at køre.

(4)
Implementationen af escape-behavioren, kan findes her. I al sin simpelhed fungerer den ved at returnere sandt i takeControl, såfremt escape-knappen er trykket ned, hvor efter action-metoden afslutter hele programmet. Exiteren fungerer som ventet, når den indsættes sidst i behavior-arrayet.

(5)
Som ventet ser vi, at programmet terminerer ved tryk på escape-knappen, dette skyldes naturligvis, at den højere liggende behavior bliver injectet i actionthreaden uden at vente på, at denne afslutter den igangværende opgave.

(6)
Det viser sig, at det er muligt for Hitwall-behavioren at bevare kontrollen over motorerne i et forventet kort tidsrum efter suppress metoden er kaldt. Dette kan lade sig gøre, hvis der sker et trådskift lige efter suppress-metoden er kaldt, så vil actionthreaden nå at udføre action metoden, før der igen skiftes så suppress-metoden bliver fuldført.

(7)
Sound-behavioren er implementeret således, den minder meget om exit-behavioren, blot aktiveres den ved en anden knap og i stedet for at lukke programmet spiller den en lille melodi. Efter indsættelsen af sounder-behavioren, ser vores behaviorhieraki således ud:

DriveForward > PlaySound > HitWall > Exit

(8)
Dette eksperiment udførtes ved at starte robotten, aktivere tryk-sensoren og derefter, mens hitwall-behavioren er aktiv, aktivere sounder-behavioren. Vi havde forventet at sounder-behavioren ville overtage når den overliggende hitwall var færdig med at køre, dette var dog ikke tilfældet, istedet begyndte robotten blot at køre lige ud igen. Efter at have gransket koden igen, viser det sig at sounder-behavioren aldrig kommer i kø, da den lavest prioriterede behavior(DriveForward), som altid ønsker at køre, nærmest ikke kan undgå at komme først i køen(med mindre man er endog meget hurtig på knappen) og når der allerede er en behavior i kø ignoreres alle de andres ønske om at køre.

(9)
Her findes implementationen af vores egen abitrator, OurArbitrator.java. Til forskel fra den oprindelige klasse, sikrer vi os at hver behavior får tid til at køre i hvert gennemløb af arbitratorens løkke. Hver behavior startes i en ny tråd, som nedlægges når behaviorens har udført sin handling eller den interruptes af en højere prioriteret behavior, dette står i kontrast til den oprindelige arbitrator hvor den valgte behavior injectes i den allerede kørende tråd. I vores implementation er det hver behaviors ansvar holde øje med hvor vidt den er blevet interrupted. Vores arbitrator giver mulighed for at gentage en behavior lige så mange gange det skulle være nødvendigt og hvis der er tale om en gentagelse hvor den sidste udførelse ikke er færdig, så vil den gamle tråd fortsætte sin udførsel, således opnår vi, at en behavior ikke resettes unødigt.

Conclusion:
Meningen med denne uges labøvelser, var bl.a. at undersøge Arbitrator klassen i lejos.subsumption pakken.
Igennem arbejdet med de opsatte punkter for labøvelsen, fik vi et indtryk af en ikke helt gennemtænkt / veldesignet 'Behaviour-based-architecture'.
Umiddelbart er det ikke oplagt hvorledes pakken skal bruges, dvs. hvis man ikke har lavet ovenstående øvelser eller selv skrevet koden, kan man nemt misse den initielle idé med hvordan koden skal anvendes, dvs. komme til at misforstå intentionen og derved misbruge koden.
Gennem de noget ledende spørgsmål, her ovenfor, viser lejos.subsuption.Arbitrator sig at blive mindre og mindre smuk.

Et delmål for ugens labøvese var også at konstruere en alternativ Arbitrator. Vi mener vi er kommet frem til noget der i det mindste er lidt bedre end den oprindelige. Metoden takeControl kaldes nu for all Behaviour i hvert gennemløb af Arbitrator løkken.
Et trick-spørgsmål var, om der er situationer hvor en lavere prioriteret Behavior ikke bliver suppressed af interrupt mekanismen. Svaret hertil er ja, idet det nu er Behaviour'erne selv der får ansvaret for at tjekke om de er interrupted.
Metoden takeControl i HitWall klassen er nu sat til at returnere den boolske værdi fra touchsensoren OR'et med en boolsk variabel 'working'. 'working' sættes til true som første statement i action metoden, og sættes til false igen som sidste statement i action metoden. I tilfælde af HitWall-Behaviour'en interruptes catches denne og 'working' sættes til false.

Angående returnering af motivationsværdier:
Så nåede vi ikke at eksperimentere med dette. Ideen er dog at i stedet for en absolut boolsk værdi. På f.eks. HitWalls action kunne man subtract'e en factor fra motivationsvariablen, indtil denne bliver nul, og sætte variablen til en maksimal værdi hver gang touch aktiveres.
En Behaviour som DriveForward kan sættes til altid at returnere en "næsten" maks værdi. Den må ikke være den maksimale værdi for en motivation fordi den ligger nederst i hierakiet, og der skal være plads til at højereprioritets behaviour, der meget gerne vil til, for lov at køre istedet.


Ingen kommentarer:

tagtagtag