Back to Expert Projects

🧊 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

ComponentSpecificationQtyNotes
ESP32Dual Core1Needed for fast matrix math
Brushless MotorsGimbal motors3Low KV
SimpleFOC MiniMotor Driver3
MPU6050IMU1
Brass FlywheelsHeavy3For 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 loop

Reviews & Ratings

0 reviews
5★
0
4★
0
3★
0
2★
0
1★
0
...

Loading reviews...