HC-SR504 Challenges


#1

Hello!

I having an issue with the HC-SR504 ultrasonic sensor that accompanied the CamJam Robotics kit. Perhaps someone may have had a similar issue and resolved it.

The sensor emits a pulse but no echo is detected ever (verified using pigpio and piscope) - stuck in the first while loop per Pimoroni sample code. I substituted the sensor with two others in my collection and but these changes made no difference. I have used several flavors of code (posted in the public domain and most of these have the “uninitialized variables” bug sadly) but the results remained unchanged.

I am using 330 and 470 ohms resistors (and also other variations) with RPi3B+ (under current Raspbian Stretch). The same setup works fine with Arduino UNO (using the pulseIn method for the elapsed time). The assignment of the echo/trigger pins were rotated based on the available pins on the CamJam HAT. The pins were verified to be in working order (via HAT) by blinking LEDs. I even rearranged the initialization of the timer variables such that the emission of the pulse was followed immediately by the two while loops to eliminate latency (at the expense of some accuracy, of course). None of these adjustments made any difference.

The code is very simple and I wonder if Stretch has something against me. I gave up on using DHT11 temperature/humidity sensor with Python for a related timing issue. This family of sensors, DHTxx, worked thankfully to WiringPi after reading Gordon Henderson’s comments at his site. Has anyone else experienced any issue (apart from the “uninitialized variables” bug) with the HC-SR504 ultrasonic sensor using Python?

Thanks.


#2

Do you have any code snippets to share, detailing how you’re reading the sensor?

I’ve seen people having trouble with these sensors before, but it’s usually when using a library such as Explorer HAT that adds unacceptable amounts of latency to the IO operations.


#3

Sure (thx for stepping in, much appreciated).

The simplest version of the many parametric changes I’ve tried is as follows:

import RPi.GPIO as GPIO
import sys, time

pinTrigger = 22
pinEcho = 23
pinLED = 24

def debug5(args):
	GPIO.output(pinTrigger, False)
	started = time.time()
	time.sleep(0.001)
	stopped = time.time()
	GPIO.output(pinTrigger, True) # pulse detected by piscope
	time.sleep(0.00001)
	GPIO.output(pinTrigger, False)
	while GPIO.input(pinEcho) == 0: # stuck in this loop
		started = time.time()
	while GPIO.input(pinEcho) == 1:
		stopped = time.time()
	distance = (stopped - started) * 34300 / 2
	print(distance)

	return 0

if __name__ == '__main__':
	GPIO.setmode(GPIO.BCM)
	GPIO.setwarnings(False)
	GPIO.setup(pinTrigger, GPIO.OUT)
	GPIO.setup(pinEcho, GPIO.IN)
	GPIO.setup(pinLED, GPIO.OUT)
	sys.exit(debug5(sys.argv))

Looking forward to your suggestions; at this stage I’ll try anything. I’ve annotated the two key lines in the code (from my perspective):

  • Pulse transmission on the Trigger pin
  • Waiting for the RISING_EDGE equivalent on the Echo pin

Thanks once again. Regards.


#4

Did I imagine a schematic somewhere? This all looks like familiar code- I need to dig up an HC-SR04 and try it.

The fact the echo pin is stuck low feels a little like it’s lacking a pull-up resistor, but you say it’s working on an Arduino?

BCM 23 is nothing particularly special on the Pi- so there shouldn’t be any alt modes interfering. Are you running any other Python code that could be using that pin? Or using any other add-ons?


#5


I’ve uploaded the images for the breadboard layout and schematic. Of course, I could not superimpose the HAT (for the CamJam Robot) here but I hope that I’ve conveyed the layout as far as practical (pardon the layout of the schematic - didn’t spend time to clean up the dog legs).

Based on the CamJam docs, I started with pins 17/18 for the Trig/Echo and then migrated to 22/23 respectively (I’ve tried pin 24 too). All these pins blink LEDs (through the HAT) when suitably configured and coded. No issues with electrical connectivity. I used the kit supplied resistors at first but then changed to 330/470 ohms (with slightly higher W) to no effect. I’ve used three different sensors (and the current sensor works with Arduino UNO).

The CPU meter on the menu bar hovers between 0-1% utilization before the Python code is launched. There is no other foreground task running (I will perhaps spend some time pruning the processes to ensure bare minimum necessary now that you have raised the thought).

In the interim, I’ve also tried some C++ code using the wiringPi library. The echo is detected in this code but the distance value is spurious (< 1 cm) when I have the reflection surface over 10 cm away. Clearly something to do with extraneous processes in the background perhaps interfering with the echo location time slice.

Anyhow, looking forward to your suggestions because at this stage I’d rather struggle with Python (if I can) instead of forking over to debug C++.

Thanks.


#6

I don’t recall the HC-SR04 being this problematic- I’ve done some digging for inspiration but I’m also at a loss. I’ll have to dig one up and see if I can get it working myself.


#7

I couldn’t find an HC-SR04, but I did find a DYP-ME007 V1 and, using an Explorer HAT Pro to buffer the 5v “Echo” pin managed to get a reading using this code on an older Pi 3:

 import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)

PIN_TRIG = 18
PIN_ECHO = 23

GPIO.setup(PIN_TRIG, GPIO.OUT)
GPIO.setup(PIN_ECHO, GPIO.IN)

def ping():
    GPIO.output(PIN_TRIG, False)
    time.sleep(0.06)

    # Send trigger pulse
    GPIO.output(PIN_TRIG, True)
    time.sleep(0.00001)
    GPIO.output(PIN_TRIG, False)

    while GPIO.input(PIN_ECHO) == 0:
        t_start = time.time()

    while GPIO.input(PIN_ECHO) == 1:
        t_stop = time.time()

    distance = (t_stop - t_start) * 34300 / 2

    return distance

while True:
    print(ping())

Edit: Also works on a Pi 3B+

I’ll see if I can dig up an HC-SR04. I wonder if your voltage divider circuit is at fault here?


#8

Thanks a bunch for your efforts and guidance.

I’m using RPi3 (ARMv7 rev 5 v71) with kernel 4.14.34-v7+ Apr 16 2018 (just for reference/info purposes).

I ran your code (cut-n-paste from your reply with the obligatory GPIO.setwarnings(False) statement added appropriately. Changed the wire for the Trigger pin connection to 18 (as indicated in the code). The code ran code but did not see anything printed in the terminal window. Presumably stuck in one of the while loops.

Based on your observation about voltage, I changed the resistors for the voltage divider between the Echo pin and GPIO23 to 220 ohms (nearest available in my collection although calculations indicated 240 ohms would be preferable). Measured the values after inserting the resistors onto the breadboard and the values matched the resistor color codes.

Your observation about the GPIO pin (#23 in your code) voltage not going HIGH is spot on (based on my inference of the piscope display).

I will use your code to capture more piscope sessions and parametrically change the two resistors (steps of 10x per trial) keeping Ohm’s Law in mind to deliver the 3.3V to the GPIO pin being used for echo detection.

Thanks again.

P.S. On a pedantic note, I’m sure you are aware that in your code snippet, t_start and t_stop could be uninitialized in corner cases. The fact that it doesn’t happen (since I’ve seen others do the same) perhaps is a testament that the corner cases do not occur in the real world.


#9

Ooof. You’re correct! I’d probably normally do something like:

    while GPIO.input(PIN_ECHO) == 0:
        pass

    t_start = time.time()

    while GPIO.input(PIN_ECHO) == 1:
        pass

    t_stop = time.time()

Or, most likely move the pin polling to C so I get a timeout for free and don’t have to worry about the implementation detail:

if GPIO.wait_for_edge(PIN_ECHO, GPIO.RISING, timeout=1000) is None:
    raise RuntimeError("Timeout waiting for rising edge on ECHO pin")
t_start = time.time()
if GPIO.wait_for_edge(PIN_ECHO, GPIO.FALLING, timeout=1000) is None:
    raise RuntimeError("Timeout waiting for falling edge on ECHO pin")
t_stop = time.time()

#10

Actually GPIO.wait_for_edge doesn’t work for me at all- presumably because of the time it takes to set up the handler.


#11

Reportedly, it takes 430 us for the interrupt handler setup.

Attached is a sample piscope screen shot using your code. The ping call is layered with a 1 sec LED blink (pin 24) - for my timestamp purposes. The Trig pin (#22) fires for the specified duration (0.00001 secs - square wave clearly visible when I zoom in) but the Echo pin (#23) does not register anything - lies flat and LOW!?? This is using the 220/470 ohms resistor combination. I will try a few more resistor pair combinations before moving on to C code using your concept with interrupt handlers. I had good success with that approach for the PIR sensor.

Regards.