← All projects
Sensors Intermediate

A Parking Sensor on the VL53L0X Laser Range Finder: LCD and Buzzer

The VL53L0X measures distance by the time of flight of a laser pulse: up to 1.2–2 m with millimetre resolution. We build a parking sensor: centimetres and a bar on an LCD 1602, and a buzzer that beeps faster as the obstacle gets closer.

Difficulty
Intermediate
Time
45 min
Category
Sensors
Updated

About the project

The VL53L0X is a tiny laser range finder (ToF, time-of-flight) from ST. It sends an invisible 940 nm infrared pulse and counts how many picoseconds the light takes to come back. Unlike the ultrasonic HC-SR04, it has a narrow beam, copes with soft surfaces and talks I2C. We build a parking sensor for the garage.

What you need

  • ESP32 DevKit
  • VL53L0X module (GY-530 or Pololu)
  • LCD 1602 with an I2C backpack
  • A buzzer (passive or active) and a 100 Ω resistor
  • The VL53L0X (Pololu) and LiquidCrystal_I2C libraries

Wiring

The VL53L0X and the LCD share one I2C bus, at addresses 0x29 and 0x27:

Module VIN/VCC GND SDA SCL
VL53L0X 3V3 GND GPIO21 GPIO22
LCD 1602 3V3 GND GPIO21 GPIO22

Buzzer: GPIO25 → 100 Ω → buzzer "+", "−" → GND. The resistor limits the pin current; without it the simulator warns about exceeding 20 mA.

The GPIO1 (measurement-ready interrupt) and XSHUT (shutdown) pins can stay unconnected. XSHUT matters with several sensors: they all share address 0x29, so you enable them one by one and reassign the addresses with setAddress().

How it works

  • startContinuous() makes the sensor measure non-stop, ~33 ms per reading (the default timing budget).
  • readRangeContinuousMillimeters() returns the latest value in mm. 8190/8191 means nothing is within range.
  • setTimeout(500) + timeoutOccurred() keep the sketch from hanging if the sensor drops off the bus.
  • Range: ~1.2 m in the standard mode, up to 2 m in "long range" (setSignalRateLimit(0.1) plus longer VCSEL pulses), at the cost of accuracy.

Code

// Parking sensor: VL53L0X laser rangefinder + LCD 1602 (both on I2C) + buzzer
#include <Wire.h>
#include <VL53L0X.h>
#include <LiquidCrystal_I2C.h>

VL53L0X sensor;
LiquidCrystal_I2C lcd(0x27, 16, 2);
const int BUZZER = 25;
unsigned long lastBeep = 0;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  lcd.init();
  lcd.backlight();
  sensor.setTimeout(500);
  if (!sensor.init()) {
    lcd.print("VL53L0X error");
    while (true) delay(1000);
  }
  sensor.startContinuous();
  pinMode(BUZZER, OUTPUT);
}

void loop() {
  uint16_t mm = sensor.readRangeContinuousMillimeters();
  bool valid = !sensor.timeoutOccurred() && mm < 8000;   // 8190 = nothing in range

  lcd.setCursor(0, 0);
  if (valid) {
    lcd.print("Distance: ");
    lcd.print(mm / 10);
    lcd.print(" cm   ");
  } else {
    lcd.print("Too far         ");
  }
  lcd.setCursor(0, 1);
  int bars = valid ? constrain(map(mm, 50, 1000, 16, 0), 0, 16) : 0;
  for (int i = 0; i < 16; i++) lcd.write(i < bars ? 0xFF : ' ');   // 0xFF = a filled cell

  // the closer, the faster the beeps; a continuous tone under 10 cm
  if (!valid || mm > 1000) {
    noTone(BUZZER);
  } else if (mm < 100) {
    tone(BUZZER, 2000);
  } else {
    unsigned long interval = map(mm, 100, 1000, 80, 800);
    if (millis() - lastBeep > interval) {
      tone(BUZZER, 2000, 40);
      lastBeep = millis();
    }
  }
}

Good to know

  • Colour and material. Matte black plastic reflects poorly, and the range drops to 50–70 cm. Glass and mirrors can give false distances.
  • Bright sunlight blinds the sensor, so the range is noticeably shorter outdoors.
  • A cover glass in front of the sensor, without special calibration, causes crosstalk and a "permanent 3 cm". An open window is better.
  • The VL53L1X is the big brother: up to 4 m and a programmable field of view, with an almost identical library.