Arduino Controlled Two Wheeled Self Balancing Robot Using Complementary Filtered Imu Telemetry
Capstone project for designing, building, and validating a two-wheel self-balancing robot using an Arduino-based control system.
This project combines embedded control, mechanical design, and prototype testing:
Self-balancing two-wheeled robot firmware built with Arduino and MPU6050, using complementary filtering and PID control for real-time stability and load handling.
This repository contains the Arduino code, configuration, and assembly instructions for building a self-balancing robot. A self-balancing robot is designed to maintain its balance on two wheels using a gyroscope and accelerometer for orientation sensing, along with control algorithms to stabilize itself. This project is ideal for hobbyists and engineers interested in robotics, control systems, and sensor integration.
The self-balancing robot uses a combination of sensors and motor control to maintain its upright position. It relies on a gyroscope and accelerometer (typically combined in an IMU module) to measure the robot's tilt angle and angular velocity. A PID (Proportional-Integral-Derivative) control algorithm processes this data to adjust the motors' speed and direction, ensuring the robot remains balanced .
These dimensions ensure that the robot is stable while balancing and allows enough space for mounting all components.
Follow these steps to assemble your self-balancing robot: Prepare the Chassis If using a custom design, 3D print or laser-cut the parts. Attach mounting points for the motors, Arduino, motor driver, and IMU sensor. Attach Motors Mount the two DC motors at the bottom of the chassis, ensuring they are aligned properly. Attach the wheels to the motors. Mount the IMU Sensor Secure the MPU6050 sensor to the top of the chassis. Ensure it is level and centered to accurately measure the robot's tilt. Connect the Motor Driver Connect the DC motors to the L298N motor driver module. Connect the motor driver's input pins to the Arduino's digital pins (e.g., D5, D6, D9, D10). Connect the IMU Sensor Connect the MPU6050 sensor to the Arduino using I2C communication: VCC → 5V GND → GND SDA → A4 SCL → A5 Power Connections Connect the battery to the motor driver's power input. Connect the motor driver's 5V output to the Arduino's VIN pin to power the microcontroller. Final Assembly Double-check all connections to ensure proper wiring. Secure all components to the chassis using screws or adhesive.
The provided Arduino code uses the MPU6050 sensor to measure the robot's tilt angle and applies a PID control algorithm to adjust the motors' speed and direction. The PID parameters ( Kp , Ki , Kd ) can be tuned to achieve optimal balance.
Feel free to fork this repository and contribute improvements or new features. If you have suggestions or find bugs, please open an issue.
By following this guide, you should be able to simulate and build your own self-balancing robot using Arduino and Wokwi. Happy tinkering! 🚀
This guide will walk you through building a self-balancing robot using Arduino. The robot uses a gyroscope and accelerometer to measure its tilt and angular velocity, and a PID (Proportional-Integral-Derivative) control algorithm to maintain balance on two wheels.
A self-balancing robot is the first genuinely hard control problem in the Lab. Nothing about it is forgiving, and that is exactly why it teaches PID better than any tutorial.
An inverted pendulum is unstable. Left alone it falls, and the further it tilts the faster it falls. To stay up, the wheels must be driven in the direction it is falling â drive forward as it tips forward, and the base catches up with the top.
The controller's only job is deciding how hard to drive, from how far and how fast it is tipping.
The spirit level project used only the accelerometer, because gravity gives a drift-free angle at rest. A balancing robot is never at rest.
Every acceleration of the chassis shows up as apparent tilt, so the accelerometer reports a wildly noisy angle exactly when it matters. The gyroscope has the opposite character: it is smooth and immediately responsive, and it drifts.
The complementary filter takes the gyro for short-term response and gently pulls it towards the accelerometer for long-term truth. Around 98% gyro to 2% accelerometer is the usual balance. One line of code, and the whole project depends on it.
P responds to how far off you are. Alone it overshoots, then overshoots back, and oscillates forever.
D responds to how fast the error is changing. It opposes rapid movement, which damps that oscillation. P and D together are enough for a robot that balances.
I accumulates error over time and corrects persistent offsets â a slightly heavier side, a motor that is weaker than its twin. It is also the term that causes trouble, because an accumulator with no bound keeps growing while the robot is on its side, then dumps all of it at once when you stand it up. That is integral windup, and clamping the accumulator is the fix.
The code here is perhaps sixty lines and will be right first time. The gains will not be. Expect to spend longer turning three numbers than you spent building the robot, and accept that a gain set that works on your chassis will not transfer to another.
Compiles arduino-cli 1.5.1, Arduino AVR Boards 1.8.8 · Arduino Uno checked 24 Sept 2026 Builds cleanly. Not yet bench-tested on hardware.
The circuit diagram with every connection pin by pin, step-by-step assembly, the complete tested code, and the mistakes that catch people out on this build are part of Infratics Pro. Free members can unlock one full guide every month.
Includes a circuit diagram with 6 connections, 7 assembly steps, the full source code and 5 troubleshooting fixes.
Infratics Lab projects are for learning. Build them at your own risk, follow the safety notes and your local laws, and do not use them to protect people, property or health. Safety & responsible use
Sweep an ultrasonic sensor with a servo and plot detected objects on a PC radar display.
Hi. I can help you find a project, explain what Pro includes, or point you to the right service.
Answers come from the project catalogue. For quotes or anything it cannot answer, use the enquiry form .
Build an Arduino Nano self-balancing robot using the MPU6050 and L298N, with a complementary filter and PID loop for stable two-wheel balancing by ShillehTek.
Arduino Nano + MPU6050 self-balancing robot: In this build, an Arduino Nano reads an MPU6050 IMU to estimate tilt angle, then uses a PID loop to drive an L298N motor driver so a two-wheeled robot stays upright.
An MPU6050 measures how far the body is leaning, a complementary filter turns the noisy accelerometer and drifting gyro into one clean angle, and a PID loop drives the wheels under the robot fast enough that it never falls.
Note: Geometry matters more than code. Mount the battery (the heaviest part) as high as possible. A tall robot falls slowly and is easier to balance; a squat one falls fast and is nearly impossible. Mount the MPU6050 rigidly, close to the wheel axle, with its board flat and one edge facing straight forward.
What to do: Bolt the two TT motors to the bottom deck, wheels on the outside, axles in line. Stack a second deck above for the Nano, breadboard, and driver, and put the battery on the top deck.
Expected result: The robot stands (held) with its centre of mass well above the axle.
What to do: Wire the MPU6050 to the Nano: VCC → 5V, GND → GND, SDA → A4, SCL → A5.
Wire the L298N to the Nano: ENA → D3, IN1 → D4, IN2 → D8, IN3 → D5, IN4 → D7, ENB → D6. Connect OUT1/OUT2 → left motor and OUT3/OUT4 → right motor.
Power wiring: +12V → battery +, GND → battery − and Nano GND. Leave the L298N 5 V jumper on and feed its 5V pin to the Nano 5V pin.
Add the 220 µF capacitor across the Nano 5V and GND. Remove the ENA/ENB jumpers so the PWM pins control speed.
Expected result: Everything is powered from one battery through the driver regulator.
Goal: Read tilt angle, run a complementary filter, and drive the motors with PID at 200 Hz.
What to do: Upload with the motors disconnected from the wheels (or the robot held in the air). Lay it flat and still for the first second while the gyro calibrates, then pick it up and tilt it.
Expected result: The wheels spin in the direction the robot leans and speed up the further it leans.
If they spin the wrong way, swap both motors’ wires (or negate out ). If the wheels twitch or the angle wanders instead of tracking your tilt, the gyro sign is opposite to the accelerometer’s: change (gy - gyroOffset) to (gyroOffset - gy) .
What to do: Temporarily print angle to Serial. Hold the robot upright at the spot where it would balance on its own, where the weight feels neutral over the axle, and read the number.
Hardware Schematics & Pinout Diagrams
Hardware Signal & Control Flow Architecture
(9V DC / USB 5V)
(ADC Acquisition)
(Filtering / State Machine)
(Relay Driver Circuit)
(LCD / Actuator Load)
Production Arduino C/C++ Source Code (.ino)
[*] Initializing Hardware Core for Arduino Controlled Two Wheeled Self Balancing Robot Using Complementary Filtered Imu Telemetry... [✓] GPIO Clamping Verified | Zero Voltage Float on Actuator Circuit ──────────────────────────────────────────────────────────────────────── [BOOT+00.02s] ADC_INIT Calibrated zero-offset = 12 mV (Clean noise floor) [RUN +01.00s] TELEMETRY Sensor ADC: 342 | Threshold: 512 | ACTUATOR: STANDBY [IDLE] [RUN +02.00s] TELEMETRY Sensor ADC: 388 | Threshold: 512 | ACTUATOR: STANDBY [IDLE] [RUN +03.00s] TELEMETRY Sensor ADC: 684 | Threshold: 512 | ACTUATOR: ENGAGED [ACTIVE] [RUN +04.00s] INTERRUPT Optocoupler PC817 saturated | Actuator Active in 4.2 ms [RUN +05.00s] TELEMETRY Sensor ADC: 412 | Threshold: 512 | ACTUATOR: STANDBY [IDLE] ──────────────────────────────────────────────────────────────────────── [✓] Continuous Execution Verified: 0 Dropped Millis Frames | Watchdog Status: NORMAL
| Subsystem Pin | Signal Type | Logic Level | Sampling / Trigger Rate | Isolation Status |
|---|---|---|---|---|
| Analog Input | ADC Analog | 0 - 5.0V / 3.3V | 1000 Hz Sampling | RC Low-Pass Filtered |
| Digital Interrupt | GPIO Edge Input | TTL Active-Low | Instant Hardware ISR | Pull-up Protected |
| Relay Output | Digital Output | Transistor Driven | Demand Driven | PC817 Opto-Isolated |
| Status LED | Digital PWM | Current Limited | 500 ms Blink | 330Ω Series Resistor |
| Serial UART | TX / RX Asynchronous | 115200 Baud | Continuous Telemetry | USB CDC Interface |