Built-in project · Raspberry Pi Pico

MicroPython HC-SR04 on a Pico, timed by hand

MicroPython on a Raspberry Pi Pico: an HC-SR04 with TRIG on GP19 and ECHO on GP18, its echo timed with ticks_us, prints centimeters twice a second. The whole build, a Raspberry Pi Pico and 3 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Intermediate About 20 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $7.10. On Mokxi they're free.

The circuit runs here once the page has loaded.

What you'll learn

  • Timing a pulse by hand
  • Turning echo time into distance
  • A resistor divider for a 3.3 V input
  • Timeouts that stop the loop from hanging
  • Difficulty: Intermediate
  • Time: About 20 minutes
  • Board: Raspberry Pi Pico
  • Parts: 5

How it works

The HC-SR04 sends out a burst of sound when TRIG (GP19) gets a short pulse. ECHO then goes high until the sound comes back. The sensor runs on 5 V, so ECHO goes through a 1k and 2k divider to bring it down to 3.3 V for GP18.

The MicroPython code sends a 20 microsecond pulse and times how long ECHO stays high with ticks_us. Sound goes there and back at 343 m/s, so the distance is the time times 0.0343 centimeters per microsecond, divided by 2. It prints a result twice a second.

Parts list

5 parts, plus the jumper wires. They retail for about $7.10; on Mokxi they're free.

Kits that can build it

This starter kit has every part in the circuit. Each kit's page lists what else it can build.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
Ultrasonic ranger pin TRIGRaspberry Pi Pico pin GP19
Resistor, 1k Ω pin 2Raspberry Pi Pico pin GP18
Resistor, 2k Ω pin 1Raspberry Pi Pico pin GP18
Ultrasonic ranger pin VCC5 V
Resistor, 1k Ω pin 1Ultrasonic ranger pin ECHO
Ultrasonic ranger pin GNDGround
Resistor, 2k Ω pin 2Ground

The code

The MicroPython code exactly as the editor opens it. Change a line there and press Run: the board runs it on the official MicroPython firmware, with nothing to compile.

main.py · Raspberry Pi Pico
# Ultrasonic ranging by hand: a 20 us pulse on TRIG (GP19), then time how
# long ECHO (GP18) stays high. Sound goes there and back at 343 m/s.
from machine import Pin
import time

trig = Pin(19, Pin.OUT, value=0)
echo = Pin(18, Pin.IN)

def distance_cm():
    trig.value(1)
    time.sleep_us(20)                         # 20 us: the datasheet asks for at least 10
    trig.value(0)
    start = time.ticks_us()
    while echo.value() == 0:                 # wait for the echo to start
        if time.ticks_diff(time.ticks_us(), start) > 30000:
            return None
    began = time.ticks_us()
    while echo.value() == 1:                 # and time it
        if time.ticks_diff(time.ticks_us(), began) > 30000:
            return None
    return time.ticks_diff(time.ticks_us(), began) * 0.0343 / 2

while True:
    d = distance_cm()
    print("distance: %.1f cm" % d if d is not None else "nothing in range")
    time.sleep_ms(500)

Code walkthrough

The key functions of the sketch, and what each one does.

distance_cm main.py

Sets trig high for 20 us, then low. It waits for echo to go high, then times how long it stays high. If either wait lasts more than 30000 us, it returns None, which the main loop prints as "nothing in range". Otherwise it returns the time times 0.0343 divided by 2.

def distance_cm():
    trig.value(1)
    time.sleep_us(20)                         # 20 us: the datasheet asks for at least 10
    trig.value(0)
    start = time.ticks_us()
    while echo.value() == 0:                 # wait for the echo to start
        if time.ticks_diff(time.ticks_us(), start) > 30000:
            return None
    began = time.ticks_us()
    while echo.value() == 1:                 # and time it
        if time.ticks_diff(time.ticks_us(), began) > 30000:
            return None
    return time.ticks_diff(time.ticks_us(), began) * 0.0343 / 2

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • It always says "nothing in range" This project
    Check TRIG on GP19, ECHO through the divider to GP18, and 5 V on the sensor's VCC.
  • ECHO goes straight to the Pico This project
    Keep the divider: 1k from ECHO to GP18, and 2k from GP18 to ground.
  • Distance reads zero, or never changes. Ultrasonic ranger
    Power it from 5 V and share ground. Send a 10 microsecond HIGH pulse on TRIG, then time ECHO with pulseIn. Check TRIG and ECHO are not swapped.
  • Readings jump around or are wrong on a 3.3 V board. Ultrasonic ranger
    ECHO outputs 5 V, so divide it down for 3.3 V boards. Aim at flat, hard surfaces. The range is about 2 cm to 4 m, and soft or angled targets bounce the sound away.
  • The LED is dim, burns out, or the pin reads wrong because the resistor value is off. Resistor
    Read the color bands again. A 220 ohm to 330 ohm resistor suits a typical LED on 5 V. 10k is a common pull-up or pull-down value. Check with a multimeter if unsure.
  • A pull-up or pull-down resistor is missing, so the input floats and reads random values. Resistor
    Tie the input to 5 V or ground through about 10k. Or use INPUT_PULLUP and wire the switch to ground.
  • The Pico does not show up as a drive, or the program will not load. Raspberry Pi Pico
    Hold the BOOTSEL button while you plug in USB. A drive named RPI-RP2 appears. Then copy the UF2 file onto it.
  • A 5 V signal or sensor is wired to a GPIO pin. Raspberry Pi Pico
    Pico GPIO pins are 3.3 V only and are not 5 V tolerant. Use a level shifter or a voltage divider for any 5 V output going into the board.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.