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".
Ingen kommentarer:
Send en kommentar