Sensore di parcheggio con Raspberry Pi Pico (HC-SR04 + 3 LED + buzzer)
Il sensore di parcheggio dell'auto, in versione da scrivania! Il **Raspberry Pi Pico** misura con un **sensore a ultrasuoni HC-SR04** la distanza dall'ostacolo circa 16 volte al secondo. Più si avvicina, più **LED verde, giallo e rosso** si accendono e più veloce suona il **buzzer**; sotto i 10 cm il suono diventa continuo e il LED rosso lampeggia. Misura a ultrasuoni, suono con il PWM e temporizzazione non bloccante in un solo progetto.

Video
Schema circuito

Codice sorgente
1# ─────────────────────────────────────────
2# BlueGrays · bluegrays.com
3# Sensore di parcheggio con Raspberry Pi Pico (HC-SR04 + 3 LED + buzzer)
4# ─────────────────────────────────────────
5# Sensore di parcheggio per auto. L'HC-SR04 misura la distanza da un
6# ostacolo; man mano che si avvicina si accendono a turno i LED verde,
7# giallo e rosso e i bip accelerano. Molto vicino, il tono diventa
8# continuo e il LED rosso lampeggia.
9#
10# Pin:
11# GP27 -> TRIG dell'HC-SR04
12# GP26 -> ECHO dell'HC-SR04 (partitore 1k + 2k su hardware reale)
13# VBUS -> VCC dell'HC-SR04 (5V), GND.6 -> GND dell'HC-SR04
14# GP4 -> 220 ohm -> LED rosso (catodo a GND)
15# GP8 -> 220 ohm -> LED giallo (catodo a GND)
16# GP12 -> 220 ohm -> LED verde (catodo a GND)
17# GP17 -> Buzzer (+), altro piedino a GND
18
19from machine import Pin, PWM, time_pulse_us
20import time
21
22# ============ IMPOSTAZIONI ============
23GREEN_CM = 100 # Verde acceso, parte il bip
24YELLOW_CM = 50 # Si aggiunge il giallo
25RED_CM = 25 # Si aggiunge il rosso
26STOP_CM = 10 # Tono continuo + rosso lampeggiante
27
28BEEP_MS = 60 # Durata di un bip
29SLOW_GAP_MS = 700 # Pausa tra i bip a GREEN_CM
30FAST_GAP_MS = 50 # Pausa tra i bip vicino a STOP_CM
31VOLUME = 32768 # Duty PWM, 32768 = 50%
32FLASH_MS = 120 # Periodo del lampeggio rosso nella zona STOP
33
34MEASURE_MS = 60 # Intervallo di misura, minimo 60 ms
35PRINT_MS = 250 # Intervallo di stampa seriale
36ECHO_TIMEOUT_US = 12000 # oltre ~2 m = nessun ostacolo
37SOUND_CM_PER_US = 0.0343 # Velocità del suono (20 C)
38LOOP_MS = 5 # Passo del ciclo principale
39
40# Zone dalla più vicina alla più lontana: (nome, limite superiore cm, (verde, giallo, rosso), tono
41# Hz)
42ZONES = (
43 ("DUR / STOP", STOP_CM, (1, 1, 1), 1900),
44 ("KIRMIZI / RED", RED_CM, (1, 1, 1), 1900),
45 ("SARI / YELLOW", YELLOW_CM, (1, 1, 0), 1500),
46 ("YESIL / GREEN", GREEN_CM, (1, 0, 0), 1200),
47)
48CLEAR = len(ZONES) # Zona senza ostacoli
49STOP = 0 # Indice della zona STOP
50
51# ============ HARDWARE ============
52trig = Pin(27, Pin.OUT, value=0)
53echo = Pin(26, Pin.IN)
54led_green = Pin(12, Pin.OUT, value=0)
55led_yellow = Pin(8, Pin.OUT, value=0)
56led_red = Pin(4, Pin.OUT, value=0)
57buzzer = PWM(Pin(17))
58buzzer.duty_u16(0)
59
60
61# ============ MISURA ============
62def measure_cm():
63 # Inviare un impulso TRIG di 10 us, misurare per quanto tempo ECHO resta HIGH
64 trig.value(0)
65 time.sleep_us(2)
66 trig.value(1)
67 time.sleep_us(10)
68 trig.value(0)
69 pulse = time_pulse_us(echo, 1, ECHO_TIMEOUT_US)
70 if pulse < 0:
71 return None # Nessun eco o troppo lontano
72 # Il suono va e torna: metà
73 return pulse * SOUND_CM_PER_US / 2
74
75
76def median3(values):
77 # Mediana delle ultime 3 letture: una lettura sbagliata non fa sfarfallare i LED
78 a, b, c = values
79 return max(min(a, b), min(max(a, b), c))
80
81
82def zone_of(dist):
83 if dist is None:
84 return CLEAR
85 for i, zone in enumerate(ZONES):
86 if dist <= zone[1]:
87 return i
88 return CLEAR
89
90
91def beep_gap_ms(dist):
92 # Tra STOP_CM e GREEN_CM la pausa del bip cresce linearmente da FAST a SLOW
93 ratio = (dist - STOP_CM) / (GREEN_CM - STOP_CM)
94 ratio = min(1.0, max(0.0, ratio))
95 return int(FAST_GAP_MS + ratio * (SLOW_GAP_MS - FAST_GAP_MS))
96
97
98# ============ SUONO ============
99tone_on = False
100tone_hz = 0
101
102
103def tone(hz):
104 # Non toccare il PWM se il tono è già attivo
105 global tone_on, tone_hz
106 if tone_on and tone_hz == hz:
107 return
108 buzzer.freq(hz)
109 buzzer.duty_u16(VOLUME)
110 tone_on = True
111 tone_hz = hz
112
113
114def silence():
115 global tone_on
116 if tone_on:
117 buzzer.duty_u16(0)
118 tone_on = False
119
120
121def set_leds(green, yellow, red):
122 led_green.value(green)
123 led_yellow.value(yellow)
124 led_red.value(red)
125
126
127def self_test():
128 # Breve test all'accensione di LED e buzzer: verde -> giallo -> rosso
129 for leds, hz in (((1, 0, 0), 1200), ((1, 1, 0), 1500), ((1, 1, 1), 1900)):
130 set_leds(*leds)
131 tone(hz)
132 time.sleep_ms(90)
133 silence()
134 time.sleep_ms(160)
135 set_leds(0, 0, 0)
136
137
138# ============ CICLO PRINCIPALE ============
139print("== BlueGrays · bluegrays.com ==")
140print("Pico Park Sensoru / Parking Sensor")
141print("Yesil <= %d cm, sari <= %d cm, kirmizi <= %d cm, surekli ses <= %d cm"
142 % (GREEN_CM, YELLOW_CM, RED_CM, STOP_CM))
143print("Green <= %d cm, yellow <= %d cm, red <= %d cm, continuous tone <= %d cm"
144 % (GREEN_CM, YELLOW_CM, RED_CM, STOP_CM))
145self_test()
146
147FAR = 999.0 # Segnaposto per nessun ostacolo
148history = [FAR, FAR, FAR] # Ultime 3 letture
149distance = None # Distanza filtrata (cm)
150zone = CLEAR
151last_zone = -1
152now = time.ticks_ms()
153next_measure = now
154next_print = now
155last_beep = time.ticks_add(now, -10000) # Il primo bip suona subito
156beep_end = now
157
158while True:
159 now = time.ticks_ms()
160
161 # 1) Misura: ogni MEASURE_MS, con un filtro mediano
162 if time.ticks_diff(now, next_measure) >= 0:
163 next_measure = time.ticks_add(now, MEASURE_MS)
164 reading = measure_cm()
165 history = history[1:] + [reading if reading is not None else FAR]
166 filtered = median3(history)
167 distance = None if filtered >= FAR else filtered
168 zone = zone_of(distance)
169 if zone != last_zone:
170 name = "ENGEL YOK / CLEAR" if zone == CLEAR else ZONES[zone][0]
171 print("Bolge / Zone ->", name)
172 last_zone = zone
173
174 # 2) LED: barra grafica, il rosso lampeggia nella zona STOP
175 if zone == CLEAR:
176 set_leds(0, 0, 0)
177 elif zone == STOP:
178 flash_on = (now // FLASH_MS) % 2 == 0
179 set_leds(1, 1, 1 if flash_on else 0)
180 else:
181 set_leds(*ZONES[zone][2])
182
183 # 3) Suono: timer del bip non bloccante
184 if zone == CLEAR:
185 silence()
186 elif zone == STOP:
187 tone(ZONES[STOP][3]) # Molto vicino: tono continuo
188 else:
189 if tone_on and time.ticks_diff(now, beep_end) >= 0:
190 silence()
191 # La pausa viene ricalcolata a ogni passaggio: il bip successivo accelera appena ti avvicini
192 period = BEEP_MS + beep_gap_ms(distance)
193 if not tone_on and time.ticks_diff(now, last_beep) >= period:
194 tone(ZONES[zone][3])
195 last_beep = now
196 beep_end = time.ticks_add(now, BEEP_MS)
197
198 # 4) Monitor seriale: distanza in cm
199 if time.ticks_diff(now, next_print) >= 0:
200 next_print = time.ticks_add(now, PRINT_MS)
201 if distance is None:
202 print("Mesafe / Distance: --- (engel yok / no obstacle)")
203 else:
204 print("Mesafe / Distance: %5.1f cm" % distance)
205
206 time.sleep_ms(LOOP_MS)
207FAQ
Perché ECHO ha bisogno di un partitore di tensione nel circuito reale?▾
L'HC-SR04 funziona a 5V e la sua uscita ECHO dà 5V, ma i pin del Pico accettano al massimo 3,3V. Collega ECHO a GP26 tramite 1 kΩ e GP26 a GND tramite 2 kΩ: al pin arrivano circa 3,3V. Su Wokwi il partitore non serve.
Come cambio le distanze di avviso?▾
Modifica le costanti `GREEN_CM`, `YELLOW_CM`, `RED_CM` e `STOP_CM` all'inizio del codice. Mantieni le soglie nell'ordine `STOP_CM < RED_CM < YELLOW_CM < GREEN_CM`; per esempio, usa `STOP_CM = 30`, `RED_CM = 50`, `YELLOW_CM = 100` e `GREEN_CM = 150`. LED e bip seguono da soli le nuove soglie.
Perché i bip accelerano in modo continuo e non a zone?▾
`beep_gap_ms()` calcola la pausa in modo lineare in base alla distanza: 700 ms a 100 cm, 50 ms a 10 cm. Viene ricalcolata a ogni giro del ciclo principale, quindi il bip successivo arriva prima non appena l'ostacolo si avvicina. Le zone cambiano solo i LED e il tono.
Devo installare qualche libreria?▾
No. La funzione `time_pulse_us()` usata per la misura fa parte del modulo `machine`, già incluso in MicroPython. Installa MicroPython sul Pico e salva il codice su di esso come `main.py` con Thonny; il sensore parte da solo con un test dei LED e tre bip.
