Wearables & IoTTechnician

ESP32 Posture Reminder That Buzzes When You Slouch

A tiny clip-on device learns your upright position and gives a gentle vibration after 30 seconds of slouching.

LevelTechnician
Time1.5 h
Est. cost~$75
Steps5

An IMU measures which way gravity pulls, so it knows the tilt of whatever it is clipped to. Worn on your upper back or shirt collar, a XIAO ESP32-C3 compares your current tilt with your calibrated upright posture.

⚠ SAFETY
This is a habit reminder, not a medical or therapy device. LiPo batteries can catch fire if punctured, overcharged or shorted. Charge in a LiPo bag, never unattended, and always remove propellers while working on the bench.

Mission steps

  1. Wire the IMU

    MPU6050 SDA to D4 (GPIO6), SCL to D5 (GPIO7), VCC to 3V3 and GND to GND.

  2. Drive the motor

    Switch the vibration motor with an NPN transistor from D0 (GPIO2) through a 1 kΩ resistor, with a diode across the motor.

  3. Flash MicroPython

    Install MicroPython for the ESP32-C3 and save the script as main.py with Thonny.

  4. Calibrate

    Sit up straight when it powers on; it averages 20 readings as your good posture.

  5. Wear and adjust

    Change the 15° threshold and 30-second delay until reminders feel helpful, not annoying.

Code

# main.py (MicroPython, XIAO ESP32-C3 + MPU6050)
from machine import I2C, Pin
import math, struct, time

i2c = I2C(0, sda=Pin(6), scl=Pin(7), freq=400000)
MPU = 0x68
i2c.writeto_mem(MPU, 0x6B, b'\x00')          # wake the sensor
motor = Pin(2, Pin.OUT, value=0)

def pitch():
    ax, ay, az = struct.unpack('>hhh', i2c.readfrom_mem(MPU, 0x3B, 6))
    return math.degrees(math.atan2(ax, math.sqrt(ay * ay + az * az)))

def buzz(n=3):
    for _ in range(n):
        motor.on(); time.sleep(0.3); motor.off(); time.sleep(0.3)

time.sleep(3)                                  # sit up straight now
ref = sum(pitch() for _ in range(20)) / 20
buzz(1)
slouch_since = None

while True:
    if abs(pitch() - ref) > 15:
        slouch_since = slouch_since or time.time()
        if time.time() - slouch_since > 30:
            buzz(); slouch_since = time.time()
    else:
        slouch_since = None
    time.sleep(0.5)

Tip: test every script on the bench before installing it in a moving machine.

Questions

Which axis should I use?

It depends on how the board sits on your body. Print ax, ay and az while leaning forward and use the axis that changes most.