Mechatronics Exercises

Workspace Navigation

Awesome self-balancing robot



Alex Suomala

Markus Nevalainen


The goal of the project is to make a remote-controlled two-wheeled robot, that smoothly and accurately balances on two wheels and may be controlled from a smart phone over bluetooth so that it acts like any other RC-car. The concept is nothing new, and plenty of similar projects can be found in the internet. This kind of project is quite simple in the algorithm level, but still very good exercise in control systems and tuning a controller in practice, as it uses a simple PID-controller to balance itself. To reach the goal we have to make the robot to 

  1. balance itself
  2. balance itself and maintain its position
  3. move as the user wants (by commands over bluetooth)

These goals need to be reached in this order to successfully make the robot work. Let’s look at those steps a bit more closely.


1) Balancing the robot (making the robot to maintain its upright position)

This is the very core of the problem, and it’s called the problem of inverted pendulum (see Wikipedia). Inverted pendulum is a classic problem in dynamics and control theory and used as a benchmark for testing control systems. The algorithm for balancing the robot is very simple: We get the angle of the robot from the gyroscope and enter the error between the measured angle and the setpoint (the angle of the upright position) to a PID-controller. Then the PID-controller calculates the needed speed (and direction) for the motors to move the pivot point of the pendulum. The motors turn as the PID calculated and the robot maintains its balance in upright position. However, even though the robot stays upright, it still wanders around. Let’s then look at how to prevent that.


2) Making the robot to maintain its position

So, now we have our robot balanced, using the angle data from the gyro and a PID-controller. To make the robot stay in place, we first have to know the its position or, like in this case, the distance it has travelled. To get the data needed, we chose motors that have also rotary encoders. From the encoders we get the angular position data (from both motors separately) and from that we can calculate the distance robot has travelled, which we call the position error. To get the robot to stay in place we will have another PID-controller that takes in the position error and by that it controls the angular setpoint  (which previously has always been zero i.e. vertical) to move the robot back to its original position.


3)  Making the robot remote-controllable via Bluetooth

To move the robot back and forth, we will need yet another PID-controller to control the speed of the robot. We get the speed desired by the user from the serial Bluetooth signal and use it as a setpoint for the PID-controller. As the error input for the PID we use the measured speed of the robot that is calculated from the encoder data. The output of the controller i.e. the variable it controls will be the angular setpoint of the first PID that is used to balance the robot (similarly as in the previous step when keeping the robot in place). Whenever the robot is controlled by the user, the controller (step 2) that keeps the robot in place, has to be “turned off”. That may be done by setting the setpoint of the position-PID zero whenever the robot receives commands via Bluetooth. This means that the robot will re-position itself only when it’s not driven by the user.

Now we can drive the robot back and forth, but we still need to be able to turn. In this point, that would be fairly easy. Since the robot has only two wheels, the turning has to be nothing but an offset between the speeds of the motors. So in the code, the offset for turning is the last thing to add before sending the pwm-signal to motors. We simply just get the data from the serial Bluetooth signal and add the value to one of the motor speeds and subtract it from the another.



UNO R3 Development board17,75€
DC Motor with encoder, mounting bracket and wheel226,96€
MPU6050 3-Axis acceleration gyro12,66€
L298N Stepper motor driver13,32€
JY-MCU Bluetooth serial port module15,25€
Panasonic NCR18650B Li-ion battery219,90€
2-Slot 18650 battery holder12,35€


Total price: 68,19€



We rendered a design on Solid Edge.

We wanted the center of mass to be high so the balancing would be easier because of the bigger moment of inertia. To understand the principle, think about balancing a pencil on your finger compared to balancing a one meter pole. To get the center of mass high we placed the batteries on top of the robot. We also wanted to place the inertia measurement unit as close to the axis of the motors as possible, so the data would have minimal errors. To get the best data, we placed the inertia measurement unit on the bottom of the robot. All the other components were placed so that wiring would be as easy as possible.

Making of

  1. Cut the acrylic sheet into three pieces and four M5 threaded rods for bolting the acrylic sheets into a frame of the robot
  2. Drilled four holes into acrylic sheets and assembled them with the rods and nuts
  3. Drilled holes for the motor mountings and other electronics and bolted them on
  4. Did a ton of wiring for all of the electronics
  5. Did some coding and testing
  6. And some more coding and testing



The code itself can be found here.

As the MPU6050 IMU chip uses I2C bus to communicate with arduino, which neither of us was really familiar with, it was a big help for us to use some libraries found in the internet. The communication with the MPU6050, reading the raw data and especially processing it to get some useful motion sensor data, was not only the most difficult and time-consuming part of the coding, but also one of the most crucial part for the robot to work properly. 

The code uses I2Cdev and MPU6050 libraries, that can be found here (external link), to read the data from gyro and process it. To calibrate the system we also used a special calibration sketch for the library, that can be found here (external link).  Also, a great help was youtube with many and many tutorials to understand the I2C bus, the MPU6050 chip, inertial measurement units in general, and the use of the libraries. With these we finally managed to get very good data out of the gyro, that we could really use. From the movement data we used only one rotational axis data that is called pitch angle in the code. It is the angle around the axis of the motors i.e. the angle that of the robot, and when the pitch angle is zero the robot stands upright.

In the code, there are a lot of varables and some lines of codes that are really not in use (yet), since the movement of the robot is not controllable. These features mostly deal with movement variables such as offset values for turning, or movement data from the encoders.


What could the final robot do?

  • balance itself, although quite unsteadily
  • send data, e.g. about its movement (gyro data) and battery voltage, via bluetooth so the robot could be monitored on a computer screen wirelessly during testing and tuning
  • receive new set of PID-controller parameters (Kp, Ki, Kd) via bluetooth so the robot could be tuned wirelessly
  • measure the voltage level of the battery pack and compesate the voltage change so that the motors (and the balance controlling system) would work similarly regardless of the dropped battery voltage after time, as long as the battery level stays within the set limits 




Connection over bluetooth

Screenshots of a serial bluetooth terminal on an android smartphone, about monitoring and tuning the robot.


Robot just powered on or reseted. At the start, the robot initializes itself and shows the current tuning parameter values. There is a 1,5 seconds delay here, so the user has time to see the values before the scripts starts running.
Script running and robot balancing itself. The robot constantly sends the pitch angle, the battery voltage level and the output value of the PID controller to the serial bluetooth. Here, the battery voltage is just over 8 volts ("full voltage") so the arduino it sees it to be 8,0 V. The voltage measurement would still need some improvements.
New tuning parameter values for the controller can be set wirelessly over bluetooth by typing the new values in correct order. For instance here, sending the line "15 7 0" means setting the values Kp=15, Ki=7, Kd=0. 
When the robot receives new values, it stops running the code and stops its motors, and sends a confirmation of receiving the new values to the user via bluetooth. After a delay of three seconds (for user to have time to see the confirmation) the robot starts to run again, but now with the new tuning values. This feature made the tuning of the robot way faster, since we didn't need it to be connected with cables at all when testing and tuning.

Problems and how to solve them

We had a lot of problems with tuning the PID-controller, and so we didn't really get the robot stable. The best we got was just some tens of seconds that the robot could maintain its balance for before falling over, and the behaviour could be described anything but steady. There was a lot of oscillation and all the time the robot was wandering around pretty unpredictably. 

What we think was the biggest problem, is that we controlled the movement of the motors just by the pwm-signal that we sent to them. That means that basically we assumed that both of the motors behave exactly the same, and that the angular velocity of a motor is linearly dependent to the voltage. Neither of those assumptions seem to bo even close to the truth. It can be clearly seen that, for instance, the lowest voltage i.e. the smallest angle where the motors start, varies not just between the two motors but also when focusing on just one motor for some time. Therefore, the best place of improvement have been coding some kind of a speed controller circuit for the motors, so we could try to balance the robot not only by just controlling the pwm-signal to the motors, but the actual speed of the motors.

Since the balancing itself ("the first goal"), which obviously is the most crucial, was not really reached properly, we couldn't really try if we could've get it somehow remote-controllable. However, we think that at least in theory the remote-controllability could have been a fairly easy part, if we just had got the robot to steadily stay upright.

After all, in this project it is all about balancing the robot and especially adjusting the controller system, for which this kind of project is a great excercise.


  • No labels
  File Modified
Text File balancebot_code.txt Jun 18, 2017 by Markus Nevalainen
PNG File kytkennat.png Jun 03, 2017 by Markus Nevalainen
PNG File osat_wiki.png Apr 12, 2017 by Markus Nevalainen
JPEG File photo5992085093319026677.jpg May 08, 2017 by Alex Suomala
JPEG File robo.jpg Jul 01, 2017 by Markus Nevalainen
PNG File Screenshot1.png Jul 01, 2017 by Markus Nevalainen
PNG File Screenshot2.png Jul 01, 2017 by Markus Nevalainen
PNG File Screenshot3.png Jul 01, 2017 by Markus Nevalainen
PNG File wiring.png Jun 20, 2017 by Markus Nevalainen