Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

VL53L1X with ESP32 DevKit V1 — 4 m laser ranging on D21/D22

Wire a VL53L1X to an ESP32 DevKit V1 at 3.3 V, reset it safely through XSHUT on D4, and measure up to about 4 m in long mode with the Pololu library.

Arduino C++Verified — core esp32 3.3.12, VL53L1X 1.3.1, 3 Nov 2026Compile-only

Community draft — report a mistake

The VL53L1X measures distance with an invisible laser and a time-of-flight detector: up to about 4 m, independent of colour, in a package smaller than a fingernail. It suits people counters, parking guides, tank levels and robot obstacle sensing.

On the ESP32 DevKit V1 it uses the default I2C pins D21/D22 at 3.3 V, plus an optional XSHUT wire on D4 that the sketch uses to hard-reset the sensor at start-up. The sketch runs it in long mode with a 50 ms timing budget and prints the distance, range status and signal strength.

Wiring

ESP32 DevKit V1Only the pins used are shown · 3.3 V logicVL53L1X time-of-flight distance sensor (up to 4 m)GNDD22D21D43V3VINGNDSCLSDAGPIO1 (not connected)XSHUT
Every connection
ESP32 DevKit V1VL53L1X time-of-flight distance sensor (up to 4 m)WireNotes
3V3VINredBreakouts with VIN have their own 2.8 V regulator. The sensor draws about 20 mA while ranging.
GNDGNDblack
D22SCLyellow
D21SDAblue
D4XSHUTorangeDriven LOW to switch the sensor off, otherwise released (input). Never driven HIGH.

2.6–5.5 V on boards with a regulator (VIN) part, 3.3 V board. Breakouts with a VIN pin have a 2.8 V regulator and level shifting, so ESP32, Pico and Uno all work. Bare-chip boards without a regulator are 2.6–3.5 V only — check for the regulator before giving it 5 V.

Board quirks

  • XSHUT is pulled up to the sensor’s own 2.8 V supply on most breakouts and is often not level-shifted. The sketch only ever pulls it LOW or lets it float (INPUT), so 3.3 V is never forced into it.
  • A short XSHUT pulse at start-up gives the sensor a clean reset after an ESP32 crash or upload — without it the VL53L1X can stay stuck mid-measurement and init() fails until you unplug it.
  • With several sensors, XSHUT is how you give each one its own address: hold all but one LOW, call setAddress(), release the next, and so on. One GPIO per sensor.
  • Long mode reaches about 4 m indoors on a white wall but is easily blinded by sunlight; Short mode stops at about 1.3 m and copes much better outdoors. A longer timing budget (e.g. 100 ms) steadies long-range readings.
  • The range status matters: only “range valid” readings are trustworthy. “signal fail” or “wrap target fail” mean the target is too far, too dark or outside the beam.
  • Compared with the VL53L0X (2 m), the L1X reaches twice as far and can narrow its field of view (ROI), but costs more.

Code

vl53l1x-esp32.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// VL53L1X time-of-flight sensor on an ESP32 DevKit V1 — long mode, up to about 4 m indoors.
// VIN → 3V3, GND → GND, SDA → D21, SCL → D22, XSHUT → D4 (driven LOW or released, never driven HIGH).
#include <Wire.h>
#include <VL53L1X.h>

constexpr uint8_t XSHUT_PIN = 4;
VL53L1X sensor;

void setup() {
  Serial.begin(115200);
  // Hard-reset the sensor: XSHUT LOW = off. Then release it (INPUT): the board's pull-up turns it on.
  pinMode(XSHUT_PIN, OUTPUT);
  digitalWrite(XSHUT_PIN, LOW);
  delay(10);
  pinMode(XSHUT_PIN, INPUT);
  delay(10);
  Wire.begin(21, 22);
  Wire.setClock(400000);
  sensor.setTimeout(500);
  if (!sensor.init()) {
    Serial.println("No VL53L1X at 0x29 - check wiring, and that XSHUT is not held LOW");
    while (true) delay(1000);
  }
  sensor.setDistanceMode(VL53L1X::Long);     // Short ≈ 1.3 m (copes better with sunlight), Long ≈ 4 m indoors
  sensor.setMeasurementTimingBudget(50000);  // 50 ms per reading; longer = steadier at long range
  sensor.startContinuous(50);
  Serial.println("VL53L1X ready, long mode, 50 ms");
}

void loop() {
  uint16_t mm = sensor.read();
  if (sensor.timeoutOccurred()) {
    Serial.println("Timeout");
    return;
  }
  Serial.printf("%u mm  status: %s  signal %.1f MCPS\n", mm, VL53L1X::rangeStatusToString(sensor.ranging_data.range_status),
                sensor.ranging_data.peak_signal_count_rate_MCPS);
  delay(200);
}

Library: VL53L1X (Pololu) — compiled with VL53L1X 1.3.1.

Expected serial output

Serial Monitor · 115200Output
VL53L1X ready, long mode, 50 ms
1342 mm  status: range valid  signal 4.8 MCPS
1339 mm  status: range valid  signal 4.9 MCPS
3872 mm  status: signal fail  signal 0.3 MCPS

Common errors

“No VL53L1X at 0x29”

Check SDA/SCL, and that XSHUT isn’t wired to GND or held LOW. Run the I2C scanner — a VL53L0X also answers at 0x29 but needs a different library.

Readings stuck at 0 or a fixed value

The protective film is still on the sensor window, or a cover glass reflects the laser. Remove the film; cover glass needs crosstalk calibration.

Works indoors, fails outside

Sunlight swamps the 940 nm laser. Use Short mode and shade the sensor.

↑↓ to move · Enter to open