Technical Papers |
|
| Home>Papers>GP2D02 | |
|
|
Interfacing with GP2D02 sensorsIntroductionOn Dilbert, my fire fighting robotics platform, I use three Sharp GP2D02 Proximity sensors. They are used for wall following and detecting end of walls and passages. The GP2D02 sensor takes approximately 50ms to complete a measurement. The actual time varies with a specified maximum of 70ms. In practice one can poll the return data line of the sensor to determine when it is ready to be read. When the sensor has completed a reading the Vout line is raised. Typically the sensors raise Vout in ~50ms. The exact timing varies with surface reflectivity, distance and other factors. Please refer to the GP2D02 data sheet to learn about the specifics of communicating with the sensors, and the sensor output vs. distance. Note: the GP2D02 is no longer supported by Sharp. However, the linearization formulas, below, will still work with the analog units. Connecting and reading the sensorsTo conserve I/O ports on the Atmel 8515 AVR processor, I multiplexed the sensors by using one I/O bit to be the control line for all sensors and connecting the three return data lines to bits 0, 1 and 2 of an I/O port. The software initiates a reading by dropping the control line, then it polls the three data lines waiting for all three to become 1's (0x07 in my case), then it clocks the data into the CPU. Since the three sensors are connected to sequential bits of a port, the software simply rotate the bits through the carry bit and into their respective destination bytes.
Note, the Sharp sensors require 3v logic on the input pin,, hence R1 and R2. Linearizing and calibrating the output of the sensorsThe sensors have an output curve that is the inverse of the distance of the target. The farther away the target, the lower the output value. The following chart is from the Sharp GP2D02 Data Sheet.
It turns out that the curve has a 1/X relationship. In fact, the formula D = Kg/(X-Ko), where X is the output of the sensor, can give very accurate values for distance. This calibration is easy to perform: it involves one division and one subtract. On Dilbert, the results are calculated in 10th of an inch and returned in a byte value, so the maximum distance that can be measured is ~25". Since the calibration calculation only involves two constants, one can figure out what those are using two measurements from the unit. For details on how I got these formulas, see Derivation Of GP2D02 linearization formulas. For the linearization formula D = Kg/(X-Ko) Kg is the gain, or overall shape of the curve
described by Kg/X Let D and X be the distance and output,
respectively of your first measurement. Kg = (X'-X) D'D/(D-D') For Dilbert, I measured the sensor output at 5" and 20", respectively. That translates into an X and X' of 50 and 200 (10th of an inch). I needed to calibrate each sensor separately. Below are the results for the three sensors on Dilbert. The values for Kg and Ko are similar, but different enough to warrant individual calibration. hardware.inc; With the above numbers the GP2D02 is typically within .2" of the actual distance. At long distances, however, the results are chunkier than .2" so the maximum error does rise a bit. Physical mounting issuesThe case of the sensors is a conductive plastic material. Don't believe me, check it out with an ohm meter. To insure reliable, noise free measurements, make sure you ground the case. If the case is not grounded and there is no target, or the return signal is weak, the sensor sometimes "thinks" there is a target and that it is wandering around. Before I put in a grounded copper (pcb) top plate on Dilbert, the distance sensors would measure anything from 15-25" when there was no target (looking down a long hallway in the fire fighting case). Grounded the sensors became much more stable with reading no target, or targets at long distances (e.g. > 36" away). A second issue is the mounting orientation. At first glance it seems like horizontal makes sense. However, as in the Fire Fighting contest, if you point the sensor towards a corner that is reflective, you can get false readings when the sensor picks up the reflected signal. This was expressed by Dilbert thinking he was much farther away from a wall or end of passage than he really was when nearing or going around corners. The solution to this problem is to mount the sensors in the vertical direction. SoftwareThe following software is for the Atmel AVR processor and is written to the IAR v1.40 assembler. Note, the freeware version of IAR v1.4 is no longer available on the IAR website, however, whatever is there should work fine. Go to products, then to the AVR section. There should be free & demo downloads available there. Sensor is a stand-alone task under the AvrX RTOS, that Dilbert is based upon. The task definition uses the context save/restore fragment from another task to preserve registers R20-R31, SREG and R0. TASK() and TIMER() declarations are macros defined in AvrX.inc. The software routine div16x8u can be found on the Dilbert web page in the file math.asm (Get the zip file of all software). Because the Sharp sensors consume quite a bit of current when running, the task has an Sram flag that it checks before activating the sensors. There must be a better way to do this, but, at the time polling made the most sense, hence the startup code of "Sensor" When activated I want to read the sensor as fast as possible, hence the endless loop of the task. The essence of the multiplexing routine is contained between "WaitUntilReady" and "Cook and store results". Because of the speed of the AVR processors, I needed to introduce some delays when clocking out the data from the GP2D02 sensor. The specifications for the sensor imply a much slower clocking speed but experiments done by others in the SRS have shown that a 10-16us clock period works Ok. The symbol CPUCLK is defined in the file harware.inc and is simply the crystal frequency of the CPU. I use that define when calculating UART divisors and system clock tick values. Then I can change crystals, and one define, and have everything still work when I recompile. If you want to use this code in your own application, just remove the AvrX stuff, replace the delays with hard coded loops and replace the rjmp at the end of the routine with a ret. hardware.inc; Drivers.asm PUBLIC
SensorFlag Front Right Left FrontRaw RightRaw LeftRaw |