Skip to the content
4 layers120 × 103.9 mmBALANCING CUBEV1.01, the printed circuit board in 3D

BALANCING CUBEV1.01

Evc-r/Balancing-Cube-STM322

STM32F411CEU6 and ICM-20948 v2 self-balancing cube firmware port and integration plan.

Size
120 × 103.9 mm
Copper layers
4
Thickness
1.6 mm
Parts
76
Nets
73
Pads
238
Tracks, vias
325, 55
Pours
2
Routed
Yes
KiCad
KiCad 10.0 (file 20260206)
Created
17 Jul 2026
Updated
15 Sep 2026

Overview

BALANCING CUBEV1.01 is an open-source printed circuit board by Evc-r, from the Evc-r/Balancing-Cube-STM32 repository on GitHub. It is a 4-layer board of 120 × 103.9 mm with 76 parts on 73 nets, routed with 325 tracks and 55 vias.

It is built around the R-78E5.0-0.5, MMBT3904 and BSS84, with the SMBJ13CA and SUD50P04-08-VB among its other parts. Its parts include 36 resistors, 14 capacitors, 9 transistors, 8 connectors and 4 diodes.

Main components

5

README

README.md

STM32F411/ICM-20948 v2 Self-Balancing Cube

Firmware and integration work for a three-axis reaction-wheel balancing cube based on the open-source remrc/Self-Balancing-Cube project.

This version replaces the original ESP32 and MPU6050 with:

  • STM32F411CEU6 microcontroller
  • ICM-20948 v2 breakout intelligent IMU
  • Three Nidec 24H reaction-wheel motors with integrated drivers and quadrature encoders
  • 3S LiPo power system

[!WARNING] This project contains high-speed reaction wheels and a LiPo battery. Incorrect PWM polarity, wiring, firmware, or mechanical assembly can cause an unexpected full-power motor start. Read the safety section and complete every diagnostic stage before enabling closed-loop balancing.

Project status

Current phase: transitioning into firmware development and software integration. CAD and the first custom PCB design are complete; electrical bring-up and balancing validation remain ahead.

AreaCurrent progress
Mechanical design / CADComplete for the current build
Mechanical assemblyFrame and reaction-wheel assembly completed; final wiring/integration remains
Custom four-layer PCBFirst design complete and sent for fabrication; known issues require rework and validation
STM32 connectionHeader spacing mismatch identified; plan to connect the board through wires
IMU connectionJ7 connector unavailable; plan to solder the IMU wiring directly
FirmwareNext active development phase: STM32 project setup, peripheral bring-up, and integration
Closed-loop balancingNot yet demonstrated or validated

Current hardware issues

  • Power protection: an unintended VBAT connection was identified that may bypass the protection stage. A trace-isolation/bodge-wire repair is planned. The repair and its effectiveness have not yet been verified.
  • STM32 header spacing: the PCB's two long header rows do not match the STM32 board. A wired connection is planned, with a pin-by-pin wiring map and continuity checks before power-up.
  • IMU J7 connection: direct-soldered wiring is planned because the connector is unavailable. Pin order, logic compatibility, and strain relief still need verification.

These are open integration tasks, not completed fixes. The first PCB revision should not be treated as a validated design for replication.

Next milestones

  1. Document the as-built wiring and verify the PCB rework, power rails, and pin allocation.
  2. Create the STM32CubeIDE project and establish basic diagnostics.
  3. Bring up safe motor PWM/brake control and validate the encoders.
  4. Integrate and characterize the ICM-20948 v2.
  5. Implement attitude estimation, calibration, and fault handling.
  6. Perform output-limited control tests, then tune vertex balancing.
  7. Add edge balancing and usability features after the initial controller is reliable.

See JOURNAL.md for retrospective CAD/PCB notes and future session logs, and PROJECT_PLAN.md for the planned architecture and acceptance criteria.

Documentation and project files

The repository currently contains project documentation, not a buildable firmware release. CAD, KiCad source files, manufacturing outputs, photos, and firmware still need to be added here. The existing project media folder is linked for reference.

Earlier CAD/PCB work is documented retrospectively without reconstructed work hours. Future sessions should record what changed, evidence, test results, and actual tracked time.

Why this is a firmware port, not a board substitution

The original Arduino/ESP32 sketch cannot be compiled unchanged for this hardware. Several subsystems are fundamentally different:

Original designThis design
ESP32 ArduinoSTM32CubeIDE and STM32 HAL
MPU6050 raw accelerometer/gyroICM-20948 v2 raw accelerometer/gyro with STM32 attitude estimation
Original complementary filterSTM32 complementary/Mahony filter using calibrated ICM-20948 data
GPIO encoder interruptsSTM32 hardware timer encoder mode
ESP32 LEDC PWMSTM32 timer PWM
EEPROM APIVersioned internal Flash record with CRC
BluetoothSerialUSB CDC or UART initially
15 ms millis() loopDeterministic 200 Hz hardware-timed loop

The original three-wheel coordinate transformations and controller concept remain useful, but controller gains, timing, calibration, drivers, and safety behavior must be implemented and tested again.

Hardware

Required core components

  • STM32F411CEU6 board, typically a Black Pill-style board
  • ICM-20948 v2 breakout
  • Three Nidec 24H motors with integrated motor electronics and encoder outputs
  • 3S LiPo battery and suitable connector
  • Regulated logic supply appropriate for the selected STM32 board and peripherals
  • Motor brake, direction, PWM, and encoder wiring
  • Battery-voltage divider
  • Active buzzer or another fault indicator
  • USB-to-UART adapter if USB CDC is not used
  • Physical power disconnect

Items that must be verified before connection

ICM-20948 v2 breakout and STM32 breakout boards vary. Confirm from the actual boards and schematics:

  • STM32 board HSE frequency; this project currently assumes 25 MHz
  • ICM-20948 v2 regulator and permitted supply voltage
  • ICM-20948 v2 logic voltage, pull-ups, level shifters, and interface-selection pins
  • Motor encoder output voltage and whether it is push-pull or open-collector
  • Need for external encoder pull-ups
  • Maximum battery-divider voltage at a fully charged 3S pack
  • Ground continuity between logic, IMU, motors, and battery measurement

Do not assume that a module accepting 5 V power also has 5 V-safe signal pins.

Planned firmware architecture

The architecture, interfaces, safety behavior, and timing values below are implementation targets. Firmware bring-up, execution timing, and successful balancing have not been verified.

text
ICM-20948 v2 interrupt
    -> SPI or I2C transfer
    -> register/FIFO driver and sample validation
    -> calibrated accelerometer and gyro sample
    -> STM32 attitude estimator
    -> latest timestamped quaternion and angular rate

200 Hz control timer
    -> validate IMU freshness
    -> read three encoder counters
    -> calculate quaternion balance error
    -> determine vertex, edge, fallen, or fault state
    -> run state-feedback controller
    -> mix X/Y/Z corrections into three wheel commands
    -> update PWM, direction, and brake

Background processing
    -> command interface and telemetry
    -> calibration workflow
    -> Flash parameter storage
    -> battery monitoring
    -> diagnostics and fault reporting

Serial output, Flash writes, and blocking IMU transfers must never run inside the control interrupt.

Clock and timing

A 25 MHz external crystal is assumed for the selected board and still needs confirmation; it is not the intended CPU speed. The STM32F411 will be configured through its PLL for a target system clock of 100 MHz.

Initial timing targets:

FunctionTarget
ICM-20948 accelerometer and gyro sampling500 Hz initially
STM32 attitude estimator500 Hz initially
Balance controller200 Hz initially
Motor PWM20 kHz
Maximum accepted IMU age15 ms initially

The final CubeMX clock tree must also produce a valid peripheral clock if USB CDC is enabled.

ICM-20948 v2 approach

The ICM-20948 is a 9-axis IMU containing a 3-axis gyroscope, 3-axis accelerometer, AK09916 3-axis magnetometer, FIFO, programmable filters, and an embedded DMP. It supports SPI up to 7 MHz or I2C up to 400 kHz. The initial controller will read raw accelerometer and gyroscope data and perform attitude estimation on the STM32.

Initial sensing strategy:

  • Gyroscope and accelerometer sampled at 500 Hz
  • Configurable digital low-pass filtering
  • Startup stationary gyro-bias calibration
  • Six-axis complementary or Mahony quaternion estimator on the STM32
  • Magnetometer disabled for balancing initially because motor currents can disturb it
  • DMP integration deferred until the raw-data controller is validated

SPI is preferred for deterministic high-rate acquisition. I2C is acceptable for initial testing if the breakout exposes it more conveniently. Connect and use the data-ready interrupt. Every accepted sample must be timestamped locally, checked for plausibility, and monitored for staleness.

The exact v2 breakout must be inspected for its regulator, level shifting, pull-ups, address selection, and exposed interrupt/chip-select pins. The bare ICM-20948 has lower VDDIO limits than the STM32's 3.3 V logic, so compatibility depends on the breakout circuitry.

Coordinate frames

All sensor measurements must be transformed into a documented mechanical cube frame before they reach the controller.

The mapping will be bench-tested so that positive physical rotation around cube X, Y, and Z produces positive cube-frame gyro X, Y, and Z respectively. Axis swaps and sign changes will be centralized in one module rather than distributed through the controller.

The wheel numbering, positive rotation direction, encoder sign, and cube-frame force direction will also be documented before closed-loop testing.

Calibration

The MPU6050 offset procedure will be replaced with two layers: stationary accelerometer/gyro calibration, followed by quaternion reference calibration for the mechanical vertex and edge poses.

The firmware will store:

  • Vertex reference quaternion
  • Edge reference quaternion
  • Sensor-to-cube mapping
  • Controller gains
  • Battery calibration
  • Version, record length, magic value, and CRC32

At runtime the orientation error is calculated from:

text
q_error = inverse(q_reference) * q_current

Calibration will only be accepted when IMU data is fresh, sensor accuracy is acceptable, gyro magnitude is low, and the pose remains stable for a defined interval.

Planned commands:

text
cal vertex
cal edge
cal status
save

An absent, corrupt, or incompatible calibration record must prevent balancing.

Controller

The controller will retain the reference project's general state-feedback structure while using explicit units:

text
wheel command =
      angle gain * angle error
    + gyro gain * angular velocity
    + wheel velocity gain * wheel velocity
    + wheel position gain * accumulated wheel position

Yaw damping uses vertical-axis gyro and combined wheel motion.

The reference three-wheel transformation will be ported and verified against the actual wheel layout:

text
m1 = (0.5*x - 0.866*y) / 1.37 + z
m2 = (0.5*x + 0.866*y) / 1.37 + z
m3 = -x / 1.37 + z

Original numeric gains will not be copied blindly. The new firmware uses different units, sample timing, sensor latency, encoder scaling, and motor-command scaling.

Development environment

Planned tools:

  • STM32CubeIDE
  • STM32CubeMX configuration integrated with CubeIDE
  • ST-LINK programmer/debugger
  • Git
  • Serial terminal
  • Multimeter
  • Oscilloscope or logic analyzer strongly recommended

The repository will eventually contain the complete CubeIDE project and generated configuration needed for a clean build.

Planned source layout

text
Core/Inc/                Public module headers
Core/Src/                Application and driver implementation
Drivers/                 STM32 HAL and device support
Docs/                    Wiring, coordinate frames, calibration, and tuning
Tests/                   Host-side and hardware test support
JOURNAL.md               Retrospective hardware notes and future session logs
PROJECT_PLAN.md          Detailed engineering plan
README.md                 Project overview and bring-up guide

Bring-up order

Do not skip ahead to balance tuning. Each stage is a gate for the next.

1. Power and MCU

  • Verify every regulated rail without motor output enabled.
  • Confirm the STM32 HSE and generated 100 MHz clock.
  • Establish UART or USB diagnostics.
  • Report firmware version and reset cause at boot.

2. Brake and PWM

  • Assert brake before PWM initialization.
  • Test one motor at a time at a low command limit.
  • Verify direction control.
  • Measure the real zero-torque PWM polarity.
  • Confirm reset and debugger attachment never start a motor.

The reference Nidec interface uses active-low PWM. Treat that as a hypothesis to verify electrically, not an assumption.

3. Encoders

  • Configure timer encoder mode where possible.
  • Verify both channels of each encoder.
  • Test direction, stationary noise, wraparound, and maximum speed.
  • Document positive directions and counts per revolution.

4. ICM-20948 v2

  • Verify WHO_AM_I and configure the register banks, ranges, filters, FIFO, and data-ready interrupt.
  • Read calibrated accelerometer and gyro samples continuously.
  • Run the STM32 attitude estimator and measure sample interval, age, bias, saturation, and communication errors.
  • Verify all cube-frame axes.
  • Confirm individual motor operation does not interrupt reports.

5. Calibration and storage

  • Capture stable vertex and edge references.
  • Save a versioned record with CRC.
  • Verify save, reboot, load, and corrupt-record behavior.

6. Output-limited closed-loop testing

  • Use a support or tether.
  • Apply a low motor-command limit.
  • Verify by hand that every correction opposes the fall.
  • Test stale-IMU and excessive-tilt shutdown.

7. Vertex tuning

  • Tune angle feedback.
  • Add gyro damping.
  • Add wheel-velocity feedback.
  • Add a small wheel-position term to prevent saturation.
  • Add yaw damping.

8. Edge balancing and refinements

Only after vertex balance is reliable:

  • Implement edge state detection and reference
  • Tune an independent edge controller
  • Add wireless tuning
  • Add status LEDs and improved telemetry

Serial interface

Initial transport will be UART or USB CDC. Planned commands include:

text
help
status
faults
imu
encoders
battery
motor <1|2|3> <command>
motor stop
brake <on|off>
cal vertex
cal edge
cal status
save
set <parameter> <value>
get <parameter>
telemetry <on|off>

Manual motor commands will only work in a diagnostic state with the balance controller disabled.

Safety behavior

The firmware must disable motor output if any of these conditions occurs:

  • Boot or calibration is in progress
  • IMU data is missing, invalid, saturated, or stale
  • ICM-20948 v2 identity/configuration check fails or a reset is detected
  • Tilt exceeds the allowed range
  • Battery voltage is below the safe threshold
  • Encoder plausibility fails
  • Control-loop overrun occurs
  • A NaN or infinity reaches the controller
  • A stop command is received

Physical precautions:

  • Wear eye protection during powered tests.
  • Use a tether or fixture for initial control tests.
  • Keep hands, hair, tools, and loose wiring away from the wheels.
  • Secure the LiPo and all connectors mechanically.
  • Keep an accessible power disconnect.
  • Do not charge the LiPo inside the cube.
  • Use independent undervoltage and charging protection appropriate for the pack.
  • Never write Flash while the cube is balancing.

Testing and telemetry

Host-side tests are planned for:

  • Quaternion normalization, inversion, and sign handling
  • Reference-orientation error
  • Coordinate transformations
  • Three-wheel mixing and inverse mixing
  • Saturation and accumulated-state limits
  • Flash record CRC and version checks
  • Fault-state transitions

Runtime telemetry will include:

  • Control-loop execution time
  • IMU sample age and accuracy
  • Quaternion and angle errors
  • Gyro values
  • Encoder deltas and wheel velocities
  • Individual controller terms
  • Motor commands before and after saturation
  • Battery voltage
  • Active state and fault flags

Definition of the first release

Version v0.1.0 will require:

  • A clean build from documented STM32CubeIDE prerequisites
  • Documented pin map and wiring
  • Passing motor and encoder diagnostics
  • Timestamped and fault-monitored ICM-20948 v2 samples and STM32 attitude estimates
  • CRC-protected vertex calibration
  • Repeatable vertex balance without wheel-speed saturation
  • Reliable stale-IMU, over-tilt, low-battery, and software-fault shutdown
  • Documented controller units, gains, calibration, and bring-up procedure

Edge balancing may ship in a later release if it is not reliable enough for v0.1.0.

Contributing and development notes

Until the first hardware bring-up is complete, interface definitions, pin assignments, and controller parameters should be considered provisional.

When making changes:

  • Keep hardware access separate from control mathematics.
  • State physical units in names or comments.
  • Do not mix sensor-frame and cube-frame values.
  • Include safe defaults and failure behavior.
  • Update documentation whenever pin assignments, coordinate signs, or calibration data change.
  • Record test conditions and telemetry when changing controller gains.

Acknowledgements

This project is derived from and inspired by Remigijus's Self-Balancing-Cube. The original repository established the mechanical concept, Nidec motor interface, wheel mixing, balance-control structure, and practical build approach.

This repository is an independent STM32F411/ICM-20948 v2 port and will require new firmware, calibration, validation, and gain tuning.

License

No license has been selected yet. Until a license file is added, normal copyright restrictions apply to original work in this repository. Any reused or adapted material must continue to comply with its original licensing terms.

Parts

76
QtyValueFootprintReferences
1010 KiloOhmResistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolderR2, R4, R8, R15, R18, R20, R23, R27, R28, R29
9100 KiloOhmResistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolderR5, R7, R11, R12, R14, R19, R24, R35, R36
51 KiloOhmResistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolderR3, R26, R32, R33, R34
54.7 KiloOhmResistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolderR6, R10, R13, R30, R31
5MMBT3904Package_TO_SOT_SMD:SOT-23Q1, Q3, Q4, Q6, Q8
4100nF 25VCapacitor_SMD:C_0805_2012Metric_Pad1.18x1.45mm_HandSolderC3, C7, C9, C11
322 KiloOhmResistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolderR9, R16, R21
3220 OhmResistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolderR1, R17, R22
3220 uF 25VCapacitor_THT:CP_Radial_D8.0mm_P3.50mmC6, C8, C10
3BSS84Package_TO_SOT_SMD:SOT-23Q2, Q5, Q7
3MountingHole_3.2mm_M3MountingHole:MountingHole_3.2mm_M3H1, H2, H3
2100 nFCapacitor_SMD:C_0805_2012Metric_Pad1.18x1.45mm_HandSolderC12, C14
210uF 25VCapacitor_SMD:C_1210_3225Metric_Pad1.33x2.70mm_HandSolderC2, C4
2LEDLED_THT:LED_D3.0mmD2, D3
110 uFCapacitor_SMD:C_1210_3225Metric_Pad1.33x2.70mm_HandSolderC13
11000uF 25VCapacitor_THT:CP_Radial_D12.5mm_P5.00mmC1
11N4148Diode_SMD:D_SOD-123D4
122uF 10VCapacitor_SMD:C_1210_3225Metric_Pad1.33x2.70mm_HandSolderC5
127 KiloOhmResistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolderR25
1BuzzerBuzzer_Beeper:Buzzer_12x9.5RM7.6BZ1
1ICM_20948_MODULEConnector_PinSocket_2.54mm:PinSocket_1x10_P2.54mm_HorizontalJ7
1J1 BLACKPILL_LEFTConnector_PinSocket_2.54mm:PinSocket_1x20_P2.54mm_VerticalJ1
1J2 BLACKPILL_RIGHTConnector_PinSocket_2.54mm:PinSocket_1x20_P2.54mm_VerticalJ2
1MOTOR_1Connector_JST:JST_ZH_B12B-ZR_1x12_P1.50mm_VerticalJ4
1MOTOR_2Connector_JST:JST_ZH_B12B-ZR_1x12_P1.50mm_VerticalJ5
1MOTOR_3Connector_JST:JST_ZH_B12B-ZR_1x12_P1.50mm_VerticalJ6
1R-78E5.0-0.5Converter_DCDC:Converter_DCDC_RECOM_R-78E-0.5_THTU1
1SMBJ13CADiode_SMD:D_SMBD1
1SUD50P04-08Package_TO_SOT_SMD:TO-252-2Q9
1Screw_Terminal_01x02TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-2-5.08_1x02_P5.08mm_HorizontalJ9
1UARTConnector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_VerticalJ8

Similar boards

  • 2 layers100 × 100 mmHdmilight v3, the printed circuit board in 3D

    Hdmilight v3

    esar/hdmilight-v3

    HDMI Light v3 - FPGA based Ambilight clone with direct HDMI input

    259 parts8GPL-2.0
  • 2 layers147 × 92 mmVan, the printed circuit board in 3D

    Van

    blinken/vandal

    An ESP32-based lighting control system for campervans (or anything else)

    227 parts6GPL-3.0
  • 2 layers51.1 × 58.7 mmBattery switch, the printed circuit board in 3D

    Battery switch

    eclecticc/BeltPack

    Schematics and CAD for a belt PC

    40 parts5
  • 4 layers86.8 × 76 mmWebasto mainboard, the printed circuit board in 3D

    Webasto mainboard

    Beirdo/arduino-webasto-mainboard

    Custom replacement control board for Webasto Thermo Top C/E

    96 parts1MIT
  • 2 layers99 × 95 mmNew PCB, the printed circuit board in 3D

    New PCB

    xKMx1/Hexapod

    58 parts1
  • 2 layers100 × 75 mmSELDestroyer, the printed circuit board in 3D

    SELDestroyer

    HEAPLab/SELDestroyer

    The SEL destroyer can be also used as a normal voltage, current, or power monitoring device.

    82 partsMIT
  • 2 layers98.7 × 55.6 mmAquaguard, the printed circuit board in 3D

    Aquaguard

    Lekylouch/AquaBoard

    Carte électronique AquaGuard. Conçue sous KiCad, en cours de migration vers Altium Designer.

    70 parts
  • 2 layers148 × 84.5 mmPanel daisy, the printed circuit board in 3D

    Panel daisy

    ohmtech-rdi/eurorack-blocks

    Software to Hardware Prototyping for Eurorack using C++, Max/Gen~ or Faust

    259 parts410

Questions

How big is the BALANCING CUBEV1.01 PCB?

It measures 120 × 103.9 mm and has 4 copper layers, 1.6 mm thick.

What parts does the BALANCING CUBEV1.01 use?

76 parts, built around the R-78E5.0-0.5, MMBT3904, BSS84 and SMBJ13CA. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the BALANCING CUBEV1.01 KiCad files?

From the Evc-r/Balancing-Cube-STM32 repository on GitHub, at the commit this page was made from: the board is BALANCING CUBEV1.01.kicad_pcb and its schematic BALANCING CUBEV1.01.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the BALANCING CUBEV1.01 design in my own project?

Its repository states no licence, so its author keeps all rights: ask Evc-r before reusing the design.