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.
Height Measuring Station: the finished build
ESP32-C3 SuperMiniStudent projects

Contact-free height measuring station for a school health camp (ESP32-C3 + VL53L1X)

Stand under it, hear the beep, read your height — no tape, no ruler, no touching.

Difficulty
Easy
Build time
1.5 h
Parts cost
₹1,515 · $18
Verified — core esp32 3.3.12, VL53L1X 1.3.1, 3 Nov 2026Compile-only

Community draft — report a mistake

Parts list

PartQtyApprox.Buy
ESP32-C3 SuperMini1₹230Buy ESP32-C3 SuperMini
VL53L1X time-of-flight sensor (with VIN regulator)1₹900Buy VL53L1X time-of-flight sensor (with VIN regulator)
TM1637 4-digit display, 0.56" (or the big 1.2" version)1₹90Buy TM1637 4-digit display, 0.56" (or the big 1.2" version)
Active buzzer module1₹25Buy Active buzzer module
12 mm push button1₹10Buy 12 mm push button
L-bracket or shelf bracket, 25–30 cm arm1₹80Buy L-bracket or shelf bracket, 25–30 cm arm
5 V USB adapter + cable (2 m)1₹180Buy 5 V USB adapter + cable (2 m)
Total₹1,515

Affiliate disclosure: “Buy” links may earn FlashReady a small commission at no extra cost to you. Prices are indicative.

Wiring

ESP32-C3 SuperMiniOnly the pins used are shown · 3.3 V logicVL53L1X time-of-flight distance sensor (up to 4 m)TM1637 4-digit 7-segment displayPush button (6 mm tactile switch)Active buzzer module (high-level trigger)GND3V34 · 43 · 31 · 16 · 67 · 710 · 10VINGNDSCLSDAGPIO1 (not connected)XSHUT (not connected)CLKDIOVCCGND12I/OVCCGND
Every connection
ESP32-C3 SuperMiniPart · pinWireNotes
6VL53L1X time-of-flight distance sensor (up to 4 m) · SDAblueGPIO6 — I2C kept off strapping pins 8 and 9
7VL53L1X time-of-flight distance sensor (up to 4 m) · SCLyellowGPIO7
3V3VL53L1X time-of-flight distance sensor (up to 4 m) · VINred
GNDVL53L1X time-of-flight distance sensor (up to 4 m) · GNDblackGPIO1 and XSHUT on the sensor stay unconnected
3TM1637 4-digit 7-segment display · CLKyellow
4TM1637 4-digit 7-segment display · DIOgreen
3V3TM1637 4-digit 7-segment display · VCCredRuns from 3.3 V (slightly dimmer than at 5 V); keeps CLK/DIO at 3.3 V
GNDTM1637 4-digit 7-segment display · GNDblack
10Push button (6 mm tactile switch) · 1greenGPIO10 — press with nobody underneath to measure the floor
GNDPush button (6 mm tactile switch) · 2black
1Active buzzer module (high-level trigger) · I/OorangeGPIO1 — a short beep when the reading is steady
3V3Active buzzer module (high-level trigger) · VCCred
GNDActive buzzer module (high-level trigger) · GNDblack

Board quirks: Mount the sensor about 2.2 m above the floor on a bracket that sticks out from the wall, so it looks straight down at a clear patch of floor. A tilted sensor measures a slanted (longer) path. The sensor measures to the top of the hair, not the scalp. Ask people to stand straight under it with heels together, like with a tape — expect ±1 cm, a little more for thick hair or a cap. The VL53L1X’s infrared is weakened by strong sunlight. Indoors, long-distance mode reaches past 3 m; outdoors in daylight it may not see the floor at all. Calibration (the floor distance) is saved in flash, so it only needs repeating if the bracket moves. The display shows <code>CAL</code> until it has been done. I2C uses GPIO6/7 with <code>Wire.begin(6, 7)</code> because the SuperMini’s default I2C pins are strapping pins with the LED and BOOT button on them.

Code

height-measuring-station.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// Height measuring station — ESP32-C3 SuperMini + VL53L1X (pointing down) + TM1637 display.
// Mount the sensor on a bracket above head height, looking straight down at the floor.
// Height = (distance to the floor) - (distance to the top of the head). Press the button
// once with nobody underneath to measure the floor; it's saved in flash.
// The reading is the median of 15 measurements, shown when it is steady; a beep confirms.
// VL53L1X: SDA 6, SCL 7 (keeps I2C off strapping pins 8/9). TM1637: CLK 3, DIO 4.
// Button: GPIO10 to GND. Active buzzer I/O: GPIO1. Board option: USB CDC On Boot.
#include <Wire.h>
#include <VL53L1X.h>
#include <TM1637Display.h>
#include <Preferences.h>
#include <utility>

constexpr int SDA_PIN = 6, SCL_PIN = 7, TM_CLK = 3, TM_DIO = 4, BTN = 10, BUZZER = 1;
constexpr int MIN_CM = 60;  // ignore anything shorter: a hand, a bag

VL53L1X tof;
TM1637Display disp(TM_CLK, TM_DIO);
Preferences prefs;
int floorMm = 0;
const uint8_t SEG_CAL[] = {SEG_A | SEG_D | SEG_E | SEG_F, SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G, SEG_D | SEG_E | SEG_F, 0};  // "CAL"
const uint8_t SEG_DASH[] = {SEG_G, SEG_G, SEG_G, SEG_G};

int medianMm(int n) {
  int v[25], k = 0;
  for (int i = 0; i < n && i < 25; i++) {
    tof.read();
    if (!tof.timeoutOccurred() && tof.ranging_data.range_status == VL53L1X::RangeValid) v[k++] = tof.ranging_data.range_mm;
  }
  if (k < n / 2) return -1;
  for (int i = 1; i < k; i++)  // insertion sort, k <= 25
    for (int j = i; j > 0 && v[j] < v[j - 1]; j--) std::swap(v[j], v[j - 1]);
  return v[k / 2];
}

void beep(int ms) {
  digitalWrite(BUZZER, HIGH);
  delay(ms);
  digitalWrite(BUZZER, LOW);
}

void setup() {
  Serial.begin(115200);
  pinMode(BTN, INPUT_PULLUP);
  pinMode(BUZZER, OUTPUT);
  disp.setBrightness(5);
  disp.setSegments(SEG_DASH);
  Wire.begin(SDA_PIN, SCL_PIN);
  Wire.setClock(400000);
  tof.setTimeout(500);
  if (!tof.init()) {
    Serial.println("VL53L1X not found at 0x29 - check SDA 6 / SCL 7");
    disp.setSegments(SEG_CAL);
    while (true) delay(1000);
  }
  tof.setDistanceMode(VL53L1X::Long);  // up to ~4 m in the dark, ~3 m indoors
  tof.setMeasurementTimingBudget(100000);
  tof.startContinuous(100);
  prefs.begin("height", false);
  floorMm = prefs.getInt("floor", 0);
  Serial.printf("Floor at %d mm%s\n", floorMm, floorMm ? "" : " - press the button with nobody underneath");
}

void loop() {
  if (digitalRead(BTN) == LOW) {
    disp.setSegments(SEG_CAL);
    int f = medianMm(20);
    if (f > 1000) {
      floorMm = f;
      prefs.putInt("floor", floorMm);
      Serial.printf("Floor calibrated: %d mm\n", floorMm);
      beep(300);
    } else Serial.println("Calibration failed - is the sensor at least 1 m above the floor?");
    while (digitalRead(BTN) == LOW) delay(10);
  }
  if (!floorMm) {
    disp.setSegments(SEG_CAL);
    delay(200);
    return;
  }
  static int lastCm = 0, steady = 0;
  int head = medianMm(15);
  int cm = head > 0 ? (floorMm - head + 5) / 10 : 0;
  if (cm < MIN_CM) {  // nobody there
    disp.setSegments(SEG_DASH);
    steady = 0;
    lastCm = 0;
    return;
  }
  steady = abs(cm - lastCm) <= 1 ? steady + 1 : 0;
  lastCm = cm;
  disp.showNumberDec(cm);
  if (steady == 3) {  // same height three times in a row: that's the reading
    Serial.printf("Height: %d cm\n", cm);
    beep(80);
  }
}

Compiled for c3supermini on esp32 3.3.12 with VL53L1X 1.3.1 · 3 Nov 2026

How it works

School health camps and anganwadi checkups measure a lot of children, usually with a tape on the wall and a ruler balanced on each head. This station measures without touching: a laser rangefinder on a bracket above head height looks straight down, and the height appears on a large display with a beep.

The VL53L1X is a time-of-flight sensor. It sends out a tiny infrared laser pulse and times the reflection, up to about 4 m. First, with nobody underneath, you press the button: the C3 takes the median of 20 readings as the floor distance and stores it in flash. After that, when someone stands underneath, the sensor measures the distance to the top of their head, and height = floor distance − head distance.

Each reading is the median of 15 measurements, which throws away the odd reflection from a shoulder or a moving hand. Anything shorter than 60 cm is ignored. When three readings in a row agree within 1 cm, the buzzer beeps and the Serial Monitor prints the height. The TM1637 four-digit display shows it in centimetres, and dashes when nobody is there.

The ESP32-C3 SuperMini is plenty for this and costs very little. It runs everything from one USB adapter, and I2C on GPIO6/7 keeps the sensor away from the strapping pins.

Troubleshooting

It shows CAL and never a height

Press the button with nobody underneath. If the Serial Monitor says calibration failed, the sensor didn’t see anything beyond 1 m — check it points at the floor and isn’t blocked by the bracket.

Heights are a few cm off

Re-calibrate, then check with a tape on one person. The usual cause is a sensor that isn’t level; a shim under the bracket fixes it.

The display flickers between two numbers

The person is moving, or the sensor sees the edge of their head. The beep only sounds after three steady readings — wait for it.

Upgrades

  • Add a load cell platform (HX711) and show BMI next to the height.
  • Send each reading with a student ID to a Google Sheet over Wi-Fi.
  • Use the bigger 1.2″ TM1637 module so a whole queue can read it.

↑↓ to move · Enter to open