torsdag den 18. november 2010

Week 9 in LEGO lab

Date: 4. November

Duration of activity: 3 hours
Groups members participating: Heine Stokholm, Michael Vilhelmsen and Mads Møller Jensen

Dagens opgaver:
  • Byg NXT robotten om, så den kan fungere som BumperCar med koden givet fra lejos NXT distributionen i samples/BumperCar
  • Lav eksperimenter med BumperCar
BumperCar
Vi har ombygget vores robot som følger:

Vi har beholdt robotten fra uge 8 og påsat en tryksensor, så robotten kan "føle" at den kører ind i noget.
Herefter har vi uploaded programmet fra tutorialen til robotten med følgende resultat:


Eksperimenter med BumperCar
  • Hvad sker der når tryksensoren holdes i bund?
Når tryksensoren holdes i bund, kræver DetectWall opførslen hele tiden motoradgangen, og robotten forsætter med hele tiden at lave afvigelsesmanøvren.
  •  Både DriveForward og DetectWall har takeControl metoden. Undersøg i Arbitrator koden om Driveforwards takeControl metode, når DetectWall ønkser kontrollen.
I Arbitrator har vi et loop, som kører alle Behaviors igennem. Når loopet finder den Behavior med højest prioritet, som returnerer true ved takeControl, ved den at det er denne Behavior som skal afvikles. Derfor afbrydes loopet, når en sådan Behavior er fundet. Dette betyder at resten af de Behaviors med lavere prioritet ikke bliver kaldt. I BumperCar tilfældet betyder det at DriveForwards takeControl metode IKKE bliver kaldt, når DetectWalls takeControl metode returnerer true. 
  • Implementer end tredje opførsel,  Exit, med højeste prioritet. 
Vi har implementeret en Exit opførsel med højeste prioritet. Dette betyder, at hvis Exit knappen er nede, vil programmet afbrydes, i stedet for at køre fremad, eller afvige. Hvis vi øgede Sound.pause(20) til Sound.pause(2000), ville det ikke være muligt at afbryde robotten i 2 sekunder, hver gang Arbitratoren skal tjekke om DetectWall vil have adgang til motorene. Dvs. vi kan ikke afbryde i bestemte steder i loopet.
  • For at undgå ventetiden i loopet, få den ultrasoniske sensor til at tage prøver hver 20 msek og gemme værdien i en variabel, så takeControl metoden, blot kan tjekke denne værdi.
Vi har valgt at implementere en tråd, som hver 20 msek opdaterer en variable med den senest målte værdi. Fra DetectWall's takeControl metode kigger vi nu bare på den variabel som tråden opdaterer. På den måde undgår vi ventetid i loopet i Arbitration klassen. Vi prøvede at sætte måleintervallet op til 2 sek, og det betød at vi kun kunne afvige hver andet sekund (fordi det kun var der, at vi fik nye målinger). Til gengæld kan vi hele tiden afbryde, modsat før hvor vi var hæmmet af ventetiden i loopet. 
  • Lad DetectWall få robotten til at køre baglæns 1 sekund før den normale afvigelsesmanøvre sker. Implementer at DetectWall kan afbrydes(og køres forfra), hvis den efter det ene sekund stadig kan se forhindringen.
Dette er gjort.Vi har implementeret dette ved hjælp af en ekstra tråd. Tråden indeholder den afvigende opførsel. Hvis tryksensoren så rammes igen, interruptes tråd, og en ny tråd af samme slags kaldes og startes. På den måde kan robotten blive ved med at afvige hvis den bliver ved med at se forhindringer.

Koden for BumperCar efter alle implementationer på nær sidste opgave kan ses her

Koden for BumperCar efter den sidste implementation kan ses her

onsdag den 10. november 2010

Week 8 in LEGO lab

Date: 4. November

Duration of activity: 3 hours
Groups members participating: Heine Stokholm, Michael Vilhelmsen and Mads Møller Jensen

Dagens opgaver:
Thor kørte rundt, og stoppede med jævne mellemrum. Efter ca. 10 sekunder spillede han en lille lyd, og derefter fortsatte han med at køre tilfældigt rundt.
  • Look at the LCD and try to interprete the output
Vi ser 3 linjer:
Drive, Avoid og Play.
Ud for dem alle er et tal der enten er 0 eller 1. Dette tal er 1 når denne behaviour bliver suppresed. Derudover er der et lille bogstav bagved dem alle (enten f, b eller s). Desuden er der et tal fra 0-255 ud for Avoid (afstanden som sensoren måler).
Vi ser at når Avoid suppreser Drive bliver 0'et ud for Drive sat til 1. På samme måde ser vi at når Play suppreser Drive og Avoid bliver begge deres 0'er sat til 1.
  • Look into the three classes and try to identify how the triggering condition is implemented in each of the classes and how the actions for each behavior is implemented
PlaySounds har en while-true løkke. I løkken sleeper den i 10 sek. Når den ikke sleeper, kalder den suppress, og spiller en lille melodi og kalder derefter release. Triggering condition er altså at de 10 sek. er gået - Action er at spille en melodi.

AvoidFront har en while-true løkke. I løkken looper den i en while-løkke så længe den afstand sensoren måler er større end tooCloseThreshold. Så længe afstanden er større måler den en nye afstand og skriver den gamle ud på displayet. Når afstanden pludselig er mindre end threshold suppreser den, og bakker, drejer og til sidst releaser den.
Triggering condition er altså at den målte afstand er mindre end threshold - Action er at bakke og dreje lidt.

Drive har en while-true løkke. I løkken vælges en tilfældig retning og der køres i denne retning, derefter delayes der i et tilfældigt stykke tid. Drive starter med at suppresse og releaser når den er færdig.
Triggering condition er faktisk ingenting; så længe den ikke suppresses kører Thor hele tiden tilfældigt rundt.
Action er at køre i en tilfældig retning
  • Try to watch the car with only the first thread active and then with only the two first threads active to observe the behaviors more clearly.
Vi mente godt at vi kunne forestille os hvordan Thor ville opføre sig hvis vi kun havde en eller to af trådene aktive. I stedet mente vi at det var tydeligere at se hvordan Avoid suppresser Drive og Play suppresser begge dele, hvis Thor hele tiden kører rundt. Derfor fjernede vi det tilfældige delay i Drive, og så opførslen. Videoen her viser resultatet.
  • What is the purpose of making these threads daemon threads as done in the constructor of the Behavior class
Da en daemon-tråd holder op med at eksistere når de tråde den skal servicere terminerer, giver det mening at lade de 3 behaviours være daemon-tråde, da de ikke giver mening at eksistere for sig selv.



Week 7 in LEGO lab

Date: 28. October
Duration of activity: 3 hours
Groups members participating: Heine Stokholm og Mads Møller Jensen




Dagens opgaver:

  • Brug Tom Dean's noter til at implementere Braitenbergs "Vehicle 1", "Vehicle 2a" og "Vehicle 2b
  • Lav en ændring i programmet, så MIN_LIGHT og MAX_LIGHT bestemmes af N samples og altså ikke af alle samples, som robotten har set i sin levetid.
  • Implementer Vehicle 2 (a eller b) med to "threads of control" i stedet for én (Èn for hver forbindelse mellem sensor og motor).
Vehicle 1:
Vi byggede Vehicle 1:


Vehicle 1 er en robot som (i dette tilfælde) har en mikrofon og fremdriften i motorene bestemmes af det lydniveau, som mikrofonen opfanger. Idéen er at robotten skal køre hen i mod en lydkilde, men dette bliver aldrig tilfældet, da robotten ikke har nogen anelse om, hvor lydkilden befinder sig, men kun hvad et givent lydniveau er, der hvor robotten befinder sig.
Først implementerede vi bare, motorene reagerede på lyd, så robotten kørte bare den opfangede en svag lyd.
Det resulterede i at robotten kørte af sig selv p.g.a. den støj som motoren udsender. 




Derfor implementerede vi jvf. Tom Deans note "Braitenberg's Vehicles", en håndtering af baggrundsstøj. Dette gjorde vi vha. et estimat. Vi kunne have valgt at kigge på alle hørte værdier, og beregne gennemsnittet, men over tid er dette en dårlig løsning.
Derfor brugte vi estimatløsningen, hvor det kun er nødvendigt at gemme den sidste estimatværdi, for at beregne den næste.
Som Java kode ser det således ud.


double estimate = 0;
double beta = 0.2
...
estimate = estimate + beta*(volume-estimate);

Dette virkede og robotten stoppede med at reagere på baggrundstøj og dens egen motor.





Hele koden for Vehicle 1 ses her


Vehicle 2:
Vi byggede Vehicle 2:


Vehicle 2 har modsat Vehicle 1 to sensorer (i dette tilfælde lyssensorer). Motorkraften på de to motorer bestemmes så af de lysværdier, sensorerne opfanger. Der findes to forskellige udgaver af Vehicle 2:
a) Her reagerer højre motor på værdierne fra højre lyssensor, og på samme måde i venstre side. Det betyder, at robotten vil køre væk fra en lyskilde.
b) Her reagerer højre motor på værdierne fra venstre lyssensor, og omvendte. Det betyder at robotten vil køre hen imod en lyskilde.


For at få det til at virke med to sensorer ændrede vi en lille smule i koden fra Vehicle 1:


lightL = lightLeft.readNormalizedValue();
lightR = lightRight.readNormalizedValue();
...
estimateR = estimateR + beta*(volume-estimateR);
estimateL = estimateL + beta*(volume-estimateL);
...
Car.forward(normalized(lightR), normalized(lightL));


Det gav følgende resultat:


Herefter implementerede vi MIN_LIGHT og MAX_LIGHT variablene, så den normaliserede værdi (den værdi som motorene skal køre med) passer til det miljø som robotten befinder sig i. Den måler en maksimal lysværdi og en minimal lysværdi, så den reagerer optimalt i de omgivelser den er i. 
Dette gav følgende resultat:
[VIDEO]


Koden kan ses [link]


Miljøændring
I Tom Dean's noter bliver MIN_LIGHT og MAX_LIGHT værdierne kun reguleret, når en henholdsvis mindre og større værdi opfanges. Dette er dog ikke helt hensigtsmæssigt, da lysomgivelserne skifter, eksempelvis når vi går fra dag til nat. Derfor har vi brug for at rekalibrere disse værdier efter N tid eller N indsamlet data. Dette forsøgte vi at implementere med følgende resultat:
[VIDEO]


Koden kan ses [link]


To tråde
Til sidst prøvede vi at lave to "threads of control" i stedet for en. 
Det gav følgende resultat:
[VIDEO]


Koden kan ses [link]

fredag den 15. oktober 2010

Week 6 in LEGO lab

Date: 7. October
Duration of activity: 8 hours
Groups members participating: Michael Vilhelmsen, Heine Stokholm og Mads Møller Jensen


Robot race


I dag er målet at bygge en robot, der kan konkurrere i LEGOLABs officielle ROBOT RACE.
Robot kapløbet går ud på at bygge en robot, som kan gennemføre "The Alishan Train Track" på hurtigst mulig tid.


Robotten tager udgangspunkt i PID system vi lavede sidste uge. Koden kan ses her.
Svingene i denne bane er ret specielle og meget svære for en robot, der kun kan følge en sort linje.
Derfor har vi modificeret programmet som følger:


Istedet for kun at have vores pid system til at styre robotten har vi nu også nogle forskellige states robotten kan være i repræsenteret ved følgende booleans:



         boolean rightTurn = false;
boolean leftTurn = false;
boolean direction = true;
boolean rightTurnAllowed = true;
boolean leftTurnAllowed = false;
boolean rightFinished = false;
boolean rightFinished2 = false;
boolean leftFinished = false;
boolean up = true;



Når rightTurnAllowed er true tjekker vi hele tiden den venstre sensor for om den ser sort, og hvis den gør laver vi følgende ændring på motorkraften:


         if(rightTurn) powerC = (powerA * 100 ) / 175;


Det vil sige at vi giver mere kraft til den inderste motor i svinget så robotten svingere blødere. Derefter registrerer vi så om den forreste sensor registrer sort så vi har færdiggjort svinget. 



I starten kunne robotten godt køre op ad banen:


 


Men som det ses havde vi allerede her lidt problemer med lys sensoren, som var spændt helt fast. Dette viste sig også at være et problem, når vi skulle ned af banen, fordi sensoren ikke kunne se den sorte streg, når robotten kørte ud over kanten, fordi sensoren blev løftet og fik andre værdier. Derfor valgte vi at modificere lidt i robotdesignet, så sensoren kunne få mulighed for at have en konstant afstand til banen.
Desværre gjorde det, at sensoren kom for langt frem i forhold til hjulene, så robotten blev umulig at styre. Sensoren fik robotten til at køre af sporet fordi den kom til svingene før selve robotten, og sendte den dermed på afveje. 
Vi skiftede derfor tilbage til det tidligere design og arbejdede videre med koden, for at undgå de fejllæsninger som sensoren laver, når vi kører ned af banen. 

Ved første forsøg på at køre ned, prøvede vi til dels at hardcode svingene, så robotten fulgte nogle bestemte instruktioner, når den (ved første sving) venstre lysmåler så en sort streg. Det gav dog nogle problemer, da robotten ikke var konsistent i kørslen, pga. PID systemet, som gjorde at vi ramte plateauet forskelligt hver gang.
Vi brugte mange forsøg og tweakede konstanterne, men udslaget var forskelligt hver gang, så robotten nogle gange kun kunne klare første sving og andre gange kun kunne klare sving nummer 2. 

Pga. de mange komplikationer gik vi tilbage til vores oprindelige PID system, og i vores næste forsøg forsøgte vi at ændre PID systemet, når robotten var i gang med at svinge, i håb om at den så kunne finde tilbage på banen. Dette lykkedes til dels, men robotten var stadig for inkonsistent til at dette virkede hver gang. Ved et perfekt gennemløb kunne robotten godt klare nedturen, men der var for langt mellem disse.


Selvom systemet ikke var perfekt, prøvede vi alligevel at implementere rotationen på toppen og stoppet i bunden. Det gjorde vi ved at hardcode en lille fremdrift efterfulgt af en 180 grader rotation når vi var færdige med venstresvinget og både venstre og højre lyssensor så en sort streg på samme tid. Dette fungerede udemærket efter en del tweaking af de forskellige variable. Stoppet i bunden fungerede ved at hvis begge sensorer målte sort og vores boolean up fortalte vi var på vej ned, så stoppede vi. 


Vi stod altså med en robot, som nogle gange kunne køre op ad banen og nogle gange kunne køre ned. Desværre måtte vi se i øjnene at vores styring var for inkonsistent, så det lykkedes os aldrig at få robotten til at køre både op og ned. Det tætteste vi kom, var at robotten kørte op og vende og kørte igennem første sving på vej ned og derefter kørte den af sporet. 
Koden og robotdesignet var altså desværre ikke tilstrækkeligt til at gennemføre banen!





torsdag den 7. oktober 2010

Week 5 in LEGO lab

Date: 30. September
Duration of activity: 3 hours
Groups members participating: Heine Stokholm, Michael Vilhelmsen and Mads Møller Jensen

Dagens opgaver:
  • Opbyg LEGO-robotten og lav et program, der benytter og tester klassen BlackAndWhiteSensor.java
  • Prøv programmet LineFollowerCal.java, der benytter BlackAndWhiteSensor klassen. (Optimér programmet så robotten følger linjen blødere og hurtigere
  • Lav et program ColorSensor.java ved at ændre i BlackAndWhiteSensor.java. Test ColorSensor og se om et sådant program er brugbart
  • Implementer ColorSensor i LineFollower så robotten stopper i en grøn målzone.
BlackAndWhiteSensor
Efter en ombygning fra sidste uge har LEGO-robotten Thor skiftet udseende og ser nu således ud:


BlackAndWhiteSensor programmet går ud på, at man kalibrerer lyssensoren til en hvid farve og en sort farve. Programmet beregner så en median (thershold). Hvis målinger herefter er over threshold-værdien sige robotten: "White", og hvis en måling er under værdien siger robotten: "Black".
Vi har ændret lidt i programmet, så vi bruger LightSensor'ens readNormalizedValue() i stedet for den i forvejen brugte readValue(). readNormalizedValue() læser nemlig raw value (0-1032), hvorimod readValue() læser en procentvis værdi (0-100). Derved får vi mere præcision i målingerne.


LineFollower
Vi har uploaded LineFollowerCal.java med følgende resultat:

Videoen lyver lidt da Thor har problemer med at følge linjen den anden vej rundt og ryger ud i svinget.

ColorSensor
Color sensoren er en udvidelse af den tidligere omtalte b/w sensor. Den fungerer ved at man udover sort og hvid også måler en tredje værdi som ligger mellem sort og hvid som vi har kaldt grøn. Så kan man spørge sensoren om man er over hvid, grøn eller sort. Det giver dog problemer da lyssensoren registrerer den grønne værdi hver gang man er på vej væk fra stregen. 

Three level lineFollower
Vores næste forsøg var at lave en three level lineFollower. Det vil sige at når vi registrede grøn ved vores lightsensor fik vi robotten til at køre ligeud. Det fik gjort den lidt mere flydende, men slet ikke optimalt. Derfor prøver vi nu en pid LineFollower.

Pid LineFollower
Vi har lavet et PID system jvf. artiklen A PID Controller for Lego Mindstorm Robots. Vi startede med at sætte værdierne Ki og Kd til 0. Robotten var altså nu kun afhængig af Kp. Vi fandt så en passende værdi, som gjorde at robotten kunne følge en linje uden at miste sporet, og uden at oscillere alt for meget. Denne værdi valgte vi så at kalde Kc. Herefter målte vi frekvensen af de oscillationer robotten foretog. Denne værdi kaldte vi for Pc. Til sidst fandt vi ud af at vores while-loop tog cirka 0.01 sekund at gennemløbe. Med disse tal kunne vi bruge Ziegler–Nichols metoden vha. følgende skema:


I koden kom det til at se således ud:

  //critical value (Vi har fundet den vha forsøg)
  int Kc = 60;
  double Kp = Kc * 0.6;

  //2*Kp*dT/Pc, (Pc og dT målt ved forsøg) 
  double Ki = (2*Kp*0.01) / 0.5;


  //(Kp*Pc)/8dT
  double Kd = (Kp*0.5)/(0.08);

Dette betyder at vi kan optimere robotten ved at tweake Tp og Kc, hvorefter de andre værdier vil tilpasse sig.


Robotten kom til at følge linjen fornuftigt ved brug af PID kontrollen:



Hele koden kan ses her: LineFollowerCS.java


STOP!
Vi skulle herefter forsøge at få robotten til at stoppe i den grønne målzone. Ved brug af kun en sensor var dette umuligt, da robotten hele tiden læste en grå værdi, svarende til den grønne. Vi valgte derfor at tilføje en ekstra sensor, som kunne måle en grøn værdi som ikke var i forbindelse med den sorte linje.
Vores robotdesign ser nu sådan ud:


Den ekstra kode vi har tilføjet til LineFollowerCS.java er følgende:


RCXLightSensor sensorLeft = new RCXLightSensor(SensorPort.S3);
...
sensorLeft.setFloodlight(true);
...

if(sensorLeft.getNormalizedLightValue()  < 340 &&  sensorLeft.getNormalizedLightValue()  > 290)
{
stop++;
} else {
stop = 0;
}
 
if(stop > 30){
System.exit(0);
}
}



Dette gav følgende resultat:




I næste uge skal vi bruge disse egenskaber og modificerer dem til at bygge en robot, som kan deltage i en konkurrence kapløb mod andre robotter.

torsdag den 23. september 2010

week 4 in LEGO lab

Date: 23. September
Duration of activity: 3 hours
Groups members participating: Michael Vilhelmsen, Heine Stokholm og Mads Møller Jensen

Dagens opgaver:



Robotten:


Vores robot Thor har i dag taget følgende outfit på:


Den har kun to hjul som den skal prøve at balancere på, og for at hjælpe med denne opgave er der anbragt en lightsensor foran på Thor. 


Programmet:
Programmet består af to hoveddele. En getBalance() og en pidControl() metode, hvor getBalance() sørger for at få valgt det rette offset. 
Her har vi prøvet fire forskellige tilgange:

  1. At forsøge at få robotten til at balancere og derefter trykke på START-knappen. (Som var initialiseringen)
  2. At forsøge at få robotten til at balancere mens START-knappen var trykket i bund, så offset blev sat i det øjeblik START-knappen blev sluppet. -Dette var instruktorens idé, men vi havde problemer med at fornemme hvornår robotten var i balance på den måde.
  3. Vente 5 sekunder efter programmet var startet og så sætte offset til den værdi sensoren målte på det tidspunkt. På den måde kunne vi slippe for at skulle sende robotten ud af balance ved at trykke på START-knappen.
  4. Ved at hardcode offset. Vi lavede målinger med robotten for at finde den sensorværdi, hvor robotten var i balance.

pidControl() metoden udgør derimod kontrolenheden i vores feedbackloop. Den fungerer som sagt ved hjælp af et pid system der indeholder tre vigtige parametre, p, i og d. P står for proportional og det er den parameter der bestemmer hvor hurtigt robotten skal bevæge sig mod offsettet i forhold til hvor langt væk fra den ønskede position robotten er. I står for integral og sørger for at vores robot ikke kommer til at hvile i en position der ikke er vores offset, og d står for derivative og sørger for at vores robot sænker farten efterhånden som den nærmer sig den ønskede position.


afvikling:

En af vores første forgæves forsøg på at få Thor til at balance ser ud som følger:




Først prøvede vi at forbedre balanceevnen ved at ændre på den magiske error konstant. Det gjorde dog ikke den store forskel. 
Vores næste tanke var at det måske kunne hjælpe at ændre på motorhastigheden. Vi prøvede at sætte hastigheden ned først for at undgå at robotten ville ramme forbi det satte offset, men igen uden meget succes og højere hastighed hjalp heller ikke meget. 
Vi havde også nogle forsøg med at hardcode det offset som robotten skulle prøve at ramme. Det gav dog visse problemer da det optimale offset ændrede sig ofte på grund af  at vores sensor ikke var alt for sikkert fastmonteret.

Det forsøg vi havde størst held med var da vi efter et hint fra instruktoren flyttede vores robot til et mere ensfarvet bord, og med lidt ekstra tweak af pid parametrene endte vi med følgende resultat:


torsdag den 16. september 2010

Week 3 in LEGO lab

Date: 16. September
Duration of activity: 3 hours
Groups members participating: Heine Stokholm and Mads Møller Jensen

Goals of the day:

  • Mount the soundsensor to our 9797 LEGO car, and test the sensor
  • Use a datalogger
  • Reconstruct the car into soundcontrolled car
  • Try to make the car controlled by claps


The sound sensor:
We have mounted the soundsensor (microphone) to the car and uploaded our MicSensorTest.java to it. The program recorded the input from the sensor, and wrote the value (between 0-100) to the LCD display.
The MicSensorTest program was just a rewriting of the SonicSensorTest we used last week to test the Sonic Sensor.
http://www.cs.au.dk/~mmjensen/legolab/MicSensorTest.java

No problems or surprises here, as we saw the display changing in accordance with the amplitude of the sounds we made.

Datalogger:
Our second assigment of the day was to use a datalogger on our LEGO car. So we uploaded SoundSampling.java to do so. After running the program we could connect to our car and get access to a log file. This file contained a lot of measurements from the microphone. Now we had the possibillity to log a specific sound and see the amplitude as a function of time.
Here is our result for a clap:
In the log file it was very easy to see where the clap was, so this is just a little piece of the entire log file. The program wrote to the log file every 5th ms, so even though we only logged a few seconds the log file was huge.

Sound controlled car:
After this we uploaded the SoundCtrCar.java file to our car. The program listened to sound and made the car go forward, go left, go right and stop in that sequence. If the microphone measured a sound over 90 it did the next thing the sequence and looping the whole thing. The problem with the original program was that the only time it was possible to hit the exit button and make the program quit was at the end of the loop.
To change this we had two approaches.
First approach: We implemented that the program should listen to the exit button every time it listened to the input from the microphone. This gave made us able to quit the program all the time. This can be seen here:

http://www.cs.au.dk/~mmjensen/legolab/SoundCtrCar.java

Second approach: We made the program implement the ButtonListener interface and this approach had the same effect as the first.

http://www.cs.au.dk/~mmjensen/legolab/SoundCtrCarListener.java

Clap controlled car:
Then came the fun part of the day: we tried to change the SoundCtrCar to only register claps. We used Sivan Toledo definition of claps and it are as follows:

     "A clap is a pattern that starts with a low-amplitude sample (say below 50), followed by a very-high amplitude sample (say above 85) within 25 milliseconds, and then returns back to low (below 50) within another 250 milliseconds."

This definition corresponds very good with the graph we created above.

We changed the waitForLoudSound() method from the SoundCtrCar to register claps instead like this:


private static  void waitForLoudSound() throws Exception
    {
  int clap = 0; 
        int soundLevel;
        Thread.sleep(500);
        do
        {
   if(Button.ESCAPE.isPressed()){
    System.exit(0);
   }
   soundLevel = sound.readValue();
            LCD.drawInt(soundLevel,4,10,0);
   if (clap == 0 && soundLevel < 50){
    clap = 1;
    Thread.sleep(25);
   } else if(clap == 1 && soundLevel > 85){
    clap = 2;
    Thread.sleep(250);
   } else if(clap == 2 && soundLevel <50){
    clap = 3;
   } else {
    clap = 0;
   }
        }
        while ( clap < 3 );
    }
 
We basically wait the time stated in the definition and then check if the next requirement is true. As you can see in the video below it works reasonably well but there are problems. It would probably be better to loop until the next requirement is true and restart if the time goes over the time specified in the definition.

The entire code can be seen here:
http://www.cs.au.dk/~mmjensen/legolab/ClapCtrCar.java