torsdag den 25. november 2010
NXT Programming, lesson 11
Varighed: 3
Deltagere: Nick, JC
Formål med øvelsen
Formålet med øvelsen er at finde på tre mulige end-course projects og evaluere dem.
Planen for øvelsen
Beskrive hvert muligt projekt på følgende måde:
-Kort beskrivelse
-Hardware-/softwareplatform
-Mulige udfordringer
-Hvad vi vil kunne præsentere til eksamen
Vi vil ud fra disse beskrivelser vælge én af projekterne og uddybe denne med en handlingsplan.
Forventede resultater
Vi vil have en beskrivelse af et end-course project, som vi vil kunne begynde at arbejde ud fra i næste uge.
Parkeringsrobotterne:
Kort beskrivelse:
To robotter skal kunne finde parkering i et simpelt miljø bestående af én vej, med to retninger. De skal kunne parallelparkere også selvom de bliver nødt til at lave tre-punktsvending og kunne indikere til hinanden at de har tænkt sig at tage en bestemt parkeringsplads.
Hardware-/softwareplatform:
To nxt'er udstyret med den samme software. Vi forestiller os at de skal bruge følgende sensorer:
1. Ultralydssensor til at vurdere afstand til andre biler
2. Lyssensor til at kunne følge vejen
3. Lydsensor til at kunne kommunikere med hinanden gennem "dyt"
Mulige udfordringer:
1. At parkere mellem to andre biler, uden at ramme dem og vurdere om robotten har foretaget en ordenlig parkering.
2. At kunne kommunikere gennem "dyt", og vurdere om robotten er i vejen for den anden, eller om det er den anden der tager fejl.
Hvad vi vil kunne præsentere til eksamen:
En bane med mulighed for selv at placere de statisk parkeret biler, og derefter sætte to to nxt-biler ind på banen. De skulle derefter gerne finde en parkeringsplads hver og benytte dem hvis muligt.
Sorteringsrobotterne:
Kort beskrivelse:
Én robot indsamler klodser på et givent areal, og sortere dem i henhold til deres farve, i nogen bestemte områder. En anden robot kan derefter tage klodserne fra disse områder og sortere dem i henhold til deres størrelse. Så fra at have en mængde usorterede klodser spredt på et areal, får vi x antal bunker med brikker sorteret efter farve og størrelse.
Hardware-/softwareplatform:
To nxt'er udstyret med forskelligt software, og en PC med webcam til at hjælpe robotterne med at finde rundt på banen.
Følgende sensore forestiller vi os at bruge:
1. Lyssensor til at finde farven på brikken
2. Tryksensor til at vide om den har fat i en brik
3. Tryksensor for at analysere en briks størrelse
4. Webcam til at overvåge og hjælpe med position
5. Lydsensor til at kunne kommunikere mellem robotterne om der er en klods klar til sortering
6. Ultralydsensor for at undgå kollision med omgivelserne
Mulige udfordringer:
1. At samle en brik op og finde farven på denne
2. Analysere billedet som webcammet giver af banen (brug af tredieparts software)
3. Kommunikere med lyd mellem de to robotter. Alternativt kunne vi bruge bluetooth
Hvad vi vil kunne præsentere til eksamen:
En bane med to halvdele. Den ene halvdel vil tilskuerne kunne sprede en mængde klodser, hvorefter den ene robot vil kunne sorterer dem efter farve, og den anden robot vil derefter kunne sortere dem efter størrelse.
Labyrintrobotterne:
Kort beskrivelse:
En labyrint skal løses af en robot uden global viden omkring dens miljø. En anden robot har til opgave at forsøge at fange robotten som forsøger at løse labyrinten. Robotten som skal fange har global viden via webcam, men bevæger sig dog væsentligt langsommere end robotten som skal løse labyrinten.
Hardware-/softwareplatform:
To nxt'er udstyret med forskelligt software, og en pc med webcam til at hjælpe den ene robot med at fange den anden.
Følgende sensore forestiller vi os at bruge:
1. Ultralydsensor til at navigere i labyrinten
2. Tryksensor til at indikere om robotten er fanget
3. Webcam til at give global viden til den ene robot
4. Lyssensor til at se at man er i mål
Mulige udfordringer:
1. At finde vej i labyrinten og løse den
2. At skabe en intelligent fjende, der forudser løserens næste træk og agere der efter
Hvad vi vil kunne præsentere til eksamen:
En labyrint med der tilhørende to robotter, hvor den ene kan finde i mål, mens den anden måske kan fange den. Variable labyrint eller hanstighed på den to robotter kunne være muligt for tilskueren at ændre på.
End-course projekt:
Sorteringsrobotterne:
Efter samtale med Ole Caprani, blev vi enige om at gå videre med sorteringsrobotterne, da det ikke er indskræntet af for faste rammer. Vi vil kunne udvide med nye ideer, som ikke er bundet af et bestemt scenarie.
Vi ønsker at undgå brug af global viden, dvs. et webcam placeret over banen. Dette skyldes at det er mere interessant at benytte robotternes lokale viden, da dette tillader indførsel af flere robotter.
Til at starte med vil fokus ligge på banen og farvelægning af denne. Banen vil indtil videre være som følger:
Robot 1 skal samle rød/grønne brikker sammen i de rød/grønne zoner. Bølgerne ud for hver zone repræsentere to farver, hvormed robotten kan navigere hen til zonen.
Robot 2 begynder først at sortere klodserne efter størrelse når robot 1 angiver at der er en klods klar, enten via bluetooth eller lyd.
Plan:
Uger:
48: Banen og robotkonstruktion
49: Robot 1's software del og mobiltlf. som webcam
50: Robot 1's software del og mobiltlf. som webcam
51: Robot 2's software del
52: Robot 2's software del
1: Test
2: Presentation
3: Aflevering af lab rapporter
torsdag den 18. november 2010
NXT Programming, lesson 10
Varighed: 3
Deltagere: Nick, JC og Allan
Formål med øvelsen
Dagens øvelse går ud på at undersøge behavior-based architectures i Lejos API'en i form af den implementerede subsumption arkitektur i lejos.subsumption.
Planen for øvelsen
Planen for i dag er følgende:
- BumperCar projektet i "samples/BumperCar" skal kunne køres på en NXT robot.
- Eksperimenter med BumperCar, som beskrevet i øvelsesbeskrivelsen:
- Press the touch sensor and keep it pressed. What happends ? Explain.
- Both DriveForward and DetectWall have a method takeControl that are called in the Arbitrator. Investigate the source code for the Arbitrator and figure out if takeControl of DriveForward is called when the triggering condition of DetectWall is true.
- Implement a third behavior, Exit. This behavior should react to the ESCAPE button and call System.Exit(0) if ESCAPE is pressed. Exit should be the highest priority behavior. Try to press ESCAPE both when DriveForward is active and when DetectWall is active. Is the Exit behavior activated immediately ? What if the parameter to Sound.pause(20) is changed to 2000 ? Explain.
- To avoid the pause in the takeControl method of DetectWall a local thread in DetectWall could be implemented that sample the ultrasonic sensor every 20 msec and stores the result in a variable distance accessible to takeControl. Try that. For some behaviors the triggering condition depends on sensors sampled with a constant sample interval. E.g. a behavior that remembers sensor readings e.g. to sum a running average. Therefore, it might be a good idea to have a local thread to do the continous sampling.
- Try to implement the behavior DetectWall so the actions taken also involve to move backwards for 1 sec before turning.
- Try to implement the behavior DetectWall so it can be interrupted and started again e.g. if the touch sensor is pressed again while turning.
- Når BumperCar har fundet en væg, hvad sker der hvis man trykker på sensoren mens den er ved at dreje? Hvordan kan Thiemo Krink's motivations funktioner bruges til at gøre reaktivering muligt?
At opnå viden omkring Lejos implementation af en subsumption arkitektur, som i det hele taget minder mere om Fred Martins reaktive arkitektur end en decideret subsumption arkitektur, da Lejos implementationen kun kører en opførsel ad gangen.
Eksperiementer med BumpCar:
- Touch sensor
Når man trykker på touch sensoren, begynder bilen at bakke i ca. et sekund og derefter kører den fremad igen. Hvis knappen holdes inde bakker den, efterfulgt af en kort pause og bakker derefter igen. Dette skyldes at Arbitratoren kører listen af behaviors igennem, før den vælger at bakke ligesom reactive control arkitektur[Martin] og den laver en lille pause for at lave en lydprøve som ultrasonic sensoren kan tjekke for. Dette giver den lille pause mellem de to gange den bakker. - takeControl i DriveForward
takeControl() bliver aldrig kaldt i DriveForward, da der bliver kaldt break på for-loopen, når den finder den behavior med højst prioritet der skal udføres. - Exit on escape button implementeres som et nyt behaviour på følgende måde:
class Kill implements Behavior{public Kill(){}public boolean takeControl(){return Button.ESCAPE.isPressed();}public void suppress(){//Since this is highest priority behavior, suppress will never be called.}public void action(){System.exit(0);}}
Yderligere tilføjes behaviouren til Arbitratoren:Behavior b3 = new Kill();Behavior[] behaviorList = {b1, b2, b3}; //b3 has the highest priority
- For at undgå noget af pausen i takeControl i DetectWall opførslen har vi implementeret en lokal tråd som opdatere en felt variabel hvert 20 millisekund som naturligvis bruges i takeControl metoden:
private int distance = Integer.MAX_VALUE;public DetectWall(){touch = new TouchSensor(SensorPort.S1);sonar = new UltrasonicSensor(SensorPort.S3);new Thread(new Runnable() {public void run() {while (true) {sonar.ping();Sound.pause(20);distance = sonar.getDistance();LCD.drawString(""+distance, 0, 2);}}}).start();}
- DetectWall klassens action() metode modificeres ved at indsætte følgende øverst:
Motor.A.setPower(100);Motor.A.backward();Motor.C.setPower(100);Motor.C.backward();Sound.pause(1000);
- Håndtering af interrupt mens DetectWall kører
Hvis det skal være muligt at genstarte DetectWall's action, foreslår vi at lave en while-loop, der udfører selve handlingen i små skridt, mens den tjekker for en boolean felt variable, som berøringssensoren kan ændre. Hvis denne variable ændres, starter while-loopen forfra.
Som beskrevet i, [Krink], anvendes motivationsfunktioner til at bestemme hvor højt en autonomt styret enhed ønsker at udføre en given handling. Autonomt styrede enheder skal her ses som et bredt begreb, som fx. omfatter spurve, rotter, visse former for robotter mm.
Forskellen mellem LejOSs adfærdsbaserede tilgang til autonome systemer og Krinks motivationsfunktioner, er at LejOSs adfærdsmønstre (Behaviors) er inddelt i en hakkeorden hvor hvert mønster har sin plads i prioritetsrækkefølgen, mens Krinks motivationsfunktioner giver hvert adfærdsmønster mulighed for at differentiere i hvor høj grad det ønsker at blive udført. Det betyder altså at ved motivationsfunktioner beregnes en motivationsgrad som er angivende for hvilket adfærdsmønster enheden udfører – højeste motivationsgrad bliver udført.
LejOSs hakkeorden er styret ud fra en prioriteret liste af adfærdsmønstre som løbende løbes igennem for at se om et højereprioriteret mønster skal udføres i stedet for det aktuelle. Rent praktisk foregår dette ved at spørge hvert mønster i faldende prioritetsorden om det ønsker at blive udført. Når et mønsters takeControl-metode returnerer “true”, at det gerne vil udføres, tjekker skeduleringsmekanismen – Arbitrator, som også er mekanisme der hele tiden tjekker om der skal ændres adfærdsmønster – om mønsteret har højere prioritet end det alleredevalgte mønster. Hvis det har, ændres adfærd og ellers fortsættes som før.
Det er vigtigt at notere sig, at LejOSs skeduleringsmekanisme starter forfra når et mønster gerne vil udføres. Det er måden at sikre at det højest prioriteret mønster bliver opdaget når det gerne vil udføres. Ved motivationsfunktioner findes der ikke en hakkeorden, så derfor skal skeduleringsmekanismen ændres således at alle adfærdsmønstre tjekkes inden der kan skiftes mønster eller fortsættes som før. Det kan gøres ved at tilføje en heltalsfeltvariabel, hvor maximumværdien af et gennemløb af adfærdsmønstrernes takeControl-metode gemmes.
Fra ovenstående er det indlysende at det ikke er nok blot at returnere en boolean som svar på takeControl, men at mønstrernes vekslende motivationsgrad kræver at der kan gives et differentieret svar, fx. en heltalsværdi. Det giver skeduleringsmekanismen mulighed for at identificere adfærdsmønstret med højeste motivationsgrad, og efterfølgende aktiverer dette. Her skal man passe på ikke at efterligne LejOS-modellen – hvor der tjekkes op mod det aktive adfærdsmønsters prioritet for at afgøre om dette skal overtrumfes – for det kan resultere i at et bestemt adfærdsmønster konstant udføres selvom det ikke er nødvendigt (her tænkes på “nød-adfærdsmønstre” hvor der fx. undviges vægge eller flygtes fra rovdyr). Dette begrundes med at nød-adfærdsmønstrene skal udføres hvis enheden kommer i farlige situationer, og som følge deraf bliver motivationsgrader meget høj – dog kun i kort tid.
Derfor bør der, for hvert gennemløb, findes en maximumværdi som diktatorisk vælges til udføre sin handling. Her følger en liste over de ændringer vi mener er passende for at implementere motivationsfunktioner:
tilføj en heltalsfeltvariabel til opbevaring af maximum motivationsgrad
fjern tjekket hvor det aktive adfærdsmønster bliver vurderet ift. det mønster som ønsker at blive udført
for hvert adfærdsmønster opstilles en matematisk formel som beregner motivationsgraden. Denne værdi returnes.
lad hvert gennemløb i Arbitrator finde maximum motivationsgrad, og efterfølgende aktivere denne
torsdag den 11. november 2010
NXT Programming, lesson 9
TachoPilot
TachoPilot blev sat til at køre 60 cm. frem, rotere 180 grader for derefter at køre 60 cm. og igen rotere 180 grader, hvilket gentages 11 gange.
Resultatet af dette kan ses på nedenfor viste billede som tydeligt illustrere hvordan fejlen vokser med tiden/antal sving, som beskrevet i [Bagnall] på side 297-298.
Dette kan yderligere ses på følgende video:
Koden bag dette simple eksperiment ser ud som følger:
Pilot pilot = new TachoPilot(5.6f, 11.2f, Motor.B, Motor.C, false);
pilot.setMoveSpeed(10);
for(int i=0; i<3;>
pilot.travel(60);
pilot.rotate(-180);
pilot.travel(60);
pilot.rotate(-180);
}
try{Thread.sleep(1000);}
catch(InterruptedException e){}
pilot.stop();
Her bemærkes det at afstanden mellem hjulene på vores robot er målt til 11.2 cm, og hjul størrelsen er aflæst fra lego hjulet til 5.6 cm.
I det at det umiddelbart ser ud til fejlen kommer i forbindelse med sving kan vi prøve at reducere denne fejl ved at mindske den angivne afstand mellem hjulene. Vi reducerede denne med en millimeter og fik følgende resultat:
Det ses tydeligt at den ene millimeter gør en kæmpe forskel i forhold til forrige resultat. Der kan være mange årsager til at resultatet bliver så radikalt anderledes, f.eks. kan det skyldes ren og skær tilfældighed, hvilket vi dog ikke tror da vi senere hen så samme forskel ved brug af SimpleNavigator. Det tyder altså på at upræcise målinger påvirker Lejos navigations algoritmerne rigtig meget. Det er vigtigt at bemærke at på billedet ovenfor har robotten ikke kørt 11 gange frem og tilbage men kun 3, dog er afstanden mellem en streg og dens nabo streg mindre end på forrige billede.
SimpleNavigator
SimpleNavigator blev sat til at gennemføre samme rute som beskrevet i TachoPilot, med den forskel at koden selvfølgelig er lidt anderledes:
SimpleNavigator nav = new SimpleNavigator(5.6f, 11.2f, Motor.B, Motor.C);
for(int i=0; i<3;>
nav.goTo(60, 0);
nav.goTo(0, 0);
}
SimpleNavigator har dermed mere global viden omkring sin verden end TachoPilot, da man kan bede den om at vende tilbage til udgangspunktet uden selv at foretage nogen beregninger.
Med hensyn til præcisionen var SimpleNavigator ikke rigtigt bedre end TachoCounter, hvilket kan ses på følgende billede:
Dette illustreres yderligere af følgende video:
Som før forsøgte vi at reducere den angivne afstand mellem hjulene med en millimeter til 11.1 cm., hvilket igen forbedrede resultatet væsentligt:
Igen er viser billedet kun 3 ture frem og tilbage.
Sammenligning
TachoPilot og SimpleNavigator er stort set lige dårlige, og det har ikke været muligt for os at observere en radikal forbedring fra den ene til den anden.
Forskellen ligger dermed i at SimpleNavigator giver mindre kontrol end TachoPilot til fordel for en mere simpel form for navigation hvor den ved hvad dens udgangspunkt var da den startede ud. Dette kan også opnås med TachoPilot, dog vil det kræve væsentligt mere arbejde.
torsdag den 4. november 2010
NXT Programming, Lesson 8
Varighed: 3
Deltagere: Nick, JC og Allan
Formål med øvelsen
Dagens øvelse går ud på at lave en robot som, for en udefrakommende observatør, ser ud til at have mere end en type opførsel. Dette er i kontrast til lab 7 hvor robotterne kun havde en type opførsel.
Planen for øvelsen
Planen for i dag er følgende:
- Bygge Lego car 9797 med en ultrasonic sensor.
- Afprøvning af programmet SoundCar.java.
- Hvad siger LCD displayet når SoundCar.java køres?
- Analyse af koden bag SoundCar, hvilke typer opførsler har robotten? Evt. video af de forskellige opførsler, dvs. hvor kun en opførsel er aktiveret af gangen.
- Hvordan virker Behavior.java? Hvordan kontrollere den hvilken opførsel som har adgang til motorerne på et givent tidspunkt?
- Behavior.java er baseret på Rodney Brooks subsumption architecture, hvordan er denne i forhold til Fred Martin, [4, page 214-218]?
- Modificer SoundCar.java ved at tilføje en ekstra opførsel: "Kør i mod lys".
Det forventes at robotten vil være mere uforudsigelig jo flere opførsler den har at forholde sig til.
Behavior extender thread og har en run metode, som kører uafhængigt af de andre tråde på VM'en. Hver Behavior har en Behavior feltvariable som indeholde den Behavior som den er højere end i hierakiet. Den nederst Behavior indeholder ingen, så den kan ikke suppresse andre.
Når en Behavior mener at den skal udføre sin opførelse, suppresser den de Behaviors der er under den, ved at kalde suppresse, som suppresser dens egen Behavior som er under den, som suppresser den under den osv... Når den er færdig med den opførelse den skulle, kan den sende en release ud og derved give plads til de andre Behaviors.
Hvilken Behavior der kommer til afhænger af VM'ens styring af tråde, men da vi antager at det er en fair fordeling, vil alle tråde komme til.
På denne måde kan vi bygge et hieraki op af opførelser der kan overtrumfe hinanden. Da metoderne suppresse og release er synchronized, bliver alle suppressed og released samtidig.
Om en Behavior er suppressed afhænger af en counter frem for en boolean. Dette skyldes at Behavior der er i gang med sin egen udførelse, kan blive suppressed og lige efter release Behaviors under den. Det laveste niveau ville da ikke vide at en Behavior længere oppe end dens egen parent var i gang og ville da tro at den måtte udføre opgaver. Med en counter skal alle over den have kaldt release for at den kan komme til.
public class LightDrive extends BehaviorYderligere er SoundCar's main metode modificeret så den starter den nye behavior:
{
public LightDrive( String name, int LCDrow, Behavior b)
{
super(name, LCDrow, b);
}
public void run()
{
float maxRight = -1;
float minRight = -1;
float maxLeft = -1;
float minLeft = -1;
float powerR;
float powerL;
LightSensor lsRight;
LightSensor lsLeft;
lsRight = new LightSensor(SensorPort.S2);
lsRight.setFloodlight(false);
lsLeft = new LightSensor(SensorPort.S3);
lsLeft.setFloodlight(false);
while (true)
{
suppress();
float lsRightValue = lsRight.readValue();
float lsLeftValue = lsLeft.readValue();
if(maxRight == -1) {
maxRight = lsRightValue;
minRight = lsRightValue;
maxLeft = lsLeftValue;
minLeft = lsLeftValue;
} else {
if(maxRight < maxright =" lsRightValue;" maxleft =" lsLeftValue;"> lsRightValue) minRight = lsRightValue;
if(minLeft > lsLeftValue) minLeft = lsLeftValue;
}
powerR = -1;
powerL = -1;
if(lsRightValue == minRight) powerR = 0;
else if (lsRightValue == maxRight) powerR = 100;
if(lsLeftValue == minLeft) powerL = 0;
else if (lsLeftValue == maxLeft) powerL = 100;
if(powerR == -1) powerR = ((lsRightValue - minRight)/(maxRight-minRight))*100;
if(powerL == -1) powerL = ((lsLeftValue - minLeft)/(maxLeft-minLeft))*100;
forward((int) powerL, (int) powerR);
release();
}
}
}
Vi har valgt at lave sådan at robotten kun følger lys og undgår forhindringer, da dette er nemmere at teste.
public class SoundCar
{
public static void main(String [] args)
{
AvoidFront af;
// PlaySounds ps;
LightDrive ld;
LCD.drawString("Sound Car",0,0);
LCD.refresh();
//rd = new RandomDrive("Drive",1, null);
//ps = new PlaySounds ("Play ",3,af);
ld = new LightDrive("Light", 1, null);
af = new AvoidFront ("Avoid",2,ld);
//rd.start();
af.start();
//ps.start();
ld.start();
while (! Button.ESCAPE.isPressed())
{
// rd.reportState();
af.reportState();
// ps.reportState();
ld.reportState();
}
LCD.clear();
LCD.drawString("Program stopped",0,0);
LCD.refresh();
}
}