2. HC-SR04 Ultrasonic Ranger

HC-SR04 is an ultrasonic distance sensor. The sensor sends out the sound wave and starts timing. The sound will be bounced back by the object and heard by the sensor. By calculating the travel time of the sound, the distance of the object is computed by

\[distance = \frac{travel~time}{2} \times sound~speed\]

2.1. Wiring

The HC-SR04 sensor has four pins: Vcc (5v), Trig, Echo, and Gnd.

When a trigger signal (low-high-low) is sent to the pin Trig, the sensor will play the sound shortly. The pin Echo will turn from low to high (5V) when sound is played and go back to low when the sound is heard. Therefore, the pulsewidth measured at pin Echo relates to the distance to measure. However, feeding 5V to the input port directly will damage the Pi, so a voltage division circuit should be applied. The circuit is shown below. (Please double check the position of Echo pin and Trig pin on your ranger.)

../../../../../_images/HCSR04.png

2.2. Programming

The driver program reads:

#!/usr/bin/env python3
"""
"THE DIETCOKE LICENSE" (Revision 01):
uone wrote this code. As long as you retain this notice,
you can do whatever you want with this stuff. If we
meet someday, and you think this stuff is worth it, you can
buy me a bottle of diet coke in return.
Since I don't like beer and sugar, I don't use Beerware License.

uone http://homepages.rpi.edu/~wangy52
"""

import RPi.GPIO as GPIO
import time

class HCSR04:

    def __init__(self, TRIG_pin, ECHO_pin):
        self.TRIG_pin = TRIG_pin
        self.ECHO_pin = ECHO_pin
        self.__initialized = False
        self.SOUND_SPEED = 34300 # cm/sec

    def init_HCSR04(self):
        # set Trig port to be output
        # set Echo port to be input
        GPIO.setup(self.TRIG_pin, GPIO.OUT)
        GPIO.setup(self.ECHO_pin, GPIO.IN)

        # set Trig to be low
        GPIO.output(self.TRIG_pin, False)
        time.sleep(0.080) #
        # print("sensor is ready")
        self.__initialized = True

    def measure_distance(self):
        if self.__initialized == False:
            self.init_HCSR04()

        # send a 10usec gate signal to Trig
        GPIO.output(self.TRIG_pin, True)
        time.sleep(0.00001)
        GPIO.output(self.TRIG_pin, False)

        # when the wave is sent, ECHO reads 1
        pulse_start = time.time()
        while GPIO.input(self.ECHO_pin) == 0:
            pulse_start = time.time()

        # when the wave is heard, ECHO reads 0
        pulse_end = time.time()
        while GPIO.input(self.ECHO_pin) == 1:
            pulse_end = time.time()

        pulse_travel_time = pulse_end - pulse_start
        distance = pulse_travel_time * self.SOUND_SPEED / 2 # in unit cm
        time.sleep(0.080)
        return distance

or downloading via

HCSR04_lib.py.

Example main program is

#!/usr/bin/env python3
import RPi.GPIO as GPIO
import time
from HCSR04_lib import HCSR04


#GPIO Mode (BOARD / BCM)
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()

TRIG = 4
ECHO = 17

GPIO.setup(TRIG, GPIO.OUT)

instance = HCSR04(TRIG_pin=TRIG, ECHO_pin=ECHO)  # BCM17

instance.init_HCSR04()

while True:
# for _ in range(1):
    distance = instance.measure_distance()
    print("distance is:", distance, "cm")

Expected output looks like

distance is: 35.43422222137451 cm
distance is: 36.444175243377686 cm
distance is: 7.0778489112854 cm
distance is: 6.906116008758545 cm
distance is: 7.568514347076416 cm