tirsdag den 24. november 2009

Øvelse 10

Dato: 20. november 2009
Øvelsens varighed: 5 timer
Gruppemedlemmer: Annette, Samuel og Rasmus


Mål
I denne øvelse undersøges hvordan en behavior based arkitektur er blevet implementeret i subsumption API’en i leJOS NXJ. Specielt vil vi kigge på lejos.subsumption.Behavior interfacet og lejos.subsumption.Arbitrator klassen.

Baggrundsinfo
When most people start programming a robot, they think of the program flow as a series of if-thens, which is remeniscent of structured programming (Figur 1). This type of programming is very easy to get started in and hardly requires any thought or design beforehand. A programmer can just sit at the computer and start typing. The problem is, the code ends up as spaghetti code; all tangled up and difficult to expand. The behavior control model, in contrast, requires a little more planning before coding begins, but the payoff is that each behavior is nicely encapsulated within an easy to understand structure. This will theoretically make your code easier to understand by other programmers familiar with the behavior control model, but more importantly it becomes very easy to add or remove specific behaviors from the overall structure, without negative repercussions to the rest of the code. Let's examine how to do this in leJOS NXJ.
(Kilde: http://lejos.sourceforge.net/nxt/nxj/tutorial/Behaviors/BehaviorProgramming.htm)








Figur 1



Fremgangsmåde
BumperCar
1. Der monteres en touch sensor og ultralydssensor på bilen.

2. Der laves et nyt projekt ud fra BumperCar klassen.

3. Først undersøges hvad der sker når vi selv trykker touch sensoren ind og bliver ved med at holde den inde.

4. Nu skal koden til arbitratoren analyseres.

5. Der skal implementeres en tredje opførsel, Exit. Den skal reagere på tryk på ESCAPE knappen og gå ud af programmet. Den skal implementeres som den højeste prioritet og vi ser hvad der sker når ESCAPE knappen aktiveres.

6. Der laves en ny tråd som har til formål i et givent interval at aflæse den ultrasoniske sensor for at få en afstand. Værdien gemmes i en variabel som er tilgængelig i DetectWall.

7. DetectWall klassen ændres en smule så resultatet af at bilen kommer for tæt på en forhindring resulterer i at bilen først bakker i et sekund og efterfølgende drejer.

8. Undvigemanøvren skal kunne afbrydes og starte forfra igen hvis der detekteres en forhindring imens.



Resultater
Hele den færdige kode til alle øvelser kan ses under projektet Bumper.
1. Se billede af bilen i Figur 2.



Figur 2



2. Vi fandt BumperCar programmet i mappen samples/BumperCar som findes i LEJOS installationsbiblioteket.

3. Når touch sensoren trykkes ind sættes højre motor til at dreje 180 grader bagud og venstre motor sættes til at dreje 360 grader bagud. Det vil resultere i at den bakker mod højre for at undvige forhindringen.


4. I main oprettes to Behaviour instanser, b1 som er DriveForward og b2 som er DetectWall. De tilføjes til et array hvor den adfærd der ønskes lavest prioriteret står først i arrayet. DriveForward får lavest prioritet og DetectWall får næste prioritet. Efterfølgende oprettes en instans af Arbitrator med Behaviour arrayet og i Arbitratorens konstruktor oprettes en instans af Monitor klassen.

Arbitratoren har en start() metode, men den er ikke en tråd!! I start() metoden kaldes monitors start() metode og det er en tråd. Monitoren overvåger hvilken adfærd der skal have kontrollen. Det gøres ved at den går listen med behaviors igennem startende ved det højeste index, det vil sige adfærden med højeste prioritet. takeControl() kaldes på adfærden, her er det først DetectWall, som tester om touch sensoren er trykket ind eller ultralydssensoren er tættere end 25 cm fra en forhindring. Hvis der returneres false gås videre til index-1 hvilket betyder at DriveForward’s takeControl() kaldes og da den er i bunden af subsumption arkitekturen vil den altid gerne have kontrol og returnerer true.
Til sidst testes på om det er nødvendigt at undertrykke andre adfærd, hvilket det ikke er for DriveForward da det er den nederste, men hvis takeControl() på DetectWall havde returneret true skulle DriveForward adfærden undetrykkes.

5. Efter at have, implementeret exit() klassen, og lavet den til den Behavior med højst prioritet, afprøves den på robotten.
Første test, er at trykke på exit knappen, mens DriveForward opførslen er i gang. Programmet går lukket med det samme at exit knappen bliver trykket på, så der er ingen forsinkelse her. Næste test er at trykke exit, mens DetectWall opførslen er i gang. Det viser sig at der er forskel på hvornår man trykker. Hvis der trykkes mens hjulene drejer, sker der ofte ingenting. Hvis trykket lander lige i det hjulene stopper, når robotten de fleste gange at stoppe.

Efter at have rettet Sound.pause til 2000, afprøves exit metoden igen. Når touch sensoren trykkes ind første gang, går der et langt stykke tid før robotten begynder at bakke, som den skal i DetectWall. Dette skyldes at resten af programmet venter, mens Sound.pause(2000) bliver udført. Dette gør også at den ikke opdager et suppress kald mens den venter. Derfor er det nødvendigt at holde exit knappen inde, indtil den kommer til et sted i programmer, hvor dette bliver opdaget.
Hjulenes handlinger ser også ud til at blokere for andre handlinger, da der i versionen med de 20 ms pause, heller ikke blev opfattet et knaptryk på exit mens hjulene kørte. De 20 ms pause foregår inden hjulene bliver sat i gang, så det kan ikke være er overlap fra pausen.

6. Her brugte vi langt tid fordi vi havde problemer med at få implementeret tråden rigtigt. Den meldte ikke fejl under kompilering, men den ville ikke downloade programmet så det var meget vanskeligt at fejlfinde. Helt præcist hvad fejlen var lykkedes det ikke at finde ud af, for vi måtte prøve forfra med at implementere sensor klassen der nedarvede fra Thread.

Med den nye tråd implementeret, opfører robotten sig umiddelbart som den gjorde inden. Det der er forskellen på programmet som det var før, og som det er nu med tråden, er at programmet ikke bliver blokeret imens ultralyds sensoren læser.
Før var der en 20 millisekund pause, for at ultralydssensoren kunne nå at sende sin impuls ud, og få den ind igen. Denne pause gjorde at programmet ikke kunne modtage andet input i det tidsrum. Nu er alt håndtering af ultralyds sensoren lagt over i en tråd for sig, så hovedprogrammet kan køre frit imens.
Tidligere blev sleep kaldet sat op fra 20 til 2000 millisekunder, for at teste hvad der skete. Når touch sensoren blev aktiveret, eller afstanden var for lav, kunne man se, var at robotten først begyndt at bakke, efter de 2000 sekunder var gået. Samtidig kunne den ikke slukkes i tidsrummet.
Dette blev også afprøvet med den nye tråd. Her begyndte robotten med det samme at bakke, når Touch sensoren blev trykket på, men ikke ved ultralyds sensoren. Ved afstandsmålingen gik der omkring to sekunder før den reagerede, hvilket selvfølgelig skyldes at tråden venter i 2000 millisekunder mellem at den læser afstanden. Dog var det muligt at slukke robotten i disse to sekunders pause.
Sound.pause() er ikke det eneste der blokerer for slukning af robotten når den bakker. Når den bakker, sættes begge motoere til at dreje, men den første har "immidiate return" sat til True, hvilket den anden ikke har. Fordi det sidste motor kald ikke har immidiate return, blokere den stadig for resten af programmet til den er færdig.

7. Bilen sættes til først at bakke i et sekund inden den drejer ved at bruge Motors backward() metode og derefter kalde Thread.sleep() i 1000ms. Det betyder dog at det ikke umiddelbart er muligt at afbryde bagud kørslen hvis en forhindring detekteres imens så det er ikke den smarteste løsning. Vi har dog ikke tid til at gå mere ind i problemstilingen.

8. Som nævnt bruger vi Thread.sleep() metoden til at få bilen til at bakke i et sekund og derfor kan vi ikke bare afbryde og starte forfra midt i det hele.

Konklusion
Vi har undersøgt hvordan behavior og arbitrator fungerer. Der har specielt været fokus på at der ved specielle omstændigheder kan blokeres for en adfærd. Vi havde problemer med at implementere sensorlæsningen som en tråd, og det brugte vi lang tid på.

Referencer
Bumper, videreudvikling af BumperCar (Brian Bagnall and Lawrie Griffiths, modified by Roger Glassey)


torsdag den 19. november 2009

Øvelse 9


Dato: 13. november 2009


Øvelsens varighed: 3 timer


Gruppemedlemmer: Annette, Samuel og Rasmus


Mål

I denne øvelse skal vi undersøge tacho counteren af NXT motoren for at holde styr på positionen og retningen af en LEGO bil. Bilen skal være differential styret, dvs. de to motorer bruges uafhængigt til at drive og styre bilen. Desuden laves en undersøgelse af et kompas monteret på bilen. Hvornår er præcisionen størst.


Baggrundsinfo

Bilen i denne øvelse skal kunne dreje rundt på stedet. Dette opnås ved at sætte forward power på det ene hjul og backward power på det andet hjul.

Fremgangsmåde

Opgave 1: Præcision ved kørsel.
Den første øvelse handler om hvor præcist bilen kan vende tilbage til det samme sted og dermed hvor præcis tacho counteren er.


1. Montering
For at tilpasse bilen til denne øvelse monteres en tusch bag på, så den kan tegne på et white board ved undersøgelserne.


2. Navigation
I den første undersøgelse sætter vi bilen til at køre med default hastighed som er bestemt til at være 17cm/s (fundet ved udlæsning på display). Tacho counteren undersøges ved at programmere bilen til at køre 40 cm fremad (travel(40)) og efterfølgende kan vi se hvor langt bilen har kørt ved at måle længden af den tegnede streg.


3. Navigation
I denne undersøgelse sættes bilen til at køre i en lige linje fremad i 40 cm og efterfølgende dreje 180 grader om sig selv og igen køre 40cm. Dermed burde bilen ende samme sted som den startede.


4. Navigation
Nu sættes bilen til at køre i en firkant. Dette gøres ved at programmere den til at køre skiftevis 40 cm frem og drejer 90 grader til venstre indtil den skulle være tilbage ved udgangspunktet. Koden til disse undersøgelser kan ses i http://www.daimi.au.dk/~u071252/DL/Practice9/TravelTest.java.




Opgave 2: Undvige objekter.

  1. Robotten tilpasses ved at fjerne unødvendige tilbygninger, og sætte øge afstanden mellem hjulene. Dette gør at den har nemmere ved at bevæge sig. Ultralyds sensoren monteres, så robotten kan opdage de objekter den skal undgå.


  1. Øvelsen går ud på at få robotten til at undgå objekter og navigere via TachoPilot klassen. Robotten skal derfor kører tilfældigt rundt, og undgå objekter der kommer i vejen for den. Til dette bruger vi subsumtion arkitekturen fra øvelse 8.


Opgave 3: Navigation med kompas.


  1. Der monteres et kompas på robotten.


  2. Robotten skal navigere med kompasset, så præcisionen kan observeres. Til at starte med bruges TravelTest klassen fra opgave 1. Den eneste forskel er at der benyttes CompasPilot i stedet for TachoPilot.


  3. Da der i første forsøg ikke var indstillet på hjul størrelse og afstand, kalibreres dette. Derefter afprøves robottens præcision, i forhold til robotten uden kompas.


  4. Magnetisk Påvirkning
    For at se hvordan magnetisme påvirker kompasset, laves nogle ekstra tests med magnet og den kompas styrede robot.




Resultater


Opgave 1:



  1. På figur 1 herunder ses bilen med tuschen monteret.


Figur 1


  1. Tacho counteren er ret præcis. Når bilen sættes til at køre 40 cm kører den 40cm, se figur 2.


Figur 2

Under skrivning af den første testkode fandt vi ud af at klasserne der er vist i eksemplerne ikke virker eller er deprecated så vi endte med i stedet for at bruge TachoPilot klassen.

Der opstod også en smule forvirring angående F’et når man opretter en ny TachoPilot: Pilot pilot = new TachoPilot(5.6F, 20.0F, Motor.C, Motor.B, true);. Først troede vi at det betød at det var målesystemet hvor man bruger feet, så vi skulle finde ud af hvordan man angiver målene i cm. Vi fandt ud af at F betyder float, og at der ikke skulle skrives enheder på. Så længe man sørger for at bruge de samme enheder til alt hvad man angiver er det i stedet for et forhold som bliver beregnet.


3. Den er ikke så præcis når den skal dreje. Det ses på figur 3. Strækningen på de 40 cm passer igen som vi så under 2., men det går galt når den skal dreje de 180 grader om sig selv. Den kører ca. 20 grader for langt og ender altså et stykke fra udgangspunktet når den vender tilbage.

Figur 3

Problemerne skyldes blandt andet at tavlen er meget glat. Som en mulig løsning sættes et sæt ekstra hjul på og det hjalp lidt. Den skrider ikke så meget på underlaget når den skal dreje nu. Noget andet der har indflydelse er hvor hjulene er placeret, selvom man angiver afstanden mellem hjulene i koden, kan man ved at ændre på hjulenes placering få mere eller mindre fejl når bilen drejer om sig selv. Blandt andet oplevede vi at vi kunne få mindre fejl ved ikke at angive den korrekte afstand mellem hjulene.

4. Når bilen kører i en firkant spiller problemerne med underlaget selvfølgelig også ind. Derfor bliver det heller ikke en særlig lige firkant og bilen stopper et helt forkert sted i forhold til udgangspunktet, men her summeres fejlen også op da firkanten kræver at bilen drejer 90 grader tre gange, se figur 3. Dette problem med drift beskriver Brian Bagnall også.


Bare for at prøve det, satte vi bilen på gulvet uden tuschen for at se hvordan den så klarede firkanten. Det så meget bedre ud så den største fejlkilde kan altså tilskrives underlaget.

Opgave 2:




  1. På billedet herunder ses robotten med ultralyds sensoren. Desuden har vi også monteret compass sensoren, som først bruges i den 3. opgave.


Figur 4



  1. Opgaven virker umiddelbart nem, men Pilot klassen har en anderledes opførsel end de metoder der tidligere er brugt. Når robotten er sat til at udføre en handling via Pilot klassen, kan den ikke umiddelbart sættes til at gøre andet. Dette løste
    For at indføre subsumption anvendtes SoundCar programmet fra en tidligere øvelse. Koden blev passet til, så det ikke var Car der styrede robottens bevægelser, men TachoPilot. RandomDrive klassen blev også rettet til, så den brugte de rigtige metoder.

  1. Steer() i stedet for Turn()
    Et at de store problemer, var turn() metoden i TachoPilot. Denne virkede i programmet til første del af øvelsen, men i dette program var den et problem. Når metoden blev kaldt med det antal grader den skulle dreje rundt om sig selv, begyndte den i stedet bare at køre ligeud. Det var ikke muligt at finde årsagen til at metoden ikke virkede, så i stedet anvendes Steer() metoden fra TachoPilot. Denne virkede efter hensigten.

  2. Avoid Objects
    AvoidFront klassen fra SoundCar projektet anvendes til at få robotten til at undvige objekter. Denne fungerer ligesom i SoundCar, dog med TachoPilot metoder i stedet for Car klassens metoder.


Opgave 3:


  1. På filmen ses robotten kører i en firkant vha. kompas sensoren.


  2. Det første forsøg var helt uden justering af hjul afstand eller diameter. Alligevel blev robotten afprøvet på et vandret whiteboard, med en tush montere på robotten. Robotten var sat til at kører i en firkant, og det var overraskende så præcist det blev.


  3. Præcisionen var ikke betydeligt anderledes med lidt ændrede værdier for hjul diameter og afstand. Dette kan skyldes at robotten selv korrigerer, alt efter graderne kompasset viser, og ikke hvor meget Tacho tælleren viser. Hvis underlaget er glat, som det er på et whiteboard, vil hjulene dreje rundt uden at komme så langt som de burde.

    En af de muligt kilder til afvigelse for kompas navigationen, kan være at den giver for meget fart når den drejer, og derfor bliver skubbet lidt længere væk end den regner med. Det set i hvert fald sådan ud, når den kører.


  4. Det er muligt at strømkabler i kabelbakkerne kunne påvirke kompas sensoren en smule. vi prøvede at flytte whiteboardet lidt rundt i lokalet, men det var ikke muligt at afgøre. I hvertfald er det ikke meget den bliver påvirket.
    Vi prøvede også at påvirke sensoren vha. magneten i en visker til whiteboardet. Det gik selvfølgelig helt galt hvis vi påvirkede sensoren under calibreringen. På billedet herunder ses hvordan det gik da vi prøvede at lade den kører calibreringen uforstyret og så påvirkede den under kørslen. Vi har ikke lavet nogle målinger på hvilken afstand der skal til for at den bliver påvirket.

Figur 5




Konklusion

Tachocounteren fungerede fint når bilen skulle køre lige ud, men der var store problemer når den skulle dreje hvilket for en stor del kunne tilskrives underlaget. Den fejl i rotationen som vi så når den skulle køre lige frem og derefter dreje 180 grader blev summeret op når bilen skulle køre i en firkant. Dette var også de resultater Brian Bagnall nåede frem til.


Forskel mellem kompas sensoren og den almindelige sensor, er at kompas sensoren selv kan kompencere, hvis robotten kommer fysisk ud af kurs. Tacho counteren kan kun navigere efter de udregninger den har, fra hvor mange omdrejninger hjulene har taget. Hvis dette af en eller anden grund er forkert (Hjulene glider, noget sidder fast osv.) opdager den det ikke.

Kompas sensoren derimod, måler efter hvilken retning robotten befinder sig i, og er derfor ikke påvirket af robottens fysik på samme måde. Dokumentationen for denne klasse, er meget begrænset og det er derfor svært at finde ud af præcis hvordan det virker. Da konstroktoren også tager parametre for hjulene, må man gå ud fra at afstand er målt via Tacho tællerne, da kompasset kun kender retningen. Heldigvis er Tacho tællerne temmelig gode til at måle afstanden, og unøjagtighederne opstår oftest ved rotation.



Referencer

torsdag den 12. november 2009

Øvelse 8

Dato: 6. november 2009
Øvelsens varighed: 3 timer
Gruppemedlemmer: Annette, Samuel og Rasmus

Mål
Sidste øvelse handlede om Braitenbergs vehicles der kunne køre mod en kilde eller væk fra en kilde (lys, lyd). De havde alle kun én behavior. Denne øvelse handler om at en agent kan have flere synlige opførsler og hvilken opførsel der skal vælges på hvilket tidspunkt.

Baggrundsinfo
Subsumption architecture is a reactive robot architecture heavily associated with behavior-based robotics. The term was introduced by Rodney Brooks and colleagues in 1986.
A subsumption architecture is a way of decomposing complicated intelligent behaviour into many "simple" behaviour modules, which are in turn organized into layers. Each layer implements a particular goal of the agent, and higher layers are increasingly abstract. Each layer's goal subsumes that of the underlying layers, e.g. the decision to move forward by the eat-food layer takes into account the decision of the lowest obstacle-avoidance layer. As opposed to more traditional AI approaches subsumption architecture uses a bottom-up design.
For example, a robot's lowest layer could be "avoid an object", on top of it would be the layer "wander around", which in turn lies under "explore the world". Each of these horizontal layers access all of the sensor data and generate actions for the actuators — the main caveat is that separate tasks can suppress (or overrule) inputs or inhibit outputs. This way, the lowest layers can work like fast-adapting mechanisms (e.g. reflexes), while the higher layers work to achieve the overall goal. Feedback is given mainly through the environment.
The basic principles of implementing a subsumption architecture are:
1. Divide your problem into basic competencies ordered simple to more complex. Designate a level for each basic competency.
2. Further subdivide each level into multiple simple components which interact through shared variables. Limit the sharing of variables among levels to avoid incomprehensible code.
3. Implement each module as a separate light-weight thread. You might think of setting the priorities for these threads so that modules in a given level have the same priority.
4. Implement suppression and inhibition as one or more separate "arbitration" processes that serve to control access to shared variables. You might want to control access using semaphores.

Fremgangsmåde
1. Robotten
Der bygges en ultralydssensor på robotten.

2. SoundCar program
SoundCar.java programmet bruges sammen med klasserne AvoidFront.java, Behavior.java, Car.java, PlaySounds.java og RandomDrive.java. Projektet downloades til robotten og opførslen observeres.

3. Concurrent tråde
De tre forskellige opførsler; drive, avoid og play er implementeret som tre forskellige tråde. Koden til de tre opførsler undersøges og sammenlignes med hvad vi har observeret i det foregående.

4. Behavior suppression



Figur 1 - Kilde http://people.csail.mit.edu/brooks/papers/AIM-864.pdf

Hver af klasserne til de tre opførsler bygger på suppression, se Figur 1. De højere niveauer undertrykker de lavere niveauer. En lignende figur laves for vores program ud fra hvad vi har observeret og samtidig beskrives koden. Hele projektet kan ses i http://www.daimi.au.dk/~u071252/DL/Practice8/SoundCar.rar.

5. Drive towards light
I sidste øvelse skrev vi til sidst FollowLight projektet om til et flertrådet program. Til denne del af øvelsen bruges FollowLight klassen, så robotten får en ekstra opførsel, det vil sige et ekstra niveau. Udover instanser af de tre andre opførsler oprettes nu en instans af FollowLight og den bliver gjort aktiv som niveau 2, se Figur 2. Det nuværende projekt ændres ved at føje FollowLight klassen til projektet og lave nogle enkelte tilpasninger fx er det ikke direkte Car klassens forward og backward metoder der skal bruges, men Behavior klassens.


Figur 2

Forventningen til robottens kørsel er, at vi ikke vil se den tilfældige kørsel på må og få som vi hidtil har set, men i stedet en målrettet kørsel efter lys. Avoid og PlaySound er stadigvæk de højeste niveauer, så hvis den er ved at køre ind i noget vil den undgå det i stedet for at blive ved med at køre mod lyset og PlaySound vil stadigvæk sørge for at den stopper op hver tiende sekund og spiller et lille nummer. Hele projektet kan ses i http://www.daimi.au.dk/~u071252/DL/Practice8/SoundCarMedLys.rar.



Resultater
1. Robotten
Med ultralydssensoren ser robotten ud som vist i Figur 3.




Figur 3

2. Robottens opførsel
Robotten kører tilfældigt rundt. Den kører og holder stille – kører og holder stille i intervaller af ca. 3 sekunder. Strækningerne den kører er forskellige.
Ca. hvert tiende sekund spiller den en lyd. Længden af lyden der bliver spillet er forskellig.
Hvis der er en forhindring foran ultralydssensoren bakker den en smule og drejer lidt så den måske kommer fri af forhindringen.

Displayvisninger




Den første kolonne angiver hvilke opførsler der er undertrykt når en given opførsel udføres. Ved drive er ingen af opførslerne undertrykt. Når bilen er ved at undgå en forhindring er opførslen drive undertrykt. Når den spiller er både drive og avoid undertrykte.
Den anden kolonne angiver afstanden som ultralydssensoren måler så længe avoid ikke er undertrykt.
Den sidste kolonne angiver hvilken vej motorerne kører. Når bilen skal køre tilfældigt rundt skifter den mellem at køre frem og stoppe og det vises på displayet med f og s ved drive. Når bilen skal avoide er drive undertrykt og der vises s (stop) ud for drive. Ved avoid kører den først tilbage (b) og derefter drejer den lidt ved at køre tilbage på venstre hjul (b) og fremad på højre hjul (f). Når den spiller er både drive og avoid undertrykte og bilen holder stille så der står s ud for drive og avoid.

3. Concurrent tråde
RandomDrive
Random drive opførslen er styret vha. tid. Når robotten får besked om at den skal køre fremad gør den det i et tidsinterval der er givet med et kald til Math.random() der bruges til delay. Power til motorerne er også tilfældigt givet med random(). Delayet mellem fremadkørsel og stop er også tilfældigt med random(). Stop udføres også i et tidsinterval givet ved et tilfældigt delay. Vi havde observeret denne opførsel som mere kontrolleret, med kørslen fremad og tilbage i de samme intervaller hver gang, men det har været tilfældigt at random() funktionen har returneret værdier der har ligget så tæt på hinanden at vi ikke har kunnet skelne.

Avoid
Avoid aktiveres når en forhindring er mindre end tyve centimeter fra robotten, det er altså styret af en ekstern påvirkning. Reaktionen på dette er at robotten bakker i 1 sekund og efterfølgende drejer til venstre ved at sætte power på højre motor. Det var også denne opførsel vi observerede under testen.

PlaySounds
PlaySounds sker i et fast interval af ti sekunder. Hvorimod intervallet lyden bliver spillet i varierer ved kald til random() metoden, der bruges i delay().

4. Behavior suppression
Vores observationer af robotten under de tidligere tests gør det muligt at lave en figur der viser specifikt hvad de forskellige niveauer er i robotten. Drive er nederst og undertrykkes hvis det er nødvendigt at lave en avoid manøvre og playsound er øverst og undertrykker både avoid og drive opførslerne.


Figur 4

KodenI SoundCar klassen oprettes én instans af klasserne RandomDrive, AvoidFront og PlaySounds, som alle nedarver fra klassen Behavior. Ved oprettelsen sendes en instans af den klasse, der ligger ét niveau under og som derfor skal undertrykkes, med som argument.

rd = new RandomDrive("Drive",1, null);
af = new AvoidFront ("Avoid",2,rd);
ps = new PlaySounds ("Play ",3,af);

Bemærk at instansen, rd, får en null-pointer med som argument. Det skyldes at RandomDrive klassen i dette tilfælde repræsenterer det nederste niveau i suppress-mekanismen. Når en instans af de forskellige opførsler, som klasserne repræsenterer, skal undertrykke de underliggende instanser, sker det igennem et kald til metoden suppress.

public synchronized void suppress() {
if ( subsumedBehavior != null ) {
subsumedBehavior.suppressCountIncrement();
subsumedBehavior.suppress();
}
}

Suppress metoden kalder suppressCountIncrement() metoden for den instans af behavior-klassen som ligger ét niveau under. Samtidig kaldes dens suppress-metode som undertrykker dens underlæggende instans, og sådan fortsættes indtil vi når bunden af niveauet. I vores tilfælde ligger rd (RandomDrive) nederst i hirakiet, og derfor er dens instans af subsumedBehavior sat lig med null. Derfor blokerer den ikke nogle underlæggende instanser pga. if-sætningen.

Behavior-klassen implementerer også sine egne forward og backward metoder som kalder forward og backward metoderne fra Car-klassen. Behavior-klassens implementering sørger for at Car-klassens metoder kun kan kaldes hvis den kaldende instans ikke er undertrykt.

5. Drive towards light
Testen foregår i et mørkt rum med døren stående åben, men robotten søger i første omgang ikke mod lyset men mod mørket. Det gjorde dog at vi fik testet avoid opførslen, fordi den så var ved at køre ind i en væg, og avoid bryder fint ind og undertrykker FollowLight, så den ikke kolliderer med væggen.

At den kørte mod mørke i stedet for lys skyldes at venstre sensor styrede venstre motor og højre sensor højre motor og det er forkert når den skal køre mod lyset. Da det var ændret kørte den mod døråbningen og blev undervejs afbrudt hver tiende sekund af en gang musik.
Vi observerede at der var et problem hvis den kom for tæt på en grå kopimaskine i rummet fordi den fra den afstand er lysere. Ved at der kom dagslys ind gennem døren kan man sige at der var en aktiv lyskilde og det var den vi gerne vi finde og derfor er det ikke ønskeligt at den finder den lyseste overflade. Det lys sensoren registrerer, er lysrefleksionen fra kopimaskinen.

Konklusion
Øvelsen har gjort teorien fra sidste undervisningstime mere konkret. Vi har nu selv prøvet at stille en model op for robottens opførsler og tilføje en opførsel og implementere den. Først var det et eksisterende program der blev afprøvet på robotten og vi kunne nogenlunde skelne dens opførsel og bestemme hvad der aktiverede de forskellige opførsler. Til sidst tilføjede vi en ny opførsel ved at bestemme hvor i arkitekturen den skulle ligge og bagefter implementere den i testprogrammet. Dette lykkedes også som forventet.

Referencer
1. Kilder til Baggrundsinfo:
Robot Architectures by Thomas Dean.
http://www.cs.brown.edu/people/tld/courses/cs148/02/architectures.html

Wikipedia Subsumption architecturehttp://en.wikipedia.org/wiki/Subsumption_architecture

2. Kilde til arkitektur: http://people.csail.mit.edu/brooks/papers/AIM-864.pdf.

3. SoundCar projektet af Ole Caprani: http://www.daimi.au.dk/~u071252/DL/Practice8/SoundCar.rar.

4. SoundCarMedLys projektet SoundCarprojektet videreudviklet af gruppen: http://www.daimi.au.dk/~u071252/DL/Practice8/SoundCarMedLys.rar.

torsdag den 5. november 2009

Øvelse 7

Dato: 30. oktober 2009
Øvelsens varighed: 3 timer
Gruppemedlemmer: Annette, Samuel og Rasmus


Mål
Målet for denne øvelse er at bruge NXT til at bygge og programmere tre Braitenberg køretøjer og derved få en bedre forståelse af hvordan de virker.

Baggrundsinfo
Valentino Braitenberg's Vehicles
Braitenberg's vehicles consist of the simplest sort of wheeled robots in which sensors that are sensitive to different stimuli are wired directly to motors that drive the wheels. In these models, we assume that the sensor generates a signal that is proportional to the stimulus. In the simplest vehicle (see Vehicle 1 below) we imagine a sensor sensitive to light and assume that the more light that falls on face the sensor the faster the motor turns. The wire running from the sensor to the motor is labeled positive (+) indicating that sensor stimulates the motor to turn. Things become more interesting when we have multiple sensors and multiple motors.

(Fra: http://www.cs.brown.edu/people/tld/courses/cs148/02/introduction.html )


Fremgangsmåde
1. Vehicle 1
Det første køretøj som ses i Figur 1 er udstyret med en sensor og en motor. Jo større værdi der detekteres af sensoren desto hurtigere kører motoren.


Figur 1 - Braitenbergs vehicle 1

Dette princip bruges til at afprøve vores egen udgave af Braitenbergs vehicle 1. Den kan ses i Figur 2. I stedet for en lyssensor har den en lydsensor, så den vil køre hurtigere jo højere lyden er, i den retning lyden kommer fra. Da det vil være vanskeligt for bilen at undgå at vælte har den to hjul styret af to motorer, men hver motor får tilført samme power beregnet ud fra sensorværdien.


Figur 2 - Vores vehicle 1

Reguleringen af hastigheden er proportional med styrken som lydsensoren opfanger. Den læste værdi for lyden konverteres til en værdi for power til begge motorer og bilen kører lige fremad. Konverteringen foregår vha. en constant som ses beregnet i Figur 3. De indkommende sensorværdier ligger mellem 0 og 100 og det skal passes ind i intervallet mellem maksimum power og minimum power som ligger mellem 60 og 100. 60 er valgt så de bilen kører fremad ved lav hastighed selvom der ikke laves høje lyde. Desuden ganges med 100 for at forblive i integers.


Figur 3 - Beregning af constant


Convert() metoden som ses i Figur 4 har lydværdien som parameter og her bruges constant værdien beskrevet ovenfor til at konvertere lydværdien. For at kompensere for faktoren i constant divideres med 100. Derudover sørger if sætningerne for at vi holder os imellem de 0 og 100 i motorkraft i tilælde af at lyden bliver så den overskrider eller kommer under grænserne for hvad der kan sendes ud på motorerne.



Figur 4 - convert() metoden


Til sidst er tilbage at bruge værdien konverteret fra en værdi for lyden til en værdi for motor power og sende den til motorerne. Car klassen fra de tidligere øvelser bruges igen som den er. Som det ses bruger vi metoden backward og det skyldes at motorene sidder omvendt af hvad de gør, på den robot Car klassen er lavet til.


Figur 5 - Bilen styres vha. den målte lydstyrke

Test
Testen udføres ved at sætte bilen på gulvet. Når programmet startes vil den begynde at køre langsomt fremad. Forventningen er at den vil speede kraftigt op når vi klapper eller råber. Hele koden til vehicle 1 projektet kan findes her: http://www.daimi.au.dk/~u071252/DL/Practice7/SoundSpeedCar.java

2. Vehicle 2a
Vehicle 2a har som det ses på Figur 6 to sensorer. Størrelsen af den målte værdi fra den venstre sensor bruges til at beregne hvor meget power der skal til venstre motor og størrelsen af den målte værdi fra den højre sensor bruges til at beregne hvor meget power der skal til højre motor.

Figur 6 - Braitenbergs vehicle 2a

Vores udgave af dette køretøj følger dette princip, men da der kun er en lydsensor til rådighed bruges her lyssensorer. Bilen er vist i Figur 7 og den har venstre lydsensor der peger ca. 45 grader mod venstre og den højre lydsensor der peger ca. 45 grader mod højre.


Figur 7 - Vores vehicle 2a

I koden til vehicle 2a er der en konstant som bruges i convert() metoden. Denne metode er fuldstændig ligesom ved vehicle 1 og konstanten er beregnet på samme måde. Forskellen ligger i while loopen der udføres indtil escape knappen aktiveres. Den ser ud som vist i Figur 8 for vehicle 2a.

Figur 8 - Regulering af power til de to motorer

Værdierne fra de to sensorer aflæses og konverteres til en værdi til motorerne. Jo større lysstyrke desto større værdi til motorerne. Hvis der sendes størst power til venstre motor fordi lyset har størst intensitet her vil det resultere i at bilen drejer mod højre, det vil sige væk fra lyskilden. Den samlede kode til vehicle 2a projektet findes her: http://www.daimi.au.dk/~u071252/DL/Practice7/Vehicle2.java

Test
Testen består i at stille bilen på gulvet og påvirke den med lys fra en af siderne og forventningen er at bilen kører den modsatte vej.

3. Vehicle 2b

Vehicle 2b har ligesom vehicle 2a to sensorer og varierer også power til motoren ud fra værdierne fra sensorerne, men her går venstre sensor til højre motor og højre sensor til venstre motor. Ændringen fra vehicle 2a foregår udelukkende i koden så der henvises igen til Figur 7.


Figur 9 - Braitenbergs vehicle 2b


Den eneste forskel i koden kan ses i Figur 10, hvor power til venstre motor før blev beregnet ud fra sensor 1’s værdi beregnes den nu ud fra sensor 2’s værdi. Den samlede kode til vehicle 2b kan findes her: http://www.daimi.au.dk/~u071252/DL/Practice7/Vehicle3.java



Figur 10 - Kode til vehicle 2b

Test
Nu vil en stor sensorværdi fra venstre sensor resultere i mere power til højre motor og at bilen derfor drejer mod venstre. Forventningen til testen er derfor at vehicle 3 nu vil køre mod døråbningen, når den startes i et mørkt rum.

4. Flere tråde

På nuværende tidspunkt sker al udførsel i programmet fra main tråden. Venstre sensor aflæses og der beregnes en værdi til motoren og højre sensor aflæses og der beregnes en værdi til motoren, efterfølgende outputtes værdierne til de to motorer. Det kunne være interessant at se om det har nogen indflydelse hvis aflæsning af sensorværdierne og den efterfølgende beregning og styring af den tilhørende motor deles op i tråde. Det vil sige de nævnte aktiviteter skal foregå i en klasse der arver fra Thread() og der oprettes en tråd til hver sensor.

Nu vil thread scheduleren sørge for at tildele hver tråd udførselstid og spørgsmålet er om disse skift vil få indflydelse på hvordan bilen opfører sig. Forventningen er at det ikke vil have nogen betydning fordi skiftene sker så hurtigt og vores lyskilde er permanent. Derimod kunne der muligvis blive problemer i tilfælde af at der sker et lysglimt som er så kort at det sker lige i den timeslice hvor tråden til den anden sensor der vender væk er aktiv og så vil den reagere på lysglimtet i stedet for. Her er det dog nok ikke trådenes time slicing der er det største problem, men måske i lige så høj grad det interval som sensorerne kan opdatere deres værdier i.

Test
Programmet til vehicle 2b skrives om så det der lå i while loopen nu sker i en ’SensorThread’. Der oprettes en left SensorThread og en right SensorThread. Hvor Car.java klassen tidligere har kunnet bruges direkte har det været nødvendigt at lave en separat metode til at styre venstre motor og en til at styre højre motor, da kontrollen sker i forskellige time slices. Forventningen er stadigvæk at bilen vil køre mod døråbningen i et mørkt rum. Koden til dette projekt kan ses i http://www.daimi.au.dk/~u071252/DL/Practice7/V3/SensorThread.java http://www.daimi.au.dk/~u071252/DL/Practice7/V3/Vehicle3.java.

Resultater
1. Vehicle 1
Testen er udført som beskrevet ovenfor og som forventet speeder bilen kraftigt op når der laves høje lyde som klap eller tramp i gulvet. Dette kan ses her: http://www.youtube.com/watch?v=3Ro79z-tLsY

2. Vehicle 2a
Testen er udført i et mørkt lokale uden vinduer med døren stående åben og ganske som forventet kører bilen væk fra døren og altså væk fra lyskilden.

3. Vehicle 2b
Testen er igen udført i et mørkt lokale uden vinduer med døren stående åben. Som forventet kører bilen mod døråbningen og altså imod lyskilden. Dette kan ses her: http://www.youtube.com/watch?v=rk6ttAPf7DI

4. Flere tråde
Som ventet kørte bilen uden problemer mod døråbningen i det mørke rum så det har ikke ændret noget at lave det flertrådet.

Konklusion
Der blev lavet tre biler med egenskaber som Braitenbergs Vehicles 1, 2a og 2b. Vehicle 1 speedede op når den detekterede høje lyde proportionalt med værdien for lyden. 2a kørte i den modsatte retning af lys og 2b kørte i retningen af lys.
Derudover blev det undersøgt om det har nogen indvirkning på bilens opførsel når udførsel af programmet ikke sker i main tråden, men der laves en tråd til hver sensor som også sørger for at sætte en værdi for power til motoren. Der er ikke nogen synlig forskel på opførslen og det var heller ikke forventet.

Referencer
1. Opgaveoplægget: http://www.legolab.cs.au.dk/DigitalControl.dir/NXT/Lesson7.dir/Lesson.html
2. Braitenberg Vehicles intro: http://www.cs.brown.edu/people/tld/courses/cs148/02/introduction.html
3. Vehicle1 kode: http://www.daimi.au.dk/~u071252/DL/Practice7/SoundSpeedCar.java
4. Vehicle2 kode: http://www.daimi.au.dk/~u071252/DL/Practice7/Vehicle2.java
5. Vehicle3 kode: http://www.daimi.au.dk/~u071252/DL/Practice7/Vehicle3.java
6. Vehicle3thread kode: http://www.daimi.au.dk/~u071252/DL/Practice7/V3/SensorThread.java http://www.daimi.au.dk/~u071252/DL/Practice7/V3/Vehicle3.java
7. Vehicle1 film: http://www.youtube.com/watch?v=3Ro79z-tLsY
8. Vehicle2b film: http://www.youtube.com/watch?v=rk6ttAPf7DI

Faste læsere

Bidragydere