P-06 // Started

Balancing Robot

A 500 Hz STM32 balancing robot: LQR with pitch and wheel-encoder Kalman filters validated on hardware; PID/LQR controller comparison studied in simulation.

LQR + Kalman filters ยท Hardware validated
  • LQR / LQI
  • Sensor fusion
  • Delay compensation
  • STM32
  • Model-based design
Open repository
Balancing Robot project

I designed and built a self-balancing robot with model-based control, sensor fusion and real-time embedded firmware. My work covers the mechanical model, electronics, controller implementation and repeatable hardware tests.

Test setup and findings

I used a repeatable bench procedure with logged UART telemetry to compare controller and estimator configurations during position-hold and trajectory-tracking runs. The test data exposed the effect of encoder latency, step quantisation and balance-point drift; adding wheel-encoder and pitch Kalman filters gave the most stable overall hardware behaviour.

Best overall hardware configuration

LQR + wheel-encoder KF + pitch KF

This combination gave me the most stable overall behaviour on the real robot. The four-state pitch KF learns the balance point and gyro bias; the wheel KFs estimate actual joint motion instead of assuming every commanded step occurred.

With position hold: roughly 4–5 mm final reported position error and 21.0 mm tracking RMS. This is my preferred configuration, not a claim that it wins every metric: step counting was slightly smoother on holding acceleration-command RMS.

Hardware

3D-printed chassis, two direct-drive stepper motors and a LiPo battery. Total mass: 1.0175 kg; wheel diameter: 62.5 mm; wheel separation: 182 mm. The clips below show the working prototype and its telemetry interface; playback is muted and loops after pressing play.

Balancing prototype and UART control interface.
Balancing chassis in operation.

Electronics

  • Processor: NUCLEO-G474RE / STM32G474RE.
  • Inertial sensing: LSM6DS0 accelerometer and gyroscope.
  • Wheel sensing: two AS5600 magnetic encoders on separate I2C buses.
  • Motor drive: two A4988 drivers, hardware-PWM step generation, 1/16 microstepping.
  • Communication: 115200-baud UART; DMA telemetry at 10 Hz.

Simulation

Python nonlinear inverted-pendulum model with measured mass and centre of mass, estimated inertia, step quantisation and a 35 ms actuator lag. Gains, limits and plant constants are exported to the C firmware from one configuration. ROS 2 Jazzy / Gazebo Harmonic provides a separate interactive simulation. This is a model-to-firmware parameter-export workflow, not Simulink auto-coding or physical hardware-in-the-loop (HIL).

(Iy + m h2) θ̈

= m g h sin θ − m h a cos θ − c θ̇

m: body mass; h: body centre-of-mass height; Iy: body pitch inertia; a: wheel acceleration; c: damping.

Control

Closed-loop architecture: IMU and previous acceleration command feed pitch KF; wheel encoders and step-rate changes feed wheel KFs; estimated state and references feed LQR; acceleration becomes wheel speeds and motor steps, with sensor feedback.
Read clockwise: controller → drive → plant → sensors → estimators. Cyan: measured/estimated signals; amber: command-model inputs. Open the diagram to inspect the signal names.

Integral-augmented LQR regulates travel, velocity and pitch. The position integral is implemented as a bounded pitch trim with saturation-aware updates. A pitch-PD/velocity controller provides the PID baseline; its configured pitch integral gain is zero. Both output acceleration, integrated into wheel speed.

z = [∫ ex dt, ex, ev, eθ, θ̇]T

acmd = −Kz

J = ∫0∞ (zTQz + R acmd2) dt

ex, ev, eθ: position, velocity and pitch errors relative to their references. Firmware represents the integral contribution as a pitch-reference trim.

acmd = kpeθ + kdθ̇ + kv(v − vref)

Positive velocity-feedback sign for the acceleration-input convention. Motor lag is included when checking closed-loop poles.

Limits: 0.8 m/s wheel speed, 4 m/s2 commanded acceleration and 20 kHz step rate. Steering splits forward speed between the wheels:

vL = v − ωb/2,   vR = v + ωb/2

ω: commanded turn rate; b: wheel separation.

State estimation

The four-state pitch Kalman filter estimates angle, angular rate, gyro bias and the mechanical balance point. Unlike a gravity-only accelerometer correction, its model accounts for wheel acceleration and IMU lever-arm motion.

s = [θ, θ̇, bg, d]T

θ̈ = α(θ − d) − cθθ̇ − βa

ygyro = θ̇ + bg

yaccel ≈ θ − (a + hIMUθ̈)/g

d: balance-point angle; bg: gyro bias. a is the lagged command; α, β and cθ are plant constants.

The controller uses pitch relative to the learned balance point, with the LQR integral reduced to 25% strength. Complementary and two-state Kalman filters remain selectable for comparison; innovation gates and covariance checks reject inconsistent data.

Each wheel has an angle/speed Kalman filter: prediction every 2 ms, encoder correction every 10 ms. A delayed measurement model handles the 2.3 ms encoder latency:

sw = [φ, φ̇]T,   yenc = φ − τencφ̇

φ: wheel angle; τenc: sensor delay.

Lost-step detection resynchronises wheel speed. Repeated encoder failures trigger a reported step-count fallback without jumping the hold reference. Wheel odometry does not measure tyre slip against the floor.

State-space models

The controller and estimators share the same mechanics, but use different states. Below: the upright acceleration-input plant, the four-state pitch KF and the two-state wheel KF. Hats denote estimates; T = 0.002 s is the control period.

1. Mechanics → LQR plant

Taking moments about the axle gives gravity, translational inertial torque and pitch damping. With body mass m, centre-of-mass height h and body inertia Iy:

Jp = Iy + mh2

Jpθ̈ = mgh sinθ

− mha cosθ − cθ̇

θ̈ ≈ αθ − βa − γθ̇

α = mgh/Jp,   β = mh/Jp

γ = c/Jp

Small-angle approximation: sinθ ≈ θ, cosθ ≈ 1. a is forward wheel acceleration, not motor torque.

Add travel dynamics ẋ = v, v̇ = a and position-error integral η̇ = ex. For a stationary reference, z = [η, ex, ev, θ, θ̇]T. The repository's nominal gain design omits damping and actuator lag:

ż = ALz + BLa

AL =01000001000000000001000α0BL =0010−β

For the damped physical plant, the last diagonal entry is −γ. The gain-design matrix above matches the actual repository.

J = ∫0∞(zTQz + Ra2)dt

ALTP + PAL

− PBLR−1BLTP + Q = 0

K = R−1BLTP,   a = −Kz

Firmware uses estimated travel/speed, pitch relative to the learned balance point, and a bounded pitch trim for the integral term. With offset KF, the trim integral runs at 25% strength; limits and anti-windup remain active.

Actuator lag

The simulation tracks commanded wheel velocity vcmd through a first-order lag τm = 35 ms. Locally, before limits and step quantisation:

τmv̇ + v = vcmd

v̇cmd = acmd

τmȧ + a = acmd

af,k = (1 − λ)af,k−1 + λacmd,k−1

λ = T/(τm + T)

The pitch KF uses this discrete acceleration proxy from the previous tick, not measured wheel acceleration. The nonlinear simulation uses an exponential velocity-lag update and acceleration limits.

2. Pitch KF: balance point and gyro bias

Extend the linear pitch model with gyro bias bg and balance-point angle d. Both are constant in prediction, with random-walk process noise so the filter can adapt:

s = [θ, θ̇, bg, d]T

θ̈ = α(θ − d) − γθ̇ − βaf

ṡ = Aps + Bpaf + w

Ap =0100α−γ0−α00000000Bp =0−β00

Forward Euler prediction gives Fp = I + TAp and Gp = TBp, exactly as implemented:

Fp =1T00αT1 − γT0−αT00100001Gp =0−βT00

Qp = diag(0, qrT, qbT, qdT): rate disturbance, bias drift and balance-point drift. The q terms are squared noise amplitudes.

The gyro measures rate plus bias. Accelerometer-derived pitch also sees translation and angular acceleration at IMU height ℓ above the axle:

yg = θ̇ + bg + ng

ya ≈ θ − (af + ℓθ̈)/g + na

y = Hps + Dpaf + n

Hp =01101 − ℓα/gℓγ/g0ℓα/gDp =0(ℓβ − 1)/g

Rows: gyro, accelerometer angle. Substituting the pitch dynamics produces the lever-arm terms and input feedthrough. Firmware applies scalar gyro/accel updates sequentially; accel-norm and innovation gates reject unreliable corrections.

Controller outputs: θ̂ − d̂ and low-pass-filtered (yg − b̂g). The estimated rate state supports prediction; it is not directly the rate feedback sent to LQR.

3. Wheel KF: angle and speed

Each wheel has sw = [φ, Ω]T, with Ω = φ̇. The step generator changes speed at the tick and then holds it. Thus the known input is the change in commanded angular speed ΔΩcmd, not absolute speed:

sw,k− = Fwsw,k−1+ + GwΔΩcmd

Fw =1T01Gw =T1Qw / qw =T3/3T2/2T2/2T

Integrated white angular-acceleration noise models deviations from commanded motion. Prediction: 500 Hz; encoder updates: 100 Hz.

The encoder angle is τenc = 2.3 ms old. First-order back-projection gives φ(t − τ) ≈ φ(t) − τΩ(t):

yenc = Hwsw + nenc

Hw =1−τenc

x̂ = r(φ̂L + φ̂R)/2 − x0

v̂ = r(Ω̂L + Ω̂R)/2

r: wheel radius; x0: handover offset preserving position continuity. Count correction, unwrapping and axis signs precede the KF. Persistent disagreement triggers resynchronisation; wheel odometry cannot detect floor slip.

Kalman prediction and correction

Both estimators combine model prediction with measurement innovations. L below is the Kalman gain, distinct from the LQR gain K:

ŝ− = Fŝ+prev + Gu

P− = FP+prevFT + Q

ν = y − Hŝ− − Du

S = HP−HT + R

L = P−HTS−1

ŝ+ = ŝ− + Lν

P+ = (I − LH)P−(I − LH)T

+ LRLT

Noise covariances Q/R are estimator-specific. Pitch uses Joseph-form covariance updates; the wheel implementation uses the algebraically equivalent compact scalar update. Rejected observations leave the prediction unchanged.

Alternative: two-state pitch/bias KF

This selectable baseline integrates gyro rate rather than predicting pendulum dynamics. With s2 = [θ, bg]T, θ̇ = yg − bg and ḃg = 0:

s2,k− = F2s2,k−1+ + G2yg

F2 =1−T01G2 =T0H2 =10Q2 =qθT + qbT3/3−qbT2/2−qbT2/2qbT

Observation: acceleration-compensated accelerometer angle. Bias random walk induces the negative cross-covariance; qθ and qb are squared noise amplitudes. Unlike the four-state KF, this model does not learn the mechanical balance point.

Hardware tests

LQR with position hold: four pitch-estimator/wheel-feedback combinations, two runs each of 0 → +0.3 m → 0. The balance-offset filter reduced final reported position error from roughly 14–15 mm to 4–5 mm. With offset pitch estimation, encoder feedback gave 21.0 mm tracking RMS versus 23.8 mm for step counting.

Repeated hardware position-error traces for four pitch-estimator and wheel-feedback combinations
Real robot trajectory comparison: two runs per configuration, with movement and hold intervals shown separately.
Hardware tracking error, holding acceleration command and final position error by estimator configuration
Mean and individual runs. Acceleration-command RMS is a shakiness proxy, not measured chassis acceleration. Position errors use wheel odometry, not external tracking.

LQR + wheel KF + balance-offset pitch KF is my preferred, most stable overall hardware setup. These runs support the tracking/hold advantage; the smoother step-count acceleration-command metric is a separate trade-off. All four recorded configurations used LQR, so this dataset is not a hardware PID-vs-LQR ranking.

Embedded software

500 Hz TIM6 loop: IMU acquisition → state estimation → control → PWM step rates. Interrupt-driven encoder reads and DMA telemetry keep communication separate from the control path. Firmware modules isolate sensors, estimators, controllers, motor drivers and latched faults.

  • 100 ms watchdog; explicit sensor, numerical and timing faults.
  • Upright boot calibration; arming below 0.15 rad; fall fault beyond 0.70 rad.
  • 0.5 s command timeout zeros drive/turn requests while balancing stays active.
  • Host tests exercise the real C modules with a mocked HAL and simulated sensors, including encoder failure, teleoperation and fall faults.

The software stop is not an emergency stop; testing requires an independent motor-power cutoff.

Teleoperation

Tkinter keyboard interface over UART: ramped forward/turn commands, controller and estimator selection, live pitch/velocity plots and fault reporting. Releasing the keys holds the new position; disarming switches off the motors.

Keyboard teleoperation app with connection controls, motion commands and live telemetry
Keyboard driving, live telemetry and configuration controls.

Earlier builds

The original project photographs below document the earlier hardware and chassis. The videos above show the current running robot.

balancingRobot
Clipped_image_20231125_170034