Self Balancing Robot V1 (Prototype)

The foundational proof-of-concept for a Brushed DC self-balancing robot.

Project Synopsis

The V1 platform serves as the foundational hardware proof-of-concept for a Brushed DC Self-Balancing Robot.

Developed entirely within the Arduino IDE toolchain, this initial prototype focused on establishing the real-time control loops and verifying the ability to balance despite the inherent nonlinearities of encoderless Brushed DC Motors.

Focus Area Breadboard prototyping, low-level firmware architecture, and control loop verification.
Key Achievements Successfully maintained continuous upright stability against light external disturbances.
V1 Prototype Active Balancing Loop
Fig 1.1 V1 balancing demonstration under light external disturbances.

Core Engineering Skills Acquired

Embedded Architecture

Configured memory partitions, clock limits, and hardware I2C transmission on the ESP32-S3 (N16R8) microcontroller.

Power Distribution

Integrated a buck converter to regulate the voltage rails, ensuring high current motors do not starve MCU logic.

State Estimation

Implemented a discrete multivariable Kalman Filter algorithm to fuse noisy sensor data and resolve gyroscopic drift.

Non-Linear Control

Designed an independent PID controller to map vertical setpoint error into discrete PWM duty cycles for motor actuation.


Mechanical Design


Electrical Hardware

The electrical network was constructed across two half-sized breadboards, mated together with their power rails removed:

Physical Dual Half-Size Breadboard Prototyping Assembly
Fig 1.2 Physical dual half-size breadboard assembly with wiring.
Electrical Circuit Diagram Schematic
Fig 1.3 Electrical circuit diagram schematic detailing logic lines and pin layouts.

Circuit Architecture Highlights

Power Routing

The 2S LiPo Battery delivers a raw 7.4V voltage directly to the DRV8833 motor driver pins. Concurrently, the MPM3610 step-down buck converter drops that shifting battery voltage down to 3.3V to drive the ESP32-S3 and IMU.

Signal Topology

The MPU6050 communicates with the ESP32-S3 over a dedicated hardware I2C bus operating at 400kHz clock speed to ensure low latency data retrieval.


Firmware Architecture

The firmware executes on a non-blocking timing loop within the Arduino framework to ensure fixed-interval control updates.

State Estimation via a Custom Kalman Filter

1

The Challenge

Raw IMU accelerometer readings are highly susceptible to high-frequency noise from chassis vibrations, while gyroscope readings experience cumulative, low-frequency sensor drift over time.

2

The Solution

Developed a discrete, two-state Kalman filter that fuses the gyroscope and accelerometer data and dynamically injects process noise (Q) and measurement noise (R) to model real-world uncertainties.

3

The Outcome

Isolates the true tilt angle (θ) by eliminating noise, providing clean state estimation for the robot controller.

void KalmanFilter::predict(float *gyro) { 
    // A Priori State Estimate with Gyroscope Readings ( New_Angle = Old_Angle + (Angular_Velocity * dt_sec) )
    roll  += gyro[0] * RAD_TO_DEG * dt_sec;
    pitch += gyro[1] * RAD_TO_DEG * dt_sec;

    // Uncertainty Grows (To account for gyroscopic drift, inject Process Noise Q into the Covariance matrix)
    Sigma[0] += Q[0] * dt_sec;
    Sigma[3] += Q[1] * dt_sec;
}
            
void KalmanFilter::measurement_task(float *accel) {
    // Calculate True Measured Tilt with Accelerometer Readings
    m_roll  = atan2(accel[1],  sqrt(sqr(accel[0]) + sqr(accel[2]))) * RAD_TO_DEG;
    m_pitch = atan2(-accel[0], sqrt(sqr(accel[1]) + sqr(accel[2]))) * RAD_TO_DEG;
    
    // Compute Innovation Covariance S (Fuse initial uncertainty with Accelerometer measurement Noise R)
    float S0 = Sigma[0] + R[0];
    float S1 = Sigma[1];
    float S2 = Sigma[2];
    float S3 = Sigma[3] + R[1];

    // Compute Kalman Gains (($K = \Sigma * S^(-1)$))
    k_det = 1.0f / (S0 * S3 - S1 * S2);

    k_gain[0] = (Sigma[0] * S3 - Sigma[1] * S2) * k_det;
    k_gain[1] = (Sigma[1] * S0 - Sigma[0] * S1) * k_det;
    k_gain[2] = (Sigma[2] * S3 - Sigma[3] * S2) * k_det;
    k_gain[3] = (Sigma[3] * S0 - Sigma[2] * S1) * k_det;

    // Calculate the Error Between the Accelerometer Reading and the A Priori Estimate
    float r_error = m_roll - roll;
    float p_error = m_pitch - pitch;

    // Update the Roll and Pitch with Kalman Gains
    roll  += (k_gain[0] * r_error) + (k_gain[1] * p_error);
    pitch += (k_gain[2] * r_error) + (k_gain[3] * p_error);

    // Update Error Covariance Matrix (A Posteriori Estimation)
    float s0 = Sigma[0], s1 = Sigma[1], s2 = Sigma[2], s3 = Sigma[3];
    Sigma[0] = (1.0f - k_gain[0]) * s0 - k_gain[1] * s2;
    Sigma[1] = (1.0f - k_gain[0]) * s1 - k_gain[1] * s3;
    Sigma[2] = -k_gain[2] * s0 + (1.0f - k_gain[3]) * s2;
    Sigma[3] = -k_gain[2] * s1 + (1.0f - k_gain[3]) * s3;

    // Enforce Matrix Symmetry (If any rounding errors accumulate)
    float relationship_avg = (Sigma[1] + Sigma[2]) * 0.5f;
    Sigma[1] = Sigma[2] = relationship_avg;
}
            

PID Control Loop Implementation

1

The Challenge

A self-balancing robot (similar to an inverted pendulum) is inherently unstable and falls due to gravity. Simple binary motor commands fail to maintain equilibrium and cause violent over-corrections.

2

The Solution

Instead of binary motor outputs, a PID controller breaks the motor output into three scaled adjustments:

▪Proportional (P): Scales output power proportionally to tilt amount.

▪Integral (I): Tracks past errors over time to eliminate lingering tilts.

▪Derivative (D): Applies a low-pass filter to the future rate of change of error, suppressing over-corrections.

3

The Outcome

Optimal tuning of the PID parameters generates motor outputs that reliably maintain vertical equilibrium.

float PID::control(float cur_angle, float max)
{
    error = setpoint - cur_angle;

    // DERIVATIVE: Compute raw rate of error change and apply an 80/20 discrete low-pass filter
    float raw_derivative = (error - previous_error) / dt;
    derivative = (0.80f * previous_derivative) + (0.2f * raw_derivative);
    
    previous_error = error;
    previous_derivative = derivative;

    // INTEGRAL: Constrained to prevent integral windup from saturating the motor capacity
    integral = constrain((integral + (error * dt)), -1.20f, 1.20f);

    // Output the PID corrected motor output
    out = (kp * error) + (ki * integral) + (kd * derivative);
    return constrain(out, -max, max); 
}
            

Evaluation & Moving Forward

While the V1 prototype successfully validated my core stability algorithms, it highlighted critical structural, electrical, and architectural bottlenecks. The roadmap below tracks these failure modes alongside their engineered V2 solutions:

// 01_PROTOTYPE_DEFECT

Physical Circuit Instability

Jumper wires on breadboards are highly prone to disconnections caused by continuous chassis vibrations during operation.

[ CLICK_TO_REVEAL_UPGRADE ]
// NEXT_GEN_UPGRADE

Custom PCB Implementation

Transitioning away from messy breadboards to a custom printed circuit board designed in KiCad to secure all traces.

[ CLICK_TO_VIEW_DEFECT ]
// 02_PROTOTYPE_DEFECT

Microcontroller Logic Resetting

Inductive spikes from sudden motor switching periodically causes sags across power paths, introducing noise and risking ESP32 brownouts.

[ CLICK_TO_REVEAL_UPGRADE ]
// NEXT_GEN_UPGRADE

Power Isolation & Decoupling

Combating sags by using dedicated decoupling capacitors across motor signals and incorporating bulk storage capacitors near the main voltage source rails.

[ CLICK_TO_VIEW_DEFECT ]
// 03_PROTOTYPE_DEFECT

Chassis Rotational Torsion

The initial single-part chassis faced issues with rotational torsion due to the lack of a reinforcing connecting platform at the chassis base near the wheels.

[ CLICK_TO_REVEAL_UPGRADE ]
// NEXT_GEN_UPGRADE

Multiple-Part Enclosure

Redesigning the chassis as an assembly of structural components within SolidWorks, featuring a fully enclosed frame to minimize rotational torsion issues.

[ CLICK_TO_VIEW_DEFECT ]
// 04_PROTOTYPE_DEFECT

Lack of Feedback Telemetry

The current design lacked any telemetry, state indication, or physical warning systems to signify failures or falling to the user.

[ CLICK_TO_REVEAL_UPGRADE ]
// NEXT_GEN_UPGRADE

Active Auditory & Visual I/O

Integrating user feedback loops using Edison filaments paired with a front light diffuser panel for status, alongside a speaker alert to signify fallen states.

[ CLICK_TO_VIEW_DEFECT ]
// 05_PROTOTYPE_DEFECT

Static Behaviour

The system lacked flexibility in runtime, operating only on a singule execution layer with no capacity for transitioning to remote driving states.

[ CLICK_TO_REVEAL_UPGRADE ]
// NEXT_GEN_UPGRADE

Remote State Machine

Developing a secondary ESP32 remote transmitter using the ESP-NOW protocol to feed real-time inputs (Forward, Reverse, Steering) into an active FSM.

[ CLICK_TO_VIEW_DEFECT ]

Repository, Assets, and BOM

Bill of Materials
Repository Info
View Repository
Bill of Materials
Repository Info
View Repository

Bill of Materials (BOM)

To establish a clear development history, all component selections and unit costs are logged below:

POWER SOURCE
2x 3.7V LiPo Battery ↗

High-discharge power source necessary to counter immediate motor torque spikes.

£4.49
BATTERY HOLDER
1x 2 Slots LiPo Battery Holder ↗

Secure the batteries in a 2S configuration for a raw 7.4V.

£0.58
BUCK CONVERTER
1x MPM3610 3V3 ↗

Ultra-compact 21V, 1.2A step-down module providing clean 3.3V logic power.

£5.80
MICROCONTROLLER
1x ESP32-S3 (N16R8) ↗

240MHz dual-core processing power with ample flash space for control calculations.

£5.00
IMU
1x MPU6050 GY-521 ↗

3-axis accelerometer and 3-axis gyroscope combined on a single I2C bus.

£1.27
DC MOTOR DRIVER
1x DRV8833 ↗

Dual MOSFET H-Bridge supporting low-saturation resistance and slow-decay active braking routines.

£0.90
ACTUATORS
2x BDC TT Geared Motors with Wheels ↗

Budget-friendly brushed DC motors with wheels.

£2.60
3D MODEL
Custom 3D Printed Chassis (~91g PLA)

Custom structural frame designed to mount the TT motors, battery holder, and breadboard.

-
MISC
2x Half-size Breadboards, Assorted Jumper Wires

Rapid prototyping framework allowing quick hardware loop signal adjustments.

-
TOTAL_PROTOTYPE_COST £20.64

Repository Information

All firmware and hardware files are completely open-source:

Firmware

Directory containing the primary balancing_robot.ino logic core, alongside custom Kalman Filtering and PID Control Algorithm header files

Hardware

Production asset directory containing original SolidWorks CAD source models (.SLDPRT) and slice configurations (.3mf) ready for manufacturing.

View The Repository

All resources and dependencies are can be downloaded directly from the open-source branch master directory tree.