HC-SR04 Ultrasonic Sensor with Raspberry Pi Pico using MicroPython

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.

HC-SR04 Ultrasonic Sensor with Raspberry Pi Pico

We have a similar guide for ESP8266 and ESP32 using Arduino IDE:

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.

HC-SR04 Ultrasonic Sensor Pinout diagram

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-SR04 and object distance position

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

Ultrasonic sensor HC-SR04 working
  • 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.

Timing diagram HC-SR04

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.

Raspberry Pi Pico with HC-SR04 connection diagram
Raspberry Pi Pico with HC-SR04 connection diagram

Now make the connection of Raspberry Pi Pico with the HC-SR04 sensor according to this connection diagram.

HC-SR04Raspberry Pi Pico
VCCVSYS (5V)
GNDGND
TriggerGP2
EchoGP3
Raspberry Pi Pico with HC-SR04

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:

Raspberry Pi Pico with HC-SR04 Shell Console readings

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.
Raspberry Pi Pico Installing ssd1306 OLED library MicoPython 1
  • Search for “ssd1306” in the search bar by typing its name and clicking the button ‘Search on PyPI.’
Raspberry Pi Pico Installing ssd1306 OLED library MicoPython 2
  • From the following search results click on the one highlighted below: micropython-ssd1306
Raspberry Pi Pico Installing ssd1306 OLED library MicoPython 3

Install this library.

Raspberry Pi Pico Installing ssd1306 OLED library MicoPython 4

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.

  1. Raspberry Pi Pico
  2. HC-SR04
  3. SSD1306 OLED Display
  4. 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 DisplayRaspberry Pi Pico
VCC5V
SDAGP0 (I2C0 SDA)
SCLGP1 (I2C0 SCL)
GNDGND
HC-SR04Raspberry Pi Pico
VCC5V
GNDGND
TriggerGP2
EchoGP3

Schematic Raspberry Pi Pico with OLED and HC-SR04

Follow the schematic diagram below connect them accordingly.

Raspberry Pi Pico with HC-SR04 and oled connection diagram
Raspberry Pi Pico with HC-SR04 and OLED connection diagram
Raspberry Pi Pico with HC-SR04 and oled

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:

Raspberry Pi Pico with HC-SR04 and oled demo

We have other guides with popular sensors:

Related HC-SR04 tutorials:

4 thoughts on “HC-SR04 Ultrasonic Sensor with Raspberry Pi Pico using MicroPython”

  1. 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?

    Reply
    • 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

      Reply
    • 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!

      Reply

Leave a Comment