Pico W reversing aid: HC-SR04 and a beeper
MicroPython on a Pico W: an HC-SR04 on GP17 and GP16 measures the gap, and an active buzzer and an LED beep faster as an obstacle gets closer. The whole build, a Raspberry Pi Pico W and 8 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 30 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $9.80. On Mokxi they're free.
What you'll learn
- Measuring distance with an ultrasonic sensor
- Dividing a 5 V signal down for a 3.3 V pin
- Turning a distance into beep timing
- Switching a buzzer with a transistor
- Difficulty: Intermediate
- Time: About 30 minutes
- Board: Raspberry Pi Pico W
- Parts: 11
How it works
An HC-SR04 ultrasonic ranger measures the gap behind a car. The Pico W sends a short pulse on TRIG (GP17) and times how long ECHO (GP16) stays high. The echo goes through a resistor divider, 1k and 2k, so the 5 V signal is safe for the 3.3 V pin.
The closer the obstacle, the faster the beeps. Beyond 50 cm it beeps every 2000 ms. Between 20 and 50 cm it is 1000 ms, between 10 and 20 cm it is 500 ms, and under 10 cm it is 300 ms.
Each beep lasts 100 ms. The buzzer on GP15 and the LED on GP14 switch on together.
Parts list
11 parts, plus the jumper wires. They retail for about $9.80; on Mokxi they're free.
- 1 × Raspberry Pi Pico W
- 1 × Ultrasonic rangerIn Halloween Prop Kit.
- 2 × Resistor, 1k ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
- 1 × Resistor, 2k ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
- 1 × BuzzerIn Starter Kit, Rocket Flight Computer Kit.
- 1 × Transistor (NPN or PNP)In LED Cube Kit.
- 1 × Resistor, 220 ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
- 1 × LED, redIn Starter Kit, Halloween Prop Kit, Logic Lab Kit.
- 1 × Power, 5 V
- 1 × Power, 3.3 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 |
|---|---|
| Resistor, 220 Ω pin 2 | Raspberry Pi Pico W pin GP14 |
| Resistor, 1k Ω (2) pin 1 | Raspberry Pi Pico W pin GP15 |
| Ultrasonic ranger pin TRIG | Raspberry Pi Pico W pin GP17 |
| Resistor, 1k Ω (1) 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 Ω (1) pin 1 | Ultrasonic ranger pin ECHO |
| Ultrasonic ranger pin GND | Ground |
| Resistor, 2k Ω pin 2 | Ground |
| Buzzer pin 1 | 3.3 V |
| Transistor (NPN or PNP) pin C | Buzzer pin 2 |
| Resistor, 1k Ω (2) pin 2 | Transistor (NPN or PNP) pin B |
| Transistor (NPN or PNP) pin E | Ground |
| LED, red pin A | Resistor, 220 Ω pin 1 |
| LED, red pin C | 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.
# Reversing aid: the HC-SR04 (TRIG GP17, ECHO GP16) measures the gap
# behind the car. The closer the obstacle, the faster the buzzer (GP15)
# beeps and the LED (GP14) blinks.
from machine import Pin
import time
trig = Pin(17, Pin.OUT)
echo = Pin(16, Pin.IN)
buzzer = Pin(15, Pin.OUT)
led = Pin(14, Pin.OUT)
def distance_cm():
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
def interval(cm):
if cm > 50:
return 2000
if cm > 20:
return 1000
if cm > 10:
return 500
return 300
while True:
cm = distance_cm()
wait = interval(cm)
print("%.0f cm, beep every %d ms" % (cm, wait))
buzzer.value(1)
led.value(1)
time.sleep_ms(100)
buzzer.value(0)
led.value(0)
time.sleep_ms(wait - 100)
Code walkthrough
The key functions of the sketch, and what each one does.
distance_cm main.py
It sends a 20 microsecond pulse on TRIG. Then it waits for ECHO to go high and times how long it stays high. That time, multiplied by 0.0340 and halved because the sound goes out and back, gives the distance in centimeters.
def distance_cm():
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 / 2interval main.py
It turns a distance in centimeters into a wait time in milliseconds. Over 50 cm gives 2000, over 20 gives 1000, over 10 gives 500, and anything closer gives 300. The main loop uses it to space the beeps.
def interval(cm):
if cm > 50:
return 2000
if cm > 20:
return 1000
if cm > 10:
return 500
return 300Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The distance never updates or the program hangs. This project
The code waits for ECHO forever. Check TRIG is on GP17 and ECHO reaches GP16 through the divider. - The buzzer stays silent. This project
Check the transistor: collector to the buzzer, emitter to ground, base to GP15 through the 1k resistor. - 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 buzzer makes a constant tone, or you cannot change its pitch. Buzzer
An active buzzer has its own oscillator, so it only beeps on and off. A passive buzzer needs tone() to set pitch. Check which type you have. - The buzzer is silent or very quiet. Buzzer
Check polarity: the plus mark goes to the pin or supply. For loud buzzers, drive them through a transistor instead of straight from a pin.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.