I didn't just want to build someone else's project. I wanted to understand how it actually worked, and build my own robot using the components I had. I wanted to understand the theory and the code so I could design my own. So I started to dig deeper into one of the examples. I learned that the feedback from a tilt sensor is generally processed by a PID algorithm to control the power and direction of the motors to try and maintain an upright position for the robot. It all sounded simple in principle. Use a sensor to measure the angle of tilt, feed this value along with the desired angle of tilt into a PID controller library and apply the output to the motor drivers.
So what is PID?
Before you Google it and find the page on Pelvic Inflamatory Disease, we are talking about a PID Controller, or Proportional Integral Derivative controller. You might find the Wikipedia page of interest. There is a PID controller library available for Arduino, and the author Brett Beauregard has written a series of very detailed blog articles about the theory. Here I will just talk about the usage of his library for a balance bot. In simple terms, you keep reading the angle of tilt between your robot and the force of gravity. On each loop through your code you feed in this measured angle, and the PID Controller calculates a power value to apply to the motors to bring this angle closer to the desired angle. For a stationary balancing robot, we want the robot to be upright and the motors off. If the robot is starting to topple over then the angle moves away from this desired upright angle and power is applied to the motors to restore balance. The greater the difference between the actual measured angle and the desired 'upright' angle, the more power is needed to allow the motors to restore balance. But too much power and the robot is tilted over the other way. So the PID controller constantly needs updating with the current tilt, and needs to apply a new correction to the motors.The PID Controller also takes 3 input values which control the output for different changes in input over time, and these need to be tuned to make a stable robot. These tuning constants are referred to as Kp, Ki, and Kd. I was pointed to this video which demonstrates the effects of different values for these constants.
A Self Balancing Robot Development Board
To prototype and build a proof of concept you don't need a bunch of fancy machinery and a workshop. I started with a sheet of plywood from my local DIY store, a hand saw and the patio table in the garden as a workbench (so I didn't need to sweep up my mess!).In my parts boxes, I already had the following:
- An Arduino UNO.
- A pair of Adafruit motor driver breakout boards.
- A set of PiBorg motors and wheels.
- A Sparkfun 9dof IMU breakout board
I had no idea what sort of motors I needed so I took the approach of just trying out what I had to hand first, before going out and buying something I possibly didn't need. Here is what I built.
I simply cut a rectangle of plywood, and bolted everything on. I used cable ties to hold the batteries in place. The physical build did not take long at all. You can use any motor driver boards which can handle the stall current of your motors (this is now much current the motors will draw if they are powered but are prevented from turning). I used the example code from the IMU board I had to read the angle of tilt from vertical using the accelerometers. In my case, the angle was 180 degrees when the robot was balancing upright. Using this information I just needed to use the PID library to calculate the motor power needed to maintain balance, in a loop so it constantly updates based on any change in the tilt value. I am not going to give the full code here, but instead try to explain the principles I was using. We'll look at some actual fully working code in a follow up post.
The PID Controller takes the following inputs:
PID pid(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);
The variable names with & in front indicate these are pointers to the variables in my Arduino program. So any changes made to their values anywhere in my program will be available to the PID controller code. I wanted my robot to maintain a tilt of 180 degrees, so my setpoint value was 180. Kp, Ki and Kd are the tuning constants I needed to set to appropriate values for my robot. Input is the value of tilt I was reading from my accelerometer, and output is the power and direction I needed to run my motors. The PID library needs to know the range of values I want my output to range between, so I also had to setup the PID controller with this information:
pid.SetOutputLimits(-100, 100);
So now the PID controller knows my motor output values need to be in the range -100 (full power reverse) and +100 (full power forwards). In the main program loop, I now just needed to read the tilt from the IMU, run the PID Controller calculation, and apply the output power to my motors. Or so I thought. It turns out there are a number of complications I had not taken into account (and which the example project I was trying to follow did not use). What actually happened when I turned it on was that my robot just vibrated very loudly and fell over. Then once it hit the floor it shot off across the room with the top of the board scraping along the floor!
It turned out that the motors were put into full power forwards, which generated a shock to the IMU making the accelerometer read a very high value. This cause the PID controller to put the motors into full reverse, causing an opposite direction shock to the board. This repeated on every iteration of the loop. So the motors alternated between fast forward and fast reverse. The whole thing was shaking, causing the buzzing sound and the tilt values being calculated were not related to the angle of tilt of my robot at all, but to how hard it was being shaken by the motors.
At the time I did not understand what was wrong, so I posted my failure on Twitter:
Finished my first #PiWars hardware test platform and wrote Arduino code for balancing. It completely fails to work! Vibrations from the powerful motors changing direction shakes the accelerometer so much it cannot provide useful angle of tilt data. It just shakes violently. pic.twitter.com/4WL7ZynsL8— Dr Footleg (@drfootleg) August 12, 2018
Pretty quickly got some great pointers to more information. Clearly I had more reading to do. In my next blog post I will explain how these problems in my initial design were solved.