|
|
# Group 8
|
|
|
|
|
|
## Lab Notebook 3
|
|
|
|
|
|
**Date:** 2/3 - 2015
|
|
|
|
|
|
**Duration:** 6-8 hours
|
|
|
|
|
|
**Participants:**
|
|
|
|
|
|
- Frederik Jerløv
|
|
|
- Casper Christensen
|
|
|
- Mark Sejr Gottenborg
|
|
|
- Peder Detlefsen
|
|
|
|
|
|
## Goal
|
|
|
The goal is to equip our NXT Robot with a sound sensor and execute the exercises.[1]
|
|
|
|
|
|
## Plan
|
|
|
Our plan is to follow the exercises exactly as described.
|
|
|
|
|
|
## Results
|
|
|
|
|
|
### Exercise 1
|
|
|
In this exercise we were supposed to test the sound sensor which we mounted to our NXT according to the lego mindstorms manual. Using the program ```SoundSensorTest```[2] we tried reading the sound values when making sounds at different loudness and at varying distances.
|
|
|
|
|
|
Unfortunately at the time of the exercise a lot of group were also testing their own lego robot, with sound sensor attached which made the environment less than ideal for testing the robot, as there were a lot of background noise.
|
|
|
|
|
|
Snapping your fingers at a distance of 10 cm’s would sometimes make the sound level rise to 20 but most times it would not go beyond 10. The background environment had a sound level of 4 - 5.
|
|
|
|
|
|
Here is a picture of the setup (Figure 1):
|
|
|
|
|
|
![Robot setup for exercise 1](http://i.imgur.com/q4x0Bu2b.jpg)
|
|
|
|
|
|
### Exercise 2
|
|
|
In this exercise we used data logger[3] and ran the program ```SoundSampling.java```[4] in order to make some samples of a song.
|
|
|
After playing the song for 1 minute and 10 seconds we received a error ```FileWriter casts an Exception’’’. Our guess is that it is due to the NXT running out of memory.
|
|
|
So we measured 1 minute of a famous song. The result is seen in Figure 2.
|
|
|
|
|
|
![Rick Ashley - Never Gonna Give You Up](http://i.imgur.com/PMinZJi.png)
|
|
|
|
|
|
### Exercise 3
|
|
|
In this exercise we ran the ```SoundCtrCar.java```[5] program and observed the robots behavior. When starting the robot it would wait for any loud sounds and then move either forward, right, left or stop. The rotation was forward, right, left, stop and forward again with loud sounds separating each behavior. To determine whether a sound is loud the program uses a sound threshold. This was initially 90 but we found this value to be too high and therefore reduced it to 50. The function waitForLoudSound() will then call readValue() each 500 ms and compare it to the threshold. If the threshold is met the function returns and the robot will be given a new move command.
|
|
|
|
|
|
### Exercise 4
|
|
|
|
|
|
In the program ```SoundCtrCar.java```[5] . We set the while to while(true) and added a ButtonListener object to Button.
|
|
|
|
|
|
```Java
|
|
|
|
|
|
Button.ENTER.addButtonListener(new ButtonListener() {
|
|
|
|
|
|
@Override
|
|
|
public void buttonReleased(Button b) {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void buttonPressed(Button b) {
|
|
|
Car.stop();
|
|
|
System.exit(0);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
The call `System.exit(0)` will reboot the NXT instantly.
|
|
|
|
|
|
### Exercise 5
|
|
|
A clap is a loud noise that can be measured as a loud sound. On the figure below we have sampled some claps with the program ```SoundSampling.java```[4]. Our sampling looks similar (see Figure 3) to the result that Sivan Toledo achieved[5].
|
|
|
|
|
|
![Sound value (0-100), Over time (miliseconds) for clapping](http://i.imgur.com/xrXYZW8.png)
|
|
|
|
|
|
We then used the results from the clap measurements as an indicator of a clap. A clap is around 25-110 milliseconds long. So if we measured a loud sound (over 85, retrieved from the sampling data) and started a timer to measure how long it took to drop under the threshold, we would handle it as a clap, if the time it took to drop under the threshold was between 25-110 milliseconds.
|
|
|
|
|
|
We implemented a program ```ClapControl.java```[6] where we have shown the method ```waitForClap``` below.
|
|
|
|
|
|
```Java
|
|
|
private static void waitForClap() throws Exception {
|
|
|
int soundLevel;
|
|
|
double timerStart;
|
|
|
double timerStop;
|
|
|
double diff;
|
|
|
|
|
|
do
|
|
|
{
|
|
|
do
|
|
|
{
|
|
|
soundLevel = soundSensor.readValue();
|
|
|
LCD.drawInt(soundLevel,4,10,0);
|
|
|
}
|
|
|
while ( soundLevel < soundThreshold );
|
|
|
|
|
|
timerStart = System.currentTimeMillis();
|
|
|
|
|
|
do
|
|
|
{
|
|
|
// Stopwatch running
|
|
|
soundLevel = soundSensor.readValue();
|
|
|
LCD.drawInt(soundLevel,4,10,0);
|
|
|
}
|
|
|
while ( soundLevel > soundThreshold );
|
|
|
|
|
|
timerStop = System.currentTimeMillis();
|
|
|
diff = timerStop - timerStart;
|
|
|
//LCD.drawInt((int)diff,4,10,1);
|
|
|
}
|
|
|
while( !(25 < diff && diff < 110));
|
|
|
}
|
|
|
|
|
|
```
|
|
|
It basically does what we just described before. Wait for loud sound, then start timer. Wait for sound to go below the threshold, then stop the timer. Then we check if the sound was in the right time interval, if it was the function is ended and we have registered a clap, else it would just wait for a clap. On the display it would count the number of clap registered.
|
|
|
The program worked great, it was good to register clap, even with background noise and background music.
|
|
|
|
|
|
### Exercise 6
|
|
|
In this exercise we tried two different approaches. In the first we had the two sound sensors in front of the robot in both sides, see Figure 4. In the second we had one sensor in the back and one in the front, each side, see Figure 5. We also used the raw values of the sound sensor. The values was between 0 and 1024 both included. After testing we noticed the robot behaved differently than we expected. We assumed low values meant low sound level etc. but then discovered that high raw values meant low sound level and low values meant high sound level, background noise was below 950.
|
|
|
|
|
|
![Robot with two sound sensors in front.](http://i.imgur.com/sPk3ohxb.jpg)
|
|
|
|
|
|
The first approach was pretty simple. We first read the raw value of both sensors. Then we calculated the difference between the two values. Based on the difference we either turned left if the difference was positive. We turned right if the difference was negative. If there was no difference we would move straight forward. Below is the program we implemented ```PartyFinder.java```[7]
|
|
|
|
|
|
```Java
|
|
|
|
|
|
while (!Button.ESCAPE.isDown()) {
|
|
|
leftValue = soundSensorLeft.readRawValue();
|
|
|
rightValue = soundSensorRight.readRawValue();
|
|
|
|
|
|
diff = leftValue - rightValue;
|
|
|
|
|
|
if(diff < 0) {
|
|
|
// Party is to right
|
|
|
right(70);
|
|
|
}
|
|
|
else if(diff > 0) {
|
|
|
// Party is to left
|
|
|
left(70);
|
|
|
}
|
|
|
else {
|
|
|
// Party is straight ahead ( or behind you :( )
|
|
|
forward(70);
|
|
|
}
|
|
|
|
|
|
// Debug info
|
|
|
LCD.drawInt(leftValue,4,0,1);
|
|
|
LCD.drawInt(rightValue,4,0,2);
|
|
|
LCD.drawInt(diff,4,0,3);
|
|
|
|
|
|
Thread.sleep(sampleInterval);
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
We tested by running the program and placed a sound source on the floor and made the robot try find it. The program works rather good. It finds the source after some time. It had some trouble when we placed the robot facing away from the sound source, because then it would move in the wrong direction, but after a while it would turn around. We also had a little trouble with turning left. We were not sure if that was the batteries fault because they were a bit low or maybe the motor power wasn’t high enough. All in all it worked ok. Further work on this would be something to filter out high peak noise, since it affected the robot a bit.
|
|
|
|
|
|
Here’s a [demonstration video](http://1drv.ms/1B4ZW46)[8] showing the robot in action.
|
|
|
|
|
|
!!complex party finder goes here….
|
|
|
|
|
|
We also experimented with a second configuration where the robot had the two sound sensors mounted in different directions; one in front and one at the back.
|
|
|
|
|
|
![New party finder robot configuration with sound sensors on opposite sides.](http://i.imgur.com/KbgeaWcb.jpg)
|
|
|
|
|
|
This setup proved to be much more complex to handle than the setup with two sensors on the front. Since the sensors were not on the same side of the robot the noise level from the motors were different. We had to cancel out the extra noise from the back of the robot by modifying the reading from the back sensor before comparing it to the front sensor.
|
|
|
|
|
|
The main logic of this variant looks is in ```PartyFinder.java```[9]
|
|
|
|
|
|
```Java
|
|
|
|
|
|
motorMode = (soundLeftAvg > soundRightAvg) ? Car.forward : Car.backward;
|
|
|
|
|
|
// Adjust angle based on difference between values.
|
|
|
if (motorMode == Car.forward) {
|
|
|
if (diffAverage < 20) { // move left
|
|
|
powerLeft = 60;
|
|
|
} else if (diffAverage < 40) { // move right
|
|
|
powerRight = 60;
|
|
|
} else { // move straight
|
|
|
|
|
|
}
|
|
|
} else if (motorMode == Car.backward) {
|
|
|
if (diffAverage > -20) { // move right
|
|
|
powerRight = 60;
|
|
|
} else if (diffAverage < 100) { // move left
|
|
|
powerLeft = 60;
|
|
|
} else { // move straight
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Car.controlLeft(powerLeft, motorMode);
|
|
|
Car.controlRight(powerRight, motorMode);
|
|
|
|
|
|
```
|
|
|
|
|
|
The hard part of this configuration was that it was more difficult to determine in which direction the sound source is. One benefit though was that this robot could more easily decide whether the party was behind it or in front of it. To make the sensor readings more stable we calculated an average based on the last 20 readings. This helped avoid sudden spikes that happened from time to time.
|
|
|
|
|
|
Overall the first configuration with two sensors in the front performed much better with a lot simpler code. Here a short [video demonstration](http://1drv.ms/1BQWYnx)[10] of the ComplexPartyFinder.
|
|
|
|
|
|
## Conclusion
|
|
|
Using the sound sensor to control the robot, poses some problems as one need to have some sort of control over the surroundings in order for it to work without errors. High levels of background sounds may offer interference for the sensor which might trigger an unwanted response.
|
|
|
|
|
|
## References
|
|
|
[1], [Exercise material](http://legolab.cs.au.dk/DigitalControl.dir/NXT/Lesson3.dir/Lesson.html)
|
|
|
|
|
|
[2], [SoundSensorTest code](https://gitlab.au.dk/lego-group-8/lego/tree/master/lesson3/SoundSensorTest/)
|
|
|
|
|
|
[3], [Data logger - Wikipedia](https://en.wikipedia.org/wiki/Data_logger)
|
|
|
|
|
|
[4], [SoundSampling code](http://legolab.cs.au.dk/DigitalControl.dir/NXT/Lesson3.dir/Lesson3programs/SoundSampling.java)
|
|
|
|
|
|
[5], [Sivan Toledo, A Clap Counter, Oct 2006.](http://www.tau.ac.il/~stoledo/lego/ClapCounter/)
|
|
|
|
|
|
[6], [ClapControl code](https://gitlab.au.dk/lego-group-8/lego/tree/master/lesson3/ClapControl/)
|
|
|
|
|
|
[7], [PartyFinder code](https://gitlab.au.dk/lego-group-8/lego/tree/master/lesson3/PartyFinder/)
|
|
|
|
|
|
[8], [PartyFinder video demonstration](http://1drv.ms/1B4ZW46)
|
|
|
|
|
|
[9], [ComplexPartyFinder](https://gitlab.au.dk/lego-group-8/lego/tree/master/lesson3/ComplexPartyFinder/)
|
|
|
|
|
|
[10], [ComplexPartyFinder video demonstration](http://1drv.ms/1BQWYnx) |