Tutorial: build a distance sensor with a Raspberry Pi Pico and CircuitPython

In a previous tutorial “build a distance sensor with an alarm” we used an Arduino Nano (coded in a C-variant). Now, we will do the same with a Raspberry Pi Pico and CircuitPython, a version of Python which runs on microcontrollers. If you are more interested in programming the Pico with the Arduino IDE (in C), check out this tutorial.

In this tutorial you will learn to build a distance sensor with an alarm. It takes the basic steps to connect electronic components and programming the Raspberry Pi Pico in Python. It uses an ultrasonic distance sensor to sense the distance to an object nearby and an OLDED display to show the measured value of the distance sensor.

It consist of the following steps:

  1. Setup the Raspberry Pi Pico
  2. Connect and test the OLED display
  3. Connect and test the Ultrasonic sensor
  4. Add an alarm depending on the distance
  5. Add comments to the code

What you need

1. Setup the Raspberry Pi Pico

First, install the latest version of CircuitPython to the board. Download the .UF2 file here. Connect the USB-cable to the board. While pressing the BOOTSEL button on the board, connect the other end of the cable to your computer. Continue to hold the BOOTSEL button until a drive appears: a new drive labelled ‘RPI-RP2’ will appear in your Windows Explorer (or Finder on a Mac). In the example this is the D: drive, but it might be different on your computer:

Now drag the downloaded .UF2 file to the RPI-RP2 drive. Now wait for the RPI-RP2 drive to disappear and then re-appear (labelled CIRCUITPY).

For more detailed steps check out the tutorial “Installing CircuitPython”.

Check the Raspberry Pi Pico, blink the onboard LED

To start writing code, you need an editor. We recommend to use Thonny. So, download and install that. Alternative editors are the Mu Editor or Visual Studio Code.

After you have installed the editor, you can create your first Python file. Select File > New. And copy-paste the code below into the editor.

# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""Example for Pico. Blinks the built-in LED."""
import time
import board
import digitalio

led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT

while True:
    led.value = not led.value
    time.sleep(0.5)

This code comes from the first part of this tutorial, at “The LED blinks!”. If you want to learn more of how exactly it works follow the steps in that tutorial!

The first lines start by importing several modules using the import statement. A module is a set of code which can be reused easily. It contains code to avoid you having to ‘re-invent the wheel’ all the time.

Before you can run the script, first connect the Raspberry Pi Pico board to your computer using a USB cable. Wait a few seconds to let it initialize. Then, in the Thonny editor, choose Run > Configure interpreter and set the interpreter to CircuitPython and choose the active port (in Windows: the one that has CircuitPython CDC control…):

Configure Thonny editor: choose interpreter and Port

Close the Options Window (Press Ok). Now, you should be able to run the script. Press Run and see what happens… If all is well, the LED next to the USB connector on the board should start blinking.

2. Connect and test the OLED display

The  0.96 inch OLED Display (128*64 pixels) is an i2c module, which makes it easy to connect as it has only 4 wires. It is assumed you have some basic understanding of using electronics and wiring a breadboard. For making the right connections you need the pinout diagram of the Pico:

See the image below. Pins of the display are on the board itself. Please take great care: pins on your display might be in a different order! The one below has GND-VCC-SCL-SDA, but yours might be different!

Unplug the USB cable. Plug the Pico onto the breadboard. Start wiring the power lines (blue and red lines on the breadboard) to GND and 3V3 of the Pico:

Then plug the display onto the board and wire it:

Display:    Pico:                   Wire color in diagram:
GND         GND                     black
VCC         3V3                     red
SCL         pin 5 (I2C1 SCL/GP3)    yellow
SDA         pin 4 (I2C1 SDA/GP2)    blue

(you are free to choose any other color for the wires)

Download example code

To test the display, you can use this example script: display.py. Open it in the editor. Please be aware that the script is saved in your Download folder. If you do not want this, Select File > Save As to save it to another folder, for instance the Documents\Python folder.

After you double check the wiring from the previous step, plug in the USB cable. Press Run and check if “Hello World!” is shown on the display.

You can also run a simulation of this circuit here and take a closer look at the wiring.

3. Connect and test the Ultrasonic sensor

This part of this tutorial introduces the HC-SR04 Ultrasonic sensor. There are older versions of this sensor that need 5V power to operate properly. We assume you will use a more modern version, which will operate at voltages between 2.8 – 5.5V. If that is not the case, look here for a solution.

Disconnect the USB cable before you continue.

This image has an empty alt attribute; its file name is hc-sr04.png

To use this sensor, you can connect it to power (GND and VCC) and connect the Echo and Trig pins to pin 21 and 22 of the Pico:

Sensor:     Pico:         Wire color:
Gnd         GND           black
Vcc         3V3           red
Echo        pin 21 (GP16) magenta
Trig        pin 22 (GP17) cyan

The result should look something like:

To test the sensor, you can use this example script: display_distance.py. Open it in the editor and save it to your documents folder.

After you double check the wiring from the previous step, plug in the USB cable. Press Run and check if measured values of the distance measured are shown on the display.

You can also run a simulation of this circuit here and take a closer look at the wiring.

The values are displayed with 3 decimals, which is unnecessary. Try to round the value using round(…)

4. Add an alarm depending on the distance

We are going to use a buzzer, which is a small device that can generate tones. There are different types, as explained in this video:

Function wise they all work the same: a Pulse-Width-Modulated (PWM) signal is sent to it to generate the sound. Usually, the + pin of the buzzer is indicated by a + sign on the housing or on the bottom. If it is not, the longest leg is the +. If there is no visible indication of a + pin, just connect it. You cannot break it by connecting it wrong, just give it a try. If it does not work, reverse the connection and try again.

Connect the + pin of the buzzer to pin 20 (GP15) of the Pico (scroll up for pinout diagram) and connect the other pin to the (blue) GND track of the breadboard.

Next, start a new file in the editor and copy the code below into it.

import time
import board
import digitalio
import pwmio

buzzer = pwmio.PWMOut(board.GP15, frequency=660, duty_cycle=0, variable_frequency=True)

while True:
    buzzer.duty_cycle = 2 ** 15
    time.sleep(0.5)
    buzzer.duty_cycle = 0
    time.sleep(0.5)

Connect the USB cable, press Run and the buzzer should start beeping.

If you are already an experienced programmer, you should be able to combine the previous example (from step 3) with this one and make an alarm dependent on how close an object is. But combining two scripts might be a bit much for a start, so we have done this for you. The only thing we left out is the part which determines when the alarm has to sound. (This will be an if statement with a call to a function).

The combined example can be downloaded here: ultrasonic_sensor_warning.py. Browse through the code, and check for parts you recognize from the previous examples. Try the example (upload it). As you may notice, it beeps shortly at the start. Can you find the lines of code which do this? This is the part:

def beep():
    buzzer.duty_cycle = 2 ** 15
    time.sleep(0.5)
    buzzer.duty_cycle = 0
    time.sleep(0.5)
    
# beep two times:
for x in range(2):
    beep()

To make an alarm, two things have to be done:

  1. Determine if an alarm has to be sound (with a condition)
  2. Make the alarm sound

Determine if an alarm has to be sound (with a condition)

In the while-loop at the end, find this line of comment:

# something nearby?

After that line, add an if-statement, with the next line of comment inside it:

if condition:
    # sound alarm

If something is close, the variable distance is smaller than a certain value. So an example of the condition is distance < 100. Add this to the code (replace the condition of the if-statement).

Make the alarm sound

Inside the if-statement, add the line of code which makes a beep (look at the code before the while-loop for an example): what you must add is a call to the beep() function.

Now test the script (upload it). Does it work? Adjust the distance checked for in the condition. It should NOT be a meter (100cm) but a closer distance.

5. Add comments to the code

Add more comments to the part of the code that you added/modified. The comments should explain, in your own words, what this code does. Use multi line comments or single line comments. Some examples:

"""
Example of a multi line comment.
This is the second line of the comment.
"""

# Example of a line of code with comment at the end of the line:
print("Start of distance measurement") # display text on standard output

At the top of the script, add general comments. The first line of comments should contain your name and student number. Add at least one more line which explains the general meaning of the script as a whole (what does it do?).

Summary

With this tutorial you have familiarized yourself with building an electronic circuit using a breadboard and you have used an editor to program the Raspberry Pi Pico with a script.
In addition, you have learned the following:

  • Adding components like a display and a sensor to a breadboard and wiring them
  • Using an example script to test the components
  • Use and setup modules
  • Add code to an existing script
  • Explain and document code by adding comments to code

More information