Obstacle Detection with the Atom and GP2D12

 

By Chuck Hellebuyck

 

On a recent trip to BasicMicro.com I noticed a small Atom based robot platform sitting on a desk. It looked really interesting since it had an infrared detector on the front of it. The detector turned out to be a Sharp GP2D12 detector. I knew very little about that Sharp detector, and they had a data sheet sitting nearby so I quickly scanned it. The sensor outputs a nonlinear signal according to the distance of the object in front of it.

 

 

I asked Nathan, co-owner of BasicMicro if he would show me the Atom code for reading the detector and he did. It was such a short but powerful listing that I asked, is that it? That’s when it hit me; the Atom was doing something I have not seen any Basic Stamp or even a Basic compiler do this easy. I told them, you need to tell people about this. Dale, the other owner, quickly handed me the robot and said, you tell people about it, we don’t have time. They were busy getting the 40pin Atom version ready for release. So here I am writing a quick article to share my excitement.

 

 

First, lets look closer at the Sharp sensor. As the graph GP2D12 graph shows, the output is exponential and senses from a minimum distance of 10cm to a maximum 80cm although it’s difficult to get that full range. My crude measurements with the Atom robot setup gave me a range of 4” to 25”, which was within the specification, and quite a range. The further away the detected obstacle is from the sensor, the less resolution you have. If the obstacle is too close then the output is unreliable.

 

 

The sensor outputs a voltage that ranges from around 0.4volts to 2.4volts. This is easily read with an A/D port, which the Atom has three of. The code listing demonstrates how simple the Atom makes reading this sensor with just a few command lines. This code listing also illustrates some unique capabilities of the Atom module‘s code capability.

Let's look at it in some detail.

 

 

 

First, the Atom code VAR directive is used to establish three variables; “scanrange” which is setup as a word variable, “val” which is setup as a byte and finally the “floating” variable. The "floating" variable is made into a long 32-bit variable because we later perform floating-point math on it. Yes, the Atom performs floating-point math.

 

Next the Atom code establishes the byte table. This is handy and actually I didn’t know you could do this with an Atom. Nathan had established a 100-point table in the original code that didn’t correlate to any specific unit of measure. I took some measurements and then changed the table to contain the conversion values in centimeters that correlated to the A/D readings.

 

In doing the measurements for the table, I found the first 16 values of the table were rarely used.  Some of this is because the A/D input never gets below 0.4 volts even though the A/D register reserves values for below that. That left me 84 useful table values, which was more than enough resolution for making decision based on how far an obstacle is away from the robot.

 

After the table, the main loop of code is entered. The first step is to read the A/D value from the sensor. The Atom makes it easy with a single ADIN command line.

 

adin AX0,2,AD_RON,scanrange

 

AX0 - is the Atom pin connected to the Sharp GP2D12 detector.

2 - is the sampling time for the A/D converter.

AD_RON - establishes right justified 10 bit result.

scanrange - is where the measured A/D result is stored.

 

If you want to understand the Atom A/D converter better, it's best to consult a PIC16F876 data sheet (the Atom is based on that chip). You really don’t have to though because the ADIN command was written to contain all the features in one command line.

 

Once the code has the A/D value in “scanrange”, the program performs floating-point math to reduce the size of our lookup table conversion value. You see, the Atom has a 10 bit A/D register and defaults to a 5-volt reference. That results in a resolution of 5 volts/1024 A/D values (10bits) or 0.0048volts per A/D value. With the maximum input of 2.4 volts, the A/D result would be 491 A/D counts (2.4 volts / 0.0048 = 491.52). Because the output is not linear, we would have to build a 491-byte table.

 

By taking the “scanrange” value and dividing it by 5.12 using floating-point math, we reduce the table required to exactly 200 points. This is because a 10 bit A/D will reserve1024 A/D counts. If we divide the result by 5.12 the maximum A/D count will be 200. And since we are only using half of the A/D voltage range (2.4 volt max / 5 volt A/D Vref = 1/2) we end up needing only a 100 point table. Are you beginning to see why I thought this small Atom code project was so interesting? The variable “floating” stores the floating point math result.

 

 The next line, shown below, converts it back into an integer so we can use it as the operator in an array format. That array is used to look for the proper value in the byte-table we setup at label "scantable".

 

val = scantable(int floating)

 

What I just said might sound a bit confusing. That’s because I described what the Atom code does not what intuitively made sense. You see, I learned something about the Atom from Nathan’s code. When a table is setup, it can be accessed as an array without first establishing an array variable. This simple concept goes beyond anything the Basic Stamp can do and even improves on what some of the higher priced Basic Compilers can do. It works because, each value of a table is a reserved byte just like establishing an array variable with 100 values. Therefore we can access any value in the table with a simple array format. Does it make more sense now?

 

These little tricks are why I told Dale and Nathan that they needed to let people know about this. It’s also why I decided to write this down.

 

I also added an If-Then-Else command to the program so the A/D value that was read could be tested. If it was greater than 100, the table would not have a value. It also indicates that the detector is too close to the object to really trust the reading. If it is greater than 100, the program sends a statement "Too Close To Measure" using the SEROUT command. A terminal window built right into the Atom's development screen displays that with ease.

 

Finally, if the A/D value is within range, the code uses another SEROUT command line to send back both the floating-point result and the scantable result as the distance measured in centimeters (cm). This is the value of the table that corresponds with the measurement between the detector and the obstacle detected. I commented out the DEBUG version for sending the data since I wanted to display it in a terminal window rather than in the debug window of the Atom's development screen. The debug screen is really handy for testing since it allows you to watch the variable values, RAM values, internal register values and step through the program command by command.

 

From these output values we could expand the code to make all kinds of autonomous decisions about where to guide the robot.  Since that wasn’t the point of this quick article it will have to wait for another time. Besides, I just got my first chance to play with the 40 pin Atom so I’m out of time also.

 

If you want more information on the Atom, you can visit my website and www.elproducts.com or the BasicMicro.com website.

 

' -----[ Title ]-----------------------------------------------------------

'

' File...... Range.bas

' Purpose... Atom Module -> GP2D12  IRD

' Author.... Nathan Scherdin and Chuck Hellebuyck

' Started... March 21, 2002

' Updated... April 6, 2002

 

 

' -----[ Program Description ]---------------------------------------------

'

' This program demonstrates how to read the Sharp GP2D12 infrared analog output

' detector with an Atom module and display the results in a terminal window.

 

' Hardware Connections:

'

' Atom Module           Sharp Sensor              

' ------                          --------------------------------    

' AX0                          Pin 1                      

'

'-----[ Variables ]------------------------------------------------------------

 

scanrange var word                 ' A/D result variable

floating var long                      ' Floating point math result storage

val var byte                             ' Table conversion result storage

 

'----[ Table Setup ] ----------------------------------------------------------

scantable bytetable     80,80,80,80,80,80,80,80,80,78, |

                                    76,74,72,70,68,66,64,62,60,59, |

                                    58,57,55,53,52,51,50,49,48,47, |

                                    45,43,42,41,40,39,38,37,35,33, |

                                    32,31,30,30,29,29,28,28,27,27, |

                                    26,26,26,25,25,25,24,24,24,23, |

                                    23,22,22,21,21,20,20,20,19,19, |

                                    18,18,18,17,17,16,16,16,15,15, |

                                    15,14,14,13,13,13,12,12,11,11, |

                                    11,10,10,10,10,10,10,10,10,10

 

'----[ Main Loop ] -----------------------------------------------------------

 

main

            adin AX0,2,AD_RON,scanrange                   ' Read sensor value

            floating = float scanrange fdiv 5.12                 ' Limit value to <200 values

            val = scantable(int floating)                            ' Convert A/D to measurement

            if scanrange > 512 then                                   ' Test for obstacle to close to detector

            serout s_out,I9600,["Too Close To Measure", 13]   ' Send "Too Close" message

            else

'           debug [REAL floating," ",DEC val,13]           ' Output result to debug window

            serout S_OUT,i9600,[REAL floating\2," - ",DEC val," cm",13]      

            endif                                                                ' End If-Then-Else command

           

            goto main                                            ' Loop back and get another reading