Ultrasonic distance sensor HC-SR04 lack of timeout problem

Slimicus:
I’m using the HY-SRF05 (the one from Upgrade Industries sold by robot-electronics,) which I bought because they stated it is supposed to time out and it doesn’t time out.

After my last post here I bought an HY-SRF05 also, and it seems to work fine… I mean, if it timeouts I get a 0 cm distance most of the times, but without the long delays you’re complaining about. Don’t know if yours is an issue of a somehow “buggy” series…

Please note I said “most of the times” returns zero, because mine has a small quirk: it seems to return an anomalous 3 cm distance alternated to (correct) zero, so I return “0” if current measure is 3 cm and the previous one was 0. And it worked fine this way.

So, the reason why I delayed this reply to original post is I made a library to help me (and anyone with the same problem too) manage either SR-04 or SRF-05 idiosyncrasies…:slight_smile: I hope you enjoy it, but I’ll appreciate any feedback as I’m open to any suggestions and critics… :wink:

Please note the class is called SRF05, but it works with both SRF05 and SR04.

After installing the library, open the example:

// SENSOR DEMO
#include "SRF05.h"

// trigPin, echoPin, MaxDist, readInterval
SRF05 Sensor(6, 7, 200, 500);

void setup() {
    Serial.begin(9600);
	// If using SR04 enable the following line:
	//Sensor.Unlock = true;
}

void loop() {
    // Distance read
    if ( Sensor.Read() > -1 ) {
        // New distance reading!
        if ( Sensor.Distance == 0 ) {
            Serial.println("Out of range");
        } else {
            // -------------
            Serial.print("Dist: ");
            Serial.print(Sensor.Distance);
            Serial.println(" cm");
        }
    }
}

As you can see, we simply create an SRF05 object with needed configuration parameters:

  • TrigPin: digital pin for Trig
  • EchoPin: digital pin for Echo
  • MaxDist: max measuring distance (cm); optional, default=300 (3mt)
  • ReadInterval: interval between measures(millis); optional, default=0

The first two don’t need particular explanations I hope, while the third simply specifies the maximum distance we want to measure, usually not higher than sensor range.
ReadInterval makes it easy to manage reading intervals without a specific timer: usually we don’t check the distance on every loop() call, so set ReadInterval to the desired milliseconds and the library will do the job for you.

This way, the loop() calls only the “Read()” method: it returns measured distance in centimeters but if called before “ReadInterval” milliseconds after the last read, it returns “-1” meaning “it’s not the time!”. 8)
If called after ReadInterval milliseconds or more, performs a new ping and returns the updated distance. If the sensor doesn’t read obstacles within the range (no echo or echo after “MadDist” cm), the Read() method returns zero.

If for any reason you need to continuously read the distance, simpy set ReadInterval=0 and each Read() call will ping the sensor.

Apart from Read(), some public properties are available anyway, including constructor parameters and latest measured distance:

  • int TrigPin;
  • int EchoPin;
  • long MaxDistance;
  • long ReadInterval;
  • long Distance; // Last Read()

Library version 1.1 (attached one) includes a workaround for “locking” SR04 sensors when no echo is received. To enable this feature simply set “Unlock=true;” inside “setup()”, as shown in the example.

SRF05.ZIP (4.83 KB)

I also had the problem that the sensor stayed HIGH when it couldn't reflect anything. I tried to solve the problem through switching the Arduino ECHO input into output mode and setting it LOW, like docdoc it adviced. But this didn't help. The direct power connect of the sensor to a Arduino output like mjbmikeb wrote worked either. It didn't hung but didn't also measure at all. The only thing that helped was what SaintGimp wrote, to power the sensor over a transistor and switch that shortly off if the sensor hangs. Nevertheless thanks to all for your effort.

Yep, that's why I bought an SRF-05 and I'll never buy SR-04 anymore...

I had the same problem, but docdoc’s solution worked for me.

Thanks docdoc!

You're welcome, I'm happy to see someone else solved this problem with this "too chinese" SR04! ;D

Btw, just to know, did you included my SRF05 library (and used Unlock=true) or changed your code?

Or, you could use the NewPing library which has this and many other advantages (smaller code size, one pin mode, timer interrupt method, etc.).

Tim

Are you sure NewPing fixes SR04 "lockout" on echo timeout? I have seen nothing about this in its docs...

docdoc: Are you sure NewPing fixes SR04 "lockout" on echo timeout? I have seen nothing about this in its docs...

That was the primary reason NewPing was written 3 years ago. It's evolved from there. This feature is listed as bullet item #3 in the introduction:

Doesn't lag for a full second if no ping echo is received like all other ultrasonic libraries.

NewPing

Tim

teckel: That was the primary reason NewPing was written 3 years ago. It's evolved from there. This feature is listed as bullet item #3 in the introduction: Doesn't lag for a full second if no ping echo is received like all other ultrasonic libraries.

Yeah, but i think you haven't got the point, that's not the problem I'm talking about (and solved with my lib)...

My SR04 sensor(s) doesn't simply "lag for a second" if no echo is received, it completeliy LOCKS UP, returning 0ms for all and every subsequent reads, until turned off and on, as suggested in other topics (using a pin to control a transistor to simulate physical disconnection of SR04 power cable). I still don't know if my SR04 (and the one used by many other users here) is a faulty series, or made by a "too-much-chinese" factory, by the way the problem was real and NewPing didn't solve it. After trying with 3 different SR04, I decided to buy SRF05 from now on, btw SF04 is a bit cheaper and I wanted to use them for low-purpose projects, and with my SRF05 library I have full control over it, without any hardware change!

docdoc: Yeah, but i think you haven't got the point, that's not the problem I'm talking about (and solved with my lib)...

My SR04 sensor(s) doesn't simply "lag for a second" if no echo is received, it completeliy LOCKS UP, returning 0ms for all and every subsequent reads, until turned off and on, as suggested in other topics (using a pin to control a transistor to simulate physical disconnection of SR04 power cable). I still don't know if my SR04 (and the one used by many other users here) is a faulty series, or made by a "too-much-chinese" factory, by the way the problem was real and NewPing didn't solve it. After trying with 3 different SR04, I decided to buy SRF05 from now on, btw SF04 is a bit cheaper and I wanted to use them for low-purpose projects, and with my SRF05 library I have full control over it, without any hardware change!

Sounds like you have a faulty sensor. Obviously, it shouldn't stop working if it doesn't get a ping echo. I have dozens of sensors, and none do that. But, sounds like testing the state of the echo pin when a 0ms ping is received and if it's locked up cycling power to the sensor seems like the simple thing to do.

There's no need for a transistor to power the sensor to do this, the sensor doesn't draw much power so you can supply power directly from an Arduino pin. Using my NewPing library and the one pin method, you could probably still control the sensor with just two pins (one for power and one for trigger/echo). I do this with a ultra low power sensor that combines a PIR sensor and an ultrasonic sensor. The PIR sensor detects motion, and if detected it activates a pin which turns on the ultrasonic sensor to get a distance measurement. Not only does this reduce the power used to a trickle (using a pin interrupt), it also allows for a mostly passive sensor (except for the distance measurement).

Anyway, if this is just a defective sensor, I would think getting a working sensor would be the correct solution (as they cost about $1). If there's a model of sensor that does this by design (not sure why), I would like to have one so my library could be modified to accommodate it. It seems testing pin state when getting a 0cm result and cycling power would the easy thing to do. Or something simple like this which is done after a ping:

  if (cm == 0 && digitalRead(ECHO_PIN) == LOW) {
    pinMode(ECHO_PIN, OUTPUT);
    digitalWrite(ECHO_PIN, LOW);
    delay(100);
    pinMode(ECHO_PIN, INPUT);    
  }

But, there's really no way for NewPing to be modified if no one can source a sensor that has this problem. Also, there's a question of if anything should be done if it's just a defective sensor. Heck, I'm not even sure the sensors are defective, maybe some people are just doing something else incorrectly. In any case, can't know and can't really attempt to fix a problem that doesn't exist (at least for me).

Tim

Yep, Tim, I agree it'd be a faulty sensor series (I already said I suspect the sensor is "too-much-chinese", no? :-) ), even if I have 3 of them, bought from two different ebay stores (none of them chinese), but other users also reported the same issue I experienced, so it's not so rare. So I solved definitely the problem buying some SRF05 instead of the cheaper SR04, but I wanted to make my library still compatible.

If you agree, I'd like to contribute to NewPing by suggesting you to add a workaround for those "faulty" sensors, to let it cover even such "chinenest" :-) ones: if SR04 is in this "locked" state it always returns zero "pulse duration" immediately, so this is what you could track down. This is the code portion of my workaround (looks similar to yours, I use "pulseDuration" variable you use "cm"), where the feature si activated if "Unlock" public variabile is set to true:

if ( Unlock && pulseDuration == 0 ) {
  // SR04 unlock
  pinMode(EchoPin, OUTPUT);
  digitalWrite(EchoPin, LOW);
  delay(100);
  pinMode(EchoPin, INPUT);
}

As I see no similar solution inside NewPing, I think you could include it in next NewPing release, if you want to. And adding an explicit reference to this issue, and how to fix it by setting "Unlock=true".

docdoc:
Yep, Tim, I agree it’d be a faulty sensor series (I already said I suspect the sensor is “too-much-chinese”, no? :slight_smile: ), even if I have 3 of them, bought from two different ebay stores (none of them chinese), but other users also reported the same issue I experienced, so it’s not so rare. So I solved definitely the problem buying some SRF05 instead of the cheaper SR04, but I wanted to make my library still compatible.

If you agree, I’d like to contribute to NewPing by suggesting you to add a workaround for those “faulty” sensors, to let it cover even such “chinenest” :slight_smile: ones: if SR04 is in this “locked” state it always returns zero “pulse duration” immediately, so this is what you could track down. This is the code portion of my workaround (looks similar to yours, I use “pulseDuration” variable you use “cm”), where the feature si activated if “Unlock” public variabile is set to true:

if ( Unlock && pulseDuration == 0 ) {

// SR04 unlock
  pinMode(EchoPin, OUTPUT);
  digitalWrite(EchoPin, LOW);
  delay(100);
  pinMode(EchoPin, INPUT);
}




As I see no similar solution inside NewPing, I think you could include it in next NewPing release, if you want to. And adding an explicit reference to this issue, and how to fix it by setting "Unlock=true".

NewPing uses all port registers so that inside the library wouldn’t be correct. But, anyone could easily add the code I provided outside the library in their sketch. Basically use NewPing as normal, but test for an invalid state and cycle the sensor (either by just cycling the power to the sensor or using the above method).

Doing it inside NewPing poses a few problems. First, in the attempt to be as fast and small as possible, adding additional code for broken sensors seems a bit unwarranted. Also, as NewPing has methods which create event-driven pings, having something that breaks that for 100ms would also break your sketch or the ping polling process if multiple sensors are being pinged. This would require the user to add additional code to their sketch to deal with this situation.

Instead, it seems more logical for the user to simply add a couple lines of code in their sketch if they happen to have a defective sensor and don’t want to get a replacement. Code in their sketch would be required anyway if they were polling multiple sensors in the background as I would hightly suggest anyway.

Then there’s the problem of not having a defective sensor to be able to test any type of possible modification to the library. Just dropping in some code that’s not tested doesn’t sound like the best idea. Especially when using the ping_timer() method and associated sketches for multiple sensors in the background.

Anyway, here’s what I would suggest doing for those that have a defective sensor and are using NewPing:

#include <NewPing.h>

#define TRIGGER_PIN  12  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     11  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

void setup() {
  Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
}

void loop() {
  delay(50);                     // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
  unsigned int cm = sonar.ping_cm();
  Serial.print("Ping: ");
  Serial.print(cm); // Send ping, get distance in cm and print result (0 = outside set distance range)
  Serial.println("cm");

  if (cm == 0 && digitalRead(ECHO_PIN) == LOW) {
    pinMode(ECHO_PIN, OUTPUT);
    digitalWrite(ECHO_PIN, LOW);
    delay(100);
    pinMode(ECHO_PIN, INPUT);    
  }
}

Just use the standard NewPing library as normal, but do a check for a bad state for your defective sensor and do the reset. If this works, I can add a Wiki page for NewPing for people if they have a defective sensor that just shows a distance of 0 after getting no ping echo.

Again, I can’t test this as all of my sensors work. But, if someone could confirm this works, I’ll be more than happy to build a Wiki page devoted to defective sensors.

Tim

I have some of these HC-SR04 sensors. They are not all identical. I actually run them in a sensor off an ATTiny85.

I would like to test for the fault being discussed. Could someone please: - post the minimal code that reveals the fault/problem - describe the setup you are using - how to check for the error

TIA.

aisc:
I have some of these HC-SR04 sensors. They are not all identical.
I actually run them in a sensor off an ATTiny85.

I would like to test for the fault being discussed.
Could someone please:

  • post the minimal code that reveals the fault/problem
  • describe the setup you are using
  • how to check for the error

TIA.

Using the NewPing library use the following sketch:

#include <NewPing.h>
NewPing sonar(11, 12);  // Trigger pin, echo pin.
void setup() {
  Serial.begin(115200);
}
void loop() {
  delay(50);
  Serial.println(sonar.ping_cm());
}

Sensor is connected to power, ground, pin 11 to trigger, and pin 12 to echo. Monitor the distance measurement via the Serial Monitor in Arduino IDE.

To test for defective sensor, run the above sketch and you should get distance readings. Then, point it in a direction it won’t get an echo (nothing at least 5 meters away). This will correctly give a zero (0) reading on the serial monitor. Then, point the sensor back at something close to the sensor. If the sensor is defective it will continue to report a zero (0) reading no matter where you point the sensor. A working sensor will show zero (0) when there’s no echo, but then show a reading when pointed towards something within close proximity.

I have over a dozen ultrasonic sensors, and all work correctly. However, others have reported that they have many sensors and all fail using the above test.

Let me know if you have any questions.

Tim

teckel: To test for defective sensor, run the above sketch and you should get distance readings. Then, point it in a direction it won't get an echo (nothing at least 5 meters away). This will correctly give a zero (0) reading on the serial monitor. Then, point the sensor back at something close to the sensor. If the sensor is defective it will continue to report a zero (0) reading no matter where you point the sensor.

Exactly, this is my SR04s behavior. None of them are working, thus becoming almost useless. Unless I try to "recover" that deadlock, by either temporarily "physically" turning off the SR04, or with that software workaround I implemented in my SRF05 library.

By the way tonight I replaced my last SR04 with an SRF05 from one of my projects, so I'll definitely throw that away. I'm gonna buy a couple of SRF05 just to have a spare, I won't buy SR04 anymore,

Sensor is connected to power, ground, pin 11 to trigger, and pin 12 to echo. Monitor the distance measurement via the Serial Monitor in Arduino IDE.

To test for defective sensor, run the above sketch and you should get distance readings. Then, point it in a direction it won't get an echo (nothing at least 5 meters away). This will correctly give a zero (0) reading on the serial monitor. Then, point the sensor back at something close to the sensor. If the sensor is defective it will continue to report a zero (0) reading no matter where you point the sensor. A working sensor will show zero (0) when there's no echo, but then show a reading when pointed towards something within close proximity.

I have over a dozen ultrasonic sensors, and all work correctly. However, others have reported that they have many sensors and all fail using the above test.

Let me know if you have any questions.

Tim

Thanks for the concise instructions. Now I just have to find somewhere with 5 metres of nothing - a tall order where I am :)

Well of my total of 5 sensors, I have 3 on hand and tested them. None have any problem being pointed to "infinity" (showing 0) then to something within range and displaying the distance.

Guess I must have gotten some from a "good batch" :)

I have saved the sketch as a "testing tool" - handy to have when buying more. Thanks Tim.

Tim I have tried your code with no avail. copied it directly.

#include <NewPing.h>

#define TRIGGER_PIN  12  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     11  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

void setup() {
  Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
}

void loop() {
  delay(50);                     // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
  unsigned int cm = sonar.ping_cm();
  Serial.print("Ping: ");
  Serial.print(cm); // Send ping, get distance in cm and print result (0 = outside set distance range)
  Serial.println("cm");

  if (cm == 0 && digitalRead(ECHO_PIN) == LOW) {
    pinMode(ECHO_PIN, OUTPUT);
    digitalWrite(ECHO_PIN, LOW);
    delay(100);
    pinMode(ECHO_PIN, INPUT);    
  }
}

Once the sensor returns to 0 (no echo) when something is in front of the sensor. it does not reset. Am I missing something?
thank you

docdoc: Exactly, this is my SR04s behavior. None of them are working, thus becoming almost useless. Unless I try to "recover" that deadlock, by either temporarily "physically" turning off the SR04, or with that software workaround I implemented in my SRF05 library.

By the way tonight I replaced my last SR04 with an SRF05 from one of my projects, so I'll definitely throw that away. I'm gonna buy a couple of SRF05 just to have a spare, I won't buy SR04 anymore,

Could I have one of the defective SR04 sensors? With it I could test and implement a deadlock recover in the NewPing library.

Also, if you have multiple sensors you're using in the same project, have you considered using the ping_timer() method with NewPing? It would allow your sketch to never need to wait for the pings to process as it does everything in the background.

Tim

aisc:
Thanks for the concise instructions. Now I just have to find somewhere with 5 metres of nothing - a tall order where I am :slight_smile:

Do you have “outside” where you are? :wink:

Tim