Log #40 · Sep 27, 2026
Build an Arduino Parking Sensor
A garage parking assistant with an HC-SR04 sensor, a buzzer that beeps faster as you get closer and LEDs that go from green to red.
Cars with parking sensors beep slowly when an obstacle is far away and faster as you get closer, until the tone becomes continuous. This project recreates that with an ultrasonic sensor, a buzzer and three LEDs. Mounted on a garage wall, it tells you exactly when to stop. It is also a good exercise in turning a measurement into smooth, responsive feedback without blocking the program.
Parts list
| Part | Quantity | Notes |
|---|---|---|
| Arduino Uno or Nano | 1 | |
| HC-SR04 ultrasonic sensor | 1 | See the HC-SR04 guide |
| Active or passive buzzer | 1 | |
| Green, yellow and red LEDs | 1 each | |
| 220 Ω resistors | 3 | For the LEDs |
| Breadboard, wires | ||
| 5 V USB power adapter | 1 | For permanent installation |
How it behaves
| Distance | LEDs | Sound |
|---|---|---|
| More than 100 cm | Green | Silent |
| 100 to 50 cm | Yellow | Slow beeps, faster as you approach |
| 50 to 20 cm | Red | Fast beeps |
| Under 20 cm | Red flashing | Continuous tone: stop |
Wiring
| Part | Arduino pin |
|---|---|
| HC-SR04 VCC / GND | 5 V / GND |
| HC-SR04 TRIG / ECHO | 9 / 10 |
| Green LED + 220 Ω | 4 |
| Yellow LED + 220 Ω | 5 |
| Red LED + 220 Ω | 6 |
| Buzzer + | 8 (− to GND) |
The code
The key idea is to map distance to the interval between beeps, and to time the beeps with millis() so the sensor keeps measuring continuously. The millis() guide explains the pattern.
const int TRIG = 9, ECHO = 10;
const int GREEN = 4, YELLOW = 5, RED = 6, BUZZ = 8;
unsigned long lastPing = 0, lastBeep = 0;
float distance = 400;
bool beepOn = false;
float readCm() {
digitalWrite(TRIG, LOW); delayMicroseconds(2);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
unsigned long us = pulseIn(ECHO, HIGH, 30000);
return us == 0 ? 400 : us / 58.0;
}
void lights(bool g, bool y, bool r) {
digitalWrite(GREEN, g); digitalWrite(YELLOW, y); digitalWrite(RED, r);
}
void setup() {
pinMode(TRIG, OUTPUT); pinMode(ECHO, INPUT);
pinMode(GREEN, OUTPUT); pinMode(YELLOW, OUTPUT); pinMode(RED, OUTPUT);
pinMode(BUZZ, OUTPUT);
}
void loop() {
unsigned long now = millis();
if (now - lastPing >= 60) { // measure ~16 times per second
lastPing = now;
float d = readCm();
distance = distance * 0.6 + d * 0.4; // smooth out jumps
}
if (distance > 100) { // far: all quiet
lights(1, 0, 0);
noTone(BUZZ);
return;
}
if (distance < 20) { // stop!
bool flash = (now / 150) % 2;
lights(0, 0, flash);
tone(BUZZ, 2000);
return;
}
lights(0, distance >= 50, distance < 50);
// 100 cm -> 600 ms between beeps, 20 cm -> 80 ms
unsigned long interval = map((long)distance, 20, 100, 80, 600);
if (now - lastBeep >= (beepOn ? 60 : interval)) {
lastBeep = now;
beepOn = !beepOn;
if (beepOn) tone(BUZZ, 2000); else noTone(BUZZ);
}
}
How the beeping works
Each beep lasts 60 ms; the silent gap between beeps is the mapped interval. At 100 cm the gap is 600 ms, and at 20 cm it is only 80 ms, so the beeps speed up smoothly as the car approaches. The simple smoothing line blends each new reading with the previous value, which stops the beep rate from stuttering when a reading jumps.
If you use an active buzzer, which beeps by itself with power, replace tone(BUZZ, 2000) with digitalWrite(BUZZ, HIGH) and noTone(BUZZ) with digitalWrite(BUZZ, LOW).
Why the readings are smoothed
The HC-SR04 occasionally returns a wrong value, for example when the sound bounces off an angled part of the car. Without smoothing, one bad reading would make the beeping suddenly jump faster or slower, which is distracting while you are driving. The line distance = distance * 0.6 + d * 0.4 is an exponential filter: each new reading only moves the result 40% of the way toward the new value. A single spike barely changes it, while a real, steady approach still comes through within a few tenths of a second. Raise the 0.4 for a faster response, or lower it for a steadier one.
Testing on the bench
- Upload the sketch and move your hand slowly toward the sensor. The LEDs should change at 100, 50 and 20 cm.
- If readings are erratic, check the sensor is not pointing at the edge of the table; see the tips in the HC-SR04 guide.
- If nothing lights at all, check the LED orientation and the breadboard rows, as explained in breadboard basics.
Installing it in a garage
- Mount the sensor at bumper height, pointing straight at where the car's front will be. Ultrasound reflects well from a flat bumper or number plate.
- Adjust the "stop" distance to your garage: park where you want the car, read the distance with the Serial Monitor and use that value instead of 20.
- Put the electronics in a small box and power it from a USB adapter.
- Place the LEDs where the driver can see them, for example on a strip of wire at eye level.
Ideas to extend it
- Add a PIR sensor from the motion sensor guide so the system only wakes up when someone is in the garage.
- Show the distance in centimeters on an OLED display.
- Turn off the buzzer automatically after the car has been stopped for 10 seconds, so it does not beep all night.
— TheSolderBench · found a mistake? tell me