Ultrasonic distance sensor HC-SR04 lack of timeout problem

Related to my previous post (now I know how to attach an image)

Enjoy

I have an HC-SR04 module that works well - without issues, and have just received the aforementioned cheap eBay alternative which hangs/timeout. I have attached a picture for comparison.

Hope this helps someone out there who is trying to identify if their module is in "crappy" category.

The one on the left is the one that works well.
The one on the right is the crappy version from eBay.

Thanks a lot, ScottC. I do have a couple of crappy units very alike to yours, though not really "equal". I also bought a couple of HC-SRO5 that seems to work as they have.

I have also alway's this problem with the HC-SR04 until I find out that on the backside board of the HC-SR04 is a possibility to make a reset with a 1k resistor, this works very stable.
I create all kind of errors with the sensor try to let it crash, but now it keep recover itself and runs all the time fine. Try the code below to test;

/* Ping))) Sensor
The circuit:

  • Vcc of the Sensor attached to +5V
  • GND of the Sensor attached to ground
  • Trigger and Echo of the Sensor together attached to digital pin 7
    */
    const int pingPin = 7; // Digital Pin 7 on Arduino
    const int ResetPin = 8; // Digital Pin 8 on Arduino, I use as Reset

void setup() {
Serial.begin(9600);
pinMode(pingPin, OUTPUT);

pinMode(ResetPin, OUTPUT);
digitalWrite(ResetPin, LOW);
}

void loop() {
long duration, inches, cm;// The distance result in inches and centimeters:

// 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();

delay(100);

if (cm <1) //************ Reset Sensor ************
{
digitalWrite(ResetPin, HIGH);
delay(2);
digitalWrite(ResetPin, LOW);
Serial.println("********** Reset Sensor **********");
}
}

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;
}

The image in post 67, showing "good" and "crappy" sensors...not verified by me...I'm just showing the pic so you don't have to click on the link...

Interestingly, I have just received two HC-SR04 sensors from Geekcreit® Ultrasonic Module HC-SR04 Distance Measuring Ranging Transducer Sensor DC 5V 2-450cm Sale - Banggood USA sold out These appear to be of "Not good" variety mentioned in the previous post with the tiny "J1" mark to the right of the terminal block and other identifying characteristics.

Indeed, when I tried these with the sample code on the Sparkfun Site linked from "example code" on this page Ultrasonic Distance Sensor - HC-SR04 - SEN-15569 - SparkFun Electronics I got the typical freeze problem due to the missing timeouts.

However, I was able to solve the problem purely by hacking the sketch to add my own timeouts and the devices work perfectly with it. There was no need for any of the "hardware" tricks mentioned in this thread.

There is probably a large number of slightly different HC-SR04 designs, all exhibiting different behaviour.

Anyway, here is the adapted code which works for exactly the devices I have just acquired:

/**
 * ex. sparkFun
 * 
 * mod  20.10.2016 timeouts on waits
 * 
 * 
 * HC-SR04 Demo  
 * Demonstration of the HC-SR04 Ultrasonic Sensor
 * Date: August 3, 2016
 * 
 * Description:
 *  Connect the ultrasonic sensor to the Arduino as per the
 *  hardware connections below. Run the sketch and open a serial
 *  monitor. The distance read from the sensor will be displayed
 *  in centimeters and inches.
 * 
 * Hardware Connections:
 *  Arduino | HC-SR04 
 *  -------------------
 *    5V    |   VCC     
 *    7     |   Trig     
 *    8     |   Echo     
 *    GND   |   GND
 *  
 * License:
 *  Public Domain
 */

// Pins
const int TRIG_PIN = 7;
const int ECHO_PIN = 8;

// Anything over 400 cm (23200 us pulse) is "out of range"
const unsigned int MAX_DIST = 23200;

void setup() {

  // The Trigger pin will tell the sensor to range find
  pinMode(TRIG_PIN, OUTPUT);
  digitalWrite(TRIG_PIN, LOW);

  // We'll use the serial monitor to view the sensor output
  Serial.begin(9600);
}

void loop() {

  unsigned long t1;
  unsigned long t2;
  unsigned long pulse_width;
  float cm;
  float inches;

  // Hold the trigger pin high for at least 10 us
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  // Wait for pulse on echo pin

  unsigned long wait1 = micros();
  while ( digitalRead(ECHO_PIN) == 0  ) {
    if ( micros() - wait1 > MAX_DIST ) {
        Serial.println("wait1 Out of range");
        return ;
    }
  }

  // Measure how long the echo pin was held high (pulse width)
  // Note: the micros() counter will overflow after ~70 min
  t1 = micros();
    while ( digitalRead(ECHO_PIN) == 1  ) {
    if ( micros() - t1 > MAX_DIST ) {
        Serial.println("wait2 Out of range");
        return ;
    }
  } 
  
  t2 = micros();
  pulse_width = t2 - t1;

  // Calculate distance in centimeters and inches. The constants
  // are found in the datasheet, and calculated from the assumed speed 
  //of sound in air at sea level (~340 m/s).
  cm = pulse_width / 58.0;
  inches = pulse_width / 148.0;

  // Print out results
  if ( pulse_width > MAX_DIST ) {
    Serial.println("Out of range");
  } else {
    Serial.print(cm);
    Serial.print(" cm \t");
    Serial.print(inches);
    Serial.println(" in");
  }
  
  // Wait at least 60ms before next measurement
  delay(60);
}

Incidentally, the finish on the devices is not too good. They have obviously added the transducers after washing the board, but then not cleaned away the flux from the transducer solder joints, leaving large white powdery deposits. But for the price I paid, I will not complain too loudly.

The device is quite susceptible to electrical noise and needs a capacitor (say 100 uF) across the supply terminals.

SaintGimp:
Some knock-off models of the HC-SR04 do not implement a timeout if no echo is detected at all. In that case, the echo pin will simply remain high forever and will not generate any new pings, regardless of what you do with the trigger pin. The original model from Robot Electronics times out after 36 ms and does not have this problem, but many (all?) cheap knock-off models do.

You can reproduce the problem easily by covering the receiver transducer with your thumb, then removing your thumb. If your sensor doesn't have a timeout, it will stop generating pings and the only way to recover is to power cycle the sensor.

A workaround that works for me so far is to test the state of the echo pin 100 ms after triggering a ping. If it's still high, you're in a stuck state. If you wire power to the sensor through a transistor and control that transistor via another pin, then you can power cycle the sensor via software and get back to a working state.

I was banging my head against this for quite some time until I found this. I tried your suggestion to power cycle it and it's got me up and running. Thank you!

The idea of powering the HC-SR04 from an Arduino output is working perfectly for me.

I used Tim's code from post #31, modified with with DocDoc's correction on the "If" (change "LOW" to "HIGH")

and refinements for my particular sensors. The following code adds only 110 mS for a power reset on the sensor when an out of range is detected.

Notice, inside the IF loop, the section "delay(60); sonar.ping_cm();" may be deleted if your sensors do not return false echo after reset. I have 2 that do not need it. Total time added for reset is then only 50 mS.

#include <NewPing.h>

#define TRIGGER_PIN  2  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     3  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define USPOWER_PIN  4
#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.
  pinMode(USPOWER_PIN, OUTPUT);
  digitalWrite(USPOWER_PIN, HIGH);
}

void loop() {
  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");
  delay(30);                     // Wait 30ms between pings (about 30 pings/sec). 29ms should be the                                // shortest delay between pings.
  
  if (cm == 0 && digitalRead(ECHO_PIN) == HIGH) {
    digitalWrite(USPOWER_PIN, LOW);
    delay(50);                // 50 mS is the minimum Off time to get clean restart
    digitalWrite(USPOWER_PIN, HIGH); // Adjust this value if your sensors don't read after reset
    delay(60);                // Some sensors throw out a very short false echo after timeout
    sonar.ping_cm();       // 5cm-10cm value.  If your sensors do not throw out
                                  // this false echo, you can get rid of this delay and ping after power HIGH
  }                              // Conversely, if you still get a false echo, you may need to increase
}                                // the delay.

Good Luck!

Alex "docdoc",

Your SRF05 lib worked on my SR04 sensor with the lockup on zero output when out of range. Works perfectly now. Thanks.

John

I ran into this today while putting together a blog video for how to daisy-chain my little octosonar board to drive 12 of these little buggers with my sonari2c library (apologies for the plug).

I prototyped all this using SR04s I bought last year from somewhere in China (not banggood - it's not in my purchase history there) and it all works just dandy. Those units don't look like either of the ones pictured above.

The new ones I did get from Bangood recently and look like the "bad" ones above (same circuit, narrow silk screen) and my tests/demos were locking up occasionall (I was blaming it on wiring). I finally got to the bottom of this today (reproduce 100% by putting thumb over sensor) and google found this thread.

The most obvious difference between my "good" ones and the "bad" ones is the "bad' ones have 10K pullup resistors on Trig and Echo. My "good" ones do not - very high resistance between Trig, Echo and Vcc,Gnd.

The "good" and "bad" ones above both seem to have the pullups (R1/R2) so they are clones. Sometimes clones have different component values due to the cloners not being as good as the dudes on Kamino.

I tried tying the Echo to ground - seemed to clear it, but I can't do that through my board, nor can I flap the power.

While debugging I connected echo to the LED on my protoshield so I'd have a visual indicator. Bingo. Problem cleared right up. The protoshield has an inline resistor with the LED, but I figured these pulses are short, so how about just connecting a LED directly across Trig and GND. Seems to work....

Can someone else try this and verify?

Also can the guy with the good and bad clones check the resistance on r1/r2 on the "good" ones? I suspect they may be more than 10k i.e. weaker.

Update: I tried a variety of LEDs direct connect and they did not all work. The little red ones with 1.6V forward voltage did not lock up my board, but did not give a signal back from the rogue sensor either - probably pulling the voltage too low for the logic gate.

The rest seem to be 2V forward voltage and work direct without a resistor. All the LEDs fix the issues with a 220 ohm series resistor.

I was thinking of putting blinky activity LEDs on the next version of my board anyway, I think this clinches it.

Why does this work? No idea.

I take it back about the clone thing and cheaper components. A closer squint at the picture DaveEvans posted on Oct 10 tells me these are a clone with fewer components. The overall circuit layout looks almost identical, but there are a lot less capacitors.

Is that an LED and resistor on each sensor?
Thanks.

yes, attached between the sensor echo and ground. I just tried a 1k resistor (no LED) and that worked too.

It occurs to me that those 10K pullups may be supposed to be 10k pull-downs. I got some protoshields last month that had one of the tracks mis-designed and connected Vcc direct to Groun, so dumbassity like this definitely happens in the knock-off world.

If someone could check that on the "good" ones it might explain a lot.

How to solder diode to prevent locking problem. Almost any diode will go (no need such big one, i just didn't have other in my inventory).

How can I Stop the measurement of ultrasonic sensor.... during program ruining.....please help me

I was updating my tindie text for these sensors and came back here and realized I had never come back and listed the solution found to this issue.

My sincere apologies. Open source is give and take, not just take.

many thanks to @jlmyra above for figuring out the actual cause - and persuading me by this action to buy an oscilloscope. BitScope Micro Model 5 | A tiny USB Mixed Signal Oscilloscope

The bad sensors raise the echo pin when they don't get a response. They never time out. Period. In brief: avoid.

They do reset the echo when a new cycle is started, so they are not a completely lost cause, once their behavior is understood.

The data sheets say that the timeout from no response is 37ms. While this may have been true for the original HC-SR04, the observed value for the not-bad clones is between 150ms and 200ms. So even with the "good" sensors my original octosonar board was getting interference between adjacent sensors when there was no echo as that sensor would still be hanging up the pin when the next one came active after the 50ms rotation period. This was patched in software to force a wait until the pin dropped.

The revised version of my "OctoSonar" board uses tri-state buffers to isolate the echoes from each other entirely and enforces a sensible 50ms (software changeable) time window to each sensor, eliminating the lockups and delays above, regardless of whether the sensor is one of the "good" or "bad" ones.

The "good" sensors I use have a different board layout from either of the ones shown in port #70. They are distinguished by having the passive components arrranged in two vertical rows.

(New poster.)
I got my super cheap HC-SR04 sensors working with a software only solution after they all experienced the same error of getting stuck waiting for lost echos.

I have modifed the arduino Examples -> Sensors -> Ping code for the Ping Ultrasonic Range Finder and explained all steps in comments.

I hope this will be of help for others that come looking for a software only solution. (Based on docdoc's solution in reply #16)

/*
 Ultrasonic distance sensor

 This sketch reads a ultrasonic rangefinder and returns the distance
 to the closest object in range. To initiate a reading it sends out a
 sound pulse and then listens for the echo of the pulse to return. 
 The time it takes before the echo is registered is proportional to 
 the distance of the object from the sensor.

 The circuit:
- +V connection of the Sensor attached to +5V
- GND connection of the Sensor attached to ground
- SIG connection of the Sensor  attached to digital pin 7 (TRIG and ECHO can be combined)


 created 3 Nov 2008
 by David A. Mellis
 modified 30 Aug 2011
 by Tom Igoe
 modified 1 Sept 2018
 by Jakob Nilsson
 
 This example code is in the public domain.

 http://www.arduino.cc/en/Tutorial/Ping
*/

// This constant won't change. It's the arduino pin that communicates with the sensor:
const int pingPin = 7;

// We need to add a timeout for the longes range that the Sensor can sense, so that
// it does not get stuck waiting for an echo that never comes.
// long timeout = 157 / 74 / 2;//Timeout in microseconds for a max range of 157 inches
const long timeout = 400 * 29 * 2; //Timeout in microseconds for a max range of 400 cm

void setup() {
 // initialize serial communication:
 Serial.begin(9600);
}

void loop() {
 // establish variables for duration of the ping, and the distance result
 // in inches and centimeters:
 long duration, inches, cm, mm;

 // The sensor is triggered by a HIGH signal for 10 microseconds.
 // Give a short LOW pulse beforehand to ensure a clean HIGH pulse and 
 // to reset the sensor if it didn't register an echo from the last ping:
 pinMode(pingPin, OUTPUT);
 digitalWrite(pingPin, LOW);
 delayMicroseconds(10); //This delay lets the capacitors empty and resets the sensor
 digitalWrite(pingPin, HIGH);
 delayMicroseconds(10); 
 digitalWrite(pingPin, LOW);

 // The same pin is used to read the signal from the Sensor: 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,timeout);

 // convert the time into a distance
 inches = microsecondsToInches(duration);
 cm = microsecondsToCentimeters(duration);
 mm = microsecondsToMillimeters(duration);

 Serial.print(inches);
 Serial.print(" in, ");
 Serial.print(cm);
 Serial.print(" cm, ");
 Serial.print(mm);
 Serial.print(" mm");
 Serial.println();
 
 delay(100); //Recommended minimum cycle time is 50ms so that the echo has time to fade
}

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 343 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;
}

long microsecondsToMillimeters(long microseconds) {
 // The speed of sound is 343 m/s or 2.9215 microseconds per millimeter.
 // The ping travels out and back, so to find the distance of the object we
 // take half of the distance travelled.
 return microseconds * 10000 /29215 / 2;
}

Hope it helps!

Hello,

detect an echo.
This sometimes results in the echo line staying high forever

have you check the connector for the echoPin?

and what is the code that you input to the HC-004.

1 Like