5 kg payload · 50×30×30 cm · 2 h autonomy · 80 cm doors
Budget
€500 cap, reached
Deliverables
43-page technical dossier · assembly guide · test videos
SolidWorks assembly · aluminium profiles, ABS platesStability test 3 · 11 June 2025
01 · The problemCampus logistics
Parcels on campus were hand-delivered. The volume kept growing; the people didn’t.
The robot has to cross indoor and outdoor ground, fit through standard doors and lifts, carry a 5 kg parcel and run two hours. Two driven wheels keep it compact and agile, and turn balance into the central engineering problem.
What I owned
The maths of balance and locomotion, the Simulink digital twin, then the C++ control firmware and the controller interface, with Erwan on the code.
Standards in scope
ISO 13482 (personal-care robots), 9001, 14001, 45001.
02 · Sizing the drivetrainInputs → motor choice
Inputsm = 30 kg · v = 5 km/h = 1.39 m/s · 0 → v in 5 s · wheel Ø 0.5 m
Acceleration a = Δv / Δt0.278m/s²
Driving force F = m · a8.34N
Wheel torque C = F · r2.09N·m
Wheel speed N = v / (2πr)53.1rpm
Mechanical power P = C · ω11.6W
Electrical power at η = 0.814.5W
Chosen: a 57BLR50-24-01 brushless motor (84 W, 24 V, 0.23 N·m at 3500 rpm) behind a 10:1 MG23-G10-D8 gearbox, so 2.3 N·m at 350 rpm with a 400 N load rating.
03 · Digital twin firstMATLAB Simulink · Simscape Multibody
Tune the loops on the model, then port them to the metal.
A multibody model of chassis, wheels and centre of gravity, with two PID loops: one holds the tilt angle, the other the travel speed. Gains were tuned by hand until a simulated push returned to equilibrium quickly, with low steady-state error and controlled overshoot.
Simulink · angle PID
P4.75I0.49D0.15N5.6
Simulink · speed PID
P0.2I100D2N20
Firmware · main PID
P10.0I0.4D1.5
Continuous tilt control, setpoint driven by the user.
Firmware · fine PID
P3.0I0D0.12
Active only within ±2° of the setpoint to kill micro-oscillations.
MPU-6050 IMU fused with a complementary filter, 98 % gyroscope / 2 % accelerometer. Auto-calibration at boot averages 1 000 samples.
Actuation
Two drivers, one sign
BLD-4055 brushless drivers under PWM, polarity flipped with the direction of travel. The robot takes small pushes and rights itself.
Interface
A PS5 controller
DualSense over Bluetooth. Left stick sets the tilt setpoint, right stick spins in place, ✕ toggles stabilisation, △ recalibrates the gyro. ±12 deadband on both sticks.
05 · The control loopWhat the firmware does, 200 times a second
The Simulink block diagram became a single C++ loop on the ESP32. Read the IMU, fuse it into one angle, run the right PID, write PWM to both drivers, handle the controller. Same structure as the model, so the gains transferred with only re-tuning.
Two PIDs, one output. The main loop tracks the tilt setpoint; inside ±2° a softer fine loop takes over so the robot stops hunting.
Filter before control. The gyro integrates cleanly but drifts; the accelerometer is noisy but absolute. 98 / 2 keeps the best of both.
Calibrate every boot. 1 000 samples averaged on the ground so the zero angle is the real zero.
Deadbands and toggles. ±12 on the sticks; ✕ disarms the loop, △ recalibrates.
// simplified from the ESP32 firmwarevoidloop() {
float gyro = mpu.gyroX() * dt;
float accel = atan2(mpu.accY(), mpu.accZ());
angle = 0.98 * (angle + gyro) + 0.02 * accel;
float target = map(ps5.LStickY(), deadband 12);
float err = target - angle;
float out = fabs(err) < 2.0
? finePID.step(err) // P 3.0 I 0 D 0.12
: mainPID.step(err); // P 10.0 I 0.4 D 1.5float turn = map(ps5.RStickX(), deadband 12);
driveL.pwm(out + turn); // BLD-4055, sign = direction
driveR.pwm(out - turn);
if (ps5.Cross()) stabilise = !stabilise;
if (ps5.Triangle()) calibrate(1000);
}
Control loop · C++ · Arduino framework · ps5Controller library
06 · Test logSpring 2025
16 AprBase componentsPartialModules healthy, integration not yet working.
30 AprMotor control · direction ×3ValidatedDrive and steering respond; stability still to do.
11 JunStability ×3Good balanceSlight tipping at steady state.
13 JunControl + stability, fwd/backFunctionalCorrect reaction to commands, one bug left to fix.
07 · Mechanics & costSolidWorks · FEA · Costing
Exploded view · every part namedBill of materials
3 mm steel motor bracket checked by finite elements: Von Mises stress, displacement and strain under the drive loads.
Aluminium profiles and ABS plates, chosen for weight, stiffness and quick disassembly.
3D-printed caster supports costed with SolidWorks Costing on the Fablab’s parameters: €17.02 per part.
€500 held by reusing last year’s battery, wheel axles, wheels and motors.