torsdag den 25. november 2010

NXT Programming, lesson 11

Dato: 25-11-2010
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

Dato: 18-11-2010
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:
  1. Press the touch sensor and keep it pressed. What happends ? Explain.
  2. 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.
  3. 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.
  4. 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.
  5. Try to implement the behavior DetectWall so the actions taken also involve to move backwards for 1 sec before turning.
  6. 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?
Forventede resultater
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:



  1. 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.
  2. 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.
  3. 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
  4. 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();}

  5. 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);


  6. 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.
Motivational Functions

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

Dato: 11. nov. 2010
Varighed: 3
Deltagere: Nick & Allan

Formål med øvelsen

Denne lab. session handler om at udforske hvordan det er muligt at få en robot til at navigere på en intelligent måde. Det betyder at robotten skal vide hvor den er (localization), samt den skal kunne vide hvor den vil hen (navigation). Metoderne til at undersøge ovenstående omfatter alle brug af tachometret som Lego motorerne er udstyret med.

Planen for øvelsen
* Ombygge Lego Car 9797 så den kan skrive på kørselsunderlaget med en boardmarker.
* Uploade et program som bruger leJOSs TachoPilot for at udforske hvordan localization og navigation virker.
* Uploade et program som bruger leJOSs SimpleNavigator for at udforske hvordan localization og navigation virker.
*Sammenligning af TachoPilot og SimpleNavigator
* Diskussion af hvordan navigationen kan forbedres i henhold til forskelligt teori.

Forventede resultater
Det forventes at robotten kan bringes til at navigere tilnærmelsesvist korrekt af sig selv. Det skal dog bemærkes at der spiller mange faktorer ind, og at det er bliver nødvendigt at approximere dels konkrete locations, og dels navigationsruter, således kan det derfor ikke forventes at robotten følger perfekte ruter.

Robotten med boardmarker
Til at udføre eksperimentet brugte vi en robot med whiteboard tusch påsat. Billede kan ses nedenfor.

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.


Forbedret navigation
Grundlæggende bygger RidgeSoft-tutorial [RS1] (svarende til leJOSs SimplePilot) på samme principper som "Forward Kinematics" [FK]. Dvs. at begge udnytter diameteren af hjulet og længde af akslen til at beregne den nye position (som et punkt i et koordinatsystem). Forskellen består i at [FK] tager højde for forskellig fart på højre og venstre hjul, således at omdrejningspunktet (kaldet "ICC" i [FK]) kan variere. Dette giver teoretisk et mere præcist resultat end RidgeSoft som altid anvender midten af hjulakslen på de drivende hjul som omdrejningspunkt.
I de forsøg som vi har gennemgået idag, vil beregningsmetoden i [FK] dog ikke have nogen effekt, da kun drejer "på stedet", altså at robotten drejer om hjulasklen. Blev robotten programmeret til at køre i buer, vil metoden [FK] teoretisk give et mere præcist resultat. Grunden til der lægges stor vægt på teoretiske resultater er, at der er mange faktorer som den robot vi anvender dag ikke lægger mærke til, og derfor giver anledning til fejlkørsler. Disse er:
- modstand i boardmarkertuschen som bevirker at robotten tvinges ud af kurs
- modstand i baghjulet som har samme effekt som ovenstående fejlkilde (vi så også tidligere at forsøg måtte afbrydes pga. baghjulet så tydeligt påvirkede kørselsretningen)
- underlaget kan have indflydelse på kørslen, fx. kan robotten lave hjulspind eller krænge pga. af forskelle i underlaget. Derudover gælder for begge metoder at underlaget skal være plant - ellers regnes positionerne forkert.
- fejlmålinger i størrelser af hjul, aksellængder - [Bagnall, side 297] antyder også at målingen af aksellængden kan være svær at måle præcist.



torsdag den 4. november 2010

NXT Programming, Lesson 8

Dato: 04-11-2010
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".

Forventede resultater
Det forventes at robotten vil være mere uforudsigelig jo flere opførsler den har at forholde sig til.

Afprøvning af programmet SoundCar.java
Ved kørsel af SoundCar ser displayed ud som følger:


Her repræsentere Drive, Avoid og Play de tre forskellige simple opførsler robotten kan have, som tilsammen giver den mere avancerede opførsel.
Drive køre tilfældigt rundt og har i denne kode laveste prioritet, hvilket vil resultere i at det er robottens standard opførsel som udføres så snart ingen tråde er undertrykte. [AIMEMO]
Robotten kører play hvert 10 sekund, hvilket har top prioritet. Det at Play har top prioritet betyder at hvis der ikke var 10 sekunders ventetid ville den spille lyden hele tiden, da denne har højere prioritet end de to andre (Drive og Avoid har et 1 tal, mens Play har 0).
Avoid har en prioritet som ligger under Play og over Drive, hvilket betyder den kan undertrykke Drive og blive undertrykt af Play.
Den sidste række på diplayet repræsentere motor kald, dvs. forward (f), backward (b) og stop (s).

Behavior.java
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.

Behavior.java er baseret på Rodney Brooks subsumption architecture, hvordan er denne i forhold til Fred Martin, [4, page 214-218]
Fred Martin beskriver en form for hjemmelavet schedulerings algoritme som kan bruges i systemer som ikke understøtter threading, hvilket er relevant for nogle embedded systemer. NXT'en understøtter threading og derfor ville det ikke være relevant at benytte Fred Martins løsning.
Den helt store forskel er dog at der ikke er tale om tråde, hvilket vil sige koden altid vil køre færdig og aldrig vil blive afbrudt, hvilket kan lade sig gøre når tråde benyttes.

Kør i mod lys
SoundCar er blevet modificeret så den kører mod lyset, ved at tilføje en ekstra opførsel fra lab7. Dette gøres ved at oprette en tråd ved at nedarve fra Behavior og implementere run metoden.

public class LightDrive extends 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();
}
}
}
Yderligere er SoundCar's main metode modificeret så den starter den nye behavior:




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();

}
}
Vi har valgt at lave sådan at robotten kun følger lys og undgår forhindringer, da dette er nemmere at teste.