How To Control a Ultrasonic Distance Sensor with Raspberry PI

4.5
(4)

Last Updated on 9th June 2024 by peppe8o

Ultrasonic Sensors are great for all kind of projects that need distance measurements, avoiding obstacles as example. The HC-SR04 is inexpensive and easy to use and can be easily connected with a Raspberry PI

Ultrasonic sensor module HC-SR04 provides 2cm-400cm non-contact measurement function, the ranging accuracy can reach to 3mm. The basic principle of work:

HC-SR04 Ultrasonic Sensor
  • IO trigger high level signal (for at least 10us) starts the process
  • The module automatically sends eight micro signals at 40 kHz and starts to ear to detect whether there is a feedback signal back.
  • If there is a signal back, the time of high input IO duration is the time taker for ultrasonic to hit an object and turn back.

So, distance = (high level ingress duration × speed of sound (34300cm/s) / 2.

The final division is because we have feedback for roundtrip, distance is the half.

The Timing diagram is shown below:

HC-SR04 timing diagram

Voltage levels must be kept in consideration. HC-SR04 module works with 5V current (except trigger, which can be lower) and outputs a 5V signal on echo. Echo goes back to Raspberry PI for duration measurement on GPIOs. Raspberry PI GPIO reading should be at 3,3V to avoid circuit failure, so we need to implement a simple voltage reduction circuit with resistors. A good solution can be found from learningaboutelectronics.com: How to Reduce Voltage with Resistors. Our voltage circuit will follow this physical diagram:

RPI HC-SR04 resistore organization

Calculations are according to the following formulas:

So, once defined:

  • Vgpio = 3,3 Volt,
  • Vecho = 5 Volt

We choose R1 and derive R2 from following:

In my kits, I have 100 Ohm resistors, so I use it for R1. From the last equation, I need to supply 194,12 Ohm from R2, but I have only 100 Ohm and 220 Ohm resistors. Instead of using a 220 Ohm resistor with 10% of error margin, I use for R2 two 100 Ohm resistors in series, so that the resulting value is returned by their sum (200 Ohm). The final voltage reduction circuit is:

RPI HC-SR04 resistore implementation

Now we can start our project.

In this article we’ll control our HC-SR04 ultrasonic distance sensor from a Raspberry PI Zero W. This article applies also to newer Raspberry PI boards.

What We Need

Raspberry PI Zero WH board

As usual, I suggest adding from now to your favourite e-commerce shopping cart all the needed hardware, so that at the end you will be able to evaluate overall costs and decide if to continue with the project or remove them from the shopping cart. So, hardware will be only:

Step-by-Step Procedure

Wiring Diagram

Prepare cabling according to the following wiring diagram:

RPI HC-SR04 wiring diagram

Please find below the overall picture:

Raspberry PI HC-SR04 picture 2
Raspberry PI HC-SR04 picture

OS Preparation

Start with OS installation using install Raspberry PI OS Lite guide. This procedure also works with Raspberry PI OS Desktop, using its internal terminal.

Make your OS up-to-date:

sudo apt update
sudo apt upgrade

Python Scripting

RPI.GPIO should be already installed (otherwise, you can get it installed with the command “sudo apt install python3-rpi.gpio”).

Get from my download area ultrasonic-hcsr04.py script:

wget https://peppe8o.com/download/python/ultrasonic-hcsr04.py

In this script version, I also added a code portion managing occasional HC-SR04 freezes occurring during measurement.

Script Usage

This script can be used by simply calling from the terminal:

python3 ultrasonic-hcsr04.py

It will start measuring object’s distance showing it in cm.

To stop the program, just press CTRL+C

Script explanation

First of all, the required libraries are imported:

import RPi.GPIO as GPIO
import time

Then we configure GPIO pins we are going to use. We’ll use BCM GPIO naming. Please refer to Raspberry PI Pinout for more info.

No need to set Vcc and Ground, so only the trigger pin (output) and echo pin (input) will be used:

echoPIN = 15
triggerPIN = 14
GPIO.setmode(GPIO.BCM)
GPIO.setup(echoPIN,GPIO.IN)
GPIO.setup(triggerPIN,GPIO.OUT)

“Distance()” function makes all the work. It starts setting defaults to 0 for distance and duration variables. Also, counter and new_reading variables are set, to manage freezes:

def distance ():
 new_reading = False
 counter = 0
 distance = 0
 duration = 0

Now, it triggers from triggerPIN to send the ultrasonic signal:

GPIO.output(triggerPIN, 0)
time.sleep(0.000002)
GPIO.output(triggerPIN, 1) # here the trigger is put on
time.sleep(0.000010) # 10us of trigger duration
GPIO.output(triggerPIN, 0) # now trigger is put off
time.sleep(0.000002) # this time delay to avoid interference between trigger and echo

As described in the timing diagram, we must measure feedback duration to calculate distance. So we set a “startT” time variable when the echo goes to high and a “feedbackT” time variable when the echo goes back to low. While cycles with “pass” do nothing but wait for conditions to change. If statements are to manage and avoid freezes:

while GPIO.input(echoPIN) == 0:
  pass
  counter += 1
  if counter == 5000:
      new_reading = True
      break

if new_reading:
    return False
startT = time.time()

while GPIO.input(echoPIN) == 1: pass
feedbackT = time.time()

Distance is calculated based on feedback duration as already explained. A small “if” check is done to avoid possible strange conditions. This can be used in future for additional checks on failures.

if feedbackT == startT:
 distance = "N/A"
else:
 duration = feedbackT - startT
 soundSpeed = 34300 # cm/s
 distance = duration * soundSpeed / 2
 distance = round(distance, 1)

Finally, “distance()” function returns the distance above calculated as the result:

return distance

Going to the main loop, the simple print command is enriched to write results always on the same terminal line:

try:
 print (" Distance: " + str(distance())+ " ", end='\r')

Users can terminate this script by pressing CTRL+C. This prints a courtesy message of “interrupted!” and cleans GPIO status:

except KeyboardInterrupt:
 print('interrupted!')
 GPIO.cleanup()

Enjoy!

How useful was this post?

Click on a star to rate it anonymously!

Average rating 4.5 / 5. Vote count: 4

No votes so far! Be the first to rate this post.

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?