0
Offline
Jr. Member
Karma: 0
Posts: 66
Arduino rocks
|
 |
« on: June 08, 2011, 10:27:15 am » |
Hey Guys, Let me pick your brain for a minute here. I'm having some trouble getting useful stuff out of this Sharp GP2D120XJ00F. The datasheet for this thing is here: http://www.sparkfun.com/datasheets/Sensors/Infrared/GP2D120XJ00F_SS.pdfI'm connecting it to an Arduino UNO, and it runs on the 5V power line. I've got a few questions about this thing. - Can somebody talk me trough "linearising" the readings from this sensor? (I've read up a bit, but it makes little sense to me)
- The data sheet mentions one should add a 10 (or more) uF bypass capacitor beween Vcc and Ground.
I used a 33uF, 10V tantalium capacitor, but this got pretty hot pretty quick, so I must be doing something wrong. - Does anybody have any idea if it is at all possible to use two of these close together, or is it necesarry to (physically) seperate the sensors?
Thanks in advance, Jim
|
|
|
|
« Last Edit: June 08, 2011, 10:38:52 am by Blue_Boy »
|
Logged
|
|
|
|
|
0
Offline
Faraday Member
Karma: 12
Posts: 2857
ruggedcircuits.com
|
 |
« Reply #1 on: June 08, 2011, 10:41:26 am » |
The simplest way to linearize is to use a lookup table. Declare an array of 256 bytes (say) and for byte 0, store the distance that represents an analog reading of 0 (analogRead() >> 2, so we only look at 256 bytes). For byte 1 of the array, store the distance that represents an analog reading of 1, and so on. Then, to map a reading to distance: distance = lookupArray[analogRead(IR_PIN) >> 2]; I used a 33uF, 10V tantalium capacitor, but this got pretty hot pretty quick, so I must be doing something wrong. Any chance you put it in backwards? Tantalum capacitors are polarized and only go in one way. Does anybody have any idea if it is at all possible to use two of these close together, or is it necesarry to (physically) seperate the sensors? Should be possible, but I'll let others weigh in. -- The Rugged Circuits Yellowjacket: 802.11 WiFi module with ATmega328P microcontroller, only 1.6" x 1.2", bootloader
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Jr. Member
Karma: 0
Posts: 66
Arduino rocks
|
 |
« Reply #2 on: June 08, 2011, 12:17:49 pm » |
So the lookup table - this poses another problem - how does one get the values to store in this lookup table. The graph is not quite precise enough, and doing it by hand / experimentation seems a long and arduous process. I found this info - http://luckylarry.co.uk/arduino-projects/arduino-using-a-sharp-ir-sensor-for-distance-calculation/But I could use some extra background information on the idea, I don't quite understand it enough to modify this to get linear 0 -> 1024 values out of my sensor. About the cap - it was a ceramic one then, because it wasn't polarized.
|
|
|
|
« Last Edit: June 08, 2011, 12:22:06 pm by Blue_Boy »
|
Logged
|
|
|
|
|
Left Coast, CA (USA)
Online
Brattain Member
Karma: 279
Posts: 15316
Measurement changes behavior
|
 |
« Reply #3 on: June 08, 2011, 12:23:25 pm » |
About the cap - it was a ceramic one then, because it wasn't polarized.
A 33ufd ceramic cap? Are you sure? It's hard to believe you found a non-polarized cap of that size. You have made some kind of error in either the cap you selected or how you wired it up. Caps don't get warm or hot if used properly. Lefty
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 90
Posts: 9401
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #4 on: June 08, 2011, 03:06:01 pm » |
Can somebody talk me trough "linearising" the readings from this sensor? (I've read up a bit, but it makes little sense to me) Worked with another sharp distance sensor and wrote the multimap() function just to do that. See - http://arduino.cc/playground/Main/MultiMap - it interpolates linear between points of the graph. More points means less error more processing time. Hopes this helps, Rob
|
|
|
|
« Last Edit: June 08, 2011, 03:08:41 pm by robtillaart »
|
Logged
|
|
|
|
|
0
Offline
Jr. Member
Karma: 0
Posts: 66
Arduino rocks
|
 |
« Reply #5 on: June 08, 2011, 03:21:04 pm » |
I'll upload a picture of that cap in a bit. About the multimap - that looks great! Only problem is, it takes around 300 millis, best case scenario to run the code. I have to run it twice, and also at least 24 times a second. So, that solution will not be fast enough.
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 90
Posts: 9401
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #6 on: June 08, 2011, 04:03:39 pm » |
Only problem is, it takes around 300 millis, best case scenario to run the code. Where does this 300 millis come from? In my indicative test I did 10.000 worst case calls in ~1 seconds so 24 times per second would take approx 2.5 millis..... (from the playground muiltimap article) Performance In a small test with an input array of 14 elements, 10.000 worst case calls took 1003 millis, 10.000 best case calls took 358 millis so on average 1361/2 = 680 micros per call. This performance is most affected by the size of the array it has to search, so the general advice is keep the array as small as possible. Note these numbers are only indicative. Ihave to run it twice, and also at least 24 times a second. Can you explain why you have to make 24++ measurements? Can you tell more about your project? If you need max speed the lookupcode proposed by RuggedCircuits in reply #1 is fastest. The # entries in the array can be as low or large (max 1024) as you want but multiples of makes the simplest math. You can even use 2 (or more) lookuparrays - one with bigger steps for the flat part and one with more steps for the dynamic part. You get something like: int distance(int reading) { if (reading < 256) return lookup1[reading>>1]; if reading < 512) return lookup2[reading>>2]; return lookup3[reading>>4]; } in fact you might combine these three arrays into one (by using an offset) int distance(int reading) { if (reading < 256) return lookup1[reading>>1]; if reading < 512) return lookup1[reading>>2 + 128]; return lookup1[reading>>4 + 192]; }
|
|
|
|
|
Logged
|
|
|
|
|
New Hampshire
Offline
God Member
Karma: 13
Posts: 776
There are 10 kinds of people, those who know binary, and those who don't.
|
 |
« Reply #7 on: June 08, 2011, 04:20:05 pm » |
The following is a much more efficient linearization function than that other link: http://www.acroname.com/robotics/info/articles/irlinear/irlinear.htmlWith a little effort, you can get that formula to work entirely with ints (or longs, depending on the kind of resolution you're looking for, but the resolution on those sharp sensors isn't all that great either way) and it'll run very fast.
|
|
|
|
|
Logged
|
|
|
|
|
Left Coast, CA (USA)
Online
Brattain Member
Karma: 279
Posts: 15316
Measurement changes behavior
|
 |
« Reply #8 on: June 08, 2011, 06:43:45 pm » |
Here is a sketch that I played around with to try and linearize the IR output. It's been awhile sense I used it so I don't recall my success with it, but it is something that might give you a starting point for further development. /* IR distance Analog input, serial output Reads an analog input pin from a sharp IR2D120 analog IR sensor, prints the results to the serial monitor.
*/
// These constants won't change. They're used to give names // to the pins used: const int analogInPin = A0; // Analog input pin that the IR sensor is attached to
int R; int scaled; int avg; int sensorValue;
void setup() { // initialize serial communications at 9600 bps: Serial.begin(9600); }
void loop() { // read the analog in value 10 times to get a stable average reading: avg = 0; for (int i=0; i <= 9; i++){ avg = avg + analogRead(analogInPin); } sensorValue = avg / 10;
R = (29140/ (sensorValue + 5)) -1; // R is millimeters if (R > 350) { // clamp value for out of range readings R = 350;} if (R < 50) { R= 50;}
Serial.print("sensor = " ); Serial.print(sensorValue); Serial.print("\t output = "); Serial.println(R); delay(200); }
Lefty
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 71
|
 |
« Reply #9 on: June 08, 2011, 07:44:44 pm » |
- just a short comment to all the "linearizing functions" mentioned: The one jraskell posted ( http://www.acroname.com/robotics/info/articles/irlinear/irlinear.html) is the only one to use if you want to do it right. All Sharp IR-distance sensors function by the way of triangulation and if you do the math, you will end up with a formula distance = const / ( Measurement + offset). Note that this is an inverse law, not a linear functional relationship. So it is generally not a good idea to use linearized methods for getting distance values out of such a sensor. By the way - for many applications, for example object avoidance, you do not need the distance in cm or inches. You can directly work with the raw measurements. These Sharp sensors are quite fascinating devices - with two servos, you can even turn them into a slow 3D scanner (see attached image). They easily outperform ultrasound devices in terms of resolution. One additional (important) note: these Sharp sensors are power hungry. The datasheet mentions a rather low current - but this is only the time averaged current consumption. The peak current these sensors are drawing when they are firing is immense! So in order to get good results, it helps to have a big capacitor close to the IR-sensors power connectors. Be sure to connect it with the right polarity, otherwise, things might get explosive... Ideally, one pairs this big capacitor with a small capacitor to block high frequency noise as well (Google or any other search engine is certainly your friend here). And be sure to sample the output voltage with the appropriate delay after triggering a measurement... 
|
|
|
|
« Last Edit: June 08, 2011, 07:46:37 pm by cpixip »
|
Logged
|
|
|
|
|
0
Offline
Jr. Member
Karma: 0
Posts: 66
Arduino rocks
|
 |
« Reply #10 on: June 10, 2011, 09:58:22 am » |
Hey Guys, Here's an image of the capacitor, and the way I hooked it up. (except for the fact that the capacitor I used did not seem to have a polarity) I'll tinker a bit with the code you provided me with, and will keep you posted. Thanks, Jim  
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Jr. Member
Karma: 0
Posts: 66
Arduino rocks
|
 |
« Reply #11 on: June 10, 2011, 03:22:51 pm » |
Ok, Here's a little update. Got me some new capacitors, hooked up a big one and a small one (for HF filtering) and this seems to work. I used the formulas found here - http://www.acroname.com/robotics/info/articles/irlinear/irlinear.html. I more or less wrapped my head around the theory. But, when I use the "R = (2914 / (V + 5)) - 1" as proposed at the end of the page, I get almost perfect distance readings in cm. I would like to have them as a value from 0 - 254 though, but since I'm using floating point values, I don't think the map function is working out quite right. Here's my code. unsigned long previousMillis; unsigned long currentMillis;
int sensorPin = A0; float sensorValue = 0; unsigned long sensorValueTotal = 0; unsigned long numberOfSteps = 0; float voltage;
void setup() { Serial.begin(9600); }
void loop() { currentMillis = millis(); if (currentMillis - previousMillis > 40) { sensorValue = sensorValueTotal / numberOfSteps; sensorValue = (2914 / (sensorValue + 5)) - 1; sensorValue = map(sensorValue, 3, 40, 0, 255); Serial.println(sensorValue); //Serial.println(numberOfSteps); numberOfSteps = 0; sensorValueTotal = 0; previousMillis = millis(); } sensorValueTotal = sensorValueTotal + analogRead(sensorPin); numberOfSteps ++; }
|
|
|
|
« Last Edit: June 10, 2011, 03:51:01 pm by Blue_Boy »
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 71
|
 |
« Reply #12 on: June 11, 2011, 05:02:21 am » |
Hi Blue_Boy - nice that it worked out that easy...  Have a look at the reference to the map-function ( http://arduino.cc/en/Reference/Map) - pretty easy to use, I think. As the reference mentions in the appendix, the library version is working with longs; if you want to use your floats, either do an explict cast to long, or, even better, simply implement the formula given in the appendix yourself, with floats. Here's one possibility: float myMap(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } As you want to map to 0-254, your call should read x_new = myMap(x,lowest_distance,highest_distance,0,254); Note that you might want to reject too large and to small distance values coming from the Sharp-sensor, as these units have a limited operating range. As for your capacitor - this is indeed a tantal one, and it has a polarity. Sometimes, there's a really tiny dot or "plus" on one of the legs, sometimes a single leg is slightly longer bend away from the main body of the capacitor. That's the plus pole....
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Jr. Member
Karma: 0
Posts: 66
Arduino rocks
|
 |
« Reply #13 on: June 29, 2011, 04:47:02 am » |
Hey Guys, Here's my code. The analog reads from inputs 0 and 1 are the IR rangers. At the top of the range I get severe jitter though. Are they just that imprecise, or is it a problem in my code? Like suggested, I connected the rangers to capacitors to stabilize the voltage. Also, I take many readings and average them out. Should that not make them more stable? So - any suggestions? unsigned long previousMillis; unsigned long currentMillis;
int numberOfSteps = 0; int sensorValue[6]; long sensorValueTotal[6];
float tempFloat;
// Set calibrate to 255 to disable calibration int calibrate = 255 ; int sensorTop[] = {25500, 27000, 510, 530, 530, 480}; int sensorBottom[] = {3500, 3500, 610, 650, 630, 600};
byte dataStart = 0xFF;
void setup() { Serial.begin(9600); }
void loop() { numberOfSteps ++; currentMillis = millis(); for (int i = 0; i < 6; i++) { sensorValueTotal[i] = sensorValueTotal[i] + analogRead(i); } if (currentMillis - previousMillis > 40) { if (calibrate == 255) Serial.print(dataStart); for (int i = 0; i < 6; i++) { tempFloat = sensorValueTotal[i] / numberOfSteps; sensorValue[i] = (int) tempFloat; sensorValueTotal[i] = 0; // IR Ranger specifics if (i < 2) { tempFloat = (float) sensorValue[i]; tempFloat = (2914 / (tempFloat + 5)) - 1; tempFloat = tempFloat * 1000; sensorValue[i] = (int) tempFloat; } if (calibrate == i) Serial.println(sensorValue[i]); if (calibrate == 255) { /// Only map to 254 because 255 is start byte! sensorValue[i] = map(sensorValue[i], sensorBottom[i], sensorTop[i], 0, 254); sensorValue[i] = constrain(sensorValue[i], 0, 254); Serial.print((byte)sensorValue[i]); } } numberOfSteps = 0; previousMillis = millis(); } }
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 90
Posts: 9401
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #14 on: June 29, 2011, 05:32:21 am » |
|
|
|
|
|
Logged
|
|
|
|
|
|