Source: https://mokxi.com/learn/arduino-self-balancing-robot
Updated: 2026-10-26

Learn

# A self-balancing robot on an Arduino

Advanced

Written by the Mokxi team, updated October 26, 2026

Start building free Open the editor

Or see every lesson.

- 455 parts on the bench
- 43 boards running now
- 1.00x real time, on every board

Click to open it in the editor

The Balance bot example: an MPU6050 through a complementary filter and a PID on three knobs. Push it with the arrow buttons.

A self-balancing robot stands on two wheels, like an upside-down pendulum, and stays up only because it keeps driving its wheels under itself. It is a classic Arduino project because it puts two big ideas in one build: turning a noisy sensor into a good angle, and a PID controller that acts on it hundreds of times a second.

The circuit above is an Uno running a two-wheel robot with its own MPU6050 and TB6612 motor driver. Three knobs set the PID gains while it runs, and an OLED shows the angle and the gains. Press Run: the robot is held upright for a moment, then let go, and it catches itself. Then push it with the arrow buttons on the robot, and turn the knobs to see what each gain does.

## What you need

- An Arduino Uno
- A two-wheel robot chassis with geared DC motors
- An MPU6050 accelerometer and gyroscope
- A TB6612FNG motor driver
- Three 10k potentiometers
- An SSD1306 OLED, 128x64, I2C (optional)
- A battery pack for the motors

## Wiring

Part and pin | Goes to | Note

Robot SCL and SDA | Pins 12 and 2 | The robot’s MPU6050 at 0x68, on its own software I2C

AIN1, AIN2, PWMA | Pins 10, 9 and 6 | Left motor

BIN1, BIN2, PWMB | Pins 5, 4 and 3 | Right motor

STBY | 5 V | The driver runs whenever it has power

Kp, Ki and Kd knobs | A0, A1 and A2 | Ends to 5 V and GND

OLED SCL and SDA | A5 and A4 | Angle and gains

## Step 1: work out the tilt

The MPU6050 has two sensors, and neither is good enough alone. The accelerometer knows which way is down, so atan2(-ax, az) gives the tilt from gravity. But it also feels every shove the wheels give the body, so while the robot moves it is noisy and wrong. The gyroscope measures how fast the body is turning, smoothly, but you have to add up that rate to get an angle, and the small errors add up too, so the angle drifts.

The complementary filter takes the best of each: angle = 0.98 * (angle + rate * dt) + 0.02 * accelAngle. From moment to moment the gyro moves the angle, and the accelerometer pulls it gently back to the truth, 2% each step. It is one line of code, and it is what most balancing robots use.

## Step 2: a PID on the angle

Every 10 ms the sketch works out how far the body leans from upright and drives the wheels to fix it. The output is three terms added together. P (proportional) is the lean times Kp: lean more, drive harder. D (derivative) is the gyro rate times Kd: it resists the body swinging fast, which stops it overshooting. I (integral) adds up the lean over time times Ki: it supplies the steady push a motor needs just to hold a speed.

The sum is clamped to -255 to 255, and its sign picks the direction (AIN1 and AIN2) while its size goes to analogWrite on PWMA and PWMB. Leaning forward, the wheels drive forward to get back under the body.

The three knobs set Kp from 0 to 80, Ki from 0 to 600 and Kd from 0 to 2. With each knob in the middle (40, 300 and 1) the robot balances: let go at one second, it stands, and about four seconds after Run the serial monitor reports "Balanced for 3 s". Push it with the arrow and it says "Caught it: upright again" a moment later.

The heart of the balance bot loop, trimmed

## What each gain does: try it

Turn Ki all the way down. Without the integral, the robot cannot hold the push a motor needs at speed, so it creeps off, leans more and more to keep up, and falls: the serial monitor says "FALLEN". That is the I term earning its place.

Turn Kd all the way down, then press the stand-up button on the robot. Without the damping, each swing overshoots the last: it rocks harder and harder until it falls. With Kd back up, the same push dies away in a swing or two.

Kp sets how hard it fights a lean. Too low and it is lazy and wobbly; too high and it shakes. People tune a real robot in that order: Kp until it nearly stands and starts to shake, Kd until the shake stops, then Ki until it stops drifting.

## Held, let go, fallen

A real robot is held upright while it powers up. If the PID ran during that time, the integral would fill up with a lean the wheels cannot fix (your hand is holding it), and the stored push would throw it over the moment you let go. So the sketch keeps the motors braked while the gyro says the body is still, and starts balancing when the rate goes over 1 degree a second: the hand has let go.

Past 45 degrees it has fallen. The motors brake, the integral resets, and on the robot it lies on the floor at about 80 degrees. Stand it up with the button and it is held again, ready for the next try.

The model is a real pendulum on wheels, worked out every millisecond, with motors that push the body back as they drive the wheels forward. What it leaves out is the floor’s bumps, the backlash in cheap gearboxes and a battery that sags, which are the things that make a real one harder to tune.

## Common mistakes

The wheels going the wrong way. If the robot drives away from its lean, it falls at once. Swap one motor’s wires, or flip the sign of the output.

The angle with the wrong sign, because the MPU6050 is mounted a different way around. Lean it forward by hand and check the angle goes positive before you ever run the motors.

Trusting the accelerometer alone. It reads the wheels’ shoves as tilt. Blend it with the gyro.

STBY on the TB6612 left unwired. It has a pull-down, so the driver stays off and the motors never turn. Pull STBY in the circuit above and the robot falls as soon as it is let go.

A slow loop. Printing to the serial monitor every loop, or drawing the whole OLED at once, steals the time the PID needs. The sketch prints four times a second and draws one row of the OLED per call.

Integral windup. Without a limit, the I term keeps growing while the robot is held or stuck. The sketch caps it and resets it on a fall.

## Questions

What sensor does a self-balancing robot need?

An accelerometer and a gyroscope together, such as the MPU6050. The accelerometer gives the angle from gravity, the gyroscope how fast it is turning, and a complementary or Kalman filter blends them.

How do I tune the PID on a balancing robot?

Start with Ki and Kd at zero. Raise Kp until it almost stands and begins to shake, raise Kd until the shaking stops, then add a little Ki to stop it drifting off.

Which motor driver is best for a balancing robot?

A TB6612FNG is a good choice for small geared motors: it is efficient and switches quickly. An L298N works but wastes more power as heat.

Why does my balancing robot drift off and fall?

Usually too little integral, so it cannot hold the push it needs at speed, or a balance point that is not quite upright. Add some Ki, or adjust the zero angle.

Related

## Keep going

Arduino MPU6050: Accelerometer and Tilt Arduino L298N Motor Driver: Wiring, Jumpers and Code Arduino Potentiometer Wiring and Code: Dim an LED Arduino OLED Display (SSD1306) Tutorial Arduino Line Follower Robot: Code and Circuit The PID simulator, on the same robot The course: Build a balance bot, in three lessons How the balance bot is modeled The Balance bot project Advanced The project page, with the full sketch Advanced

## Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.

Start building free Open the editor
