Let's Make Robots!

PID Control

Thought I would edit this and put it back on the front page. There seems to be quite a lot of PID talk at the moment, may be helpful to someone.

I have built several robots which were capable of avoiding obstacles and driving around without bumping into anything. For a university project i wanted to make a robot that could build some kind of map of it environment. During this project i found i needed better control of my robot, to allow it to drive in a straight line and follow walls. So i started experimenting with PID control. I thought i would write a walkthrough to share what i have achieved.

Before using PID control i was simply telling the robots wheels to drive at a certain speed, set by a PWM output. I was then assuming that the robot wheels would turn at the same speed and the robot would travel in a straight line. This is known as open loop control. This means that you send an output to the motors with no feedback and assume they travel at the speed you set. It is very unlikely that two motors, even two identical motors will turn at the same speed. So some sort of feedback is required to control the speed. This is normally achieved using an encoder. When the speed of the motor is controlled using feedback it is known as closed loop control.


I have implemented PID control to control both wheels of my robot, meaning the wheels turn at the same speed and the robot can travel in a straight line. I have also used it to allow my robot to follow walls. In this case the feedback is not from the encoders on the motors but from a sensor looking at the wall being followed. The idea behind PID control is that you set a value that you want maintained, either a speed of a motor of a reading from a sensor. You then take readings from the encoder or the sensor and compare them to the setpoint. From this an error value can be calculated, i.e, (error = setpoint - actual reading). This error value is then used to calculate how much to alter the motor speed by to make the actual reading closer to the setpoint.

The maths behind PID control can be pretty heavy. However, the process can be simplified greatly if the frequency at which you sample the encoders or the sensor is fixed. This is an important point and one that i wish someone had told me when i started experimenting. I will now attempt to explain how i implemented PID control, its quite a tricky thing to explain so i will do my best and if anyone has any tips on how the explanation can be improved, let me know and ill try again.


Ill use an example of controlling one motor with encoder feedback to try and explain how ive implemented PID control. I use an ATMEGA32 on my robot, using 8bit PWM to drive a motor with an encoder that sends a series of pulses as the motor turns. These pulses are counted by the microcontroller. I use an internal interrupt that triggers when to sample the encoder. I use a sampling time of around 1/10th of a second. So i am taking a reading from the encoder 10 times a second, comparing the reading to the setpoint to give me an error value, and using this to calculate how much to alter the motor speed by.

So what do you do with the error value to calculate how much to change the motor speed by? i hear you ask. The simplest method is to simply add the error value to the PWM output to change the motor speed. And this would work, and is known as proportional control (the P in PID). It is often necessary to scale the error value before adding it to the output by using a gain contant. For example. Say the PWM output to the motor is 200, you have chosen a setpoint of 10. You are therefore expecting that when you sample the encoder it should have sent 10 pulses to the microcontroller since last time you sampled it. If the has only sent 6 pulses the motor is going to slow. The error (the difference between the actual reading and the setpoint) is therefore 4. You could add this value straight to the PWM output (200+4=204), which would speed up the motor. It may take many samples before the motor speed matched the setpoint, so it may be necessary to scale the error value, by multiplying it by 2 for example. This would improve the response time. As an equation this would look something like this:

c = E*Kp

where c is the value to be added to the PWM output, E is the error value and Kp is the gain constant. You only ever have to add c to the PWM output as if the motor was going to fast, the error value would be negative, and therefore c would also be negative.



AS i mentioned this approach would work, but you may find that if you want a quick response time, by using a large gain constant, or the error is very large, the motor speed will go much higher than the setpoint, known as overshoot. The motor speed may then go much lower than the setpoint, then higher again and so on. When this approach is used on a robot, the robot tends to oscillate in a jerky manner. This is when the D bit of the PID comes into play. D stands for Derivative. It is used to look at the rate of change of the error, i.e is the error changing quickly of slowly. Another error value is calculate which i call Ed, which is the difference between the previous error and the current error (Ed = E - Eprev). This gives a value that is larger if the error is changing quicky and a smaller value if the error is changing slowly. If this is used as well as the proportial control it is known as PD control, and an equation like this can be used:

c = (E*Kp)+(Ed*Kd)

where c, E and Kp are the same as before, Ed is calculated as shown above and Kd is the derivative gain constant.



The I bit of PID refers to Integral control. I have found that generally PD control is sufficient for controlling motor speeds and gives a good performance. The integral control improves steady state perfomance, that is when the motor speed has settled to a fairly consistant speed, how far away from the setpoint is it running. By adding together all prevoius errors it is possible to monitor if there are accumulating errors. As if the motor is turning stightly too fast all the time, the error will always be positive so the sum of the errors will get bigger, the inverse is true if the motor is always going to slowly. An addition error value, which i call Ei is simply the sum of all previous error. This can be added into the equation, again with a gain contant to give the full PID equation:

c = (E*Kp)+(Ed*Kd)+(Ei*Ki)

The values of the K gain contants affect how much of each error are used to alter the motor speed. Their values are usually found by trial and error. To give an example the picture i have used for this walkthrough is a graph of actual encoder values taken from my robot when it is moving, with a setpoint of 10, You can see that the readings increase above 10, oscillate around 10, before settling to around 10. This is a common PID control loop response. I used settings of:

Kp = 1
Kd = 0.5
Ki = 0.3

I hope this is helpful, as i said it is quite a tricky thing to explain and im not sure i have done a very good job, please ask if there is something i have not explained very well and i will try and improve it.

The example i have given using a motor and an encoder is just one application. If using a sensor to follow a wall the error value can be calculated from the sensor reading compared to a setpoint. I have done this using my two wheeled robot and just altered the speed of one wheel while the other ran at a set speed. It worked very well using just PD control. To make my two wheeled robot go in a straight line is had to alter the speed of both wheels. To do this i sampled the left and right encoders, and found an error value for each. I then put these values into the PID equation and found a value to add to each motor.

Below is the code i have used to control two motors on my robot. the doPID loop is called everytime the encoders are sampled and the motor speeds altered.



int preverrorl; //left motor previous error
int preverrorr; //right motor previous error
int Ierrorl=0; //left motor intergral error
int Ierrorr=0; //right motor intergral error
int encodercountl = 0;
int encodercountr = 0;
int setpoint = 20; //setpoint

void doPID(void)
int errorl; //error from left encoder
int errorr; //error from right encoder
int derrorl; //derivative error left
int derrorr; //derivative error right
int cl;
int cr;
int KP = 2; //PID proportional gain constant
float KD = 1; //PID derivative gain constant
float KI = 0.5; //PID intergral gain constant

errorl = setpoint - encodercountl; //calculate error values
errorr = setpoint - encodercountr;

encodercountl = 0; //reset encoder counts ready for next sample
encodercountr = 0;

derrorl = (errorl - preverrorl);
derrorr = (errorr - preverrorr);

cl = ((KP*errorl) + (KD*derrorl) + (KI*Ierrorl)); //PID equations
cr = ((KP*errorr) + (KD*derrorr) + (KI*Ierrorr));

if((OCR0 + cl) > 255) //prevent OCR0 and OCR2 from overrunning 255
OCR0 = 255;
OCR0 = OCR0 + cl; //use output from PID equations to alter motor speeds
if((OCR2 + cr) > 255) //where OCR0 and OCR2 are PWM output values
OCR2 = 255;
OCR2 = OCR2 + cr;

preverrorl = errorl; //set previous error to current error
preverrorr = errorr;

Ierrorl = Ierrorl + errorl; //add current error to integral error
Ierrorr = Ierrorr + errorr;



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Great walkthrough!!! Although i dont know how i would implement this, this would be a awsome future reference for when i get to a stage on where i can make a robot that can use this.. Everything was described perfectly!!





 Wow, thank you so much for this post. I am working on an encoder as we speak. The encoder works well although I am having some code issues. I am sure a lot of the info in this post will be of great help to me! Again, thanks bunches. 

My encoder...


www.rocketbrandcustom.com baby!!

This is an excellent, well writeen, idiot-resistant article.

Closed loop control and integration of inputs are one focus of my job (I design closed loop control rigs which pretend to be aircraft jet engines, so that jet engine embedded control software can be tested). This was on my list of things to write and I'afraid my version would have been a lot more technical. People probably wouldn't have bothered reading it. This article is the right length, explains the terminology and does everything from first principles.

Well done.

Nice! I have taken a note of this, and am going to read it VERy carfully as soon as I get the time. Looking forward, may base new project on it etc :) Thanks!
Tellin' you.

I have also used PD-regulation for a line follower, where the error measured was how far the robot center was from the line. This worked quite nicely. Hoorray for PID (or just PD)!

I think that whenever you can measure the error directly from sensors (like when you want to keep a certain distance to a wall) you only need PD-regulation. PID is only necessary when you cannot measure the error directly. For example when a robot is supposed to go in a straight line, it can't measure directly if it's going in a straight line. It can only measure if the wheels are rotating at the same speed. Is this correct?

The Integral part of PID helps reduce steady state error.  I think that generally this is not too much of a problem if you are following a wall say, as you may be a couple of mm closer or further from the wall than expected, which you probably wouldnt notice and PD would do. When trying to go in a straight line you are still measuring the error directly but with respect to each wheel.  In this case steady state error may be more of an issue, especially if travelling a long distance.  Any steady state error on each wheel will eventually make the robots path curve slightly.

An obscure example of "I" might be direct measurement of acceleration such as by an acceleromter, but your actual error is speed. You need to integrate to obtain the speed. Hmmm... Not sure why you'd use an acceleromter to measure speed. Thinking outside the box, it may be the case that your robot is stuck in mud so the wheels are spinning like mad but it's not going anywhere.

So, you're kind of right in one sphere of thinking, but there's no rule.

First of all, great walkthru. 

Second, hello to all, I'm a newcomer :)

Now, for what I wanted to say...

Software PID regulation tends to be rather heavy and wasteful on processor and memory. As you probably already know, you can also implement P, I, and D with analog circuits, which bypasses your microcontroller entirely. thus leaving you with enough processor power to do other stuff (like driving around shooting people). In my school we made these ourselves, as an exercise (both the passive and active versions), but there are circuits with built-in PID regulation which you can buy.

Analog PID also tends to be much more precice (at least in my expirience, not that I have much of it, anyway),

Just a suggestion. of course :)

Do you feel a "hints & tips" page coming on?