This code is working excellent. But if I remove the sensor or if I fire in free space, the pulseIn() function should return 0 because of the timeout --> Particle Docs pulseIn()
But the function returns values round about 9000.
Can anybody explain me what I’m doing wrong?
Thanks!
I think that in the “open air” you’re probably still getting an echo from something (that’s what I saw when I tested), and without the sensor, the code is probably not set up correctly to work with pulseIn. I tested with no sensor with the following code, and got the expected result.
int trigPin = D0;
int echoPin = D2; // Connected trigPin to echoPin with a wire to simulate the sensor
unsigned long distance;
bool timeToTrigger = true;
Timer intervalTimer(1000*10, timerHandler);
Timer startPulseTimer(10, startHandler, true);
Timer endPulseTimer(3001, endHandler, true);
void setup() {
Serial.begin(9600);
Serial.setTimeout(10000);
Serial.readStringUntil(' ');
pinMode(echoPin, INPUT);
pinMode(trigPin, OUTPUT);
digitalWrite(trigPin, LOW);
intervalTimer.start();
}
void loop() {
if (timeToTrigger) {
timeToTrigger = false;
triggerSensor();
distance = pulseIn(echoPin, HIGH)/5.82; // distance in mm
Serial.printlnf("Distance is: %d ", distance);
}
}
void timerHandler() {
timeToTrigger = true;
}
void triggerSensor() {
startPulseTimer.start();
}
void startHandler() {
digitalWrite(trigPin, HIGH);
endPulseTimer.start();
}
void endHandler() {
digitalWrite(trigPin, LOW);
}
With the values shown, that is a 3001 millisecond pulse, I get 0 for the distance, whereas a value of 2900 gives me a distance of 498,279 mm.
BTW, if you are just removing the sensor, and not changing your code at all, then you have a free floating input on the echo pin which can randomly change between high and low. Are you getting a consistent reading of ~9000 when you test that way?
After Edit: The data sheet for the HC-SR04 says that the pulse width will be 38 ms if there is no return pulse (that is, the device itself times out). I tested mine outside pointing it at a clear sky, and I got 117 ms. So it seems that 38 ms number is not very accurate, but the sensor will definitely time out before the 3 seconds that pulseIn times out.
Thank you four your answer.
I tried out your code but if I connect trigger to D0 and echo to D2 the result is always 0. If I remove the D0-pin I am getting the correct distances.
Yes, thats true. Without the sensor I have values about ~9000.
Okay, the sensor times out before pulseIn() times out. Is there a possibility to check if the sensor has a timeout or is there a solution to set a timeout in the pulseIn()-function (see pulseIn() from Arduino)
That code was just meant to test the timeout behavior of pulseIn(), not for use with the sensor; it shows that the documentation for pulseIn() is correct.
I don't think there's no need to check that; it does have a timeout according to the data sheet. It is supposed to be at 38 ms, but seems to be a lot longer than that on one of my sensors. I have 4 of these sensors, I'll have to test them all, and see if the timeout period varies a lot. If you're getting a maximum number of ~9000, and you're sure that you've pointed it at the open sky, then maybe yours is timing out there. Why you would get 9000 with no sensor, I can't understand without knowing how you tested that. Did you just remove the sensor, and use the same code you posted?
No, there is not a way to do that currently (at least with the exposed api). What exactly is the problem that you're trying to solve? How are you using the sensor? If you're getting 9000 with your sensor at essentially infinite distance, that sounds like there's something wrong with that sensor -- it should give valid values up to about 25,000 microseconds, or a distance of ~14 feet. What range of distances are you interested in measuring?
After Edit: I tested my other 3 devices, and i got readings of 116 ms, 128 ms, and 241 ms with the devices pointed at the open sky, so those should be the timeout values for those sensors.
For my bachelor thesis I have to develop a positioning system with ultrasonic. The idea is that I measure the distance between one sender and multiple receivers. That works already or that is not the main problem.
The main problem is that the sender and receiver have to be synced with each other. My idea is that the sender has a timer of a second. Each second there a three impulses to send ultrasonic signals.
The receiver detect the signals and have three pulseIn in the loop. I measure the time from the first pulseIn to the last pulseIn and calculate the difference. If the difference match with the delay-Time from the sender, the measuring is okay. Otherwise I have to wait for a ultrasonic signal to measure again. And for that I need a working function which detect if no signal was detected.
The receivers loop:
ts_start = millis();
digitalWrite(TriggerPin, HIGH);
delayMicroseconds(100);
digitalWrite(TriggerPin, LOW);
duration1 = pulseIn(EchoPin, HIGH); // first
digitalWrite(EchoPin, LOW);
digitalWrite(TriggerPin, HIGH);
delayMicroseconds(100);
digitalWrite(TriggerPin, LOW);
duration2 = pulseIn(EchoPin, HIGH); // second
digitalWrite(EchoPin, LOW);
digitalWrite(TriggerPin, HIGH);
delayMicroseconds(100);
digitalWrite(TriggerPin, LOW);
duration3 = pulseIn(EchoPin, HIGH); // third
digitalWrite(EchoPin, LOW);
ts_passed = ts_start - millis();
// anybody has a timeout? --> not working
if(duration1 == 0 || duration2 == 0 || duration3 == 0) {
}
With the HC-SR04, the only thing that distinguishes between receiving a pulse vs not receiving one is the width of the high pulse. If that width is >38 ms (according to the docs, though my testing shows it to be much longer than that), then that is defined as no return. You could use that in your code; instead of checking for equality with 0 for your durations, check if they are greater than 38 ms. You can use whatever number you think is best based on what ranges you’re trying to measure; the docs say that it can only measure to ~25 ms, so you could use that number instead, to be a little more conservative.
BTW, if you want a pulseIn like function that has a timeout parameter, it shouldn’t be that difficult to write one yourself. pulseIn is a blocking function, so you don’t need to use interrupts or anything fancy; while loops whose condition is the pin’s state with a check on millis() or micros() in the body for the timeout should do it.
Even though the timing is really short, you could try interrupts:
volatile unsigned long range = 1;
void echoISR()
{
static unsigned long start;
if(digitalRead(ECHO) == HIGH) // rising edge is start of signal
start = micros();
else
range = micros() - start; // falling edge ends it
}
Before you pulse the output, set range to 0, then when range is non-zero, that means it’s done and ready to go again. The timing could easily be set low that way. Just an idea.