#170Débutant

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.

0.0(0)
1 terminé
Radar de recul avec Raspberry Pi Pico (HC-SR04 + 3 LED + buzzer)
Le radar de recul des voitures, en version de bureau. Le HC-SR04 envoie un son trop aigu pour tes oreilles et écoute son écho pour mesurer la distance d'un obstacle ; dès que quelque chose arrive à moins d'un mètre, la LED verte s'allume et le buzzer bipe lentement. Plus il approche, plus le jaune puis le rouge s'allument et plus les bips deviennent rapides et aigus ; sous 10 centimètres, le son ne s'arrête plus et la lumière rouge clignote.

Vidéo

Schéma du circuit

Radar de recul avec Raspberry Pi Pico (HC-SR04 + 3 LED + buzzer) - Circuit

Code source

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

FAQ

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.