Awesome self-balancing robot
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
- balance itself
- balance itself and maintain its position
- 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.
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.
- Cut the acrylic sheet into three pieces and four M5 threaded rods for bolting the acrylic sheets into a frame of the robot
- Drilled four holes into acrylic sheets and assembled them with the rods and nuts
- Drilled holes for the motor mountings and other electronics and bolted them on
- Did a ton of wiring for all of the electronics
- Did some coding and testing
- 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.
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.