Introduction: Make:it Robotics Starter Kit - Analyzing LineFollowing.ino Part 1

About: Software Developer, like to work with electronics, embedded systems, robots etc.

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/

Step 1: 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

Step 2: 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.