NEW: RoboRover Core is live! Educational robot base with USB-C rechargeable battery, sensors, OLED + Wi-Fi β€” ready for projects. πŸ€–

Orders via Akis Express or Box Now (before 12β€―PM) Mon–Fri ship same day. Cyprus Post orders ship next working day. πŸš€

How To Build BalanceBot

How To Build BalanceBot

Team Robo |

In this project, we will build a two-wheeled self-balancing robot using a Kypruino, an MPU6050 motion sensor, an L298N motor driver and a single TT gear motor.

The robot has no stand, no third wheel and nothing holding it up. It stays upright the same way you balance a broom on the palm of your hand: 200 times every second, it measures how far it is leaning and drives its wheels back underneath itself before it can fall.

This is a more advanced build than our other Kypruino projects. You should be comfortable wiring a motor driver, uploading an Arduino sketch and reading values in the Serial Monitor. In return, it covers some of the most important ideas in robotics: feedback control, sensor fusion and motor control.

Project Resources: Source Code & 3D Printing Files.

The finished self-balancing robot standing on its own, with the batteries at the top and a single TT gear motor driving both wheels.

What the project does

Once it is standing, the robot keeps itself upright without any help.

  • Self-balancing: it measures its tilt 200 times per second and drives its wheels to stay upright
  • Holds its position: it leans gently against its own movement, so it does not simply drive away
  • Finds its balance point: it fine-tunes the exact angle it balances at while it is running
  • Starts by itself: hold it upright and still for a moment, and it starts balancing
  • Status lights and sounds: the onboard NeoPixels act as a spirit level, and the buzzer signals when it is ready or has fallen
  • Safety cut-off: if it tips past 25Β° forwards, backwards or sideways, the motor stops

The result is a robot that can stand by itself for minutes at a time, constantly making small corrections to stay upright.


Components needed

For this build, you will need:

The project uses the Kypruino’s onboard NeoPixels, buzzer and button B, so no separate LEDs, buzzer or buttons are required.


How a balancing robot works

The inverted pendulum

A balancing robot is an inverted pendulum: a weight sitting on top of a pivot. A normal pendulum always swings back to hang straight down, but an inverted pendulum always wants to fall. The only way to keep it up is to keep moving the pivot back underneath the weight.

That is exactly what the robot does. If it starts leaning forwards, the wheels drive forwards to get back under the weight. If it leans backwards, they drive backwards. Done quickly and smoothly enough, the robot stays upright.

Measuring the tilt

The MPU6050 gives us two different ways to measure tilt, and neither is good enough on its own:

  • The gyroscope measures how fast the robot is rotating. Adding this up over time gives a smooth and fast tilt reading, but small errors build up, so the reading slowly drifts.
  • The accelerometer measures which way gravity is pulling. It never drifts, but it is noisy, and it gets confused when the robot itself speeds up or slows down.

The program combines the two with a complementary filter: it trusts the gyroscope from moment to moment and uses the accelerometer to slowly correct the drift. This is called sensor fusion, and the same idea is used in phones, drones and aircraft.

Deciding how hard to drive

Each time the robot measures its tilt, it calculates how hard to drive the motor using a PD controller:

  • P (proportional): the further it leans, the harder it drives
  • D (derivative): the faster it is falling, the harder it drives, which catches a fall early and stops it from overshooting

Staying in one place

Balancing alone is not enough. If the robot’s balance angle is even slightly off, it can only hold itself up by slowly speeding up, so it drives away across the table. Our robot has no wheel sensors (rotary encoders), so it estimates how fast it is moving and how far it has travelled from the commands it has sent to the motor. When it is moving forwards, it aims to lean slightly backwards, which slows it down and brings it back.


The Kypruino

The Kypruino is the brain of the robot. 200 times every second, it reads the MPU6050, works out the tilt, calculates the motor command and sends it to the L298N.

Besides acting as the main controller, the Kypruino provides several onboard features that this project uses:

  • NeoPixels on D8 for status lights and a live spirit level
  • Buzzer on D9 for ready, fall and fault sounds
  • Button B on D6 to start or stop the robot manually
  • USB-C for programming and for reading data back from the robot

The MPU6050 motion sensor

The MPU6050 combines a 3-axis gyroscope and a 3-axis accelerometer on one small board. It communicates with the Kypruino using the I2C protocol, which needs only two signal wires.

For a balancing robot, a few sensor settings make a big difference:

  • Gyroscope range: Β±500 Β°/s, enough for fast falls without losing precision
  • Accelerometer range: Β±4 g, so hard jolts from the motor do not overload the sensor
  • Built-in low-pass filter: about 44 Hz, which smooths out vibration from the gearbox
  • Calibration: the gyroscope is calibrated every time the robot starts, so it must lie completely still for a few seconds

Mount the sensor firmly to the frame. If it wobbles on its wires, it measures its own wobble instead of the robot’s tilt.


The L298N motor driver

The Kypruino cannot power a motor directly, so the L298N dual motor controller does the heavy lifting. It is an H-bridge: a set of electronic switches that can connect the motor to the battery in either direction. It has two channels, but this robot only needs one.

  • ENA sets the speed, using a PWM signal from 0 to 255. Remove the jumper on ENA so that the Kypruino can control it
  • IN1 and IN2 set the direction
  • 5V is an output from the board’s built-in 5 V regulator, which we use to power the Kypruino

One detail matters a lot for balancing. A geared motor does not move at all until the PWM value passes a certain threshold, called the deadband. In the air, our wheel only started turning at around 90–110. On the ground, the robot already reacted from about 75, so we settled on 90. The program adds this amount to its corrections, so even a small correction actually turns the wheel.


Designing and 3D printing the frame

The frame is a tall 3D-printed beam, about 27 cm high, with the motor at the bottom and the heaviest parts at the top.

  1. The batteries and the Kypruino sit at the top. A tall robot with its weight up high falls more slowly, which gives the controller more time to react. This is why a broom is easier to balance on your hand than a pencil.
  2. The L298N is mounted partway up the beam, between the batteries and the motor.
  3. A single TT gear motor at the bottom drives both wheels through its double-ended shaft.
  4. The MPU6050 is fixed firmly to the frame, so it moves exactly with the robot.

The 3D-printed frame, designed to hold the batteries and Kypruino at the top, the L298N partway up and the TT gear motor at the bottom.

Wheel spacing

The robot can only balance forwards and backwards. Sideways, it relies entirely on how far apart its wheels are. On our robot, the wheels were only 24 mm apart, so a sideways lean of just 6–8Β° was enough to tip it over. Tipping sideways is what ended our longest run, so if you design your own frame, place the wheels as far apart as you can.


Powering the robot

The robot runs on two 9V batteries wired in parallel: the two positive wires are joined together, and so are the two negative wires. This keeps the voltage at 9 V but doubles the capacity, so the robot runs for longer before the batteries need replacing. The robot also works with a single 9V battery.

  • The batteries power the L298N through its 12V terminal, which drives the motor
  • The L298N’s built-in regulator turns this into 5 V, and its 5V terminal powers the Kypruino through the Kypruino’s 5V pin
  • The Kypruino’s GND is connected to the L298N’s GND, so the control signals share a common reference

Use two batteries of the same type and charge level, and replace them together. Otherwise, the fuller battery drains into the weaker one.


Wiring the project

Make sure the Kypruino’s onboard NeoPixel and buzzer switches are turned on. The motor direction pins use D10 and D11, so that D8 and D9 stay free for the NeoPixels and the buzzer.

MPU6050 motion sensor

MPU6050 Pin Connects to Kypruino
SDA A4
SCL A5
VCC 5V
GND GND

L298N motor driver

L298N Pin Connects to
ENA (jumper removed) Kypruino D5
IN1 Kypruino D10
IN2 Kypruino D11
5V Kypruino 5V
GND Kypruino GND
OUT1 / OUT2 TT gear motor

Keep the L298N’s 5V-enable jumper in place. It switches on the built-in regulator that powers the Kypruino.

Power

Part Connects to
Both 9V batteries (+) L298N 12V
Both 9V batteries (βˆ’) L298N GND

Keep the sensor wires away from the motor wires, and make sure every connection is secure. A loose wire that briefly loses contact when the robot shakes can make the sensor drop out mid-run.

Wiring overview: 9V battery/ies power the L298N, and the L298N’s 5V output powers the Kypruino, which in turn powers the MPU6050.

Installing the Arduino libraries

Before uploading the code, install the two libraries the sketch uses.

  1. Open the Arduino IDE
  2. Go to Sketch β†’ Include Library β†’ Manage Libraries...
  3. Search for MPU6050_light and install it
  4. Search for Adafruit NeoPixel and install it

Uploading the code

Connect the Kypruino to your computer using the USB-C cable, select the correct board and port, then upload the balancing sketch. Lay the robot flat and still while it starts up, because it calibrates the gyroscope as soon as it is powered on.

The motor driver, lights, buzzer and button are connected to:

const uint8_t ENA = 5;              // L298N speed (PWM)
const uint8_t IN1 = D10, IN2 = D11;   // L298N direction
const uint8_t PIX_PIN = 8;          // onboard NeoPixels
const uint8_t BUZZER = 9;           // onboard buzzer
const uint8_t BUTTON = 6;           // button B: start / stop

These are the balancing settings we ended up with after testing:

float Kp = 32;        // push per degree of lean
float Kd = 2.5;       // push per degree/second of falling speed
float KV = 10;        // lean against estimated wheel speed
float KX = 2;         // lean against estimated distance travelled
int   DEADBAND = 90;  // PWM where the motor starts to move

You can find the complete code in our GitHub repository.


Understanding the program

1. Calibrating the gyroscope

When it is powered on, the robot measures the gyroscope’s reading while lying still and then checks that the result is close to zero. If the robot was moved during calibration, it gives a low beep and tries again. When it is ready, it plays two short rising beeps.

Between runs, it also re-measures this zero point whenever it lies still, because the gyroscope drifts slightly as it warms up.

2. Measuring the tilt

Every 5 milliseconds, the program predicts the new angle from the gyroscope and then nudges it slightly towards the angle the accelerometer reports:

float predicted = pitch + gyroRate * dt;            // where the gyro says we are
float accAngle  = atan2(ay, az) * RAD_TO_DEG;       // where gravity says we are
pitch = predicted + 0.01 * (accAngle - predicted);  // trust the gyro, correct slowly

Accelerometer readings that make no physical sense, for example during a hard jolt from the motor, are ignored, and the gyroscope carries the angle through them.

3. Balancing

The program compares the measured tilt with the balance angle and calculates the motor command:

float push = Kp * lean + Kd * rate;

It then adds the deadband, limits the result to the 0–255 PWM range, and sets the motor direction from the sign of the result.

4. Staying in place

The robot has no wheel sensors, so it estimates its own speed and distance from the commands it has sent to the motor. These estimates shift the balance target slightly: moving forwards makes it aim a little further back, so it brakes and returns.

A slow trim also adjusts the balance angle itself while the robot is running. If the robot keeps having to push in one direction, its balance angle is slightly off, so the trim moves it until the push disappears. After a long run, the robot saves part of this correction, so it starts closer to its true balance point next time. This lets it balance even if the weight is not perfectly centred.

5. Starting and stopping

When the robot is held near upright and still for 0.4 seconds, it starts balancing by itself. To avoid a sudden jerk, the target starts at the angle where you let go and glides to the balance angle within about a second. Pressing button B also starts or stops it.

If the robot tips past 25Β° forwards, backwards or sideways, the motor switches off and the robot waits to be stood up again.


Testing and tuning

Test the robot in stages:

  1. Calibrate: power it on lying flat and still. The LEDs glow blue while it calibrates, and two rising beeps mean it is ready
  2. Check the directions in the air: hold the robot upright with its wheels off the ground. All three LEDs turn green, and a moment later it starts. Tip it slightly forwards or backwards: the LED on the side it is leaning towards should glow red, and the wheels should spin as if driving in the direction of the lean
  3. First balance: stand it on a flat surface, wait for it to start and let go. Keep a soft surface nearby, and only catch it once it is clearly falling
  4. Check the readings: connect the USB cable and open the Serial Monitor at 115200 baud. Send s to see the measured angle, the balance angle and the current settings

If the wheels drive away from the lean instead of towards it, swap the two motor wires on OUT1 and OUT2, or send f in the Serial Monitor. If the opposite LED lights up, swap the values of PIX_BACK and PIX_FWD in the code.

If the robot buzzes or shakes rapidly, the D value is too high. If it reacts too slowly and falls over, increase P. You can try new values without uploading again by sending, for example, p30 or d2 in the Serial Monitor. These are forgotten when the board restarts, so copy the values that work into the code.

Test the robot on the floor, or well away from the edge of a table. Until it is tuned, it can wander off before you have time to catch it.


Final result

The finished robot stands on its own, constantly making small corrections. In testing, it balanced for 13 minutes in a single run, and for more than 24 minutes across three runs.

It is not perfectly still. Without wheel sensors, it can only estimate where it is, so it sways slowly back and forth by up to about 18 cm, once every 4–6 seconds, and can slowly creep away over time. Its longest run ended when it tipped over sideways on its narrow wheels, not because the balancing failed.


What students can learn

This project introduces several useful STEM concepts:

  • How an inverted pendulum behaves, and why it needs active control
  • Reading a gyroscope and an accelerometer over I2C
  • Sensor fusion with a complementary filter
  • Feedback control with P and D terms
  • Driving a DC motor with an H-bridge and PWM
  • Motor deadband and how to compensate for it
  • Wiring batteries in parallel with a common ground
  • Tuning a control system by testing it on real hardware
  • Designing a frame around its centre of mass

It also demonstrates an important engineering idea: a system that looks simple from the outside, a stick on two wheels, depends on many small details working together, from sensing and timing to motor control and tuning.


Possible extensions

  • Move the wheels further apart to stop the robot tipping sideways
  • Add a second motor on the L298N’s second channel, so the robot can turn
  • Add wheel encoders, so the robot knows exactly how far it has moved and can stay perfectly in place
  • Add Bluetooth or Wi-Fi remote control to drive it around while it balances
  • Compare different batteries and see how they affect motor power and run time
  • Show the tilt angle live on an OLED display

Final thoughts

A self-balancing robot is one of the most satisfying projects to complete, because you can see the control loop working. A robot that falls over instantly without power stands on its own as soon as the code takes over.

Using a Kypruino, an MPU6050, an L298N and a single TT motor, this build combines sensors, motors, control theory and tuning in one project. It is a challenging build, but every step teaches something that applies to real robots, drones and vehicles.

Final view of the completed self-balancing robot, standing upright on its own and ready for the next test.

Leave a comment

Please note: comments must be approved before they are published.