A PID Controller is a software algorithm typically used to control industrial processes. A PID Controller (Proportional Integral Derivative Controller) calculates the difference between a measured variable and a desired set point. The controller attempts to minimize the error by adjusting the input.

A good example of why a PID Controller is better than other methods of control, is an electric oven. The input is the power to the heating element, the output is the temperature and the set point is the desired temperature.

Without a PID controller, If you turn the power on and off using a simple thermostat, when the temperature of the oven reaches the set point the oven will over shoot the temperature as there is residual heat left in the heating element. If you want the temperature of the oven to be 200 degrees, and have the element fully on until it reaches 200 degrees, then turn it fully off, the temperature will overshoot to maybe 205 degrees, then slowly cool until it reached 199 degrees when it will turn fully on again, however it will take time to heat up, in which time the oven has cooled to 195 degrees, and so it repeats. The oven will oscillate between 195 and 205 degrees, and not actually be a steady 200. This is fine for cooking sausages, but no good for a delicate chemical process.

The PID Controller has three values; the Proportional, the Integral and the Derivative values, denoted P, I, and D. Heuristically, these values can be interpreted in terms of time: P depends on the present error, I depends on the accumulation of past errors, and D is a prediction of future errors, based on current rate of change. By combining the three terms continuously the algorithm maintains the desired set point with minimal errors.

Simple huh ? Well kind of… The maths is a bit complex, but again, there are existing libraries that do it for you. On the Arduino site you can download a fully working PID Controller library, to integrate in to your project : http://playground.arduino.cc/Code/PIDLibrary

The only problem is you need to “tune” a PID Controller to your specific application. The P, I & D terms will be different for an oven, chemical tank, or balancing robot. There are lots of ways of tuning a PID Controller, from mathematical, to trial and error. A control systems friend of mine recommended I try the Ziegler–Nichols method.

The Ziegler–Nichols tuning method is as follows;

- The P, I & D terms are referred to as “gains” Kp, Ki & Kd.
- The Ki and Kd terms are first set to zero.
- The Kp term is manually increased until the robot reaches the ultimate gain, Ku, at which point the it starts to oscillate.
- The oscillation period Pu is measured and used to set the PID terms as follows :
- Kp = 0.6 * Ku
- Ki = (2 * Kp) / Pu
- Kd = (Kp * Pu) / 8

This isn’t perfectly tuned to our specific system, but it’s a good approximation. PID tuning is a black art that requires a lot of knowledge and skill. This will do for the time being.

I am using the tilt angle of the robot as the input and the speed of the motors as the output.

The code is quite simple. The three variables are all floating point numbers.

double Setpoint, Input, Output;

The PID object is instantiated with the three PID values I calculated from my Ziegler–Nichols tuning method

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

The desired set point is 0 degrees, i.e. the robot is perfectly upright

Setpoint = 0;

Then in my main loop I get the angle of the robot, run the PID compute function, and using the output set the motor speeds.

void loop() { my3IMU.getYawPitchRoll(ypr); Input = ypr[IMU_ROLL]; myPID.Compute(); md.setSpeeds(Output, Output); }

That’s the theory anyway … the results were mixed. It took a number of attempts to find the oscillation gain and period (Ku & Pu) accurately. And with those values, the PID controller wouldn’t balance the robot. It took lots of manually trial and error of various values to find something that was stable. PID tuning is very much a black art.

I did get it to balance though and it was more stable that the equivalent “cubed” algorithm I was using. However with the IMU code and the PID code on the Arduino, I started getting problems with the Arduino crashing. I can only assume it was running out of RAM.

I switched to an Arduino Mega and everything worked fine. So I’ve stuck with that for the time being. The Mega is much more stable, however the custom PCBs I made don’t fit the Mega, so the wiring is messy, plus the Mega sticks out of the frame. Next job is to make the PCB as a Mega Shield and turn the board round long ways so it fits better.

The PID controller is still not perfect, but it’s relatively stable. You can see it recovers from oscillation, which the basic controller didn’t. But It still drifts badly, and still falls over eventually. But progress none the less.I need to get the Quadrature decoders working so I can stop the drifting.

Here’s a short video of the PID Controlled BalanaceBot in action.

Prerna ChikersalHi! I am trying to tune a PID controller. In this post, how do you know when Kp has reached its critical gain and how do you measure the oscillation period? Thanks for your help! 🙂 Cheers!

mostlyrobots2012Post authorYou turn up Kp slowly until the system oscillates. It was pretty obvious when this happens, my bot became unstable pretty quickly, and oscillated from side to side. I then supported it with my fingers lightly, to allow it to oscillate without falling over, and counted the time it took for 10 oscillations, then divided by 10.

Huycould you tell me what angle that it start to oscillate about 6 or more?

mostlyrobots2012Post authorFrom my observations, the bot is stable if the angle is less than 5 degrees. If it exceeds this angle, the response seems to overshoot and then it either falls, or oscillates.

Huyyour bot is drift, Can u make it stand ?

sejalCan you help me write a code for Pid controller in frdm46z?

mostlyrobots2012Post authorHi. I used an existing PID library from here http://playground.arduino.cc/Code/PIDLibrary . It will compile fine on mBed with a simple change. The only change I had to make was to replace all the calls to millis() with an mBed equivalent timer t. Where it calls millis(), replace it with t.read_ms() and t.reset(). It worked fine for me. I hope this helps.

sejalohh That was so sweet of you sir..thank you..!!!

Neliushave you tried controlling the sine of the tilt instead of tilt angle? Gravity only acts on the sine of tilt angle and likewise the controller should only counteract the sine of the tilt angle. There will be a very small difference in the proportional part of the controller, especially at small angles such as <6, but potentially a larger difference could show up in the integral and derivative?? Maybe something that the matlab boffins could model? I have not built any controller but am planning to build a temperature controller. Found yours interesting.