Denne blog bruges af Kim Munk Petersen (20063667), Andreas Koefoed-Hansen (20062154) og Tim Rasmussen (20061947) som dagbog i forbindelse med kurset Embedded Systems/Legolab på Århus Universitet.

mandag den 21. december 2009

Projekt - 2

Dato:
11-12-2009

Antal timer brugt:
7 timer

Deltagende personer:
Kim Munk Petersen, Andreas Koefoed-Hansen og Tim Rasmussen

Målet:
  • Få robotten til at balancere vha. vores gyroskop-sensor-klasse. 
Planen:
På baggrund af sidste blogindlæg, hvor vi havde store problemer med at gyroskopets værdier drifter, vil vi forsøge at finde frem til en løsning på dette. Vi ved at problemet blev løst af en gruppe fra tidligere år, så derfor vil vi forsøge at finde inspiration herfra. Når vi har løst drift-problemet, vil vi prøve at få robotten til at balancere vha. vores gyroskop klasse.

Processen:
For at kunne komme videre med projektet, blev vi nødt til at finde en løsning på gyroskopets drift-problem. En af grupperne fra forrige år havde prøvet at  løse problemet ved at løbende ændre offset'et ud fra de målte værdier fra gyroskopet. Offset'et beregnes således som et eksponentielt løbende gennemsnit [1] af det aktuelle offset og målte gyroskop-værdier. Formlen hertil er følgende, hvor alpha bestemmer vægten af de forskellige værdier.
offset = alpha * offset + (1-alpha) * sensorValue
Hvis værdien af alpha er omkring 1, vægtes de tidligere offsets højere end den målte værdi. Hvis den omvendt tæt på 0, vægtes den målte værdi højere end de tidligere offsets. Den målte værdi ændrer sig fra -533 til 391 ifølge vores tests fra tidligere [2]. Det betyder at en meget stor alpha-værdi gør at offset'et ikke ændres for meget, men alligevel at det langsomt flytter sig langsomt svarende til gyroskopets drift. For at dette virker, er antagelsen at der kommer lige meget udsving til begge sider. Denne antagelse burde holde idet at robotten netop skal holde sig oprejst og dermed skal en tiltning til den ene side ophæves af en ligeså stor tiltning til den anden side. Dette virkede udmærket i starten, men efter noget tid resulterede fejl-værdier i at den beregnede vinkel blev ukorrekt. Vi kunne ikke korrigere for denne fejl idet vinklen nogle gange driftede til den ene side og andre gange til den anden side.

På baggrund af ovenstående ledte vi efter en løsning på nettet. Vi fandt frem til en side hvor en kandidatstuderende, Steven Witzand, fra Australien havde bygget en "GELway" som hans speciale[5]. Navnet GELway kommer fra LEGO i omvendt orden uden O'et konkateneret med "way", inspireret af Segway. Koden til robotten er skrevet i leJOS, men er til version 0.80 så derfor var vi nødt til at ændre lidt på koden for at få den til at virke på vores NXT brick der bruger firmware version 0.85. Resultatet af dette var dog ikke særligt godt, da robotten satte begge motorer til at køre med fuld kraft fremad. Vi prøvede at skrive forskellige værdier ud for at se hvad problemet kunne være, men uden held. Først troede vi at det kunne være på grund af at forskellig firmware. Så vi hentede leJOS v. 0.80 og uploadede firmwaren til NXT´en. Dette havde heller ikke nogen indflydelse på opførslen af robotten.

Ved at prøve os frem med forskellige ting fandt vi frem til at gyro-sensoren skulle monteres omvendt, hvilket resulterede i at robotten i de første 3 sekunder prøvede at balancere, men herefter skiftede til at sætte fuld kraft på motorerne.
Vi overvejede hvad grunden til denne opførsel kunne være overvejede at det kunne være forskelle i design af robotten. Vi fandt en byggevejledning[3] til hans robot og så at han brugte 81,6 x 15 mm hjul hvor vi brugte 56 x 26 mm hjul. Vi udskiftede hjulene, men uden resultat. På billedet herunder til venstre er et billede af vores robot som vi byggede ved første projekt-gang. Vi besluttede os for at prøve at bygge vores robot om således at den blev magen til GELway'en. Den resulterende konstruktion ses på billedet herunder til højre.



Da vi testede den nye konstruktion, var den i stand til at balancere langt bedre end før. Det fysiske design af robotten viste sig altså at være meget betydningsfuldt. Vi konverterede igen alt koden i projektet til at passe til leJOS 0.85, men var denne gang mere påpasselige med at gøre det korrekt. Der var en del ting der skulle ændres, blandt andet at der som default ikke bliver givet strøm til en port hvis der ikke bliver oprettet en motor eller et sensor objekt der benytter porten. En anden ting der skulle ændres var at der på motorerne ikke findes en getActualSpeed()-metode i den nye firmware. Vi fandt ud af at metoden getRotationSpeed() virkede som en god erstatning. Efter disse ændringer blev foretaget og koden uploadet til NXT´en viste det sig stadig at virke. Vi tog tid på hvor længe robotten kunne balancere og det var op til 4 minutter før den kom for meget ud af balance og væltede.

Koden der er tilpasset version 0.85 kan ses på Google SVN vi har oprettet i forbindelse med kurset:
http://code.google.com/p/legolab/source/detail?r=19

- Ændring af mål:
På baggrund af det kode vi fandt på nettet og de resultater dette gav, ændrede vi vores mål til følgende. 
  • Forstå principperne i koden fundet på nettet, og på baggrund af dette konstrurere vores egen gyroskopklasse. 
  • Kontrollere at vores egen gyroskopklasse leverer fornuftige tal.
Vi prøvede at teste gyroskopklassen fra GELway for sig selv for at sammenligne resultaterne med den klasse vi selv havde lavet og det viste sig at den vinkel vi hentede ud, når vi gjorde brug af vores egen gyroskopklasse var noget mere nøjagtig end den vinkel vi fik når vi gjorde brug af den anden.
Desværre virker vores gyroskopklasse ikke særligt godt sammen med PID kontrolleren. Selv om værdierne er mere korrekte, så vælter robotten hurtigt.

- Fysiske overvejelser:
Som beskrevet fulgte vi samlevejledningen til GELwayen [3] da vi ombyggede vores robot. Selvom vi ikke fulgte den til punkt og prikke, var der kun tale om mindre forskelle. Bl.a. skulle der ifølge samlevejledningen bruges en EOPD-sensor (Electro Optical Proximity Decetion), men denne har vi ingen intentioner om at bruge, så det gjorde vi ikke. Efter at have samlet robotten, vurderede vi at dens design var utroligt solidt, i modsætning til vores initielle robot, hvilket er en god egenskab, både pga. at det giver robotten mere kontante bevægelser hvilket gør det nemmere at analysere og tune dens PID controller, men også at den kan holde til at vælte uden at falde fra hinanden. Desuden resonerede vi over følgende elementer i konstruktionen: den største forskel på vores initielle konstruktion og den nye er at robotten er blevet noget højere. Dette giver et større inerti-moment hvilket medfører en langsommere vinkelacceleration når robotten vælter. Det giver også en forøgelse af luftmodstanden idet vinkelfarten er højere jo længere væk fra omdrejningspunktet man kommer, men dette har dog ikke den store betydning i denne sammenhæng. Alt i alt har robotten altså længere tid til at korrigere hvilket selvsagt gør det lettere for den at holde balancen. Den nye konstruktion er også langt mere solid end den gamle. Den primære grund hertil, er de mange klodser der er brugt til at afstive den. Klart nok medfører det en øget vægt, men i forhold til NXT-brick'en og motorerne er dette negligibelt. Gyro'ens placering er for så vidt ubetydelig så længe den blot vender rigtigt. Dette skyldes at dens output ikke påvirkes af bevægelse, hvilket kunne mindskes ved at placere den tæt på robottens tyngdepunkt, men udelukkende af robottens hældning. Robottens hjul er placeret på ydersiden af robotten. Vi kunne også have placeret dem på indersiden, men det vil gøre robotten mere sidevejrs ustabil og besværliggøre eller umuliggøre placering af lyssensorer som vi måske får brug for til implementering af line-following. De store LEGO-hjul vi bruger gør at robotten kan bevæge sig hurtigt og dermed også korrigere for fejl hurtigere end med mindre hjul. Idet motorerne har intern gearing med en udveksling der giver meget trækkraft, er de på trods af de store hjul i stand til at give robotten en god accelerationsevne. Ultralydssensoren, som vi får brug for til implementering af en opførsel der får robotten til at undvige objekter foran den, er placeret over NXT-brick'en. Den er nødt til at være placeret højt eller pege opad for at undgå at pege ned i jorden når robotten læner sig forover eller kører op af en skråning. Idet vi regner med at placere lyssensorer under NXT-brick'en, er der ikke også plads til ultralydssensoren, og det er derfor plausibelt at placere den oven på robotten. NXT-brick'en er klart den dyreste komponent på robotten og den er derfor beskyttet af klodser både for og bag således at det ikke er den der rammes når robotten vælter. Ligeledes er gyro-sensoren beskyttet af en klods der absorberer noget af slaget når robotten vælter bagud.

Konklusion:
Vi fik endelig noget til at virke ved at benytte noget kode fundet op nettet fik vi en robot der kan balancere i et godt stykke tid. Planen er i første omgang at benytte Stevens kode og forstå hvordan den virker, og senere bygge vores egne udvidelser på. Senere kan vi lave vores egen gyroskopklasse og BalanceControl der virker sammen med de nye moduler.

Den første Legway vi byggede, var ud fra den samme samlevejledning som vi anvendte under den 4. øvelsesgang. Det viste sig at denne robot vi utrolig ustabil og vi byggede derfor en ny og mere solid en. Selv om samlevejledningen beskrev hvordan gyroskop- og ultralydsensoren kunne placeres på robotten, overvejede vi nøje hvor de var placeret mest optimalt. Efter nøje overvejelser besluttede vi at følge anvisningen til hvordan sensorerne kunne placeres. Samlevejledningen beskrev ikke noget om hvordan lyssensorerne til en senere line-following behavior kunne placeret. Det vigtige her, er at sensorerne skal sidde forholdsvis tæt på jorden for at kunne registrere lysændringer. Vi vender tilbage til dette senere hvis vi når at implementere behavioren.

Alt i alt kom vi frem til en solid robot hvor vi mener at de forskellige sensorer og hjul er placeret på den mest optimale måde.

fredag den 11. december 2009

Projekt - 1

Dato:
04-12-2009

Antal timer brugt:
7 timer

Deltagende personer:
Kim Munk Petersen, Andreas Koefoed-Hansen og Tim Rasmussen

Introduktion til projektet:
Ved øvelsesgang 4 [1] forsøgte vi at lave en Legway vha. en lyssensor. Som beskrevet i vores projektbeskrivelse vil vi i dette projekt lave en Legway, men denne gang med et gyroskop i stedet for en lyssensor. Den virkelige Segway® Personal Transporter [2] benytter også et gyroskop, eller rettere sagt 5 hvoraf de 2 er sikkerheds-redundans [3][4]. Idet vores Legway ikke styres ved direkte manipulation af tyngdepunktet som en Segway, har vores robot ikke brug for at detektere "roll". I modsætning til Segway der bruger to gyroskoper til forlæns/baglæns rotation, bruger vi kun et enkelt. Alt i alt kan vi altså nøjes med et enkelt gyroskop. Fordelen ved at bruge et gyroskop i stedet for en lyssensor er at lyssensoren naturligvis afhænger af lysforholdende og farven af underlaget. Derudover vil den hele tiden prøve at holde afstanden til overfladen konstant, hvilket vil resultere i at den vælter når den kommer til en skrå overflade som illustreret på figuren herunder.


Der er to typer af gyroskoper: det mekaniske og det optiske [5]. Gyroskopet vi bruger til Legway'en er et optisk gyroskop fra HiTechnic. Udover at der er stor forskel i konstruktionen er der også forskel på den værdi de returnerer. Hvor et mekanisk gyroskop er i stand til at returnere dets rotation ift. alle tre akser, er det optiske kun i stand til at returnere en ændring i rotation, dvs. vinkelfart, omkring én akse. Ved at lave numerisk integration over vinkelfarten fås vinklen i forhold til omverdenen ud fra et bestemt nul-punkt. Det er vores plan at vi bruger en bestemt vinkel som goal-værdi [6] og så vinkelfarten til at afgøre hvor hurtigt robotten skal flytte sig for at kompensere for afvigelsen fra goal-værdien.

Målet:
Målet for denne projekt-gang er først og fremmest at få bygget en robot og få fundet en fornuftig placering til gyroskopet. Vores initielle robot laves ud fra NXTway building instructions [7]. Ud over at få lavet en robot at arbejde på, er målet også enten at finde en god leJOS klasse til gyroskopet på nettet eller kode en selv. På de klasser vi finder eller koder selv, vil vi lave nogle test for at se hvordan værdierne fra gyroskopet passer med det forventede. Dette kunne f.eks. være at test hvor meget værdierne fra gyroskopet drifter når gyroskopet holdes i ro.

Planen:
Planen stemmer meget overens med det beskrevet i målet. Robotten med en gyroskop-sensor når vi helt sikkert at få bygget, men om vi når at få fundet eller lavet en fornuftig klasse til håndtere gyroskobet er mere uvis.

Processen:
I leJOS er der en klasse til HiTechnic-gyroskopet, men det fremgår fra dokumentationen er den ikke er testet. HiTechnic-gyroskopet returnerer ifølge den medfølgende folder ændring i grader pr. sekund, med et offset på 620. Vi prøvede klassen og satte offset'et til 620, men fandt ud af at alle HiTechnic's gyroskoper er forskellige og at vi målte et offset på ca. 600 på vores. Grunden til at vi ikke kan give det nøjagtige tal er at det bl.a. afhænger af temperaturen. En sådan ændring af offset kaldes "drift" og er et kendt problem ved gyroskoper. Selv et meget lille drift kan få stor betydning når man bruger et optisk gyroskop idet man som beskrevet integrerer over målingerne for at finde vinklen. Herved summeres afvigelsen hvilket betyder at den beregnede vinkel forøges eller formindskes selvom gyroskopet er i ro.

Før vi begyndte at kode på vores egen gyroskop-klasse, søgte vi på nettet for at se hvad andre havde udviklet i lignende projekter. Vi fandt frem til en gruppe [8] der havde dette kursus for et år siden og læste at de også havde problemer med at gyrosensoren ”driftede” og derfor var nødsaget til at bruge en EOPD-sensor (Electro Optical Proximity Detector) for at få robotten til at balancere. Vi fandt mange andre der havde bygget deres robot med kun en gyrosensor og fået den til at balancere og køre rundt, men i de fleste tilfælde var der ikke en særlig god beskrivelse af processen og koden var ikke frigivet. De steder hvor vi fandt noget kode [9] var det oftest C-kode eller skrevet til en anden firmware.

Vi besluttede derfor at vi ville lave vores egen gyroskop-klasse til leJOS. Klassen vi lavede er ret simpel. De to vigtigste metoder er getAngularSpeed() der returnerer den rå værdi aflæst fra gyro-sensoren, fratrukket et offset, og metoden getAngle() der returnerer resultatet af den numeriske integration af vinkelfarten (angular speed). Denne numeriske integration laves vha. en Riemann-sum med en intervalstørrelse på ca. 4 ms, hvilket er den højst mulige sample rate for gyroskopet ifølge den medfølgende folder. For at teste vores klasse og ikke mindst gyroskopet, fastgjorde vi gyroskopet til en motor således at vi nøjagtigt kunne styre rotationen via et test-program. Konstruktionen er vist herunder:

Vi lavede først en test af gyroskopets stabilitet, dvs. de rå værdier vi fik når det var i fuldstændig ro. Herunder er et plot der viser at gyroskopet står og svinger mellem værdien 600 og 601. Testen er foretaget over 1 sekund hvor der blev opsamlet 121 samples. Gyroskopets output er som grafen viser altså ikke helt stabilt.



Som nævnt er gyroskop-drift et kendt problem. Herunder er et plot der viser hvor meget gyroskopet drifter i løbet af 2 timer (120 minutter).

Det ses at gyroskopet drifter meget i starten. Efter ca. en halv time er det stabilt på 598-599. Udover at målingerne drifter, ses det også at det er ustabilt pga. de sporadiske udsving på trods af at gyroskopet lå helt stille under testen.

Vi lavede en test af den maksimale værdi gyroskopet kan returnere, dvs. den maksimalt målelige vinkelfart. Ifølge folderen der fulgte med gyroskopet er den 360 grader pr. sekund, men vores målinger viser at vi rent faktisk kan måle større værdier end dette. Målingerne er lavet ved hurtigt at rotere gyroskopet den ene vej og derefter tilbage igen. Til den ene side kan vi måle 391 og til den anden side 533, hvilket fremgår af nedenstående diagram:

At der er så stor forskel på de to yderpunkter kan få betydning hvis robotten er ved at vælte og forsøger at rette sig selv op igen. Idet målingerne muligvis bliver meget større til den ene side end til den anden, bliver den beregnede vinkel forkert. Vi vil derfor muligvis indsætte en begrænsning på 391 grader/sekund til hver side i vores program i håb om at udligne forskellen, hvis dette viser sig at blive et problem.

Ifølge gyroskopets specifikationer returnerer det som beskrevet tidligere en værdi der angiver vinkelfarten målt i grader/sekund. For at teste om dette passer, brugte vi tacho-counteren i motoren til at give den reelle rotation. Målingerne er vist herunder:



Ved at sætte motoren til at rotere med 391 grader pr. sekund, altså den maksimalt målelige vinkelfart fås ovenstående graf. Det ses at gyroskopet tilnærmelsesvis måler den rigtige rotation. Tacho counteren er dog ret upræcis hvilket kan ses ved at dens graf er meget "kantet".

På nedenstående graf ses vinkelfarten returneret fra gyroskopet samt den beregnede vinkel fra vores gyroskop-klasse. Målingen blev lavet ved at starte robotten i lodret position og derefter læne den til den ene side og derefter til den anden. Som det ses er der en lille afvigelse i vinklen hvilket vi tilskriver gyroskopets drift.




Konklusion
:
Efter at have arbejdet med gyroskopsensoren en uges tid, er vores indtryk af den ikke særligt godt. Vi har været igennem en lang og til tider meget frustrerende proces med at få håndteret gyroskopets drifting problem. Vi har forsøgt flere metoder for at få gjort tallene stabile, men lige lidt hjalp det. Vi var derfor på et tidspunkt overbevist om at der nok var en fejl i gyroskopet, men efter at have snakket med den anden gruppe der også laver en Legway, ændrede vi denne overbevisning. De sad også fast i det samme problem som vi, så med mindre at begge gyroskoper er defekte er dette ikke problemet. Lige nu er vi meget usikre på hvordan vi skal løse dette problem med gyroskopet, da vi føler at vi har prøvet alt.

Vi har været ude at undersøge andre muligheder for hvordan man kan få en robot til at balancere og i den forbindelse er vi kommet frem til at der eksisterer en tilt sensor. Det kunne være interessant at se hvile data denne sensor sender retur. Eftersom der ikke er andre der anvender denne sensor i forbindelse med en selvbalancerende robot, har vi vores betænkeligheder ved den. Vores bekymring ved tilt sensoren går på at den måske ikke kan opdatere hurtigt nok til at dens data kan bruges i forbindelse med en robot af denne type. I hvert fald må det være muligt at få en robot til at balancere vha. et gyroskop idet vi på Internettet har fundet flere videoer der viser  legway-lignende robotter gøre dette [10]. Af den grund giver vi ikke op med gyroskop-sensoren og arbejdet fortsætter derfor i morgen.

Referencer:
  1. NXT Programming, Lesson 4, http://www.legolab.daimi.au.dk/DigitalControl.dir/NXT/Lesson4.dir/Lesson.html
  2. Segway® Personal Transporter, http://www.segway.dk/personal-transporter/
  3. Segway® Personal Transporter, how it works, http://www.segway.dk/personal-transporter/how_it_works.php
  4. How Segways work, http://www.howstuffworks.com/ginger.htm
  5. Wikipedia: Gyroscope, http://en.wikipedia.org/wiki/Gyroscope
  6. "Goal" value. Chapter 5, pp. 175+179 of Fred G. MartinRobotic Explorations: A Hands-on Introduction to Engineering, Prentice Hall, 2001. 
  7. NXTway building instruction, http://www.philohome.com/nxtway/bi_nxtway.htm
  8. Legolab2008 (SecretMan), http://lego.secretman.dk/wiki/Forside
  9. NXTway gs, http://lejos-osek.sourceforge.net/nxtway_gs.htm
  10. Balancing robot, http://www.youtube.com/watch?v=hpCwdu0e3i0

torsdag den 3. december 2009

Valg af projekt

Dato:
27-11-2009

Antal timer brugt:
5 timer

Deltagende personer:
Kim Munk Petersen, Andreas Koefoed-Hansen og Tim Rasmussen

Denne uges opgave:
Denne uges opgave går ud på at bestemme hvilket projekt der ønskes at arbejde med. Vi skal overveje alle projekter fra listen og dertil gerne tilføje nye selv. Der skal udvælges 3 projekter, hvor det ene er projektet med højeste prioritet og de sidste to er alternative projekter. Til hvert projekt skal der laves et beskrivelse, overvejelser omkring software og hardware, beskrivelse af problemer der skal løses og hvad vi forventer at præsentere når projektforløbet er slut. Efter denne korte beskrivelse, skal der laves en mere detaljeret beskrivelse af det projekt vi har valgt at arbejde med samt en plan for projektets forløb.

Overvejelser omkring projekterne:
Vi har snakket de 6 projekter igennem og har på baggrund af dette udvalgt 2 af projekterne vi kunne have lyst til at arbejde videre med. Ud over de 2 projekter, er vi også selv kommet frem til et projekt der kunne være spændende at arbejde med. De udvalgte projekter, i prioriteret rækkefølge, er:
  1. LegWay
  2. Farve-scanner (der bygger billedet i lego)
  3. Pacman
Vi vil kun koncentrere os om disse projekter fra nu af.

Legway:
Dette projekt går ud på at bygge en Legway robot der kan balancere ved at benytte en gyroskop-sensor fremfor en lyssensor som ved øvelse 4. Ifølge vores overbevisning lykkedes det ikke for nogen gruppe at få den SegWay-lignende robot til at balancere ved øvelse 4. Idet vi af den grund ikke har nogen anelse om hvor lang tid det tager os at få robotten til at balancere, tillader vi os at definere projektet en smule løst. Hermed menes at vi i første omgang koncenterer os om at få robotten til at balancere hvorefter vi implementerer en række features hvis der er tid tilovers.

1x NXT

Sensors:
1x Gyroskop
1x Ultralydssensor
1x Lyssensor
1x Kompassensor

Actuators:
2x Motorer

Achitecture:
I første omgang vil vi benytte en simpel klasse, der implementerer en PID kontroller[1] som sender input til motorerne ved at fortolke inputtet fra gyroskopsensoren. For at udvide funktionaliteten til at kunne køre frem og tilbage vil vi bruge en car klasse der som default sørger for at robotten hele tiden balancerer. Klassen skal også have metoder til at få robotten til at bevæge sig. Senere hen kan der anvendes en behavior-baseret achitecture[2], hvor opførsler fx får robotten til at følge en linje på gulvet, gør det muligt at styre robotten fra en computer eller får den til at undgå forhindringer.

Difficulties:
Det sværeste vil i dette projekt være at implementere en PID kontroller og justere den ved at ændre på parameterne, således at robotten kan balancere. En anden ting der muligvis bliver svært er at få robotten til at dreje samtidigt med at den holder balancen.

Presentation:
Til præsentationen forventer vi at kunne præsentere en kørende robot der balancerer på egen hånd og er i stand til at køre op og ned af ramper samt få små skub uden at vælte. Derudover vil vi demonstrere nogle af de valgfrie features, forklaret længere nede, hvis vi når at implementere disse.

Pacman:
Projektet går ud på at simulerer et pac-man spil med Lego-robotter. Der er en pac-man og tre spøgelser der skal bevæge sig rundt på en fastlagt bane. Målet for pac-man er at "overleve" i et stykke tid, og hvor spøgelserne bliver aktiveret med faste intervaller. For at gøre spillet sværere kan hastigheden af spøgelserne øges efterhånden som spillet skrider frem.

4x NXT

Sensors:
8x Lyssensorer

Actuators:
8x Motorer

Achitecture:
Til pac-man kunne der godt bruges en behavior styret achitecture, hvor en tråd finder ud af om man er i live eller om man er blevet fanget af spøgelserne, og andre tråde der bruges til at holde sig inden for banen og modtage indput via Bluetooth.

Spøgelserne kan bruge noget af den samme ide, hvor der også skal holdes styr på om de er inden for banen og hvor der er en tråd afvikler noget AI der bruges til at forfølge pac-man.

Difficulties:
Det sværeste i dette projekt vil være at progammere en AI der får spøgelserne til at forfølge pac-man og samtidigt holde sig inden for banens grænser.

Presentation:
Ved præsentationen vil vi demonstrere hvordan spillet virker ved at starte et kortvarigt spil. Her vil vi både vise et scenarie hvor man vinder spillet, dvs. ikke bliver fanget af spøgelserne, samt hvad der sker når man bliver fanget og dermed taber. Hvis der er stemning for det, vil vi evt. lade en frivillig teste spillet.

Farve skanner:
Dette går ud på at bytte en scanner der kan aflæse et billede og enten sende informationerne til en pc eller replicerer billedet ved at placere legoklodser på en plade.

Hvis billedet skal kunne repliceres i lego skal der bruges:

2x NXT: En der bruges til at scanne billedet og en der bruges til at bygge replikationen.

Sensors:
1x Lys / Farve sensor

Actuators:
5x Motorer
2x til at scanne, 3x til at bygge.

Achitecture:
Ideen er at fordele ansvaret på de to NXT´er så en sørger for at scanne billedet samt sende informationerne via Bluetooth, og en anden bruges til at finde de korrekte klodser og placere dem. Der er ingen grund til bruge tråde da der ikke er flere behaviors der spiller ind, derfor vil en sekventiel struktur være oplagt.

Difficulties:
Den sværeste del vil være at få lavet den del der bygger billedet i Lego, da der skal kunne placeres forskelligt farvede klodser alt efter hvilke informationer der modtages. Der kunne også være problemer med at få vendt klodserne rigtigt så de kan placeres på pladen.

Presentation:
Vi regner med at kunne demonstrere en scanning og "printning" af et billede. For at det ikke kommer til at tage for lang tid, kunne man starte midtvejs i en scanning og printning. Desuden vil vi forklare hvordan vi har løst de sværeste problemer og evt. præsentere kvantitative målinger udført.

Beskrivelse af valgte projekt:
Vil har valgt at arbejde med projektet LegWay. Grunden til dette, skyldes at vi her føler at vi her bedre kan dele problemet med at få robotten til at balancere og køre op i flere problemer. F.eks. vil det først problem der skal løses blot være at få robotten til at balancere. Herefter kan robotten udvides til at kunne kører og derefter også til at kunne dreje. Samtidig giver projektet os også mulighed for at kommer mere i dybden med PID controlleren, som ikke rigtig lykkes for os under øvelsesgangen.

Vi håber på at kunne udvide funktionaliteten så den kan køre frem og tilbage og muligvis også dreje. Hvis vi får den til at køre rundt kan vi også tilføje ekstra features som fx. følge en linje og/eller undgå forhindringer. Tilføjelsen af ekstra sensorer, kunne give mulighed for at tilføje ekstra opførsler til robotten. Som basis for at få robotten til at balancere, køre og dreje, kunne man forestille sig at man har en opførsel der får robotten til at balancere, en til at få robotten til at køre/dreje. Hvis robotten udvides med ekstra sensorer, vil der også kunne tilføjes en opførsel der sørger for at robotten undgår at køre ind i objekter.

Prioiriteter:
  1. Balacere vha. PID kontroller.
  2. Køre frem og tilbage evt. styret via Bluetooth.
  3. Dreje
  4. Follow the line
  5. Undgå objekter.
  6. Navigation vha. kompas.
Plan for projektforløbet:
Først vil i bygge robotten og udføre eksperimenter på gyroskop-sensoren, hvorefter vi vil arbejde på at udvide funktionaliteten.

Vi tager udgangspunkt i de ovenstående prioriteter. Planen vil være at opdele projektet i faser, hvor vi arbejder på at implementere og dokumentere en feature af gangen og først begynder på den næste fase når arbejdet på den forrige er færdig. Der kan opstå situationer hvor vi er nødt til at opgive at implementere en feature, hvis vi kommet til at sted hvor vi ikke kan komme videre. I denne situation vil vi i stedet vælge at gå videre til en anden fase.

Referencer:
  1. PID controller, http://en.wikipedia.org/wiki/PID_controller
  2. leJOS behavior programming tutorial, http://lejos.sourceforge.net/nxt/nxj/tutorial/Behaviors/BehaviorProgramming.htm

torsdag den 26. november 2009

Øvelsesgang 10

Dato:
19-11-2009

Antal timer brugt:
3 timer

Deltagende personer:
Kim Munk Petersen, Andreas Koefoed-Hansen og Tim Rasmussen

Denne uges opgaver:
Ugens opgave er at eksperimentere med subsumption, ligesom ved øvelse 8, men denne gang bruge leJOS's subsumption framework bestående af interface'et lejos.subsumption.Behavior og klassen lejos.subsumption.Arbitrator. Derudover skal vi overveje hvorledes framework'et kan ændres så de forskellige opførslers prioritet ikke er statistk, men ændres dynamisk, svarende til Thiemo Krinks "motivation functions" [1]. Opgaverne tager udgangspunkt i BumperCar-eksemplet fra leJOS NXJ distributionen.





Fysiske overvejelser
Vi har til denne uges opgaver gjort brug af robotten fra sidste uges opgaver, som var bygget ud fra beskrivelsen i Brian Bagnall's kapitel 12. Ultralydssensoren er placeret som i sidste uge, men foran robotten er der nu placeret en slags kofanger, som registrerer om robotten kører ind i ting. Kofangeren af lavet ud fra idéen om en kofanger på den bil, men med den modifikation at vi har placeret to fjedre på hver side for at koncentrere stødene mere mod sensoren.

Opgave 1: BumperCar

Beskrivelse af BumperCar:
BumperCar indeholder 2 opførsler, DriveForward og DetectWall, der henholdsvis har til mål at få robotten til at køre fremad og undvige objekter. Oprførslen DriveForward tilkendegiver at den altid ønsker at blive udført ved at dens takeControl-metode altid returnerer true. Når den udføres, dvs. dens action-metode kaldes, sætter den begge motorer til at køre fremad og stopper først når den bliver suppresed. DetectWall's takeControl metode returnerer true hvis og kun hvis touch-sensoren er trykket ind eller der er et objekt mindre end 25cm foran robotten. Dens formål er at undgå kollision ved at få robotten til at bakke og dreje.


Initielle tests og observationer:
Vi lagde BumperCar over på NXT'en og startede programmet. Som forventet begynte robotten at undvige når dens touch-sensor blev trykket ind eller der var objekter mindre end 25cm forude, og ellers kørte den ligeud. Vi prøvede at holde touch-sensoren inde hvilket resulterede i at gentog opførslen DetectWall indtil vi slap sensoren hvorefter den atter begyndte at køre fremad efter at have fuldendt den igangværende DetectWall-opførsel. Grunden til at den vælger at udføre DetectWall i stedet for DriveForward er at DetectWall har højere prioritet idet den er indsat på en senere plads i behavior-arrayet der gives til arbitratoren. Idet der kun er en tråd til at udføre opførsler, starter en ny opførsel først efter den igangværende action-metode returnerer.

Arbitrator:
Ved at studere kildekoden for arbitratoren "Arbitrator.java", ses det at den leder efter opførsler der gerne vil udføres, dvs. deres takeControl-metode returnerer true. Idet den gennemløber behavior-arrayet bagfra, kan den stoppe søgningen så snart den har fundet en sådan opførsel da denne nødvendigvis må have højst prioritet. Koden-afsnittet ses herunder:

_highestPriority = NONE;
for (int i = maxPriority; i <= 0; i--) // maxPriority = _behavior.length - 1
{
  if (_behavior[i].takeControl())
  {
    _highestPriority = i;
    break;
  }
}

Betydningen af ovenstående kode er at DriveForward's takeControl-metode ikke kaldes når betingelsen for DetectWall er opfyldt, eftersom den break'er efter DetectWall's takeControl-metode returnerer true. Dette giver god mening i og med at den har højere prioritet.


Exit-opførsel:
Vi implementerede en opførsel "Exit" som har til formål at lukke programmet så snart escape-knappen på NXT-brick'en trykkes ned. For at programmet skal lukkes ned hurtigst muligt efter der er trykket på ESC, giver vi Exit-opførslen højest prioritet. Der er flere måder at implementere denne opførsel på:

Hvis man implementerer dens takeControl-metode således at den returnerer true hvis ESC-knappen er trykket ned vha. isPressed(), skal man holde knappen nede indtil Arbitratoren kommer til Exit-opførelsens takeControl-metode. Gør man ikke det kan man risikere at trykket "går tabt", hvilket også er beskrevet i leJOS' subsumption tutorial [2]. 
En mere robust løsning, som vi derfor valgte, er at oprette en ButtonListener på Escape-knappen der i princippet er en anden tråd der "lytter" efter tastetryk. Så snart dens buttonPressed-metode kaldes, er ESC-knappen blevet trykket ned og vi sætter en boolean hasPressed til true. I takeControl-metoden returneres denne boolean.

Det virkede umiddelbart til at Exit-opførslen blev udført øjeblikkeligt når vi trykkede escape når DriveForward var aktiv. Hvis den igangværende opførsel var DetectWall, lukkede programmet først efter opførslen var afsluttet, dvs. robotten havde bakket og drejet. Ved at forøge Sound.pause(20) til Sound.pause(2000) i DetectWall's takeControl-metode, opstod der en forsinkelse inden Exit-opførslen blev udført, ligegyldigt hvilken opførsel der var aktiv når vi trykkede escape. Forklaringen er at arbitrator'en forsinkes hvilket er uheldigt idet den netop skal være responsiv så robotten hurtigt kan skifte opførsel.

Ved nogle sensorer, bl.a. ultralydssensoren, er det umuligt at sample øjeblikkeligt. I stedet for at lave et delay i takeControl-metoden, kan man sample med en bestemt frekvens og så bruge den sidst målte værdi til at beslutte resultatet af takeControl. Denne løsning implementerede vi ved at oprette en ny tråd der sampler fra ultralydssensoren ca. hvert 20. millisekund. Herved gøres aribitratorens responstid meget kortere.

Ét sekunds bak før der drejes:
En opgave gik ud på at få robotten til at bakke et sekund inden den begyndte at dreje. Det implementerede vi først ved at sætte begge motorer til at køre baglæns, kalde Thread.sleep(1000) og så dreje robotten. det betyder at selv om der er en der forsøger at suppresse den, så skal den gøre sin handling færdig før der skiftes opførsel.

Man kan let forestille sig at man ønsker at robotten skal blive ved med at bakke indtil touch-sensoren ikke længere trykkes ind. Dette medfører at DetectWall-opførslen skal kunne interrupt'es. Vi havde store overvejelser omkring hvordan vi skulle implementere denne feature. Vi startede med at skifte sleep(1000) ud med en while-løkke og kald til System.currentTimeMillis(), således at while-løkken kørte indtil der var gået et sekund eller opførslen var blevet supressed af en med højere prioritet. Herved udføres tryk på escape øjeblikkeligt idet DetectWall-opførslen supresses og afsluttes prompte. Væsentligst er det dog at vi inde i while-løkken løbende kan tage stilling til hvorvidt opførslen skal genstartes.

I while-løkken kan man lave et rekursivt kald til action-metoden selv, hvis DetectWall-betingelsen stadig var opfyldt, dvs. takeControl() returnerer true. En ulempe ved denne løsning er at man let får call-stack overflow hvis betingelsen er opfyldt lang tid af gangen.

En anden løsning er at kalde return i while-løkken hvis betingelsen stadig er opfyldt, og derved interrupt'e opførslen og enten gentage den eller lade en anden komme til. Ulempen ved denne løsning er at opførslen ikke stopper motorerne inden der returneres, hvilket ikke er smart hvis der findes en opførsel med højere prioritet der ikke bruger motorerne (og derfor ikke kalder stop()). Hvis vi kaldte stop() inden return, ville der ske det at backward() og stop() bliver kaldt skiftevis med høj frekvens hvis DetectWall-betingelsen er opfyldt, hvilket nok medfører at robotten ikke bakker som den burde. Dette testede vi dog ikke.

Vores løsning er at opførslen genstarter sig selv så længe betingelsen er opfyldt, men vi har også et yderloop som kører indtil isDone er true. På denne måde sikrer vi at motorerne bliver stoppet selv om betingelsen længe er opfyldt. Koden ses herunder:

boolean isDone = false;
outer:while(!isDone) {
  _suppressed = false;
  Motor.A.backward();
  Motor.C.backward();
  long time = System.currentTimeMillis() + 1000;
  while(!_suppressed && System.currentTimeMillis() < time) {
    if (takeControl())
      continue outer;
  }
  Motor.A.stop();
  time = System.currentTimeMillis() + 800;
  while(!_suppressed && System.currentTimeMillis() < time) {
    if (takeControl())
      continue outer;
  }
  Motor.C.stop();
  isDone = true;
}


Referencer:

torsdag den 19. november 2009

Øvelsesgang 9

Dato:
19-11-2009

Antal timer brugt:
6 timer

Deltagende personer:
Kim Munk Petersen, Andreas Koefoed-Hansen og Tim Rasmussen

Denne uges opgaver:

Denne uges opgave går ud på at se hvordan man kan få robotten til at køre til forskellige positioner, enten via en TachoPilot eller via CompassPilot. Den første opgave gik ud på at observere hvordan man kunne bruge TachoPilot sammen med SimpleNavigator til at finde frem til forskellige koordinater og til slut vende tilbage til udgangspunktet. Robotten er derfor nødt til at vide hvor den er hele tiden. Anden opgave går ud på at få robotten til finde frem til nogle koordinater som i opgave 1, men her skal robotten også kunne undgå evt. forhindringer på vejen. Den sidste opgave går ud på at anvende et kompas til at finde frem til de forskellige koordinater og se om robotten kører mere præcis vha. et kompas frem for ved brugen af en TachoPilot.

Vi har løst opgaverne i følgende rækkefølge:
  1. Navigation
  2. Kompas navigation
  3. Navigation, hvor objekter undgås
Fysiske overvejelser

Robotten anvendt til denne uges opgaver er bygget ud fra beskrivelsen i Brian Bagnall's kapitel 12. Placeringen af kompasset har været til nøje overvejelser, eftersom den skal væres placeret minimum 10 - 15 cm fra NXT'en og motorrene. Vi har derfor først placeret kompasset i et tårn over selve NXT'en, men da dette tårn blev ustabilt, valgte vi at placere kompasset med den nødvendige afstand foran robotten.




Vi har målt følgende afstande:
  • Afstand mellem hjulene er 17.8 cm
  • Diameteren på hjulene er 56 mm
  • Afstand fra kompas til NXT midt = 11.5 cm
  • Afstand fra kompas til motor er 13 cm
Navigation

Vi brugte Brian Bagnalls kode og ændrede argumenterne der blev givet til TachoPilot constructoren til at passe med vores robot. Vi udførte først små tests hvor vi fik robotten til at køre 20 cm og prøvede at justere argumenterne efter dette. Da vi havde justeret disse, udførte vi tests på hele ruten og fik efter 3 forsøg en ret præsis gennemkørsel af ruten.

Vi brugte Lego klodser til at markere den tilbagelagte rute. Ruten blev mere kørt og mere korrekt i takt med at vi ændrede afstanden mellem hjulene. Den målte værdi var 17.8, men vi fik først en rigtig rute da vi ændrede til 18.4. Grunden til dette, kan skyldes at afstanden øges når der kommer belastning på hjulene, men dette giver ikke 6 mm, de sidste mm kan findes i unøjagtigheden i motor hastigheder.

Med en hjul diameter på 56mm kørte robotten meget præcist. Dvs. at når vi bad den om at køre 200mm så kørte den også næsten de 200mm. I vores tilfælde bad vi den køre 200cm, og den kørte godt 197cm. Da vi ændrede hjulstørrelsen til 55mm kørte den godt 199.7cm.

Kørelse 1: ca. 50 fra udgangspunkt (afstand mellem hjul 17.5)
Kørelse 2: ca. 30 fra udgangspunkt (afstand mellem hjul 17.8, her fandt vi ud af at vores måling var forkert)
Kørelse 3: ca. 7 fra udgangspunkt (afstand mellem hjul 18.4, her prøvede vi os frem med afstanden for at få den til at køre tilbage til udgangspunktet)





Navigation while avoiding objects

I forsøg på at løse denne opgave brugte vi to opførsler: en til at styre robotten hen til bestemte koordinater og en til at undvige objekter på robottens vej. Som tidligere i lignende opgaver, har den undvigende opførsel højest prioritet. Vores program bygger på Ole Capranis arkitektur til behavior based systems hvor hver opførsel er en tråd der nedarver fra en klasse Behavior og implementerer sin funktionalitet i run-metoden. Behavior-klassen stiller nogle metoder der styrer robottens motorer til rådighed og sørger for at det kun er ikke-suppressed opførsler der har adgang hertil. Vi tilføjede nogle metoder til Behavior-klassen, bl.a. goTo(x,y), travel(distance) og rotate(angle) der så kalder videre på en underliggende SimpleNavigator der styrer robotten. Alle definerede opførsler deler således en navigator hvilket gør at robotten i teorien bør opdatere sin position og retning, uanset hvilken opførsel der styrer den. Opførslen AvoidFront træder i kraft når robotten er 20cm eller mindre fra et objekt foran den. Den får herefter robotten til at rotere 90 grader og køre 20cm ligeud for at komme uden om objektet. Den anden opførsel WaypointDrive er aktiv når AvoidFront ikke er aktiv. Den har et array af koordinater og holder hele tiden styr på hvilket koordinat-sæt den er på vej hen til. Hver gang opførslen aktiveres kalder den goTo til dette koordinat-sæt, og når den når derhen skifter den til næste koordinat-sæt og fortsætter således indtil den når enden af koordinat-array'et. 


Da vi testede robotten prøvede vi i første omgang at lade den køre banen fra før uden at lade noget komme i vejen for den, og den kørte til alle punkterne som i første opgave. Derefter testede vi robottens AvoidFront opførsel og konstaterede at den blev aktiveret på de rigtige tidspunkter, dvs. når robotten nærmede sig et objekt, og den forsøgte at dreje omkring objektet som den burde. De to opførsler opfyldte derfor hver især deres mål. Når vi kombinerede de to opførsler gik det dog galt. Robotten mistede sin stedfornemmelse så snart AvoidFront-opførslen blev aktiveret. Vi fik den til at udskrive på LCD-skærmen hvor den var på vej hen, og det viste sig at den kørte til det korrekte koordinat-sæt, men at dens retning og position altså var forkert. Det lykkedes os ikke at løse problemet, men antager at problemet skyldes SimpleNavigator, som antageligt også gav problemer i forrige opgave.

Vi har hørt at andre grupper har samme problem, og heller ikke har været i stand til at løse det. I begyndelsen troede vi at problemet skyldtes at det kun var metoden goTo der opdaterede robottens interne koordinatsystem, men efter at have lavet en test med metoderne goTo, travel og rotate i SimpleNavigator, viste denne antagelse sig at være forkert. Robotten er tilsyneladende i stand til at opdatere sin position ligegyldigt hvilken af SimpleNavigators metoder man kalder.

Får vi senere brug for at have flere samtidige opførsler der skal navigere robotten rundt, vil vi løbende skrive robottens koordinater til en fil som vi så kan plotte, evt. så vi kan skelne koordinater skrevet af den ene henholdsvis den anden opførsel. Herved burde vi kunne se hvor og hvornår problemet opstår.

Compas Navigation


Til at løse denne opgave, monteres et kompas et sted på robotten. Første gange vi kørte vores program, kørte robotten rundt som om den havde været på Roskilde festival i en uge uden søvn og alt for store mængder alkohol. For at få den til at køre mere præcist vha. kompasset, valgt vi at kalibrere kompasset. Dette ændrede dog ikke meget på dens måde at køre på. Da vi placerede den på samme udgangspunkt som da vi gjorde brug af TachoPilot, kørte den meget forvildet rundt. For at finde ud af hvad grunden var til denne meget unøjagtige kørsel, lavede vi et simpelt program der blot skulle starte med at rotere robotten mod nord, hvorefter den skulle dreje 90 grader og vente 1 sekund inden den igen skulle dreje 90 grader. Heller ikke dette kunne den finde ud af. I stedet for at dreje samme vej rundt hele tiden, begyndte den pludselig at dreje den anden vej som om den var kommet forbi den ønskede position. Vi forsøgte derfor at teste om de værdier vi kunne hente ud fra CompassSensoren vha. getDegrees() var korrekte. Det viste sig at de var så korrekte som man kunne forvente.

Vi prøvede derfor forskellige ting, der kunne hjælpe os med at få robotten til at opfører sig efter hensigterne. Disse ting var følgende:
  • Ændrer placeringen af kompasset, så i stedet for at være placeret i toppen af et meget ustabilt tårn, blev den nu placeret foran robotten. Dette gjorde at den sad mere fast på robotten og derfor ikke havde de sammen udsving.

  • Ændre hastigheden af mortorerne, så vi var sikre på at grunden til den mærkelige opførelse ikke skyldtes at vi bevægede os forbi den ønskede position. Grunden til denne test, var at vi ikke vidste om SimpleNavigator på nogen måde håndtere fejltolerencer. Men selv ved meget lave motorhastigheder kørte robotten som tidligere.
På trods af de ændringer og målinger vi har lavet, er det ikke lykkes os at få robotten til at køre på en fornuftig måde når der bruges et kompas. Det er dog flere ændringer vi kunne have udført i håb om at disse kunne hjælpe med at få robotten til at opføre sig nogenlunde fornuftigt. Disse ændringer er:
  • Vi kunne undgå at bruge SimpleNavigato og i stedet blot kalde rotate metode direkte på CompassPilot. Dette vil fjerne evt. fejl der kan opstå ved at bruge SimpleNavigator på en CompassPilot.

  • Vi kunne også vælge at læse indputtet direkte fra CompassSensor og ud fra disse værdier selv styre motorerne. Herved vil vi fjerne 2 evt. fejlkilder.
Grunden til at vi kunne forestille os at disse ændringer vil have en god effekt skyldes at det virker som om SimpleNavigator ikke er så glad for at arbejde sammen med CompassPilot. Da vi gjorde brug af en TachoPilot, havde vi ingen problemer, så vi bygger ideen om at SimpleNavigatoren og CompassPiloten ikke arbejder godt sammen på baggrund af dette.

torsdag den 12. november 2009

SoundCar - Øvelsesgang 8

Dato:
06-11-2009

Antal timer brugt:
3 timer

Deltagende personer:
Kim Munk Petersen, Andreas Koefoed-Hansen og Tim Rasmussen

Denne uges opgaver:
Denne uges opgaver går ud på at se hvordan flere forskellige observerbare opførelser kan implementeres på en enkelt NXT. Til denne uges opgave skal der bruges en ultralydssensor. Vi har valgt at udfører opgaverne i den rækkefølge de er præsenteret i opgave beskrivelsen.

Dette betyder at opgaverne er løst i følgende rækkefølge:
  1. Observere robotten og se hvordan robotten opfører sig
  2. Find udløsningsbetingelserne og se hvordan robotten opfører sig med en eller to tråde aktive.
  3. Se på implementeringen af suppresser mekanismen Behavior.java, og sammenlign metoden med Fred Martin metode.
  4. Tilføjelse af "kør mod lyset" tråd.
Fysiske overvejelser
Eftersom vi allerede under sidste øvelsesgang havde monteret en ultralydsensor på toppen af robotten, har der ikke været nogen fysiske overvejelser under denne øvelse.





1. LEGO car that exhibits several behaviors
Programmet har 3 forskellige tråde der arbejder concurrent, men med forskellige prioriteter. Dette betyder at når robotten afspiller en lyd, så tager tråden PlaySound tråden kontrol over motorerne og stopper dem.
Når der ikke afspiller lyd kører robotten vha. RandomDrive tilfældigt rundt indtil den komme for tæt på et objekt. Hvis robotten kommer til en forhindring vil tråden Avoid sørge for at få robotten væk fra ved at overtage motorerne og undvige. Undvigelsesmanøvren fortsætter indtil PlaySound afspiller en lyd og tager rettigheden, eller den er langt nok væk fra objektet igen. Avoid bliver aktiveret hvis afstanden til objektet bliver mindre end 20.
På LCD panelet skriver robotten vha. definitionerne s = stop, f = forward, b = backward hvilken vej robotten kører samt hvor lang afstand der er til et objekt. Ud over disse informationer, skriver robotten også ud for drive, avoid og play hvor mange tråde der der suppresser den givne tråd.

2. Behaviors as concurrent threads
Ved at undlade at starte nogle tråde kunne vi tydeligt se den opførsel de enkelte tråde tilføjede til robotten.

Med kun RandomDrive tråden aktiv, vil robotten køre tilfældigt rundt og eftersom Avoid tråden ikke er aktiv vil robotten fortsætte med dette indtil den rammer ind i noget eller falder ud over kanten på bordet.
Når de to første tråde er aktive (RandomDrive + AvoidFront), vil robotten forsøge at undgå objekter tæt på, men stadig køre tilfældigt rundt når der ikke er forhindringer.
Når robotten opdager en forhindring suppresser den RandomDrive, som herved mister rettigheden til motorerne og AvoidFront tråden overtager alle rettigheder over motorerne.

3. Class Behavior
Et objekt er givet et andet objekt som det derefter kan suppresse. Dvs. at når tråden i PlaySound er aktiv vil den suppresse alle andre tråde, eftersom når PlaySound kalder suppress(), så vil suppress() metoden sørger for at suppressCount bliver talt op på det andet objekt. Det er lavet sådan at objekterne ikke kan udfører nogen handling hvis deres suppressCount er sat til 1 eller derover. Når f.eks. PlaySound er færdig med at udføre sin handling, så frigives motoren igen ved at tælle suppressCount ned igen. Fred Martin bruger et mere centraliseret princip, men ideen bag er stadig den samme. Han giver de forskellige tråede prioriteter, således at den tråd med den største prioritet får lov til at få den adgang den ønsker. Princippet gør brug af en metode kalder prioritize(), som kører concurrent med alle andre tråde. Den skanner igennem listen af aktive processer og finder den proces der har den højeste prioritet. Når den har fundet denne tråd, kopierer den trådens handlinger til motoren og udfører dem.

4. Add a behavior "Drive towards light"
Målet med forrige uges øvelser var at lave en robot der kørte i retning af lys. For at opnå mere erfaring med Rodney Brooks subsumption-arkitektur, tilføjede vi denne opførsel til samlingen af de tre eksisterende opførsler. Vi mener at det at følge lys bør have højere prioritet end RandomDrive og lavere prioritet end AvoidFront, hvorfor vi valgte at placere opførslen mellem disse. For at den nye opførsel, DriveTowardsLight ikke altid supress'er den underliggende opførsel, RandomDrive, har vi besluttet at den kun skal udløses når lyssensorerne ser et tilpas kraftigt lys, hvilet er implementeret vha. en justerbar tærskelværdi i vores kode. Vi har implementeret den nye opførsel ved at lave en klasse DriveTowardsLight der extender klassen Behavior.java givet i opgaven, og så copy paste'et kontrol-loop'et fra sidste uge ind i klassens run-metode, der er vist herunder:
public void run() {
while
(true) {
int leftValue, rightValue;
do {
leftValue = sensorLeft.readRawValue();
rightValue = sensorRight.readRawValue();
}
while(leftValue > lightThreshold && rightValue > lightThreshold);

suppress();
drawString("f");
forward(normalize(leftValue),normalize(rightValue));
delay(10);
release();
drawString(" ");
}
}
En anden interessant kodestump er det sted i klassen SoundCar.java, der også er givet i opgaven, hvor de forskellige opførsler instantieres og deres "prioritet", altså subsumption-ordenen, bestemmes:
rd = new RandomDrive("Drive",1, null);
dtw = new DriveTowardsLight("Light", 2, rd);
af = new AvoidFront ("Avoid",3,dtw);
ps = new PlaySounds ("Play ",4,af);

torsdag den 5. november 2009

Braitenberg/Tom Dean - Øvelsesgang 7

Dato:
05-11-2009

Antal timer brugt:
5 timer

Deltagende personer:
Kim Munk Petersen, Andreas Koefoed-Hansen og Tim Rasmussen

Denne uges opgaver:
Denne uges opgaver går ud på at benytte principperne i Tom Dean's note til at implementere Braitenberg's forskellige køretøjer. Vi har valgt at udfører opgaverne i den rækkefølge de er præsenteret i opgave beskrivelsen. Dette betyder at opgaverne er løs i følgende rækkefølge:
  1. Implementering af robot der kører mod lyset. Gjort brug af Tom Deans note.
  2. Implementering af en robot der gør brug af to tråde til at kontrollere hver forbindelse.
  3. Ændre implementering til at ændre værdien af MIN_LIGHT og MAX_LIGHT, så de følger værdierne målt levertiden n.
Formålet med denne uges øvelser er at forstå hvordan robottens handlinger kan afhænge af det miljø den færdes i.

Vigtige kodestumper vil være inkluderet i rapporten, mens der linkes til hele koden.

Fysiske overvejelser:
Vi har placeret 2 lyssensor på toppen af robotten til at indsamle oplysninger om lysforholdene. Sensorerne er placeret med ca. 10 cm mellemrum for at sikre en forskel i de målte værdier. Sensorerne kunne være placeret sammen, men herved vil forskellen på de målte værdier være mindre. Dette ville måske være en løsning hvis det er en lommelygte der f.eks. lyser på robotten. En lommelygtes spredning afhænger af hvor langt den er fra objektet, men lysstyrken vil oftest være stærkest i midten. Hvis sensorerne er placeret langt fra hinanden , vil lygtens lyskejle ikke ramme begge sensorer, hvorved robotten vil, hvis den følsomhed er lav, kører i hak. Da vi satser på at få robotten til at køre mod et vindue eller en dør, hvor der er normalt lysindfald, vælger vi at placere sensorerne med godt 10 cm. mellemrum. Et billed af robotten kan ses på nedenstående billede:





Implementation program til NXT-robotten med formålet at søge mod lys ved brug af Tom Deans note:

Vi benyttede de kodeeksempler der var i Tom Deans note til at lave metoderne til at udregne average og normalized values af inputtet fra lyssensorne, og derved bestemme hvor hurtigt motorerne skal køre.
Vi har en variabel kaldet beta der kan sættes til en værdi mellem 0 og 1. Denne variabel benyttes i forbindelse med udregning af average og bestemmer hvor meget der skal tages hensyn til de forgående læste værdier. Hvis beta er sat til 1 bliver der ikke taget hensyn til de værdier der er læst førhen, og hvis den er sat en værdi tæt på 0, får den læste værdi ikke meget indflydelse på hvordan avarage værdien bliver.

average = (int) ((beta * normalized) + ((1-beta)*average));

Vi testede dette ved printe både den nyeste læste værdi ud til skærmen, samt average værdien. Når beta var sat til 1 var værdierne ens, og når beta var lavere ændrede værdien sig langsommere til til den værdi der blev aflæst hvis sensoren tidligere har været i omgivelser med andre lysforhold.

Da vi prøvede at sætte motorerne til at køre efter den average værdi der blev udregnet var resultatet ret uventet. Når vi lyste med en lommelygte på sensoren kørte robotten imod lyset, men det var en ret ujævn motorgang.

Lyssensorens raw-values er ikke i et interval mellem 0-100 så vi var nødt til at normalisere værdierne så de kunne sendes videre til motorerne. Dette blev gjort at metoden normalize, der benytter værdierne MAX_LIGHT og MIN_LIGHT til at omregne den rå lysværdi.
Outputtet blev beregnet som følgende:
int output = (100 - ((light - MAX_LIGHT) * 100) / (MIN_LIGHT - MAX_LIGHT));

Vi lavede nogle test for at bestemme hvad MAX_LIGHT og MIN_LIGHT skulle sættes til og kom frem til at værdierne henholdsvis skulle være 300 og 600 for at robotten kunne arbejde i de omgivelser hvor vi var.

Ved normal loftsbelysning kørte robotten ikke, men hvis den blev vendt imod et vindue eller op mod loftslamperne begyndte den at køre imod lyset.

Tråde til kontrol af forbindelser
Implementeringen af tråde på NXT'en er lidt sværere end normalt, eftersom den ikke understøtter Runnable interfacet. Måden vi i stedet implementere det på er ved at lave en indre klasse kaldet WorkerThread der ekstender Thread. Konstruktøren i denne klasse tager som parameter en SensorPort og en MotorPort som derved parer de to enheder sammen. Hver objekt af WorkerThread der bliver oprettet, indeholder en række metoder til at returnere forskellige værdi tilknyttet objektet, samt en metode til at beregne den normaliserede værdi. Normalize metoden virker som beskrevet overfor.

I main metoden oprettes først LightSensor objekter, hvorefter FloorLight sættes til false.

LightSensor l1 = new LightSensor(SensorPort.S1);
LightSensor l2 = new LightSensor(SensorPort.S2);
l1.setFloodlight(false);
l2.setFloodlight(false);
herefter oprettes to objekter af WorkerThread, som derefter startes.

WorkerThread leftSensorThread = new WorkerThread(SensorPort.S1, MotorPort.C, null);
WorkerThread rightSensorThread = new WorkerThread(SensorPort.S2, MotorPort.B, null);
leftSensorThread.start();
rightSensorThread.start();
på denne måde oprettes to objekter der kører i hver sin tråd og samtidig forbinder en sensor med en motor.

Adaptivt lysinterval:
I teorien bør NXT-lyssensorerne kunne foretage målinger der resulterer i rå værdier i intervallet [0,1023]. Ved hjælp af eksperimenter har vi konstateret at dette interval er noget mindre i praksis. I vores kode bruger vi to variabler, MAX_LIGHT og MIN_LIGHT, til at angive grænsen for henholdsvis minimalt og maksimalt lys. Idet lyssensorerne fungerer således at der returneres en lav rå værdi ved kraftigt lys og en høj rå værdi ved svagt lys, har variablen MAX_LIGHT en lavere værdi end MIN_LIGHT hvilket ved første øjekast kan virke forvirrende.

Ved vores eksperimenter var den højest målte rå værdi ca. 800 (svagt lys) og den lavest målte ca. 100 (kraftigt lys). Som Tom Dean beskriver kan vi ikke vide hvilke lysforhold robotten kommer til at befinde sig i, hvilket betyder at vi med fordel kan lade MAX_LIGHT og MIN_LIGHT tilpasse sig forholdene. Dette gør vi ved at indskrænke det initielle lysinterval ift. vores målinger, og så lade det udvides automatisk hvis der er behov for det. Den initielle værdi for MAX_LIGHT er 300 og den initielle værdi for MIN_LIGHT er 600, altså begge 200 enheder fra værdierne målt i eksperimentet. Ifølge opgavebeskrivelsen skal kun de sidste N samples have indflydelse på tærsklerne, og vi har derfor implementeret en cirkulær liste indeholdende de sidste N målinger.

MAX_LIGHT og MIN_LIGHT justeres så efter henholdsvis største og mindste sample i listen, medmindre disse ligger inden for det initielle interval [300,600]. Grunden til at vi ikke tillader intervallet at blive indskrænket yderligere er at robotten vil blive for følsom over for ændringer i miljøet samt støj, og evt. risikere at få division med 0 hvor vi normaliserer lys-værdien i tilfælde af at MAX_LIGHT og MIN_LIGHT sættes til samme værdi. Som N bruger vi 5000 hvilket giver at den ældste sample i den cirkulære liste er ca. 50 sekunder gammel idet vi har indført et delay på 10ms i kontrol-loop'et.

Det selvjusterende lysinterval gør at robotten til dels "vænner" sig til dens omgivelser. Udsættes robotten for meget kraftigt lys således at dens MAX_LIGHT bliver meget lav, nedsættes dens lysfølsomhed hvilket kan ses ved at output'et fra normaliseringsfunktionen bliver lavere i takt med at MAX_LIGHT falder. Omvendt bliver den mere lysfølsom når den befinder sig i mørke områder hvilket giver en høj MIN_LIGHT, hvilket også ses ud fra normaliseringsfunktionen.

torsdag den 29. oktober 2009

Robot Race - Øvelsesgang 6

Denne uges opgave går ud på at få robotten til at køre så hurtigt som muligt, samtidig med at den følger Alishan train track. Regelsættet vi bruger under denne øvelse er en smule mindre end det oprindelige sæt, men giver stadig god udfordring. Vores regelsæt er som følgende:
  • Robotten skal starte fra startområdet. Ingen dele af robotten må stikke ud af start arealet.
  • Et tryk på ENTER starter robotten og robotten skal så følge sporet til at vende området, den øverste platform. Fra vende området skal robotten køre tilbage, indtil robotten kører ind i start området igen. Robotten skal derefter stoppe og tid der er gået siden starten skal vises på LCD. Bilen skal være inde i start området, før den stopper.
  • Når robotten er på toppen, bør robotten være inde i vende området før den kører tilbage.
Begge gruppe medlemmer har deltaget aktivt i at forsøge at løse denne opgave.

Hvordan greb vi det an?

Vi starter hvor vi slap sidste gang med vores robot og gik i gang med at få den til at følge linjen. Dette var dog ikke så let som vi troede, så vi besluttede os for at dele banen op i flere steps. Disse steps kan ses på billedet. På denne måde vidste vi hele tiden hvor på banen vi var og kunne på den måde udføre den rigtige handling ud fra dette. Vi brugte de 2 lyssensorer fra sidste gang, som hele tiden sørgede for at holde os opdateret på hvor vi var på banen. Dette betød at når vi f.eks. så sort på begge lyssensorer første gang, så vidste vi at vi var kørt ud af start området. Det var ideen, at vi ville blive ved sådan indtil ruten var gennemført. Dette lykkes dog ikke for os. Vi nåede rundt i det første sving, men kom så heller ikke videre.



Hvorfor kom vi ikke videre?

Grunden til at vi ikke nåede til toppen og ned igen var hovedsageligt manglende tid. Da klokken blev over 11 og vi begge var nødt til at gå kl. 12, måtte vi erkende at der ikke var tid nok til at kode robotten helt færdig. Så i ren panik for at se om vi kunne nå toppen, gik vi over til at anvende en sekventiel tilgangsvinkel. Dette betød at vi satte robotten til at køre ligeud et stykke tid (tiden det skulle tage at komme op til første sving) og når den tid så var gået skulle robotten dreje til højre og derefter fortsætte lige ud. Det lykkedes os også at få robotten forbi første sving, men herefter gav robotten op og begik selvmord.

Vi nåede derfor ikke til toppen, hvilket vi begge er en smule irriteret over, men man kan jo ikke vinde hver gang. Vi vidste godt at vi umuligt kunne vinde, da vi så hvor hurtigt nogle af de andres robotter kom til toppen og ned igen. Målet blev derfor for os blot at komme på toppen og ned igen.

torsdag den 8. oktober 2009

Forberedelse til robot race - Øvelsesgang 5

Denne uges opgave går ud på at få robotten til at følge en linie og stoppe når den når til målområdet. Opgaven er en god forberedelse til næste uges race, hvor det gælder om at få robotten hurtigst til toppen og tilbage igen. Under denne uges øvelser, har begge gruppemedlemmer deltaget aktivt.

Black White Detection
For at kunne udføre denne og senere opgaver, var vi nødt til endnu engang at bygge vores robot.

Opgaven går ud på at anvende klassen BlackWhiteSensor som vi har fået udleveret. Klassen indeholder en række metoder, hvor 2 bruges til at kalibrere farverne og to bruges til at bestemme om lyssensoren befinder sig over en hvid eller sort farve. Måde denne afgøre dette på er ved at lave et blackWhiteThreshold, som er summen af de to farvers værdi diveret med 2.

For at teste brugen af BlackWhiteSensor klassen, oprettede vi vores eget test program. BlackWhiteTest.
Programmet opretter en ny BlackWhiteSensor som vi herefter kalder calibrate metoden på. Denne metode sørger for at værdierne for hvid og sort bliver gemt og beregner blackWhiteThreshold.
Resten af test programmet udskriver blot den målte værdi og undersøger om der er tale om en sort eller hvid farve.

Programmet brugt i denne opgave kan findes:
http://www.cs.au.dk/~tiras/filer/LEGO/BlackWhiteSensor.java
http://www.cs.au.dk/~tiras/filer/LEGO/BlackWhiteTest.java

Line Follower with Calibration
Denne opgave går ud på at stifte bekendtskab med hvordan man kan anvende BlackWhiteSensor klassen til at få robotten til at følge en linie. Vi får udleveret programmet LineFollowerCal, som netop gør bruge af funktionerne til at bestemmer om den følger linjen.

Programmet brugt i denne opgave kan findes:
http://www.cs.au.dk/~tiras/filer/LEGO/LineFollowerCal.java

Vi vil ikke gør mere ud af denne beskrivelse da næste opgave omhandler samme enme, blot den tilføjelser og ændringer af BlackWhiteSensor klassen.

ColorSensor with Calibration
Denne opgave går ud på at lave et nyt program ColorSensor, som kan kende forskel på sort, hvid og grøn. Programmet er en udvidelse af BlackWhiteSensoren klassen. Tilføjelserne består i at vi har lavet en ekstra variabel greenLightValue, indeholder den kalibrerede værdig for grøn. Ligeledes er et nyt greenWhiteThreshold lavet, som indeholer summer af den grønne og hvide værdi divideret med 2.
Vi har nu to thresholds der indeholder gennemsnittsværdien af henholdsvis sort - grøn og grøn - hvid.

Vi har tilføjet en ny metode green(), som returnere true hvis den aflæste værdi ligger imellem de to thresholdes.

Denne løsning virker for det meste, men kan have problemer med at skelne mellem sort og grøn, da de to værdi ligger meget tæt op af hinanden. En lille forskel i lysmængden kan derfor kan derfor være med til at påvirke resultatet.

ColorSensor programmet kan findes på:
http://www.cs.au.dk/~tiras/filer/LEGO/ColorSensor.java

Line Follower that stops in a Goal Zone
Denne opgave går ud på at få robotten til at følge en linje og stopper når den når til målområdet. For at løse denne opgave har vi gjort bruge af ColorSensor klasse og LineFollowerCal. Klassen LineFollowerCal er blevet modificeret således at den nu også gør brug af metoden green() til at bestemmer om den er nået til målområdet.

Til at starte med gjorde vi kun bruge at en lyssensor, men det viste sig hurtigt at det var svært for den at følge linjen. Grunden til dette er som beskrevet i forrig opgave at den har svært ved at se forskel på sort og grøn.

Dette problem løste vi, ved at tilføje en ekstra lyssensor til robotten. Dette har gjort at den nu er meget mere præcis og nu følger linjen til punkt og prikke. :D
Grunden til at den nu følger linjen bedre, er at den nu kigger ved siden af linjen i stedet for på linjen.

Det nuværende program ser du som følgende:
http://www.cs.au.dk/~tiras/filer/LEGO/LineFollowerCalColor.java

torsdag den 1. oktober 2009

Selv-balancerende robot - Øvelsesgang 4

Opgaven i denne uge går ud på at bygge en robot der selv kan balancere. Det vil sige at den står og vipper frem og tilbage uden at vælte. Under arbejdet med denne øvelse har begge gruppemedlemmer deltaget aktivt.

Som beskrevet tidligere, så går opgaven ud på at bygge og programmere en robot til selv at kunne balancere. Det er meningen at vi skal tage udgangspunkt i Steve Hassenplug, Philippe Hurbain og Brian Bagnall ideer i konstruktionen af sådanne robotter. Vi kigge på designet, hvorefter vi så selv gik i gang med at bygge en robot. Da vi var færdige og havde fået monteret lyssensoren gik det op for os at der var en vejledning på hjemmesiden til hvordan robotten kunne samles.. Vi valgte dog at holde fast i vores eget design.

Hvordan arbejde vi os frem
Vi startede med at finde ud af hvilken værdier vores lyssensoren sendte retur. Vi var dog ikke helt sikkert på hvilken metode vi skulle bruge. Lyssensoren har følgende (og flere) valg muligheder:
readValue(); getLightValue(); getNormalizedLightValue();
Vi valgte til at starte med at anvende getLightValue(). Ved at anvende denne metode fandt vi ud af at vi skulle have robotten til at balancere omkring værdien 50. Vi mente at brugen af en proportional controller var vejen frem, da den tog hensyn til error mellem vores ønsket værdi på 50 og den målte værdi. Denne error mente vi at vi kunne bruge til at bestemme om robotten skulle køre frem eller tilbage. Efter at have kodet på dette et par timer og vores robot stadig opførte sig en syg høne der gik og hakkede i jorden, måtte vi indse at proportional controller nok ikke var vejen frem.

Vi fandt derefter frem til at man kunne anvende en PID controler i stedet. En PID controller forsøger at rette den error der er imellem den målte værdi og den ønskede værdi ved beregninger og derefter sørger for at de rigtige handlinger bliver udført. Formlen for PID controler er som følgende:
MV(t) = POUT + IOUT + DOUT
Når disse værdier er beregnet ud af en mænge målte data, vil det være muligt at få robotten til at balancere..

Hvor langt nåede vi?

Eftersom vi havde brugt alt vores tid på at kode en proportional controler, var der ikke mere tid tilbage fredag. Vi ville derfor gerne have implementeret PID controller, men pga. presset fra et andet kursus har vi desværre været nødt til at opgive håbet om at få robotten til at balancere.
Den kode vi nåede at få lavet, kan findes på
http://www.cs.au.dk/~tiras/filer/LEGO/Balance.java

Vi vil dog i den kommende evaluerings periode, hvis der bliver tid, forsøge at implementere PID controlleren.

onsdag den 30. september 2009

Lydsensor - Øvelsesgang 3

Opgaven i denne uge er at udvidde vores NXT-robotten med en lydsensor. Vi startede med at lave en "arm" som sensoren kunne sidde på og monterede den på robotten. Under denne øvelse har begge gruppemedlemmer deltaget aktivt.

Test af lydsensor:
Den første opgave bestod i at omskrive et program der var beregnet til en ultrasonicsensor så den kunne bruges i forbindelse lydsensoren. Efter et par små ændringer fik vi NXT'en til at vise lydniveauet angivet i procent.

Vi testede sensoren ved at lave lyde i forskellig styrke og afstand:

Lyd:
Afstand:
Procent aflæst på NXT:

Normal tale

45 cm

10-12

Klap

30 cm

20

Baggrundsstøj

?

2-3

pc 440 hz, 30% vol

10

18

pc 440 hz, 50% vol

10

45

pc 440 hz, 70% vol

10

91

Man kan se i tabellen at lydsensoren er meget følsom, hvilket betyder at der er er udslag på selv den mindste baggrundstøj. Vi placerede sensoren i et lukket rum og alligevel fik vi målinger på 2-3. Dette er en faktor der er meget lille, men stadig skal tages i betragtning.

Programmet kan findes på:
http://www.cs.au.dk/~tiras/filer/LEGO/SoundSensorTest.java

Data logger:

Data logger opgaven går ud på at anvende NXT'en til at gemme alle målte resultater i en txt fil, og derefter plotte dataerne i en graf. Grafen giver derefter et godt overblik over hvordan sensoren måler og hvordan det
stemmer overens med den lyd der blev mål på.

Til at løse opgaven anvendte vi følgende kode:
http://www.cs.au.dk/~tiras/filer/LEGO/DataLogger.java
http://www.cs.au.dk/~tiras/filer/LEGO/SoundSampling.java

Vi modificerede koden en smule for at få den til kun at indsætte en måling pr. linie, således det derefter var let at overføre alle målinger over i excel for at lave en graf. Eftersom det gav anledning til 3132 måling vælger vi ikke at inkludere dem her, men blot inkludere grafen. Vi udførte to sæt målinger, men da de ligner hinanden meget vælger vi kun at inkludere den ene.



Den lyd vi målte på gav anledning til at kurven skulle bevæge sig i retning af en sinuskurve, hvilket man må sige ikke helt er tilfældet med vores graf. Man kan dog alligevel godt se hvornår lydstyrken bevæger sig op og ned, men der er stadig store udsving på grafen som antyder at sensoren sender forkerte værdier tilbage til NXT'en som vi godt kendte det fra UltralydsSensoren.



Sound Controlled Car

Denne opgave går ud på at anvende noget udleveret kode og betragte hvordan robotten opfører sig på høje lyde. De udleverede kode indholder den fejl at programmet ikke er til at stoppe pga. at den måde det ene loop ligger inden i det andet loop, derfor modificeres koden så det nu bliver muligt at få programmet til at terminere.

Det udleverede program kan findes på:
http://www.cs.au.dk/~tiras/filer/LEGO/SoundCtrCar.java

Den første del af opgaven gik som sagt ud på at se hvordan robotten opfører sig når den hører høje lyde og hvordan programmet bestemmer om der er tale om høje lyde eller ej.
Da det giver mest meningen at starte med at beskrive hvordan robotten bestemmer om den har med høje lyde eller ej, er det det vi gør. Der er i starten af programmet defineret en variabel soundThreshold som er grænsen for hvornår lyden er høj. Programmet står og kører i en while løkken indtil den målte lyd overskrider værdien i soundThreshold. Når det så et tilfældet, så hopper den ud af while løkken og får robotten til at køre frem. Herefter started en ny while løkken hvor den igen står og venter på en høj lyd. Dette er måden den bestemmer om lyden er høj og får robotten til at køre. Rækkefølgenden for hvordan den kører er: Frem -> Højre -> Venstre -> Baglæns.

For at få programmet til at terminere når der trykkes på ESCAPE knappen, kan man vælge mellem to metoder. Vi valgte at gøre det ved at bruge en ButtonListener som hele tiden holder øje med om knappen ESCAPE er blevet trykket ned. Hvis det er tilfældet sættet en boolean stop = true. Denne boolean anvendes så i while løkken som en betingelse, således at når stop = true, så stopper loopet og programmet terminere.

Koden til denne opgave findes sammen med koden til clap controlled car opgaven.

Clap Controlled Car

Denne opgave går ud på at anvende Sivan Toledo's teori om at man kan bestemme et klap ved at måle på lydmønstret. Han mente at hvis en lav lyd (f.eks. under 50) blev efterfulgt af høj lyd (f.eks. over 85) inden for 25 millisekunder og derefter returnerede tilbage til en lav lyd (f.eks. under 50) inden for yderlig 250 millisekunder så var der tale om et klap.

Den måde vi løse opgaven på var at anvende et array af længe 5 til at gemme tidligere værdier i. Ligeledes oprette vi en ny metode isClapped() til at bestemmer om de forskellige betingelse er opfyldt. Hvis det er tilfældet så returneres der true elles false. Denne metode placerede vi så som betingelse i while løkken, således den først hoppede ud af løkken når der blev klappet.

Koden kan findes her:
http://www.cs.au.dk/~tiras/filer/LEGO/SoundCtrCar_Clap.java

Faste læsere