🧊 Self-Balancing Cube
Balance a 3D-printed cube on a single corner using an ESP32 and reaction wheels.
Overview
This is a marvel of modern control theory. By rapidly spinning brushless motors equipped with heavy flywheels (reaction wheels), the cube generates counter-torque to perfectly balance on its vertex.
What you'll learn: Matrix math for 3D state estimation, LQR (Linear Quadratic Regulator) or cascaded PID control, and Field Oriented Control (FOC) for brushless motors.
Estimated time: 15+ hours. Difficulty: ⭐⭐⭐⭐⭐ Expert.
Components Needed
| Component | Specification | Qty | Notes |
|---|---|---|---|
| ESP32 | Dual Core | 1 | Needed for fast matrix math |
| Brushless Motors | Gimbal motors | 3 | Low KV |
| SimpleFOC Mini | Motor Driver | 3 | |
| MPU6050 | IMU | 1 | |
| Brass Flywheels | Heavy | 3 | For momentum |
Step-by-Step Tutorial
1
Mechanical Symmetry
The center of mass must be perfectly aligned over the balancing corner. Print the frame with high infill.
2
IMU Calibration
The IMU must be perfectly calibrated. Even a 0.5-degree error in the accelerometer offset will cause the cube to accelerate and eventually fall.
3
FOC Tuning
Use the SimpleFOC library to tune the PID for the motor velocities. The motors must respond instantly without jitter.
4
State Matrices
Implement the balancing algorithm. It takes the pitch and roll from the IMU and calculates the required torque for each of the 3 motors.
Braking a fast-spinning brushless motor dumps energy back into the battery. Ensure your battery and circuitry can handle regenerative braking spikes.
Code / Configuration
balancing_cube.ino
INO
// Balancing Cube FOC setup (Snippet)
#include <SimpleFOC.h>
BLDCMotor motor1 = BLDCMotor(7);
BLDCDriver3PWM driver1 = BLDCDriver3PWM(25, 26, 27, 14);
MagneticSensorI2C sensor1 = MagneticSensorI2C(AS5600_I2C);
void setup() {
sensor1.init();
motor1.linkSensor(&sensor1);
driver1.voltage_power_supply = 12;
driver1.init();
motor1.linkDriver(&driver1);
motor1.voltage_sensor_align = 3;
motor1.controller = MotionControlType::velocity;
motor1.init();
motor1.initFOC();
}
void loop() {
motor1.loopFOC();
// Target velocity calculated by main balancing loopReviews & Ratings
—0 reviews
Sign in to leave a review
Loading reviews...