Garage Parking Assistant Intermediate

Build a parking distance indicator using an ultrasonic sensor and LEDs

🔗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:

ComponentQtyNotesBuy
ESP32 dev board1AliExpress | Amazon.de .co.uk .com
HC-SR04 ultrasonic sensor15V sensor — requires voltage divider on ECHO pinAliExpress | Amazon.de .co.uk .com
LED (green)1AliExpress | Amazon.de .co.uk .com
LED (yellow)1AliExpress | Amazon.de .co.uk .com
LED (red)1AliExpress | Amazon.de .co.uk .com
220 ohm resistor3One per LED for current limitingAliExpress | Amazon.de .co.uk .com
Active buzzer13.3V compatibleAliExpress | Amazon.de .co.uk .com
1k ohm resistor1For ECHO voltage dividerAliExpress | Amazon.de .co.uk .com
2k ohm resistor1For ECHO voltage dividerAliExpress | Amazon.de .co.uk .com
Breadboard1AliExpress | Amazon.de .co.uk .com
Jumper wires~15Male-to-male and male-to-femaleAliExpress | 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:

ComponentPinESP32 PinNotes
HC-SR04VCC5V (VIN)The sensor needs 5V to operate
HC-SR04GNDGND
HC-SR04TRIGGPIO 5Trigger pulse output
HC-SR04ECHOGPIO 18Through voltage divider (see below)
Green LED (anode)GPIO 25Through 220 ohm resistor
Green LED (cathode)GND
Yellow LED (anode)GPIO 26Through 220 ohm resistor
Yellow LED (cathode)GND
Red LED (anode)GPIO 27Through 220 ohm resistor
Red LED (cathode)GND
Buzzer (+)GPIO 14
Buzzer (−)GND

ECHO pin voltage divider wiring:

  1. Connect the HC-SR04 ECHO pin to one end of the 1k ohm resistor ($R_1$).
  2. Connect the other end of $R_1$ to GPIO 18 and to one end of the 2k ohm resistor ($R_2$).
  3. 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

  1. Upload the sketch and open the Serial Monitor at 115200 baud.
  2. 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.
  3. 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_CLOSE to the desired stopping distance (for example, 25 cm from the wall).
    • Set DIST_MED and DIST_FAR to 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:

  1. 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).
  2. Mount the LEDs where you can easily see them from the driver's seat — on the wall to the side, or above the sensor.
  3. Power the ESP32 from a USB phone charger plugged into a wall outlet.
  4. Consider putting the electronics in a small project box to protect them from dust and moisture.

🔗Common Issues and Solutions

ProblemCauseFix
Distance reads 0 or negativeNo echo received; object out of range or at a steep angleEnsure the sensor faces the target squarely. Check that ECHO is wired through the voltage divider to GPIO 18
Distance readings jump aroundUltrasonic reflections off uneven surfacesAim the sensor at a flat surface (license plate area works well). Add a small delay or averaging to smooth readings
LEDs never turn onWrong GPIO pins or missing resistorsDouble-check wiring against the table. Verify LEDs are not inserted backwards (long leg = anode = positive)
Buzzer sounds constantlyThreshold set too high or sensor too close to wallIncrease DIST_CLOSE. Make sure the sensor is not reading the wall behind it
ESP32 resets or crashes5V on ECHO pin without voltage dividerAdd the 1k + 2k voltage divider on the ECHO line. Never connect 5V directly to ESP32 GPIO
Readings are inaccurateTemperature affects speed of soundAt $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 carBeam angle too narrow or sensor misalignedThe HC-SR04 has a ~15 degree beam angle. Adjust the mounting angle so it points directly at the car's approach path