Make:it Robotics Starter Kit - Analyzing LineFollowing.ino Part 1
by jpitz31 in Circuits > Robots
1280 Views, 16 Favorites, 0 Comments
Make:it Robotics Starter Kit - Analyzing LineFollowing.ino Part 1
In our last blog post we captured some sensor data from the three different positions that our robot can encounter when following the black line, (left sensor black, left sensor/right sensor white, right sensor black).
In this blog post we are going to take that sensor data and run it thorough our readOptical.py Python program and evaluate what is happening in our lineFollow.ino program.
We are going to look at the following sections of code:
if((sensor_in & 0xf00) == 0)sensorValue1 = sensor_in & 0xff;
else if((sensor_in & 0xf00) >> 8 == 1)
sensorValue2 = sensor_in & 0xff;
if (sensorValue1 == 0x00)action1 = action1 & 0xfe;
if (sensorValue1 == 0xFF)action1 = action1 | 0x01;
if (sensorValue2 == 0x00)
action1 = action1 | 0x02;
if (sensorValue2 == 0xFF)
action1 = action1 & 0xfd;
if(action1 != action2)
{
if (action1 == 3 )
line_following.go_forward(50);
if (action1 == 1)line_following.line_following_turn_left(50);
if (action1 == 2)line_following.line_following_turn_right(50);
if (action1 == 0)
line_following.go_forward(50);
}
action2 = action1;
Our readOptical.py Python program pretty much contains the above code, but also calculates the Bitwise operators and converts the program statements (expressions) to binary so we can easily see what the program is really doing.
Check out my blog for more info:
http://joepitz.wordpress.com/
Python Comes to the Rescue
If you have not do so already, install Python and create the readOptical.py program using your favorite text editor, If you are using Windows, notepad is fine. Create a folder on your computer and place this readOptical.py program in this folder.
I am using Python 2.7, install the latest 2.x of Python from the below web site: https://www.python.org/download/ Here is a YouTube video, how to install Python and include Python in your Path. This is assuming you are running Windows operating system.
In order to run our program we need to start a Command Prompt, (located in All Programs->Accessories-Command Prompt) Launch this program type the following command at the prompt in the window:
You want to change to the location of the folder where you placed your readOptical.py program.
On my computer I created the folder C:\Code\Python\readOptical. So I would type in the following command at the Command Prompt:
>cd \Code\Python\ReadOptical
We are now going to edit our readOptical.py program to include the sensor readings that we wrote down when we captured the sensor data. So using your favorite text editor, edit readOptical.py and edit the below line to include your sensor readings.
We are going to run our readOptical.py two times,
Once with data from our sensors for when both sensors are white and the left sensor black, and a second time with data from our sensors when both sensors are white and the right sensor is black.
This way we can view all of the readOptical.py program output without any data being cut off from the command prompt window.
Edit this line in your readOptical.py program:
optValues = [0xff, 0x100, 0x00, 0x100, 0xff, 0x100]
We have included sensor readings from when both sensors are white, when the sensors on the left sensor is black and again when both sensors are white. The reason we are doing this is the give you a real example of what the robot would see as it is following a line.
First the robot would see both sensors white (robot straddling the black line) then as the circle turns the robot would see the left sensor become black, at which the robot would turn right until both sensors would see white again.
(again I am using Left and Right sensors as I look at the front of the robot.
After editing our readOptical.py program we would type the following at the Command Prompt, (you should be sitting at your folder location where you put your readOptical.py program)
>Python readOptical.py
At this point the program should run and you should see the following output in the Command Prompt. Copy the output and paste it in another Windows Notepad window, so we can look at this in a minute.
If you receive any errors, edit your readOptical.py program. Python is sensitive to indentation, Python uses space indentation to determine how the program should behave when it executes.
If you receive any indentation errors, you are going to have to go back and check that you pasted the readOptical.py program into your text exitor, that you did not move any indentation on any line of code.
Our first program output should look like the following: (attached file)
(just look this over for now, we are going to dig deeper in a bit)
(Also refer to your output, it will be formatted so the columns line up better)
Sensor readings (where black strip is located)Center Left Center C:\Code\Python\readOptical\src>python readoptical.py
Output From ReadOptical.py
Like i said in an earlier blog, I have done all of the math and logic for you, all you have to do is follow along.
Here is your chance to get use to reading binary and hexadecimal numbers. At first is looks like gibberish, but you will get use to it. If you are having problems,
Read the tutorials that I have made reference to in my earlier blog posts.
If you do not want to go into this great of detail then just look for the sections of output where the results indicate either “go forward”, “turn left” or “turn right”
Lets analyze what is happening inside the program:
First off lets look at the comments of the readOptical() method in our lineFollow.ino program:
0x000 optical1 black
0xff optical1 white
0x100 optical1 white
0x1ff optical1 black
0x2XX not ready; don't use this value
Notice that three optical sensor readings start with either 0x1 or 0x2 hex.
The rest start with 0x0 or 0xf. If you convert these numbers to binary you will see a pattern.Load Python Idle and type the following:
>>> format(oxff, ‘#018b’)
The format parameter ‘#018b’ indicates to show the passed number as a binary 16 bit number so the format command will return the following:’0b0000000011111111′
Notice that there are 8 zeros followed by 8 1′s.
This 16 bit number has the least significant 8 bits set to 1.
If you type in the following in Python:
>>>hex(int(’11111111′,2))
You will get:’0xff’
Now lets try the following:
>>>format(0×0, ‘#018b’)
Python will return: ’0b0000000000000000′
Lets try the other two values that the readOptical() function returns.
>>>format(0x1ff, ‘#018b’)
’0b0000000111111111′
>>> format(0×100, ‘#018b’)
’0b0000000100000000′
How many 1′s are shown in the binary representation of 0x1ff?
What position is the 1 in, counting from the right, for 0×100?
Correct, In both cases 1 is showing up in the ninth bit position from the right.
The readOptical() method in the lineFollow.ino only returns values that have a distinct pattern.
Optical 1 sensors only return numbers that are set within 8 bits.
Optical 2 sensors can have numbers that are set in the ninth bit position, or 16 bit numbers.
Let’s start looking at our results from the readOptical.py Python program.
First we look at the variables that are setup in the beginning of the lineFollow.ino program:
sensor _in = 0xff
action1 = 0x0
action2 = 0x0
sensorValue1 = 0x0
sensorValue2 = 0x0
The first sensor value we are reading is 0xff, the rest of the variables are 0x0.
The first If statement performs an BitWise AND on two values:
if((sensor_in & 0xf00) == 0)
Look at the output again:
0xff & 0xf00
0xff = 0b0000000011111111
0xf00 = 0b0000111100000000
if 0xff & 0xf00 == 0
inside if sensor_in & 0xf00 == 00
xff & 0xff
sensorValue1 = 0b0000000011111111
& 0b0000000011111111
——————
0b0000000011111111
sensorValue1 = 0xff
Look closely at the AND bitwise operation, we are checking to see if any of the upper 8 bits of the 16 bit number sensor_in is set.
In this case the AND comparison return 0 as there are no bits greater than the lest significant 8 bits set in the variable sensor_in.
So the first part of the if statement will only be true if sensor_in contains 0x000 or 0xff.
Since the first if statement is true, we execute the command of:
sensorValue1 = sensor_in & 0xff;
ANDing a number with itself gives us the same number, sensorValue1 = 0xff
0xff & 0xff
sensorValue1 = 0b0000000011111111
& 0b0000000011111111
--------------------------------
0b0000000011111111
sensorValue1 = 0xff
Let’s move on to the second if statement:
if (sensorValue1 == 0x00)
If we look at the sensorValue1 variable, it contains 0xff so this if statement is false and does not get executed.
Moving on:
if (sensorValue1 == 0xFF)
sensor_in is equal to 0xff so we execute the if statement:
action1 = action1 | 0x01;
In this case we are setting the variable of action1 to equal action and apply the Bitwise OR operator to the value of 0×01.
Looking at the results of the OR operation action1 gets set to a value of 0x01.
inside of sensorValue1 == 0xff
0x0 | 0x01
action1 = 0b0000000000000000
| 0b0000000000000001
-------------------------------
0b0000000000000001
action1 = 0x1
On the next if statement:
if (sensorValue2 == 0x00)
We check if sensorValue2 is equal to 0x00, and of course currently sensorValue2 is equal to 0x00 so we execute the if statement:
action1 = action1 | 0x02;
inside of sensorValue2 == 0x00
0x1 | 0x02
action1 = 0b0000000000000001
| 0b0000000000000010
-----------------------------------
0b0000000000000011
action1 = 0×3
In the last if statement we check:
if (sensorValue2 == 0xFF)
sensorValue2 is not equal to 0xff so we move on. The final value of action1 is 0×03, we exit the last if statement and proceed on the the next set of if statements:
if(action1 != action2)
{
if (action1 == 3 )
line_following.go_forward(50);
if (action1 == 1)
line_following.line_following_turn_left(50);
if (action1 == 2)
line_following.line_following_turn_right(50);
if (action1 == 0)
line_following.go_forward(50);
}
action2 = action1;
}
action1 = 0x3
action2 = 0x0
We check the first if statement:
if(action1 != action2)
This is true so we enter the nested if statement:
action1 = 0x3
so we execute the true if statement:
line_following.go_forward(50);
Now in our readOptical.py program we return to the top of the for loop and we begin again with the next value: sensor_in = 0x100
action1 = 0x3
action2 = 0x3
sensorValue1 = 0xff
sensorValue2 = 0x0
In this case sensor_in variable is equal to 0x100
Let’s look at the first if statement again:
if((sensor_in & 0xf00) == 0)
sensorValue1 = sensor_in & 0xff;
else if((sensor_in & 0xf00) >> 8 == 1)
sensorValue2 = sensor_in & 0xff;
As we pointed out during the last loop, the first if statement is looking for either 0xff or 0×00.
In this case the if statement is false, so we jump to the else if statement: In this case the if statement is doing a Bitwise AND and a Right Shift 8 bits.
So we are taking the 1 in the 9 bit location and shifting it 8 times to the right,
0×100 = 0b0000000100000000
0xf00 = 0b0000111100000000
--------------------------------------
& 0b0000000100000000
Right Shift
0b0000000000000001
This value does equal 1 so we execute the if statement.
sensorValue2 = sensor_in & 0xff;
0×100 & 0xff
sensorValue2 = 0b0000000100000000
& 0b0000000011111111
------------------------------------
0b0000000000000000
SensorValue2 = 0x0
Moving down the if statements, we check the next if statement:
if (sensorValue1 == 0x00)
sensorValue1 equals 0xff so we skip this if statement. Next if statement:
if (sensorValue1 == 0xFF)
action1 = action1 | 0x01;
The if statement is true so we execute the if statement
inside of sensorValue1 == 0xff
0x3 | 0x01
action1 = 0b0000000000000011
| 0b0000000000000001
----------------------------------
0b0000000000000011
action1 = 0x3
Next if statement:
if (sensorValue2 == 0x00)
action1 = action1 | 0x02;
The if statement is true so we execute the if statement
inside of sensorValue2 == 0×00
0x3 | 0x02
action1 = 0b0000000000000011
| 0b0000000000000010
---------------------------------------
0b0000000000000011
action1 = 0x3
We finish up the if statements and move on the the next set of if statements:
if(action1 != action2)
In this case action1 is equal to action2 so we skip the if statement that sends motor instructions.
We loop back around to the for loop again and select the next sensor_in value.
At this point we have sent the motor driver one set if instructions to go forward, as the sensors are both reading white.
In the next Instructable we will move on reading the sensor values when the left sensor is black.