Wikijunior:Raspberry Pi/Raspberry Pi Python GPIO Zero Distance Sensor
Tutorial by Jonathan Teague - Public Domain
28th Jan 2017 – www.cotswoldjam.org
This tutorial will cover using the popular HC-SR04 ultrasonic distance sensor, the Raspberry Pi and the gpiozero
library to measure distances.
The kit
[edit | edit source]In your bag you will find the following components:
- ×4 M-F Jumper leads (pin to socket)
- ×1 R1 680Ω (blue grey brown) resistor
- ×1 R2 470Ω (yellow violet brown) resistor
- ×1 Mini-breadboard
- ×1 HC-SR04 ultrasound sensor
Using a breadboard
[edit | edit source]Breadboards are used to prototype and test electronic components without needing to solder them.
Each hole is identified with a notation system using numbers horizontally across the breadboard and letters vertically down the breadboard.
Using the Raspberry Pi's GPIO pins
[edit | edit source]The Raspberry Pi has two ways of labelling the General Purpose Input-Output (GPIO) pins:
- Board numbering – just starts from the bottom-left at 1, and works its way up and right, through to 40.
- BCM numbering (Broadcom numbering) – is the way the Raspberry Pi's processor sees the pin connections.
Putting it together
[edit | edit source]The Raspberry Pi is a 3.3V device, the HC-SR04 is a 5V device, connecting this up wrong can damage the Raspberry Pi. |
The colour of the jumper wires in your kit is not important – where you put them is VERY important! Breadboard holes are numbered – make sure you connect to the correct hole. |
Step 0: Make sure your Pi is shut down and the power lead disconnected.
Step 1: Take 1 jumper lead and plug the pin (male end) into B1 on the breadboard and the socket (female end) into pin 6 (GND) on the Pi.
Step 2: Take 1 jumper lead and plug the pin into B3 on the breadboard and the socket into pin 3 (GPIO 20) on the Pi. This is the connector that the Pi will use to trigger the distance measurer to take a measurement.
Step 3: Take the R1 680Ω (blue grey brown) resistor – the one with a blue colour line on and insert the legs into holes E1 and I2 on the breadboard – it doesn’t matter which way round the resistor is.
Step 4: Take the other resistor, the R2 470Ω (yellow violet brown) – with a yellow colour line on and insert the legs into holes D2 and H2 on the breadboard – again it doesn’t matter which way round.
Step 5: Gently bend the R1 resistor away from R2 so the legs in E1 and D2 won't touch each other (if they do it won’t damage anything, it just won’t work).
Step 6: Take 1 jumper lead and plug the pin into J2 on the breadboard and the socket into pin 1 (GPIO 21) on the Pi. This is the connector that the Pi will use to listen for the measurement.
Step 7: Take the last jumper lead and plug the pin into B4 on the breadboard and the socket into pin 2 (5V).
Step 8: Finally, plug in the HC-SR04. It has 4 pins and these need to go into A1, A2, A3 and A4. The back of the sensor with all the black ICs on should be facing the breadboard and the two silver sensors pointing away from the breadboard.
Now, no matter how confident you are that you’ve got it all right, call over a tutor and get your wiring checked. Once you’re given the OK continue below to get programming. |
The program
[edit | edit source]Power up your Raspberry Pi. From the desktop menu, select Programming – Python 3 (IDLE). Then use File, New File to create a new program.
Type in the following program then use File, Save to save your program as the name of your choice (don’t forget to put .py on the end) in the ~/python/distance
folder and then run it with Run menu, Run Module.
#!/usr/bin/python
from gpiozero import DistanceSensor
from time import sleep
sensor = DistanceSensor(echo=21, trigger=20, max_distance=2.0)
while True:
distance = sensor.distance * 100
print("Distance : %.1f" % distance)
sleep(1)
What does the program do?
#!/usr/bin/python
The first line is a comment (it starts with #) and tells the operating system what language the program is written in, as you will run the program from Python yourself this is redundant (but good practice).
from gpiozero import DistanceSensor
from time import sleep
The from
lines tell the computer to learn about new things. Computers can learn from programs that other people have written; we call these other programs "libraries". Our program needs the function called DistanceSensor
from the gpiozero
library which it will use to talk to the sensor and the function sleep
from the time library so that we can insert pauses. A function is just some code located somewhere else that we can make use of to do something.
sensor = DistanceSensor(echo=21, trigger=20, max_distance=2.0)
We then create an object we call sensor
using the imported function DistanceSensor
. The parameters that we pass say that the trigger
to invoke the sensor will be on GPIO pin 20; the echo
to listen for the reply will be on GPIO pin 21 and that the maximum distance that should be returned is 2.0 metres.
while True:
This while True:
tells the program to run forever in a loop.
distance = sensor.distance * 100
print("Distance : %.1f" % distance)
sleep(1)
Then we get the current sensor reading by calling sensor.distance
, multiply this by 100 (as the returned value is in mm); print out the value with only one digit after the decimal point, and finally go to sleep for a second before the while True:
makes us go around again.
Additional notes
[edit | edit source]These notes are additonal to the main tutorial and explain the use of two resistors to make a "voltage divider" and give an example program that directly controls the sensor.
The Voltage Divider
[edit | edit source]The Raspberry Pi is a 3.3V device. The sensor used in this tutorial, an HC-SR04, is a 5V device. This means that the sensor needs 5V to power it and, crucially for the Pi, that the voltage levels that the sensor returns the results to the Pi are also at 5V. Connecting the sensor output directly to the Pi would almost certainly result in damage to the Pi.
This sort of situation is often found in the real world, you have two devices you wish to connect to each other but they operate at different voltages. There are several ways to solve this but one of the simplest, and the one used here, is to drop the voltage from 5V to just under the safe value of 3.3V by making a "voltage divider" out of two resistors.
The two resistors are placed in series across the source voltage and zero volts and the voltage at the point between the two resistors will be reduced in proporation with the values of the two resistors.
So substituting in the values for 5V as the Vin and the two resistors we have used, R1 = 680Ω and R2 = 470Ω we get:
This 2.95V is then safe to connect to the Pi.
A program to interface to the HC-SR04 directly
[edit | edit source]In the tutorial, we don't talk directly to the HC-SR04 but leave all that to the DistanceSensor
functionality of the GPIO Zero library. This is convenient, but sometimes it's useful to know exactly what is going on and to be able to understand how to control devices directly.
In the ~/python/distance
folder you will find a file rpigpio_DistanceSensor.py
which shows how to trigger and read the HC-SR04 sensor directly and which uses the RPi.GPIO
library.
Here is the important bit that triggers the HC-SR04 to take a measurement and gets the result back, it's all contained in a function called measure()
:
def measure():
# This function measures a distance
GPIO.output(GPIO_TRIGGER, True)
time.sleep(0.00001)
GPIO.output(GPIO_TRIGGER, False)
start = time.time()
while GPIO.input(GPIO_ECHO)==0:
start = time.time()
while GPIO.input(GPIO_ECHO)==1:
stop = time.time()
elapsed = stop-start
distance = (elapsed * 34300)/2
return distance
What does this do?
[edit | edit source]Setting the GPIO_TRIGGER
to True
, sleeping for 10uS then setting the GPIO_TRIGGER
to False
triggers the sensor to take a reading.
The code then sets a variable called start
to the current time and goes into a tight loop while GPIO_ECHO
is 0 (= low), every time round the loop it resets the variable start
.
Once GPIO_ECHO
is 1 (= high) this first look will stop. At this point start
contains the time when the Echo pin went high.
Now the code goes into a tight loop while GPIO_ECHO
is high, every time round the loop setting the variable stop
.
Finally, when the GPIO_ECHO
goes low again the loop exits. At this point, start contains the time when the Echo went high and stop
the time when it went low again.
Now it's just some maths to work out how long the Echo pin was high for, multiply this by the speed of sound (the 34300) and divide by 2 (because the sound from the sensor went out and back) and we get the distance
value in centimetres (cm).
Files
[edit | edit source]Distancesensor-gpiozero.pdf
[edit | edit source]The original PDF for this tutorial is on Wikicommons: Distancesensor-gpiozero.pdf
Distancesensor-gpiozero-additional.pdf
[edit | edit source]The original PDF for this tutorial is on Wikicommons: Distancesensor-gpiozero-additional.pdf
rpigpio_DistanceSensor.py
[edit | edit source]#!/usr/bin/python
import time
import RPi.GPIO as GPIO
# -----------------------
# Define measure function
# -----------------------
def measure():
# This function measures a distance
GPIO.output(GPIO_TRIGGER, True)
time.sleep(0.00001)
GPIO.output(GPIO_TRIGGER, False)
start = time.time()
while GPIO.input(GPIO_ECHO)==0:
start = time.time()
while GPIO.input(GPIO_ECHO)==1:
stop = time.time()
elapsed = stop-start
distance = (elapsed * 34300)/2
return distance
# -----------------------
# Main Script
# -----------------------
# Use BCM GPIO references instead of physical pin numbers
GPIO.setmode(GPIO.BCM)
# Define GPIO to use on Pi
GPIO_TRIGGER = 20
GPIO_ECHO = 21
# Set trigger as output and echo as input
GPIO.setup(GPIO_TRIGGER,GPIO.OUT) # Trigger
GPIO.setup(GPIO_ECHO,GPIO.IN) # Echo
# Set trigger to False (Low)
GPIO.output(GPIO_TRIGGER, False)
# Wrap main content in a try block so we can
# catch the user pressing CTRL-C and call the
# GPIO cleanup function.
try:
while True:
distance = measure()
print("Distance : %.1f" % distance)
time.sleep(1)
except KeyboardInterrupt:
# User pressed CTRL-C, reset GPIO settings
GPIO.cleanup()
gpiozero_DistanceSensor.py
[edit | edit source]#!/usr/bin/python
# -----------------------
# Import required Python libraries
# -----------------------
from gpiozero import DistanceSensor
from time import sleep
# -----------------------
# Main Script
# -----------------------
sensor = DistanceSensor(echo=21, trigger=20, max_distance=2.0)
while True:
distance = sensor.distance * 100
print("Distance : %.1f" % distance)
sleep(1)