Go Down

### Topic: linearizing sharp IR sensor graph (Read 6201 times)previous topic - next topic

#### ahhreeyell

##### Mar 27, 2011, 11:39 pm
Hello,

I have a Sharp IR sensor, and as you can see here, the relationship between the voltage produced and the distance sensed is logarithmic: http://www.danshope.com/blog/images/irSensor1.png
I want to make this relationship linear, i.e., the further the object is, the lower the voltage.
I've also been playing around with code and wiring, trying to figure things out, but to no avail thus far. Here is what I have so far. Any suggestions?

int sensorvar = 0;
int led = 9;
int outputValue = 0;
int d = 0;
double linear = 0;

void setup(){
pinMode(led, OUTPUT);
Serial.begin(9600);
}

void loop(){

d = map(sensorvar, 0, 1023, 20, 150);
linear = 1 / ( d + 0.42 );
outputValue = map(linear, 20, 150, 0, 255);
analogWrite(led, outputValue);
Serial.print("sensor value:");
Serial.println(linear);

delay(500);

}

#### robtillaart

#1
##### Mar 27, 2011, 11:47 pmLast Edit: Mar 27, 2011, 11:50 pm by robtillaart Reason: 1
I wrote a library just to handle this: - http://arduino.cc/playground/Main/MultiMap -

my sample code - you need to update the arrays used as these are 20-150 cm,  I callibrated the arrays with a measure stick (steps of 10 cm) you might do in in steps of 1 cm. but they don't need to be equidistant

Code: [Select]
`// //    FILE: SharpDistanceSensor//  AUTHOR: Rob Tillaart// VERSION: 0.1.01// PURPOSE: Demo SHARP 2Y0A02 F 9Y - distance sensor //// HISTORY: // 0.1.00 - 2011-01-22 initial version// 0.1.01 - 2011-01-24 improved multimap// Released to the public domain//#define RED    4#define GREEN  5void setup(){  Serial.begin(19200);  pinMode(RED, OUTPUT);  pinMode(GREEN, OUTPUT);  analogReference(EXTERNAL);    Serial.println("Demo SHARP 2Y0A02 F 9Y - distance sensor");  Serial.println();    Serial.println("TIME\tRAW\tCM");  Serial.println();}void loop(){  long raw = sharpRawAvg();  int mm = sharp2mm(raw);  Serial.print(millis());  Serial.print("\t");  Serial.print(raw);  Serial.print("\t");  Serial.print(mm);  Serial.print("\t");  for (int i=50; i<mm;i+=10) Serial.print("]");    if (mm > 750) digitalWrite(GREEN, HIGH);  else digitalWrite(GREEN, LOW);  if (mm < 850) digitalWrite(RED, HIGH);  else digitalWrite(RED, LOW);//  if (cm < 40) //  {//    digitalWrite(RED, HIGH);//    delay(cm/2);//    digitalWrite(RED, LOW);//    delay(cm/2);//  }  Serial.println();}/////////////////////////////////////////////////////////////////////////// SAMPLE FUNCTIONS// // multisample version// as the sensor is not very steady in its reading // doing 128 samples smooths the reading.unsigned int sharpRawAvg(){  unsigned long raw = 0;  for (byte i=0; i<32; i++)  {    raw += analogRead(A0);    //delay(1);  }  return raw/32;}// running average version// use of 1024 == 10 bit shift //    + configurable ~1/1000//    + no floatsunsigned int sharpRawRA(){  static unsigned long value = 0;  unsigned int a = 950;  value = (a * value + (1024-a) * analogRead(A0)) /1024;  return (unsigned int) value;}/*TABLE OF MEASUREMENTSCM    RAW      DELTA150   91 91 140   97 6 130  105 8 120  113 8110  124 9100  135 1190   147 1280   164 1770   185 2160   218 3350   255 3740   317 6230   408 9120   506 98*/int sharp2mm(int val){  int out[] = {1500,1400,1300,1200,1100,1000,900,800,700,600,500,400,300,200};    // calibration 17-01  // internal reference 5,00 Volt  // factor 1.0  // range = 416  int in1[]  = { 90, 97,105,113,124,134,147,164,185,218,255,317,408,506};    // (quick) calibration 24-01 (colder?)  // internal reference 5,00 Volt  // factor 1.0  // range = 396  int in2[] = { 87, 93,100,108,116,126,139,157,177,197,231,304,384,483};    // (quick) calibration 24-01  // external reference of ~3,07 V  // factor 1,6243 * _in2[]  // range = 644  int in3[] = {141,151,162,178,193,205,229,256,287,320,375,494,624,785};    return multiMap(val, in3, out, 14);}/////////////////////////////////////////////////////////////////////////// MULTILMAP FUNCTION// int multiMap(int val, int* _in, int* _out, int size){  val = constrain(val, _in[0], _in[size-1]);    // handle first value separately  if (val == _in[0]) return _out[0];  // search right interval  int pos = 0;  while(val > _in[pos] && pos < size) pos++;  // interpolate  return map(val, _in[pos-1], _in[pos], _out[pos-1], _out[pos]);}int sharp2cm2(int val){  val = constrain(val, 90, 506);  int _in[]  = {0,  90, 97,105,113,124,134,147,164,185,218,255,317,408,506};  int _out[] = {0, 150,140,130,120,110,100, 90, 80, 70, 60, 50, 40, 30, 20};  int size = 15;  int pos = 0;    while(val > _in[pos] && pos < size) pos++;  return map(val, _in[pos-1], _in[pos], _out[pos-1], _out[pos]);}`
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### MarkT

#2
##### Mar 28, 2011, 01:41 am
Just for completeness:  that's not a logarithmic relationship, its a reciprocal one.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

#### robtillaart

#3
##### Mar 28, 2011, 01:29 pm
Quote
Just for completeness:  that's not a logarithmic relationship, its a reciprocal one.

It is not reciprocal  - although the approximation formula is - I put measurements (see previous sketch)  in a spreadsheet and let it determine the formula but it allways misfit somewhere in the range. That's why I used multiMap(). And yes, it is an approximation too, but by adding extra points it can decrease the maximum error.

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### johnwasser

#4
##### Mar 28, 2011, 03:14 pm
It looks like the maximum value is near 512 which would be a voltage of about 2.5 volta.  You could get about 50% more resolution by connecting the ARef pin to 3.3v and selecting analogReference(EXTERNAL).  Then the max value would be closer to 775  (1024 * 2.5/3.3).
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

#### cpixip

#5
##### Mar 28, 2011, 04:25 pm
... just for completeness (): the way the Sharp IR-sensor is working actually leads to a reciprocal relationship.

These sensors are based on triangulation, where a tiny IR light spot is "seen" by a position sensitive device from a slightly different perspective. The perspective shift induced by this on the PSD (position sensitive device) is in fact proportional to 1/z, with z being the distance of the object seen. This can be easily derived by drawing the basic geometry of such a setup on a piece of paper and utilizing similar triangles.

Deviations from the reciprocal relationship are due to the simple sensor design. Even so, these devices are much more precise than your usual ultrasound ranger; you can even use them for 3D scanning (I have attached an example of such a scan below this post).

Another remark: even so these sensors are rated at 30mA or so, they draw much more current when "fireing" - this can lead to heavy spikes on the power supply. It's a good idea to use an appropriate capacitor as close to the sensor as possible (see http://www.robotroom.com/DistanceSensor3.html for example).

Go Up