Sharp GP2Y0A02YK Distance Measuring Sensor

References

data sheet: http://www.robotgear.com.au/Cache/Files/Files/33_GP2Y0A02YK0F_ss.pdf

methods for linearisation: http://www.acroname.com/robotics/info/articles/irlinear/irlinear.htm    l

there is an offiical sharp product guide which also defines this method but I cannot find it! Most of these guides are for an older product so make sure you reference and do the maths for the correct  sensor

More help:

Arduino.cc has a lot of guides for implementing and coding sensors and the forum is a gold mine!

Robotics Internet shops often have help and community forums they are also a good resource!

The Sensor

This is the 20cm – 150 cm range sensor I got mine from junon.org ( i have no interest but the price service and delivery were good! and that’s worth a mention ).

Overview

You feed 5V in ,and connect the sensor out to a adc, (analogue to digital converter)  pin on the arduino. The output is inversely proportional to the range sort of. The output is not really linear (straight line ) but there is a published method for doing this, which made my head ache remembering electronic control theory courses. That was a long time ago

Basically this sensor is an LED light source and a measuring unit. The light source is infra red and the measuring unit is designed to limit issues you might have with a straight light sensor. Notice I said “limit”.

Some surfaces are better than others, white A4 paper excellent, not good surfaces to have around, eg shiney black computer case is very stealth, brown cardboard boxes. Angles such as very acute even on white paper is not very good. Passing into light/shadowed areas esp sun light. Glossy dark surfaces are horrid.

Corners also give some issue, as there are reflections but i found you can code for them as they have a distinct signature well usually!

Calibrating and Coding

There are some good tutorials on the sharp range of sensors and there’s clear instructions on how to calibrate and the maths required to determine range from output.

So you need the data sheet for the sensor, it gives you a guide to input output and the relationship between output and range.

However this is only part of the story.

Noise

Like many of the sensors so far, simple code no other devices integrated the sensor is pretty good, as soon as you start arduino code and other devices, driving motors and servos with PWM noise increases, so you need to do some filtering. Now there are other methods for reducing noise and these include using shielding, keeping the wires away from other wires and sources of noise, ie motors servos and away from PCB’s . all these help but the wire only has to move a bit or you increase motor current and things got suddenly get worse. So you may need another form of noise filter

There are a couple of ways you can do this, the two I tried were:

take a number of measurements, The sensor samples at about 40  KHz I found that 20 samples was about right.

  1. mean the 20 samples and then reject top and low 15% and re-average  ( use this if you are resource limited,ie low power arduino or a busy Mega)
  2. Standard deviation reject readings outside 1 SD and re average the remaining.

If too many readings are rejected  reject all and read again.

This worked ok, but still quite inaccurate when used on a robot, hummmm!

I found the mean and reject 15% method better if the robot was moving, but stayed with the standard deviation as this may be required in the future for kalman or other forms of advanced navigation and localisation.

I am using  a Seeeduino Mega and I do not plan to be making many readings on the move, I prefer to stop and scan. I would not consider implementing SD on a less powerful/resourced arduino.

Calibration

Oh well inaccurate, time to calibrate again. Well I tried doing this a several ways but the most effective was disconnect the output of the sensor and measure with a digital multi meter. Using the ADC was just too hard even with SD.

Put some basic code on the arduino which just measures ADC disconnect everything else, make sure your power source is stable and at your nominated voltage level ( fresh batteries)

You get a nice perfect piece of plain white A4 paper. It needs to be perfectly upright and it needs to be square to the sensor. I mount some on a piece of chipboard. Carefully move the paper across the range of the sensor, taking measurements of the DVM and the range.

Plot in excel/calc etc and check against graph in the data sheet it might differ a bit but should be quite close in terms of voltage/dist and should not have to many bumps. If you have bumps go back and measure again.

ADC Conversion

The Analogue to digital converter will produce a digital number that you need to convert back to a voltage. Check the data sheet for your processor/adc. for the arduino i have the ADC ranges over 0-1023 and max voltage in is 5V.

One ADC step is 5V /1023 or 5V/1024

So Vin = ADC reading * ( 5 /1024)

If you are using tables you do not necessary have to convert ADC reading to Vin.

Tables or Calculation

Once you have the measurements you have a choice method to determine range.

On way is to use a table,

setup two arrays one for Vin (voltage from sensor output) and R corresponding range.

if vin is between Vin[next]  and Vin[next +1] then range is between R[next] and R[next+1]

else next +=

loop

I do not think this sensor is worth utilising unless your range resolution is greater than 5cm and better at 2.5.

So this adds issues over the size of the arrays in low power/resourced arduinos.You will never get perfection in electronics and whilst a great deal of effort might be  expended in calibrating and coding your range finder the surfaces you might have to measure off might well be awful.

Calculation

Making a non-linear graph linear

The various guides to using the sharp sensors state a method for making the graph linear and calculating the gradient and konstants. Fairly easy and if you have plotted the graph both excell and calc will find the values for you. However i did some checking of the linearisation and was not happy with the results.

At this stage I was trying to extract objects from the ranging data and I needed the accuracy to be slightly better than it was.

So I did some tests and some research and looked for some curve fitting methods.

First Attempt “sliced straight lines”
i tried because it was quick and dirty was to plot the data and obtain series of best fit lines and change the gradient and offsets
( y = mx +c ) across the graph, this was easy but the accuracy was a bit off still. So having spoken to my son who’s much better at maths than me I looked for a curve fitting solution.

Second Attempt Curve Fitting

Ok so time to dust off the maths, actually I cheated and found a curve fitting site on the Internet. zunzun.com takes your data and when you submit is it asks for some parameters such as algorithm.

(You need to submit data as columns)

I’ve got the plot data and submitted to zunzun.com using the “Marc Plante’s Custom Quadratic With Linear Decay And Offset” , that’s in 2D polynomials, Theres a submission of text data and some options

Data is prepared x for vin and range cm as y ( I’m not going to even try and transpose the formula)

zunzun.com returns a report with a formula and the values for a really good curve fit. I used “scilab” a matlab type engine to check data and curve fit which showed some glitches in the data, corrected resubmit and got this back

y = ( (-b + (b2 – 4 a (c – x))0.5) / 2 / a ) / (d * x) + Offset
Fitting target of sum of squared absolute error = 1.0087491765917592E+02
a = -1.9035009792227321E-10
b = 2.2117131291348640E-04
c = 4.9075752602887955E-02
d = -3.7454750379930721E+00
Offset = 1.2109501295599825E+03

DO NOT USE MY VALUES, I found that small changes made very big differences

arduino code is something like this,

range_value is the result of the noise filter.
if ( range_value >=  0.35 && range_value < 2.4     ) {

float   a = -1.9035009792227321E-10;
float b = 2.2117131291348640E-04;
float c = 4.9075752602887955E-02;
float d = -3.7454750379930721E+00;
float offset = 1.2109501295599825E+03;
float x = ( float ) range_value;
float y = 0;

y =   ( (  -b +  sqrt(sq(b)  –  4 * a * (c-x) ) ) /2    / a )  /  ( d * x ) + offset ;
range = double (y);
if (range > 150) { range = 150 };

The range finder is pretty accurate now, I’m using a seed meg and the code fits well into my resource budget. Again it is not suitable for a low power mcu.

I would not use my values, even a small change will throw the graph way off , use your own.

Tests

Seem to be getting close to -+ 1 cm from ideal surfaces measurements in near to medium range and acceptable out 130 +- 2cm as the scan passes a surface the responses map very well with the angle and distance the object is to the robot.

Conclusion

Idealising filtering or curve fitting is not going to help if the surfaces are not friendly. I did notice in a ROS/willow garage video alot of white panels around desks and started laughing rather loudly, as I knew why! Legs dark voids……

When I tried this, I was trying to extract objects from the range finder data and I needed something more accurate than I had. The curve fitting did help, it was lot better than 5cm tables, and I ‘m sure better than the linearisation, I did n’t actually test with code but doing the maths and spreadsheets I did some graph lookups on data and was n’t happy. But the curve fitting tests actually showed me where i needed to go back to my calibration and re check the vin/range  data. If you are using small occupancy grids you need finer resolution for sensor data. If you are trying to find gaps corners etc and navigate through them reliably then you need the best accuracy you can get.

You do not need to implement the curve fit or filtering on the arduino or even the robot, pass it through to a base PC via bluetooth / wifi and  use the PC ‘s power! I have n’t tried alot of maths in arduino/processing package but python is quite nice for maths. f I need to I will, but at the moment the arduino is well resourced the code is bedded in,  and I want a local range check for my environment.

IR Range finder on ROS

I do not know how well the sharp will stand up for what I want to do in ROS, I’m thinking that the more range data the better for localisation to work properly. I have the range finder mounted on a servo and the 180 degree sweep takes 19 seconds. I am in no hurry so to speak but where I have areas of low reading density i  notice the maps really skew even though odom and range are fairly good.  As I’m not into the maths I am finding it hard to work around the low data rate and usual robot sensor errors. So I’m planning a stereo cam.

pirobot have a demo of pml poor man’s laser doing obstacle avoidance without a map on you tube.

Update rangefinder and ROS

Basically data rate is too slow you need a full update 1cm/1second for gslam to work or your maps are not good!

 

Leave a comment