#170Principiante

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.

0.0(0)
1 completato
Sensore di parcheggio con Raspberry Pi Pico (HC-SR04 + 3 LED + buzzer)
Il sensore di parcheggio delle auto, in versione da scrivania. L'HC-SR04 manda un suono troppo acuto per le tue orecchie e ne ascolta l'eco per misurare quanto è lontano un ostacolo; quando qualcosa entra nel raggio di un metro si accende il LED verde e il buzzer emette bip lenti. Avvicinandosi si accendono anche il giallo e il rosso e i bip diventano più rapidi e acuti; sotto i 10 centimetri il suono non si ferma più e la luce rossa lampeggia.

Video

Schema circuito

Sensore di parcheggio con Raspberry Pi Pico (HC-SR04 + 3 LED + buzzer) - Circuit

Codice sorgente

MicroPython
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)
207

FAQ

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.