Pico W HC-SR04 distance on GP17 and GP16
MicroPython on a Pico W: an HC-SR04 with TRIG on GP17 and ECHO on GP16 times its echo with ticks_us() and prints the distance in centimeters. The whole build, a Raspberry Pi Pico W 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 $9.10. On Mokxi they're free.
What you'll learn
- Ultrasonic distance sensing
- Timing a pulse with
ticks_us - A resistor divider to bring 5 V down to 3.3 V
- Turning time into distance
- Difficulty: Intermediate
- Time: About 20 minutes
- Board: Raspberry Pi Pico W
- Parts: 5
How it works
The HC-SR04 measures distance with sound. A 20 microsecond pulse on TRIG (GP17) makes it send a ping. Then ECHO (GP16) stays high for as long as the sound takes to go out and come back. The sensor's ECHO is 5 V, so a 1k and 2k resistor pair divides it down for the Pico.
The program times that high pulse in microseconds. Sound travels about 0.034 cm per microsecond, and the pulse covers the trip both ways, so the result is halved. It prints the distance in centimeters every 300 ms.
Parts list
5 parts, plus the jumper wires. They retail for about $9.10; on Mokxi they're free.
- 1 × Raspberry Pi Pico W
- 1 × Ultrasonic rangerIn Halloween Prop Kit.
- 1 × Resistor, 1k ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
- 1 × Resistor, 2k ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
- 1 × Power, 5 V
Kits that can build it
These 2 starter kits have 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 pin | Connects to |
|---|---|
| Ultrasonic ranger pin TRIG | Raspberry Pi Pico W pin GP17 |
| Resistor, 1k Ω pin 2 | Raspberry Pi Pico W pin GP16 |
| Resistor, 2k Ω pin 1 | Raspberry Pi Pico W pin GP16 |
| Ultrasonic ranger pin VCC | 5 V |
| Resistor, 1k Ω pin 1 | Ultrasonic ranger pin ECHO |
| Ultrasonic ranger pin GND | Ground |
| Resistor, 2k Ω pin 2 | Ground |
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.
# Measuring distance: a 20 us pulse on TRIG (GP17) makes the HC-SR04
# send a ping; ECHO (GP16) stays high for as long as the sound took to
# come back. Sound goes 340 m/s, so each cm out and back is about 58 us.
from machine import Pin
import time
trig = Pin(17, Pin.OUT)
echo = Pin(16, Pin.IN)
def distance_cm():
trig.value(0)
time.sleep_us(2)
trig.value(1)
time.sleep_us(20)
trig.value(0)
while echo.value() == 0:
pass
began = time.ticks_us()
while echo.value() == 1:
pass
return time.ticks_diff(time.ticks_us(), began) * 0.0340 / 2
while True:
print("distance %.1f cm" % distance_cm())
time.sleep_ms(300)
Code walkthrough
The key functions of the sketch, and what each one does.
distance_cm main.py
Sends the ping: TRIG low for 2 us, high for 20 us, then low. It waits for ECHO to go high, notes the time with time.ticks_us(), and waits for ECHO to fall. The elapsed time times 0.0340, divided by 2, gives centimeters.
def distance_cm():
trig.value(0)
time.sleep_us(2)
trig.value(1)
time.sleep_us(20)
trig.value(0)
while echo.value() == 0:
pass
began = time.ticks_us()
while echo.value() == 1:
pass
return time.ticks_diff(time.ticks_us(), began) * 0.0340 / 2Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The program hangs and prints nothing This project
The loops wait forever for ECHO to change. Check TRIG is on GP17 and ECHO, through the divider, is on GP16. - The Pico gets a 5 V signal on ECHO This project
Keep the 1k and 2k divider between ECHO and GP16. - 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. - Pins are powered from 5 V, or a 5 V signal goes into a GPIO. The RP2040 pins are 3.3 V only and are not 5 V tolerant. Raspberry Pi Pico W
Power the board from VBUS or VSYS at 5 V, but keep GPIO signals at 3.3 V. Use a level shifter or a divider for 5 V parts. - WiFi code fails to connect, or the on-board LED code does nothing. The LED on the Pico W is not on GP25 like on the plain Pico. Raspberry Pi Pico W
Use the board's LED_BUILTIN name so the library drives it through the WiFi chip. Join a 2.4 GHz network only, with the right SSID and password, and wait for the link before sending.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.