cvf06035 created page: Lesson4 authored by Camilla Marie Vinther Frederiksen's avatar Camilla Marie Vinther Frederiksen
## Lab Notebook 4
**Date:** 3rd of March 2016
**Group number:** Group 14
**Group members participating:** Ida Larsen-Ledet and Nicolai Nibe for the first five exercises (Camilla and Emil were absent due to TERRIBLE ILLNESS, so the
two remaining members, fueled by energy drinks and a burning passion for embedded systems, powered through on their own!).
Camilla M. V. Frederiksen and Nicolai Nibe for the 6th exercise on friday the 4th.
**Activity duration:** 5 hours
## Goal
Do not kill Frej (the robot).
Hopefully succeed in making Frej, the robot, follow the black line and stop at the end, when he enters the goal zone (according to the overall goal
description in [lesson plan 4](http://legolab.cs.au.dk/DigitalControl.dir/NXT/Lesson4.dir/Lesson.html).
## Plan
We expect to be able to accomplish the goal by following the instructions in the lesson plan and completing the sub-exercises. As two group members are
missing and Nicolai forgot the charger for his computer, we will be completing the exercises using a mix of pair-programming and division into note-taker
and robot operator.
As usual, we intend to take pictures and videos of the exercises to be used for explanations of our approach and results. No specific person will be in
charge of this - whoever is available and has a recording device at hand will do it. If no one does, we have no idea what we will do, as Camilla is not here
to shout at us.
## Results
### Exercise 1: Testing and calibrating black/white detection
#### Test setup
We implemented a test of **BlackWhiteSensor.java** in the class **RacistCopCalibrationTest.java**. Below is an excerpt of the code:
```java
while (! Button.ESCAPE.isDown())
{
LCD.drawInt(sensor.light(),4,10,2);
LCD.drawString("Black: " + sensor.black(), 0, 6);
LCD.drawString("White: " + sensor.white(), 0, 8);
LCD.refresh();
Thread.sleep(10);
}
```
*Program code 1: The control loop of the RacistCopCalibrationTest class*
Our test was designed to allow us to manually compare the sensor's reading with what could be observed visually. In the loop, the sensor's reading is
checked and the truth values indicating black and white respectively are displayed (as we use strict inequalities, there might actually be a case where
both of the values display false - i.e. when the sensor's reading is the same as the threshold value). However, we accidentally supplied coordinates
that where outside the LCD screen for the white value, and so it wasn't displayed. We decided not to correct this, as it appeared from the displayed black
truth value that the sensor's readings were accurate.
#### Test execution
When calibrating, the robot's value for black was 35 and its reading for white was 58.
We investigated the functioning of the sensor by moving it over a border between black and white. The shift in registered color seemed to happen exactly
when the surface below changed color - the setting of the black/white threshold to the average between the white-value and the black-value thus seems to
be a good threshold.
We then placed the robot on surfaces of different color to see if they registered as black or white. The obtained readings are shown in table 1. The colors
chosen for these readings were the accesible colors of the LEGO robot track placed in the Zuse building.
| Color | Registered color |
| ------ | ---------------- |
| Blue | Black |
| Green | Black |
| Yellow | White |
| Orange | White |
| Red | White |
*Table 1: Colors registrered by the BlackWhiteSensor program when placing it above different colors.*
These results fit well with our results from exercise 2 in [lesson 3](https://gitlab.au.dk/LEGO/lego-kode/blob/master/report_week3.md) where we had the robot
sense different colors.
### Exercise 2: Testing the Line Follower program using the BlackWhiteSensor from exercise 1
In this exercise we loaded the **LineFollowerCal.java** program onto the robot to observe it 'acting' based on the black-white sensor.
The robot was able to identifty the line and follow it, although it had some issues with corners: It handled corners by circling a lot until it hit the line
again. We speculated that increasing the update frequency might help, as the likelihood of the robot checking the color while above the line would then be
greater. Changing the frequency from once per 10 ms to once per 5 ms improved the robot's handling of corners.
The robot appeared to be 'confused' by a grid of colors on the track; however, the reason for this could also just be that the colors were separated by
black lines which were very close to each other. This could be an issue because the robot is constantly turning a little from side to side when driving,
whereby frequently occurring turns might cause it to diverge from its path, since the robot could catch on to a side path if acctidentally turning towards
one. On the other hand, we also saw the robot missing turns on the line: When it encountered a (90 degree) turn on the line, it would just cross it instead of
turning and continuing to follow the line.
[![LineFollower with Calibration](http://img.youtube.com/vi/X11P_-ep1XA/0.jpg)](https://www.youtube.com/watch?v=X11P_-ep1XA)
*Video 1: The robot folloing the black line border with the LineFollowerCal program.*
### Exercise 3: Implementing and testing calibration of three-color detection (black/white/green)
We modified our ***BlackWhiteSensor.java*** into ***ThreeColorSensorNaive.java*** (renamed from ***ThreeColorSensor.java*** in a later exercise) and wrote a
class, ***RacistAlienCopCalibrationTest.java***, to test the sensor implementation.
The ***ThreeColorSensorNaive.java*** class decides if the sensor is reading black, white or green in a similar way to ***BlackWhiteSensor.java***,
except that it has two thresholds, a **blackGreenThrehshold** and a **whiteGreenThreshold**, which are calculated as the average of our
black/green and white/green calibration values respectively. See the code excerpt below.
```java
public void calibrate()
{
blackLightValue = read("black");
whiteLightValue = read("white");
greenLightValue = read("green");
// The thresholds are calculated as the median between
// the two readings that they are supposed to distinguish between
whiteGreenThreshold = (whiteLightValue+greenLightValue)/2;
greenBlackThreshold = (greenLightValue+blackLightValue)/2;
}
```
*Program code 2: The calibrate() method of the ThreeColorSensorNaive class*
The robot displayed true for the correct color and false for the remaining two colors, and so we concluded that it seemed to register the colors correctly.
We also tested what colors the robot registered not-included colors as. The results from this experiment can be found in table 2:
| Color | Registered color |
| ------ | ---------------- |
| Blue | - |
| Yellow | White |
| Orange | White |
| Red | White |
*Table 2: Colors registrered by the ThreeColorSensorNaive program when placing the robot's sensor above different colors.*
Blue registered as false on all three - this is possible because the code uses strict inequalities, which leaves empty "pits" for the check to fall into.
During further testing, blue sometimes registered as green, sometimes as white. If we were to change this in the code, we would need to make a decision on
where to make the cut (i.e. where to introduce equality into the comparison operator). Right now, the robot will simply end in the final else clause, if we
use an implementation like the one in the black-white-line follower without the goal registration.
Furthermore, the robot registers the border between black and white as green. This observation showed us that the robot might misinterpret being on the
border of the line as being in the goal zone. We discussed some ideas on how to amend this for the line-follower with a green goal zone:
- We could decide to only make the robot stop if it has measured green a certain number of times in a row (smoothing)
- We could use a narrower interval for green
### Exercise 4: Implementing and testing line Follower that stops in a goal zone, using the ThreeColorSensor from exercise 3
Initially we wrote a program, **ThreeColorNaive.java** which follows a black line and stops on a green area by using our **ThreeColorSensorNaive.java**
program to decide if it is seeing black, white or green. The results were expectedly atrocious, as seen in video 2: The robot seems to register borders
between black and white as green and thus stops when seen a border. When moved away from the border, it starts searching for the black line again, but
is quickly confused by a border again.
[![LineFollower with Goal Zone, 1st attempt](http://img.youtube.com/vi/MSvhh_LDYcI/0.jpg)](https://www.youtube.com/watch?v=MSvhh_LDYcI)
*Video 2: LineFollower with Goal Zone, first attempt. Here we recognize "green" lower bound as halfway between green/black calibration
value, and its upper bound halfway between green/white calibration values - see program code 2. The robot halts when encountering a border between a black
line and the white surface.*
Since the light value that we calibrated as being "green" lies inbetween the light values seen as black and white (green lies closer to black than
white), our program interprets a certain point, where it sees both some black and some white reflection, as "green". Each time it hits this point between
black and white, the robot will stop. However, as seen in the video, it doesn't immediately do a full stop, since the momentum carried by the motor doesn't
allow it to stop instantly, and by the time it would have reached a full stop, the sensor has swung enough past the "green" zone to no longer be reading a
green value, and will as such start driving again. We utilize this by calling **car.stop()**, rather than breaking the loop - this allows the robot to perform
another reading after its momentum has potentially pushed it onto a black or white surface. Because our green thresholds are very generous, it however doesn't
take very long for our robot to come a full stop.
In an attempt to improve our robot so it only stops on areas that are actually green, we created a modified version of the control program,
***ThreeColorSensorNarrow.java***, which only recognizes a light value as green if it is within +/- 2 of our calibrated green light value (as mentioned in the
discussion at the end of exercise 3; hence the extension *narrow*). If it is not green, it differentiates between black and white in the same way as the original
***BlackWhiteSensor.java***.
```java
public void calibrate()
{
blackLightValue = read("black");
whiteLightValue = read("white");
greenLightValue = read("green");
// The thresholds is calculated as the median between the black and white readings
blackWhiteThreshold = (blackLightValue + whiteLightValue)/2;
}
/*...*/
public boolean green() {
return (ls.readValue() < greenLightValue + 2 && ls.readValue() > greenLightValue - 2 );
}
```
*Program code 3: The ThreeColorSensorNarrow class' calibrate() method and green-check*
```java
while (! Button.ESCAPE.isDown())
{
LCD.drawInt(sensor.light(),4,10,2);
LCD.refresh();
//We have to check for green first, as the green interval is within the black interval
if ( sensor.green() )
//This way, we can simply move the robot to a white/black surface in order to make it start again
Car.stop();
else if (sensor.black() )
Car.forward(power, 0);
else
Car.forward(0, power);
Thread.sleep(10);
}
```
*Program code 4: The control loop of the ThreeColorNarrow class*
The class ***ThreeColorNarrow.java*** uses the *narrow*-sensor, and the resulting behaviour of the robot is seen in video 3.
[![LineFollower with Goal Zone, 2nd attempt](http://img.youtube.com/vi/Bz6aXjhIfmo/0.jpg)](https://www.youtube.com/watch?v=Bz6aXjhIfmo)
*Video 3: LineFollower with Goal Zone, second attempt. Here we recognize "green" upper and lower bounds as its calibration value +/- 2.*
By vastly reducing the interval of light values that are recognized as green, we ensure that the times where the sensor is following the black line
and might read green are so few and temporally spread out that the robot will seem to carry on unphased, due to its momentum sending it forward, onto
a surface with a clearly black or white color.
Potential ways of further preventing the sensor from seeing green when it shouldn't could be to add some counter in the program, requiring it to have
read green a certain amount of times in a row in order to actually tell our robot to stop, as mentioned in the discussion in the end of exercise 3.
This would cause a small delay when entering a green goal zone, but could eliminate most false green positives when folloing our line. However, we didn't
take the time to try to implement this approach.
### Exercise 5: Implementing a PID regulator in the line follower
We used a modified version of ***BlackWhiteSensor.java*** to include a method ***getThrehshold()*** to retrieve the ***blackWhiteThrehshold*** variable
from the calibration, as the calibrated threshold between black and white is the setpoint for our PID regulator. We then proceeded to write a class
***PIDpolice.java*** (don't ask) by basing the PID controller on the pseudo code referenced in the lesson plan [11].
```java
while (! Button.ESCAPE.isDown())
{
LCD.drawInt(sensor.light(),4,10,2);
LCD.refresh();
int error = sensor.light() - setpoint;
int turn = c * error;
Car.forward(targetPower + turn, targetPower - turn);
Thread.sleep(10);
}
```
*Program code 5: Control loop of the PIDpolice class. The variables sepoint, c and targetPower are set earlier in the code.*
For our first attempt, we used a ***targetPower*** of 80 and a scaling value ***c*** of 50 (just to see the effect of it).
This resulted in the robot spinning furiously most of the time, as seen in Video 4.
[![PID C = 50](http://img.youtube.com/vi/gbfT4Hj9My0/0.jpg)](https://www.youtube.com/watch?v=gbfT4Hj9My0)
*Video 4: PID line follower with targetPower 80, and multiplying the error by 50. Robot goes insane.*
The circkling motion resulted from one motor running forward on full speed, while the other was running backwards. This makes sense, seeing as the
scaling value for the error results in a very large value of ***turn***, which is added and subtracted respectively for the motors, resulting in a large
increase (decrease respectively) to the motor power.
When decreasing ***c*** to 1, the behavoiur of the robot improved significantly (for a ***targetPower*** of 80): It followed the line, only fluctuating slightly.
See Video 5.
[![LineFollower PID](http://img.youtube.com/vi/Qp6U7-HSuss/0.jpg)](https://www.youtube.com/watch?v=Qp6U7-HSuss)
*Video 5: LineFollower with PID. Target power: 80, no scaling of the error*
Our reason for including the scaling factor ***c*** was that it was used in the pseudo code. But in their case, the error interval is [-5, 5], which differs a lot from
the interval of possible motor power which is [0, 100]. Thereby, it makes sense to scale the error to have it impact the motor power more appropriately. In our case, however,
the interval for the possible light measurements is [0, 100]. Thereby, our potential error interval is (theoretically) [-100, 100], the same as for the motor power (including
'backwards', i.e. negative, values). This could be the reason that the robot functions so well without any scaling of the error.
### Exercise 6: Color Sensor test
Before starting on this exercise, we exchanged the NXT light sensor with the NXT color sensor.
To test whether this sensor is better at distinguishing between three different colors, than the light sensor, we used the **ColorSensorSensor.java**
program.
We started out by placing the sensor above the same colors that the light sensor was tested on. The obtained results can be found in
table 3. The table includes more than the three colors requested by the exercise description, as this gave us a better idea of what
colors the sensor could distinguish.
| Actual Color | Sensed Color |
| ------ | ---------------- |
| Blue | Blue |
| Yellow | Yellow |
| Orange | Yellow |
| Red | Red |
| Green | Green |
| Black | Green |
| White | White |
*Table 3: Colors of Zuse's LEGO robot track, and the readings from the NXT color sensor, when placed above them.*
We see from our readings that it is not possible to distinguish between black and green, as our color sensor reads a black surface as green.
This further means that it will not be possible to follow a black line and stop when reaching a green Goal Zone, since the color sensor cannot
distinguish between the black line and the green zone. It is of course still possible to follow a black line using the color sensor by basically
programming it to follow a green line, but then we'd have the green goal zone being treated as a black line.
A way to achieve a robot following a black line and stopping in a goal zone, using the color sensor, would be to use a different color for the goal zone.
If our goal zone was blue, yellow or red, we'd be able to distinguish it from the black line with a the color sensor, and there'd be no problem.
After making these rather simple observations about the uncertainty of the color sensor, we noticed that we
in no case got a 'black' reading. Therefore we wondered if such a reading were even possible. Motivated by this
observation we started playing arround with the color sensor. We found out that a black reading was indeed possible
to obtain by measuring out in the open air instead of measuring a colored surface. By this observation we assumed that
a color sensor reading was a measure of how much of the light from the color sensor was reflected by the surface.
Next we tried obtaining black readings of actual black surfaces by finding unreflective black materials. For this
purpose, Camillas jacket was used (se figure 1), and did indeed give a reading of black.
![Camillas jacket](week6/img/IMG_2227.JPG)
*Figure 1: Camillas jacket that gave a black reading when using the color sensor.*
These further experiments with the color sensor leads us to conclude that it will be possible to follow a black
line and stop in a green goal zone if the black lines are made of very matte, light absorbant materials. This means
that it is - as earlier concluded - not possible to follow the black line of the LEGO robot track as these black
lines are too reflective, but it might be possible if using another less reflective track. On the other hand, if we
simply need to follow a black line on a white surface, without ending in a green goal zone, then this sensor might
still function well, as it is able to distinguish white from other colors. And perhaps a goal zone of a different color
than green would also enable ending in a goal zone.
## Conclusion
Despite not investigating many different options in the different exercises, due to shortage of crew members (that darn Kraken!), observations from the exercises still
led to some interesting discussions and insights. One interesting observation, in exercise 6, was that the actual color sensor does not function as well for distinguishing
black as the light sensor. Seeing as black, like white, is sort of a special case of 'colors', in that it is simply the absence of light (if we are talking seriously black black),
it makes sense that a light sensor functions better for the purpose of recognizing it than a color sensor.
It would be interesting to investigate the utilization of both a light sensor and a color sensor, perhaps using one for a double check on the program's interpretations of
the other's readings.
## References
[1] Program made for exercise 1: [RacistCopCalibrationTest.java](src/Lesson4programs/RacistCopCalibrationTest.java)
[2] Program used in exercise 2: [LineFollowerCal.java](src/Lesson4programs/LineFollowerCal.java)
[3] Program for exercise 3: [ThreeColorSensorNaive.java](src/Lesson4programs/ThreeColorSensorNaive.java)
[4] Program for exercise 3: [RacistAlienCopCalibrationTest.java](src/Lesson4programs/RacistAlienCopCalibrationTest.java)
[5] Program for exercise 4: [ThreeColorNaive.java](src/Lesson4programs/ThreeColorSensorNaive.java)
[6] Program for exercise 4: [ThreeColorSensorNarrow.java](src/Lesson4programs/ThreeColorSensorNarrow.java)
[7] Program for exercise 4: [ThreeColorNarrow.java](src/Lesson4programs/ThreeColorNarrow.java)
[8] Modification of **BlackWhiteSensor** program for exercise 5: [BlackWhiteSensor.java](src/Lesson4programs/BlackWhiteSensor.java)
[9] Pid follower for exercide 5: [PIDpolice.java](src/Lesson4programs/PIDpolice.java)
[10] Program used in exercise 6: [ColorSensorSensor.java](src/Lesson4programs/ColorSensorSensor.java)
[11] A PID Controller For Lego Mindstorms Robots: [PID Controller](http://www.inpharmix.com/jps/PID_Controller_For_Lego_Mindstorms_Robots.html)
[12] Video 1: [LineFollower with Calibration](https://www.youtube.com/watch?v=X11P_-ep1XA)
[13] Video 2: [LineFollower with Goal Zone, 1st attempt](https://www.youtube.com/watch?v=MSvhh_LDYcI)
[14] Video 3: [LineFollower with Goal Zone, 2nd attempt](https://www.youtube.com/watch?v=Bz6aXjhIfmo)
[15] Video 4: [PID C = 50](https://www.youtube.com/watch?v=gbfT4Hj9My0)
[16] Video 5: [LineFollower PID](https://www.youtube.com/watch?v=Qp6U7-HSuss)
\ No newline at end of file