This tutorial shows how to interface HC-SR04 ultrasonic sensors with Raspberry Pi Pico for contactless distance measurement using MicroPython. First, we will learn to interface HC-SR04 with Raspberry Pi Pico. After that, we will see the MicroPython example code to measure distance and display it on the MicroPython terminal. Secondly, we will see a MicroPython example to display measured distance (cm) on an SSD1306 OLED.
We have a similar guide for ESP8266 and ESP32 using Arduino IDE:
- HC-SR04 Ultrasonic Sensor with ESP32 – Measure Distance
- HC-SR04 Ultrasonic Sensor with ESP8266 NodeMCU – Measure Distance
Prerequisites
Before we start this lesson make sure you are familiar with and have the latest version Python 3 in your system, have set up MicoPython in Raspberry Pi Pico, and have a running Integrated Development Environment(IDE) in which we will be doing the programming. We will be using the same Thonny IDE as we have done previously when we learned how to blink and chase LEDs in micro-python. If you have not followed our previous tutorial, you check here:
If you are using uPyCraft IDE, you can check this getting started guide:
HC-SR04 Ultrasonic Sensor Introduction
To interface the HC-SR04 ultrasonic sensor with Raspberry Pi Pico, we should know the functionality of each pin of the ultrasonic sensor. By knowing the functionality of input and output pins, we will be able to identify which GPIO pins of Raspberry Pi Pico should be used to interface with HC-SR04.
HC-SR04 Pinout
The figure given below shows the pin configuration of an ultrasonic sensor. It consists of four pins namely; Vcc, Ground, Trigger, and Echo pin.
Vcc and Ground are used to power sensor. We should supply 5 volts to the Vcc pin and connect the GND pin with the ground terminal of the power supply.
Trigger: It is an input pin. A trigger pin is used to initiate the ultrasonic sensor to start distance measurement or distance ranging. When users want to get distance measurements from the sensor, we apply a 10µs pulse to this pin.
Echo: This is a pulse output pin. The echo pin produces a pulse as an output. The width of pulse or on-time of the pulse depends on the distance between the ultrasonic sensor and the obstacle which is placed in front of the HC-SR04 sensor. In idle conditions, this pin remains at an active low level.
Further details on ultrasonic sensor working are provided in the next section.
How HC-SR04 Sensor Works?
HC-SR04 ultrasonic sensor measures distance by using inaudible ultrasonic sound waves of 40KHz frequency. Like sound waves, ultrasonic waves travel through the air and if there is any obstacle in front of them, they reflect according to their angle of incidence. Moreover, if an object is placed parallel to an ultrasonic transmitter, ultrasonic waves reflect exactly at an angle of 180 degrees. Therefore, for distance measurement with HC-SR05 sensor, we place the object under test exactly in a parallel position with an ultrasonic sensor as shown in the figure below.
HC-SR05 ultrasonic sensor consists of two basic modules such as ultrasonic transmitter and ultrasonic receiver module. The transmitter circuit converts an electrical signal into a 40KHz burst of 8 sonar wave pulses. The input electrical signal to the transmitter circuit is 10µs pulse input to the trigger pin of the HC-SR04 sensor. As we mentioned earlier, we apply this trigger input signal through Raspberry Pi Pico or any microcontroller. On the other hand, the ultrasonic receiver circuit listens to these ultrasonic waves which are produced by the transmitter circuit.
Measure HC-SR04 Echo Pulse Time with Raspberry Pi Pico
- To start ranging with HC-SR04, first, we apply 10µs pulse to the trigger pin of the HC-SR04 sensor from the Raspberry Pi Pico digital output pin.
- As soon as 10µs input trigger signal becomes active low, the transmitter circuit produces a burst of 8 ultrasonic sonar pulses. At the same time, the Echo pin also makes a transition from a logic low level to a logic high level.
- When the Echo pin goes high, We start to measure time with the Raspberry Pi Pico duration measurement function.
- These waves travel through the air and if there is any object placed in parallel to the sensor, these waves reflect back after a collision with the object.
- As soon as the ultrasonic waves received by the receiver circuit after striking with an object, the echo pin goes low. Raspberry Pi Pico detects this transition of echo output signal from active high to an active low level and stops the measurement.
In short, by measuring the on-time of the Echo output pulse signal, we can measure the distance. The following figure illustrates the echo output signal with respect input trigger signal and 8 sonar pulses.
The duration for which the echo output signal remains high depends on the distance between the ultrasonic sensor and the object which we place in front of the sensor. Higher is the distance, the higher the time sonar waves will take to reach back to the ultrasonic receiver circuit. Because ultrasonic waves travel through the air with the speed of sound and speed remains constant.
How to Convert Time Duration into Distance
In the next section, we will see how to measure pulse duration using Raspberry Pi Pico. Let’s assume that we have measured the output pulse on time (t) with Raspberry Pi Pico. Now the question is how to convert this measured time into distance.
Well, this is the most obvious part of this tutorial. In high school, we all study a well-known distance-time equation that is S = vt. We can convert the pulse duration (t) into the distance (S) using this equation.
Distance (S) = Speed (v) * t //distance in meters
Here v is the speed of ultrasonic waves in air. The speed of ultrasonic waves in air is equal to the speed of sound which is 340 m/s (meter per second).
The above equation will give distance output in units of meter. But, if you want the distance in centimeter units, multiply 340 with 100. Hence, the above equation becomes:
S = 34000 * t // distance in cm
The time given in the above formula should also be divided by two. Because ultrasonic waves travel from the transmitter to the obstacle and then reflect back to the receiver circuit by traveling the same distance. We want to find the distance between HC-SR04 and the object only. Therefore, the formula to calculate distance becomes :
S = 17000 * t // distance in cm
Note: You don’t need to worry about these calculations as we will be using the MicroPython library for the HC-SR04 ultrasonic sensor to take distance measurements.
How to Interface HC-SR04 Ultrasonic sensor with Raspberry Pi Pico?
Until now we have seen the working of the ultrasonic sensor and the pin details. Now we know that to interface an HC-SR04 sensor with Raspberry Pi Pico. We need four pins out of which two are power supply pins and two are digital input output pins. One GPIO pin of the Raspberry Pi Pico will be used as a digital output pin to provide a trigger signal to the ultrasonic sensor. Similarly, one GPIO pin will be used as a digital input pin to capture echo output signal of output sensor.
Now make the connection of Raspberry Pi Pico with the HC-SR04 sensor according to this connection diagram.
HC-SR04 | Raspberry Pi Pico |
VCC | VSYS (5V) |
GND | GND |
Trigger | GP2 |
Echo | GP3 |
HC-SR04 MicroPython Library
By default, MicroPython does not have an implementation of the HC-SR04 sensor. But, MicroPyhon provides I2C API which can be used to read values from the HC-SR04 sensor. Fortunately, there is one library available which is developed by Adafruit and can be downloaded from this link. Download the following library and upload it to Raspberry Pi Pico board with the name of hcsr04.py under the lib folder.
import machine, time
from machine import Pin
__version__ = '0.2.0'
__author__ = 'Roberto S鐠嬶箯chez'
__license__ = "Apache License 2.0. https://www.apache.org/licenses/LICENSE-2.0"
class HCSR04:
"""
Driver to use the untrasonic sensor HC-SR04.
The sensor range is between 2cm and 4m.
The timeouts received listening to echo pin are converted to OSError('Out of range')
"""
# echo_timeout_us is based in chip range limit (400cm)
def __init__(self, trigger_pin, echo_pin, echo_timeout_us=500*2*30):
"""
trigger_pin: Output pin to send pulses
echo_pin: Readonly pin to measure the distance. The pin should be protected with 1k resistor
echo_timeout_us: Timeout in microseconds to listen to echo pin.
By default is based in sensor limit range (4m)
"""
self.echo_timeout_us = echo_timeout_us
# Init trigger pin (out)
self.trigger = Pin(trigger_pin, mode=Pin.OUT, pull=None)
self.trigger.value(0)
# Init echo pin (in)
self.echo = Pin(echo_pin, mode=Pin.IN, pull=None)
def _send_pulse_and_wait(self):
"""
Send the pulse to trigger and listen on echo pin.
We use the method `machine.time_pulse_us()` to get the microseconds until the echo is received.
"""
self.trigger.value(0) # Stabilize the sensor
time.sleep_us(5)
self.trigger.value(1)
# Send a 10us pulse.
time.sleep_us(10)
self.trigger.value(0)
try:
pulse_time = machine.time_pulse_us(self.echo, 1, self.echo_timeout_us)
return pulse_time
except OSError as ex:
if ex.args[0] == 110: # 110 = ETIMEDOUT
raise OSError('Out of range')
raise ex
def distance_mm(self):
"""
Get the distance in milimeters without floating point operations.
"""
pulse_time = self._send_pulse_and_wait()
# To calculate the distance we get the pulse_time and divide it by 2
# (the pulse walk the distance twice) and by 29.1 becasue
# the sound speed on air (343.2 m/s), that It's equivalent to
# 0.34320 mm/us that is 1mm each 2.91us
# pulse_time // 2 // 2.91 -> pulse_time // 5.82 -> pulse_time * 100 // 582
mm = pulse_time * 100 // 582
return mm
def distance_cm(self):
"""
Get the distance in centimeters with floating point operations.
It returns a float
"""
pulse_time = self._send_pulse_and_wait()
# To calculate the distance we get the pulse_time and divide it by 2
# (the pulse walk the distance twice) and by 29.1 becasue
# the sound speed on air (343.2 m/s), that It's equivalent to
# 0.034320 cm/us that is 1cm each 29.1us
cms = (pulse_time / 2) / 29.1
return cms
MicroPython HC-SR04 Ultrasonic Sensor Raspberry Pi Pico Code
After uploading the HC-SR04 library to the Raspberry Pi Pico board, now we can use the functions available in the HC-SR04 library to get sensor readings.
HC-SR04 MicroPython Example
Now let’s look at the MicroPython script for HC-SR04 to get distance readings. Copy the following code to the main.py file and upload the main.py file to Raspberry Pi Pico.
This MicroPython script reads distance from the HC-SR04 sensor and prints it on the MicroPython shell console.
from hcsr04 import HCSR04
from time import sleep
sensor = HCSR04(trigger_pin=2, echo_pin=3, echo_timeout_us=10000)
while True:
distance = sensor.distance_cm()
print('Distance:', distance, 'cm')
sleep(1)
How the Code Works?
Importing Libraries
Firstly, we import hcsr04 and sleep module so that we will be able to access it methods through its defined classes.
from hcsr04 import HCSR04
from time import sleep
Defining Raspberry Pi Pico GPIO Pins for HC-SR04
Now, we initialize the gpio pins of Raspberry Pi Pico for the HC-SR04 sensor. The first argument specifies the GPIO pin for trigger pin. This is given as GPIO2. The second parameter specifies the GPIO pin for the echo pin. This is given as GPIO3. The last argument is the maximum travel time of the sound wave.
HC-SR04 creates an object of the HCSR04() method from hcsr04 class with the name of “sensor”.
sensor = HCSR04(trigger_pin=2, echo_pin=3, echo_timeout_us=10000)
Getting HC-SR04 Sensor Values
Inside the while loop, get the sensor reading by using an object “sensor” on distance_cm() ad save the value in the distance variable.
distance = sensor.distance_cm()
After that print the distance values on the MicroPython shell console after every one second.
print('Distance:', distance, 'cm')
sleep(1)
Demo
To test the MicroPython script for HC-SR04 with Raspberry Pi Pico, upload the main.py file to your board.
You will see the distance value getting printed on shell console after every one second as follows:
MicroPython: Displaying HC-SR04 Sensor values on OLED Display
In this section, we will see how to display measured distance reading on a 0.96 SSD1306 OLED display using MicroPython and Raspberry Pi Pico.
You can find more information on OLED with Raspberry Pi Pico here:
SSD1306 OLED Display MicroPython Library
For an OLED display, we will also need to upload a library to Raspberry Pi Pico.
- To successfully do that, open your Thonny IDE with your Raspberry Pi Pico plugged in your system. Go to Tools > Manage Packages. This will open up the Thonny Package Manager.
- Search for “ssd1306” in the search bar by typing its name and clicking the button ‘Search on PyPI.’
- From the following search results click on the one highlighted below: micropython-ssd1306
Install this library.
After a few moments this library will get successfully installed. Now we are ready to program our Raspberry Pi Pico with OLED display.
Connecting SSD1306 OLED Display with Raspberry Pi Pico and HC-SR04
We will need the following components to connect our Raspberry Pi Pico with the OLED Display and HC-SR04.
- Raspberry Pi Pico
- HC-SR04
- SSD1306 OLED Display
- Connecting Wires
The OLED display has 4 terminals which we will connect with the Raspberry Pi Pico. As the OLED display requires an operating voltage in the range of 3.3-5V hence we will connect the VCC terminal with 5V which will be in common with the board and HC-SR04. SCL of the display will be connected with the SCL pin of the module and the SDA of the display will be connected with the SDA of the module. The ground of all three devices will be held common.
The connections between the three devices which we are using can be seen below.
SSD1306 OLED Display | Raspberry Pi Pico |
VCC | 5V |
SDA | GP0 (I2C0 SDA) |
SCL | GP1 (I2C0 SCL) |
GND | GND |
HC-SR04 | Raspberry Pi Pico |
VCC | 5V |
GND | GND |
Trigger | GP2 |
Echo | GP3 |
Schematic Raspberry Pi Pico with OLED and HC-SR04
Follow the schematic diagram below connect them accordingly.
MicroPython Code: Displaying HC-SR04 Distance on OLED Display
from machine import Pin, I2C
from hcsr04 import HCSR04
from time import sleep
from ssd1306 import SSD1306_I2C
sensor = HCSR04(trigger_pin=2, echo_pin=3, echo_timeout_us=10000)
i2c=I2C(0,sda=Pin(0), scl=Pin(1), freq=400000) #initializing the I2C method
oled = SSD1306_I2C(128, 64, i2c)
while True:
oled.fill(0)
distance = str(sensor.distance_cm())
oled.text("Distance", 0,15)
oled.text(distance +" cm", 0,35)
oled.show()
sleep(1)
How Does the Code Work?
In the section, we only explained the Micropython code part which is used to display HC-SR04 sensor values on OLED. Because rest of the code is the same as we have used in the previous section to display distance readings on the shell console.
We will import the ssd1306 which is the OLED display library that we installed earlier. This will help us in accessing all the functions defined inside it. Also, we will be importing the Pin class and I2C class from the machine module. This is because we have to specify the pin for I2C communication.
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
Next, we will initialize the I2C GPIO pins for SCL and SDA respectively. We have used the I2C0 SCL and I2C0 SDA pins.
We have created an I2C() method which takes in four parameters. The first parameter is the I2C channel that we are using. The second parameter specifies the I2C GPIO pin of the board which is connected to the SDA line. The third parameter specifies the I2C GPIO pin of the board which is connected to the SCL line. The last parameter is the frequency connection.
We are setting the SCL on pin 1 and the SDA on pin 0.
i2c=I2C(0,sda=Pin(0), scl=Pin(1), freq=400000) #initializing the I2C method
Now, we will create an object ‘oled’ of SSD1306_I2C which uses the width, height, and the i2c object as parameters.
oled = SSD1306_I2C(128, 64, i2c)
Clears the OLED display with led.fill() routine.
oled.fill(0)
Finally, display the text along with distance reading on OLED after every 1 second.
distance = str(sensor.distance_cm())
oled.text("Distance", 0,15)
oled.text(distance +" cm", 0,35)
oled.show()
sleep(1)
In the end, call the show() method on the oled method for changes to show on OLED.
oled.show()
Demonstration
Upload the above code as main.py file to Raspberry Pi Pico. You will get HC-SR04 readings on the OLED display as follows:
We have other guides with popular sensors:
- MPU6050 with Raspberry Pi Pico (Accelerometer, Gyroscope, and Temperature)
- BME280 with Raspberry Pi Pico using MicroPython
- DHT11 DHT22 with Raspberry Pi Pico using MicroPython
- DS18B20 Temperature Sensor with Raspberry Pi Pico using MicroPython
Related HC-SR04 tutorials:
you talk about hooking VCC to 5 V but the PICO has an output of 3.3 volt. Is this the reason I get a reading of -0.03436426 cm in all the readings?
VBUS: is the micro-USB input voltage it is connected to micro-USB port pin 1. So if the input is 5V, the output is 5V.
VSYS: is the main system input voltage, which can vary in the allowed range 1.8V to 5.5V, and is used by the on-board
I also have a repeated -0.034… cm as return but haven’t solved the problem yet.
solved it. so the problem (with me at least) was that the connection to the sensor was not complete (the breadboard sucks). so try to check the connection wires. when you don’t connect the sensor at all you will get -0.0343… hope it helps!