I have used an oscilloscope to capture some ultrasonic echoes from a sensor. Right now I'm using the Arduino to send out a command to the sensor and then read in the data. I want to be able to analyze the signal coming in to the Arduino from the sensor to best guess where an object is based on the wave shape. I think I could do this using the pulseIN(pin,HIGH) and pulseIN(pin,LOW) functions to get the basic shape of the different waves. Has anyone done this? Here is an image with 3 waves captured (http://i54.tinypic.com/1zfritx.png). You can tell the object is where the first large .5v grouping is.
You might want to have a look at this project...
http://majolsurf.net/wordpress/?page_id=829
Could you please explain a bit more about what the pulses represent? I cannot tell what is an echo and what is an outgoing ping.
I did a heart rate monitor project with IR oximetry, that produced a fairly jaggy signal that I then needed to find the period of.
This may be a similar problem, in that you want to find the time to the echo.
My approach was to smooth the signal digitally then find the local minima. But that makes it sound a lot harder than it is!
If you download the sketches from here: www.arduinoevilgenius.com, then look at the sketch for project 12, that might give you some ideas.
The sensor will pull the pin down to 0 volts when it sends out a reading pulse. Then wait for the echo and pulls the pin high when it receives an echo. The longer the pin is high the larger the object. As you can see here the sensor has found a large object at a fairly close distance. I have tried using the pusleIN() commands, but this doesn't seem to work good at all. So I've moved the input to an analogue pin and wrote this code. What do you think, I'm still getting some rather inconsistent results.
const int inPin = 6;
const int outPin = 3;
int val, count;
boolean done;
long startTime, endTime, duration, inches;
void setup()
{
Serial.begin(9600);
pinMode(inPin, OUTPUT);
pinMode(outPin, INPUT);
}
void loop()
{
//make sensor take reading
digitalWrite(inPin, HIGH);
delayMicroseconds(3000);
digitalWrite(inPin, LOW);
done = false;
while (done == false)
{
val = analogRead(outPin);
if (val <= 10)
{
startTime=micros();
done = true;
}
}
done = false;
while (done == false)
{
val = analogRead(outPin);
if (val >= 1010)
{
endTime=micros();
done = true;
}
}
duration = endTime-startTime;
inches = microsecondsToInches(duration);
Serial.print(inches);
Serial.print("in, ");
Serial.print(duration);
Serial.println();
delay(500);
}
long microsecondsToInches(long microseconds)
{
return microseconds / 87;
}
The code sets the output pin high for 3 microseconds and then pulls it low starting a reading. I then start reading the analogue signal from the other sensor and when it gets to 10 or lower it grabs a start time. Then the code waits for the pin to get a reading of greater than 1010 and grabs the stop time. The total time is the stop time minus the start time. This is all I'm concerned with now. AnalogRead() works like this, the Arduino will map input voltages between 0 and 5 volts into integer values between 0 and 1023. So I'm waiting for the pin to get very close to 0 volts and then waiting for it to get very close to 5 volts.
Hi,
It looks like your code effectively does the same thing as PulseIn. So then the question is, why are you not getting a pulse of the magnitude and duration close to what you were expecting with the scope.
Are the scope measurements you posted before taken from the analog input of the Arduino? Are you getting 5V pulses there?
I added some code, to print out the value of the analogRead() and it seems that every time it looks for a low the voltage is already set to below the check value of 10 (usually around 8 or 7). Then the code looks for a high. This only prints out 1 value, every 3rd time 2 values, this means that the signal is very short and by the time the code looks the value is already set to high. Is there a way to speed up these checks, I would like to get at least 10 readings before getting a reading above the voltage I'm looking for? My code probably isn't the most efficient ether is there any way to make this work a little better, as we are working with microseconds even the littlest tweak could improve the program greatly.
AnalogRead is quite slow - I think I remember something like 100 uS. So you would be better reading it digitally.
You could keep the code you have but use digitalRead, which I would expect to be 1 clock cycle, the rest of your looping etc will not be adding much of an overhead.
With digital read, it is basically which side of 2.5 V the signal lies, so you may need to use hardware comparators.
But, I think you need more evidence of exactly what signals you are getting from the sensor. Can you put a scope on the analogIn and see what's hapenning?
I changed the program around a little bit. It now takes a bunch of readings and plugs the values into arrays. Then I evaluate the arrays and calculate the start time and end time. This seems to work very well as the code is much more efficient when taking readings. I now get many readings before a valid object is detected.
const int inPin = 6;
const int outPin = 3;
const int readings = 200;
long val [200];
long time [200];
int startVal, endVal, inches;
long duration;
void setup()
{
Serial.begin(9600);
pinMode(inPin, OUTPUT);
pinMode(outPin, INPUT);
}
void loop()
{
//make sensor take reading
digitalWrite(inPin, HIGH);
delayMicroseconds(3000);
digitalWrite(inPin, LOW);
for(int x = 0; x < readings; x++)
{
val[x] = analogRead(outPin);
time[x] = micros();
}
//for(int x = 0; x < readings; x++)
//{
//Serial.print("Value");
//Serial.print(x);
//Serial.print(": ");
//Serial.print(val[x]);
//Serial.print(" Time");
//Serial.print(x);
//Serial.print(": ");
//Serial.print(time[x]);
//Serial.println();
//}
//Find first low
for(int x = 0; x < readings; x++)
{
if(val[x] <= 50)
{
startVal = x;
break;
}
}
//Find large object high
for(int x = startVal; x < readings; x++)
{
if(val[x] >= 1010)
{
if(val[x+1] >= 1010 && val[x+2] >= 1010)
{
endVal = x;
break;
}
}
}
duration = time[endVal] - time[startVal];
inches = microsecondsToInches(duration);
Serial.println();
Serial.print("Inches: ");
Serial.print(inches);
Serial.print(" Duration: ");
Serial.print(duration);
Serial.println();
delay(1000);
}
long microsecondsToInches(long microseconds)
{
return microseconds * .17 - 120;
}