torsdag den 24. september 2009

Øvelse 3: Sound Sensor, Sound Controlled Car og Clap Controlled Car

Dato

18. September 2009

Tidsforbrug

3 timer

Deltagende gruppemedlemmer

Martin Aksel Jensen, Kim Munk Petersen

Mål

  1. Undersøge NXT Sound sensor (mikrofon)
  2. Bruge DataLogger-klassen til at gemme målinger til fil som overføres og analyseres på PC
  3. Bygge en robot der reagerer kinematisk på lyde
  4. Modificere robotten så den kun reagerer på klap-lyde

Resultater

Indledende test af lyd-sensoren

Efter at have monteret lyd-sensoren på vores LEGO 9797 robot, lavede vi et simpelt program til at teste lyd-sensoren. Programmet måler hele tiden det aktuelle lydniveau og skriver dette på LCD-displayet. Derudover skriver det den højst målte amplitude siden programmet blev startet, samt en "lokal" højst målt amplitude der nulstilles efter et bestemt stykke tid (1 sek. pr. default). Begge amplituder skrives på LCD-skærmen og idet lyde som fx klap er meget korte, brugte vi sidstnævnte til at se den maksimale amplitude for den foregående lyd.
Koden til programmet er vist herunder:

import lejos.nxt.*;
/**
 * Simple test program for the NXT Sound Sensor (microphone)
 * @author  Martin Aksel Jensen & Kim Munk Petersen
 */
public class SoundSensorTest 
{
    public static void main(String [] args)    throws Exception 
    {
        SoundSensor soundSensor = new SoundSensor(SensorPort.S1);
        long timeSet = 0;
        int soundValue = 0;
        int globalMax = 0;
        int localMax = 0;
        final int localHoldTime = 1000; // Time before local max is reset to 0

        LCD.drawString("Sound (%)  ", 0, 0);
        LCD.drawString("Local Max  ",0,1);
        LCD.drawString("Global Max ",0,2);

        while (! Button.ESCAPE.isPressed())
        {
            soundValue = soundSensor.readValue();
            LCD.drawInt(soundValue, 3, 13, 0);
            
            // Hold time elapsed, reset local max sound value
            if(System.currentTimeMillis() - timeSet > localHoldTime) {
                localMax = 0;
                LCD.drawInt(localMax, 3, 13, 1);
                timeSet = Long.MAX_VALUE;
            }
            // Set new local max sound value
            if(soundValue > localMax) {
                localMax = soundValue;
                LCD.drawInt(localMax, 3, 13, 1);
                timeSet = System.currentTimeMillis();
            }
            // Set new global max sound value
            if(soundValue > globalMax) {
                globalMax = soundValue;
                LCD.drawInt(globalMax, 3, 13, 2);
            }
        }
        LCD.clear();
        LCD.drawString("Program stopped", 0, 0);
        Thread.sleep(1000);
    }
}

I skemaet herunder er resultatet af vores målinger med ovenstående program.
Lyd
Afstand (cm)
Lyd (%)
Almen støj
N/A
3-10
Tale
10
85-95
Tale
50
20-35
Tale
100
10-20
Tale
200
4-16
Klap
10
93
Klap
50
70.90
Klap
100
50-75
Klap
200
20-45


Robot-test 1: "Sound Controlled Car"

Vi lage programmet SoundCtrCar.java (givet i opgavebeskrivelsen) over på robotten.Programmet giver robotten 5 tilstande: forward, right, left og stop som angiver om den skal køre, og i givet fald i hvilken retning. Når lyd-sensoren opfanger en høj lyd - amplitude over 50% - skifer robotten til næste tilstand. Det er således en sequential strategy[1].

Som forklaret i opgavebeskrivelsen er der et problem mht. registrering af tryk på Escape-knappen. Vi forsøgte at løse dette problem på en elegant måde vha. flere tråde. Først lavede vi en ButtonListener som asynkront lytter efter tastetryk. Når der registeres et tryk på Escape-knappen sættes en delt boolean ved navn terminate der indikerer at programmet skal lukkes. terminate bliver sat til true i buttonListener'en. Når tråden der kører selve programmet registrerer dette, lukker programmet. Noget der snød os var at tråd-metoden join() ifølge lejos dokumentationen ikke er implementeret, men det er den! Vi har testet og konkluderet at den virker efter hensigten.

Robot-test 2: "Clap Controlled Car"

For at kunne skelne klap-lyde fra andre lyde, brugte vi DataLoggeren givet i opgaven til at logge en lydmålinge ved klap-lyde. Grafen herunder viser denne lydmåling.


Det første lyd-udsving skyldes "bib"-lyden der kom fra NXT-brick'en da vi trykkede på Enter-knapper for at starte programmet og de 3 næste er klap-lyde. Det ses at de tre klap-lyde er meget ens, både i amplitude og varighed.

På grafen herunder har vi zoomet ind på det midterste klap for at kunne analysere det nærmere.


Ifølge Sivan Toledo [2], kan et klap genkendes vha. følgende "mønster":
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.
Dette mønster passer fint med vores målinger. Det er dog noget mere restriktivt hvilket tillader mere omgivende støj og gør at klap kan registreres på længere afstand end ved vores målinger.
Vores implementering af ovenstående mønster til at detektere klap-lyde ses herunder:
private static  void waitForClap() throws Exception
    {
        Thread.sleep(500);

        int state = 0;
        int soundValue;
        long starttime = System.currentTimeMillis();
        long timestamp;

        while(true) {
            if(terminate) // break out if terminate flag is set
                break;
            
            soundValue = sound.readValue(); // read current sound value from sensor
            timestamp = System.currentTimeMillis() - starttime;
            
            if(state == 0 && soundValue < 50) // in start state, wait until sound < 50%
                state = 1;
            else if(state == 1) { // if sound > 85 within 25ms, go to next state, else reset (go to state 0)
                if(timestamp > 25) {
                    state = 0;
                    starttime = System.currentTimeMillis();
                }
                else if(soundValue > 85)
                    state = 2;
            }
            else if(state == 2) { // if sound < 50 within 250ms, break out to indicate clap, else reset
                if(timestamp > 275) { // 25 + 250
                    state = 0;
                    starttime = System.currentTimeMillis();
                }
                else if(soundValue < 50)
                    break;
            }
        }
    }

LEGO model

Herunder er et billede af vores LEGO-model (Clap detector).


Referencer

Ingen kommentarer:

Send en kommentar