Radar de recul avec Raspberry Pi Pico (HC-SR04 + 3 LED + buzzer)
Le radar de recul de ta voiture, version bureau ! Le **Raspberry Pi Pico** mesure avec un **capteur à ultrasons HC-SR04** la distance jusqu'à l'obstacle environ 16 fois par seconde. Plus il approche, plus les **LED verte, jaune et rouge** s'allument et plus le **buzzer** bipe vite ; sous 10 cm, le son devient continu et la LED rouge clignote. Mesure par ultrasons, son en PWM et temporisation non bloquante dans un seul projet.

Vidéo
Schéma du circuit

Code source
1# ─────────────────────────────────────────
2# BlueGrays · bluegrays.com
3# Radar de recul avec Raspberry Pi Pico (HC-SR04 + 3 LED + buzzer)
4# ─────────────────────────────────────────
5# Capteur de stationnement pour voiture. Le HC-SR04 mesure la distance à
6# un obstacle ; en se rapprochant, les LED verte, jaune et rouge
7# s'allument tour à tour et les bips s'accélèrent. Tout près, le son
8# devient continu et la LED rouge clignote.
9#
10# Broches :
11# GP27 -> TRIG du HC-SR04
12# GP26 -> ECHO du HC-SR04 (diviseur 1k + 2k sur le vrai matériel)
13# VBUS -> VCC du HC-SR04 (5V), GND.6 -> GND du HC-SR04
14# GP4 -> 220 ohm -> LED rouge (cathode sur GND)
15# GP8 -> 220 ohm -> LED jaune (cathode sur GND)
16# GP12 -> 220 ohm -> LED verte (cathode sur GND)
17# GP17 -> Buzzer (+), autre patte sur GND
18
19from machine import Pin, PWM, time_pulse_us
20import time
21
22# ============ RÉGLAGES ============
23GREEN_CM = 100 # Vert allumé, les bips démarrent
24YELLOW_CM = 50 # Le jaune s'ajoute
25RED_CM = 25 # Le rouge s'ajoute
26STOP_CM = 10 # Son continu + rouge clignotant
27
28BEEP_MS = 60 # Durée d'un bip
29SLOW_GAP_MS = 700 # Écart entre les bips à GREEN_CM
30FAST_GAP_MS = 50 # Écart entre les bips près de STOP_CM
31VOLUME = 32768 # Rapport cyclique PWM, 32768 = 50 %
32FLASH_MS = 120 # Période du clignotement rouge dans la zone STOP
33
34MEASURE_MS = 60 # Intervalle de mesure, 60 ms minimum
35PRINT_MS = 250 # Intervalle d'affichage série
36ECHO_TIMEOUT_US = 12000 # au-delà de ~2 m = pas d'obstacle
37SOUND_CM_PER_US = 0.0343 # Vitesse du son (20 C)
38LOOP_MS = 5 # Pas de la boucle principale
39
40# Zones de la plus proche à la plus lointaine : (nom, limite haute cm, (vert, jaune, rouge),
41# tonalité 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) # Zone sans obstacle
49STOP = 0 # Indice de la zone STOP
50
51# ============ MATÉRIEL ============
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# ============ MESURE ============
62def measure_cm():
63 # Envoyer une impulsion TRIG de 10 us, chronométrer combien de temps ECHO reste 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 # Pas d'écho ou trop loin
72 # Le son fait l'aller-retour : la moitié
73 return pulse * SOUND_CM_PER_US / 2
74
75
76def median3(values):
77 # Médiane des 3 dernières lectures : une mauvaise lecture ne fait pas scintiller les 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 # Entre STOP_CM et GREEN_CM, l'écart entre les bips augmente linéairement de FAST à 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# ============ SON ============
99tone_on = False
100tone_hz = 0
101
102
103def tone(hz):
104 # Laisser le PWM tranquille si la tonalité est déjà active
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 # Court test de mise sous tension des LED et du buzzer : vert -> jaune -> rouge
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# ============ BOUCLE 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 # Valeur de remplacement pour l'absence d'obstacle
148history = [FAR, FAR, FAR] # 3 dernières lectures
149distance = None # Distance filtrée (cm)
150zone = CLEAR
151last_zone = -1
152now = time.ticks_ms()
153next_measure = now
154next_print = now
155last_beep = time.ticks_add(now, -10000) # Le premier bip joue aussitôt
156beep_end = now
157
158while True:
159 now = time.ticks_ms()
160
161 # 1) Mesure : toutes les MEASURE_MS, avec un filtre médian
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 : bargraphe, le rouge clignote dans la zone 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) Son : minuterie de bip non bloquante
184 if zone == CLEAR:
185 silence()
186 elif zone == STOP:
187 tone(ZONES[STOP][3]) # Très proche : son continu
188 else:
189 if tone_on and time.ticks_diff(now, beep_end) >= 0:
190 silence()
191 # L'écart est recalculé à chaque passage : le bip suivant s'accélère dès que tu te
192 # rapproches
193 period = BEEP_MS + beep_gap_ms(distance)
194 if not tone_on and time.ticks_diff(now, last_beep) >= period:
195 tone(ZONES[zone][3])
196 last_beep = now
197 beep_end = time.ticks_add(now, BEEP_MS)
198
199 # 4) Moniteur série : distance en cm
200 if time.ticks_diff(now, next_print) >= 0:
201 next_print = time.ticks_add(now, PRINT_MS)
202 if distance is None:
203 print("Mesafe / Distance: --- (engel yok / no obstacle)")
204 else:
205 print("Mesafe / Distance: %5.1f cm" % distance)
206
207 time.sleep_ms(LOOP_MS)
208FAQ
Pourquoi ECHO a-t-il besoin d'un pont diviseur sur le vrai montage ?▾
Le HC-SR04 fonctionne en 5V et sa sortie ECHO fournit 5V, alors que les broches du Pico acceptent 3,3V au maximum. Relie ECHO à GP26 via 1 kΩ et GP26 à GND via 2 kΩ : la broche reçoit environ 3,3V. Sur Wokwi, le diviseur est inutile.
Comment modifier les distances d'alerte ?▾
Change les constantes `GREEN_CM`, `YELLOW_CM`, `RED_CM` et `STOP_CM` en haut du code. Respecte l'ordre `STOP_CM < RED_CM < YELLOW_CM < GREEN_CM` ; par exemple, utilise `STOP_CM = 30`, `RED_CM = 50`, `YELLOW_CM = 100` et `GREEN_CM = 150`. Les LED et les bips suivent automatiquement les nouveaux seuils.
Pourquoi les bips accélèrent-ils en continu et pas par paliers ?▾
`beep_gap_ms()` calcule l'intervalle de façon linéaire selon la distance : 700 ms à 100 cm, 50 ms à 10 cm. Il est recalculé à chaque tour de la boucle principale, donc le bip suivant arrive plus tôt dès que l'obstacle se rapproche. Les zones ne changent que les LED et la tonalité.
Faut-il installer une bibliothèque ?▾
Non. La fonction `time_pulse_us()` qui sert à la mesure fait partie du module `machine`, inclus dans MicroPython. Installe MicroPython sur le Pico et enregistre le code dessus sous le nom `main.py` avec Thonny ; le capteur démarre seul avec un test des LED et trois bips.
