🔗Goal
Build a parking assistant that mounts on your garage wall and guides you as you pull in. An HC-SR04 ultrasonic sensor measures the distance to the approaching car and drives a traffic-light LED system: green when far away, yellow when approaching, red when close, and blinking red with a buzzer when too close.
Here is how the system works at a high level:
graph LR
A[HC-SR04 Sensor] -->|Distance| B[ESP32]
B -->|GPIO| C[Green LED]
B -->|GPIO| D[Yellow LED]
B -->|GPIO| E[Red LED]
B -->|GPIO| F[Buzzer]The HC-SR04 emits a short ultrasonic pulse and measures the time it takes for the echo to return. The ESP32 converts this time into a distance using the speed of sound:
$$d = \frac{t \cdot v_{sound}}{2} = \frac{t \cdot 343}{2}\,\text{m}$$
where $t$ is the round-trip time in seconds, $v_{sound} = 343\,\text{m/s}$ at room temperature, and we divide by 2 because the pulse travels to the object and back.
The distance thresholds control the LED and buzzer behavior:
graph TD
A[Measure distance] --> B{d > 100 cm?}
B -->|Yes| C[Green LED on]
B -->|No| D{d > 50 cm?}
D -->|Yes| E[Yellow LED on]
D -->|No| F{d > 20 cm?}
F -->|Yes| G[Red LED on]
F -->|No| H[Red LED blinking + buzzer]🔗Prerequisites
You will need the following components:
| Component | Qty | Notes | Buy |
|---|---|---|---|
| ESP32 dev board | 1 | AliExpress | Amazon.de .co.uk .com | |
| HC-SR04 ultrasonic sensor | 1 | 5V sensor — requires voltage divider on ECHO pin | AliExpress | Amazon.de .co.uk .com |
| LED (green) | 1 | AliExpress | Amazon.de .co.uk .com | |
| LED (yellow) | 1 | AliExpress | Amazon.de .co.uk .com | |
| LED (red) | 1 | AliExpress | Amazon.de .co.uk .com | |
| 220 ohm resistor | 3 | One per LED for current limiting | AliExpress | Amazon.de .co.uk .com |
| Active buzzer | 1 | 3.3V compatible | AliExpress | Amazon.de .co.uk .com |
| 1k ohm resistor | 1 | For ECHO voltage divider | AliExpress | Amazon.de .co.uk .com |
| 2k ohm resistor | 1 | For ECHO voltage divider | AliExpress | Amazon.de .co.uk .com |
| Breadboard | 1 | AliExpress | Amazon.de .co.uk .com | |
| Jumper wires | ~15 | Male-to-male and male-to-female | AliExpress | Amazon.de .co.uk .com |
Links marked Amazon/AliExpress are affiliate links. We may earn a small commission at no extra cost to you.
🔗Why the voltage divider?
The HC-SR04 operates at 5V, and its ECHO pin outputs a 5V signal. The ESP32 GPIO pins are only 3.3V tolerant — feeding 5V directly into a GPIO can damage the chip. A simple resistive voltage divider drops the ECHO voltage to a safe level:
$$V_{out} = V_{echo} \cdot \frac{R_2}{R_1 + R_2} = 5 \cdot \frac{2000}{1000 + 2000} = 3.33\,\text{V}$$
Using $R_1 = 1\,\text{k}\Omega$ and $R_2 = 2\,\text{k}\Omega$ brings the ECHO output down to approximately $3.3\,\text{V}$, which is safe for the ESP32.
Never connect the HC-SR04 ECHO pin directly to the ESP32 without a voltage divider. The 5V output can permanently damage the GPIO pin.
🔗Tutorial
🔗Step 1: Wiring
Connect everything according to the table below:
| Component | Pin | ESP32 Pin | Notes |
|---|---|---|---|
| HC-SR04 | VCC | 5V (VIN) | The sensor needs 5V to operate |
| HC-SR04 | GND | GND | |
| HC-SR04 | TRIG | GPIO 5 | Trigger pulse output |
| HC-SR04 | ECHO | GPIO 18 | Through voltage divider (see below) |
| Green LED (anode) | — | GPIO 25 | Through 220 ohm resistor |
| Green LED (cathode) | — | GND | |
| Yellow LED (anode) | — | GPIO 26 | Through 220 ohm resistor |
| Yellow LED (cathode) | — | GND | |
| Red LED (anode) | — | GPIO 27 | Through 220 ohm resistor |
| Red LED (cathode) | — | GND | |
| Buzzer (+) | — | GPIO 14 | |
| Buzzer (−) | — | GND |
ECHO pin voltage divider wiring:
- Connect the HC-SR04 ECHO pin to one end of the 1k ohm resistor ($R_1$).
- Connect the other end of $R_1$ to GPIO 18 and to one end of the 2k ohm resistor ($R_2$).
- Connect the other end of $R_2$ to GND.
The junction of $R_1$ and $R_2$ is the divided voltage output that goes to GPIO 18.
Pin labels and GPIO numbers vary between ESP32 boards. Always check your board's pinout diagram and datasheet.
🔗Step 2: Upload the code
The distance thresholds are defined at the top of the code so you can easily adjust them for your garage.
#define TRIG_PIN 5
#define ECHO_PIN 18
#define GREEN_PIN 25
#define YELLOW_PIN 26
#define RED_PIN 27
#define BUZZER_PIN 14
// ---- Distance thresholds (in centimeters) ----
// Adjust these to match your garage depth.
#define DIST_FAR 100 // Green: car is far away
#define DIST_MED 50 // Yellow: car is approaching
#define DIST_CLOSE 20 // Red: car is close; below this = too close
// ---- Timing ----
#define BLINK_INTERVAL 200 // Blink speed when too close (ms)
#define READ_INTERVAL 100 // How often to measure distance (ms)
// Speed of sound in cm/us (343 m/s = 0.0343 cm/us)
const float SOUND_SPEED_CM_US = 0.0343;
void allLEDsOff() {
digitalWrite(GREEN_PIN, LOW);
digitalWrite(YELLOW_PIN, LOW);
digitalWrite(RED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
}
float measureDistance() {
// Send a 10us trigger pulse
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Measure the echo pulse duration in microseconds
long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 30ms timeout (~5m max)
if (duration == 0) {
return -1; // No echo received (out of range or error)
}
// Convert to distance in cm
float distance = (duration * SOUND_SPEED_CM_US) / 2.0;
return distance;
}
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(YELLOW_PIN, OUTPUT);
pinMode(RED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
allLEDsOff();
Serial.println("Garage Parking Assistant ready");
}
void loop() {
float distance = measureDistance();
if (distance < 0) {
// No reading — turn everything off
allLEDsOff();
Serial.println("No object detected");
delay(READ_INTERVAL);
return;
}
Serial.print("Distance: ");
Serial.print(distance, 1);
Serial.println(" cm");
allLEDsOff();
if (distance > DIST_FAR) {
// Far away — green
digitalWrite(GREEN_PIN, HIGH);
}
else if (distance > DIST_MED) {
// Approaching — yellow
digitalWrite(YELLOW_PIN, HIGH);
}
else if (distance > DIST_CLOSE) {
// Close — solid red
digitalWrite(RED_PIN, HIGH);
}
else {
// Too close — blink red + buzzer
digitalWrite(RED_PIN, HIGH);
digitalWrite(BUZZER_PIN, HIGH);
delay(BLINK_INTERVAL);
digitalWrite(RED_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
delay(BLINK_INTERVAL);
return; // Skip the delay below since blinking has its own timing
}
delay(READ_INTERVAL);
}🔗Step 3: Test and calibrate
- Upload the sketch and open the Serial Monitor at 115200 baud.
- Point the sensor at a wall or flat object and move it closer and farther away. You should see the distance readings in the Serial Monitor change, and the LEDs should switch accordingly.
- Adjust the threshold constants at the top of the code to fit your garage:
- Measure the distance from the sensor mounting point to where you want to stop the car.
- Set
DIST_CLOSEto the desired stopping distance (for example, 25 cm from the wall). - Set
DIST_MEDandDIST_FARto comfortable intermediate distances.
The HC-SR04 has a minimum range of about 2 cm and a maximum range of about 400 cm. For best results, mount the sensor at bumper height, pointing straight at the approaching car.
🔗Step 4: Mounting
For a permanent installation:
- Mount the HC-SR04 sensor on the garage wall at the far end, facing the incoming car at bumper height (approximately 40–60 cm from the ground).
- Mount the LEDs where you can easily see them from the driver's seat — on the wall to the side, or above the sensor.
- Power the ESP32 from a USB phone charger plugged into a wall outlet.
- Consider putting the electronics in a small project box to protect them from dust and moisture.
🔗Common Issues and Solutions
| Problem | Cause | Fix |
|---|---|---|
| Distance reads 0 or negative | No echo received; object out of range or at a steep angle | Ensure the sensor faces the target squarely. Check that ECHO is wired through the voltage divider to GPIO 18 |
| Distance readings jump around | Ultrasonic reflections off uneven surfaces | Aim the sensor at a flat surface (license plate area works well). Add a small delay or averaging to smooth readings |
| LEDs never turn on | Wrong GPIO pins or missing resistors | Double-check wiring against the table. Verify LEDs are not inserted backwards (long leg = anode = positive) |
| Buzzer sounds constantly | Threshold set too high or sensor too close to wall | Increase DIST_CLOSE. Make sure the sensor is not reading the wall behind it |
| ESP32 resets or crashes | 5V on ECHO pin without voltage divider | Add the 1k + 2k voltage divider on the ECHO line. Never connect 5V directly to ESP32 GPIO |
| Readings are inaccurate | Temperature affects speed of sound | At $20\degree\text{C}$, sound travels at $343\,\text{m/s}$. For more accuracy, you could add a temperature sensor and adjust the speed constant |
| Sensor misses the car | Beam angle too narrow or sensor misaligned | The HC-SR04 has a ~15 degree beam angle. Adjust the mounting angle so it points directly at the car's approach path |