Obstacle Detection with
the Atom and GP2D12
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