Tiny little project just to get my head around how to use the Arduino.
So far, I have this:
/* Ping))) Sensor
This sketch reads a PING))) ultrasonic rangefinder and returns the
distance to the closest object in range. To do this, it sends a pulse
to the sensor to initiate a reading, then listens for a pulse
to return. The length of the returning pulse is proportional to
the distance of the object from the sensor.
The circuit:
* +V connection of the PING))) attached to +5V
* GND connection of the PING))) attached to ground
* SIG connection of the PING))) attached to digital pin 6
http://www.arduino.cc/en/Tutorial/Ping
created 3 Nov 2008
by David A. Mellis
modified 30 Aug 2011
by Tom Igoe
This example code is in the public domain.
*/
// this constant won't change. It's the pin number
// of the sensor's output:
const int pingPin = 3;
int ledpin = 11;
int brightness = 0; // how bright the LED is
int fadeAmount = 5; // how many points to fade the LED by
void setup() {
// initialize serial communication:
Serial.begin(9600);
pinMode(ledpin, OUTPUT);
}
void loop()
{
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, inches, cm;
// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
// The same pin is used to read the signal from the PING))): a HIGH
// pulse whose duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
// convert the time into a distance
inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);
Serial.print(inches);
Serial.print("in, ");
Serial.print(cm);
Serial.print("cm");
Serial.println();
//Controlling the LED brightness
if (inches <= 15 && inches >= 2)
{
brightness = map(inches, 15, 2, 0, 255);
}
else if (inches > 15)
{
brightness = 0;
}
else
{
brightness = 255;
}
analogWrite(11, brightness);
delay(50);
}
long microsecondsToInches(long microseconds)
{
// According to Parallax's datasheet for the PING))), there are
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
return microseconds / 74 / 2;
}
long microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;
}
As you can see, this is based heavily (ie: almost entirely) on the ping tutorial included with the program. My addition is towards the bottom.
My problem is that due to the map(), and the reading being in whole numbers, my "fade" of the LED isn't fading so much as stepping. I'd like to have readings to the second decimal place. It'd do a smoother job I think, and is more along the lines of what I'm trying to get out of this exercise.
As you can see, this is based heavily (ie: almost entirely) on the ping tutorial included with the program.
If you don't care about the value in cm, why are you still computing it?
The time taken to send and receive an echo does not limit the sensor to whole inch values. Make microsecondsToInches() return a float, so you get fractions. Of course, you need to fix the arithmetic to make this work.
And, you'll need to get rid of the call to map, and create your own mapping function.
PaulS:
If you don't care about the value in cm, why are you still computing it?
Um, because I hadn't thought about not computing it. No real reason.
PaulS:
The time taken to send and receive an echo does not limit the sensor to whole inch values. Make microsecondsToInches() return a float, so you get fractions. Of course, you need to fix the arithmetic to make this work.
And, you'll need to get rid of the call to map, and create your own mapping function.
I didn't think this was working, but I figured it out. Turns out I forgot to change some Longs to Floats. However, I'm still using the same map function. How was I supposed to make it work with a new rewritten map function?
PaulS:
The map function expects integer input and returns an integer output, so it is rather pointless to use it with floats.
Which longs (there are no Longs) did you forget to change to floats (there are no Floats)?
The longs/floats I was referring to was in the code, not the map function...
When duration, inches and cm were defined in the beginning of the loop, I had left that as Longs, and changed the others to Floats, which made it default to Long results I guess.
As far as the map function, I'd just use the format:
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
long microsecondsToHundredthsOfInches(long microseconds)
{
// According to Parallax's datasheet for the PING))), there are
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
return microseconds * 100000 / 73746 / 2;
}
And there you have your 2 decimal places into inches. But since there are less than 100 micros per inch it would probably be smarter to go by TenthsOfInches, return microseconds * 10000 / 73746 / 2
The Hundredths is good as long as you don't have a ping over 2 seconds. You can go higher by reducing the accuracy of 73.746 microseconds per inch. Notice how that fits in?
OTOH you could figure inches per microsecond to 3 or 4 places and multiply microseconds by that then do what you must to display 10ths or 100ths of an inch. Considering the conversion and speed of sound, inches is already pushing it.
Another idea would be to smooth out the steps, by instead of jumping to the new value, just moving towards the new value in much smaller steps that are not noticable
winner10920:
Another idea would be to smooth out the steps, by instead of jumping to the new value, just moving towards the new value in much smaller steps that are not noticable
That's what the map function was for, but with it only using whole numbers, and only 13 of them, it was too choppy. But I think when I rework the map function to use float numbers, using #.##, it should be much more fluid.
That's on the agenda for tonight.
Realized at lunch today that this simple little setup would work perfectly for a back up system in a car, telling you when you get close down to the nearest hundredth cm.
Realized at lunch today that this simple little setup would work perfectly for a back up system in a car, telling you when you get close down to the nearest hundredth cm.
Even at 2 mph, a delta distance of 0.01 cm is pretty silly, don't you think?
I was just stating what was possible with what I currently have. Just a conceptual statement, not like I have the tools in my hand and heading out the door.
Which, now that i think about it, the ping is only a viable option to 2 cm, so I stand corrected.
I meant more of a smoothing like slowly averaging to the next level, so even if it jumped from 0 to the top it wouldn't just kick on but fade on slowly
Even at 2 mph, a delta distance of 0.01 cm is pretty silly, don't you think?
I was just stating what was possible with what I currently have. Just a conceptual statement, not like I have the tools in my hand and heading out the door.
Which, now that i think about it, the ping is only a viable option to 2 cm, so I stand corrected.
Yah but with cars, 15 cm is about as close as you want to get with twice that (1 foot) being the real "sensed-close".
Conceptually you have the precision of microseconds that the Arduino can give within 4 microseconds. Perhaps 10 usec is as small as you really want to deal with, or maybe 8 goes into 73.4-some more evenly.
You also have that the speed of sound changes with temperature and to a lesser extent, humidity. If you want to be close-measuring as opposed to having lots of digits behind some average then you need to get temperature and humidity or make the occasional calibration to get close measures. I'd go with the occasional calibration regardless but a temperature/humidity sensor to tell you that things have changed and it's time to re-calibrate would be good. Just between noon and 6pm on a summer day can throw your range-finding off.
The map function definition in the reference section shows this:
For the mathematically inclined, here's the whole function
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
To test this, I changed all the "15.00"s to "5.00"s... If brightness was being computed as an INT, and the LED only varies when inches are between 2 and 5, that would only give me 4 variations of light (2, 3, 4, and 5). It looked like it did what I wanted it to, completely varying light.. so I'm counting that as a success.
My question is, is that proper programming? Is that how that should look?
If the to range is fixed, as makes sense for an output to be used with analogWrite(), then the 255 - 0 bit doesn't make sense. Both are constants, so just compute the result and use it.
Similarly for the + 0 bit on the end.
If the from range is going to involve all constants, then get your calculator out, and perform the calculation once.
Yes, I know the compiler will shake its head, and optimize all the stuff anyway, but it makes you look smarter.
Ugh, I feel like I'm going in circles here. I'm ignorant, I'll admit, I do not know what I'm doing, which is why I'm asking questions. I'm not trying to be difficult.
With that being said..
And, you'll need to get rid of the call to map, and create your own mapping function.
Both are constants, so just compute the result and use it.
Which is it? Again, not trying to be an ass, I just honestly do not know.
Is inches now a float?
Is this not how I get inches to the one-hundredth?
If the to range is fixed, as makes sense for an output to be used with analogWrite(), then the 255 - 0 bit doesn't make sense. Both are constants, so just compute the result and use it.
The idea is, that when Inches are 15.00, the LED is set to 0. At 2.00 the LED is set to 255. How do I compute that? With 15 and 2 (notice no .00), the map function worked, but was too 'stepped' in going from 255-0. So, I changed inches to float (in order to get values of #.00 instead of just #), used the math of the map function, but with float numbers.
Similarly for the + 0 bit on the end.
Ok yes, the +0 bit on the end makes me look like an idiot, I admit. But in hindsight, as soon as I would have simplified that math, someone would have asked where I got the number from. I've been down that road before.
I do appreciate the help.. it just seems that I'm more often confused by it than not.
If the to range is fixed, as makes sense for an output to be used with analogWrite(), then the 255 - 0 bit doesn't make sense. Both are constants, so just compute the result and use it.
255 - 0 = 255. Right? It's the - 0 bit that is useless. And, the 255 should be 255.0, to make it a float, so that all the arithmetic is performed using floats.
You could take that last step, or not. The compiler will perform the calculation for you, and it does make it obvious that 15.0 is used twice. At the same time, the values should be #defined with meaningful names