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;
else
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;
else
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.

Thank you for this amazing tutorial, this will greatly help my university project!

i have searche dthe webs for periods of time reaching months for a basic introduction to the topic an yours was spot on.

thank you!!!

regards from denmark

Firstly I would like to thank you for this post.

I had a lot of doubts about PID control which got cleared.

Currently I am trying to build a robotic arm which consists of a base, two links and a gripper with low power servo motors

When I told my guide that  I am planning to use PID control and encoder for this he said that the link connected to base will have load of second link , gripper and the object which I am picking(200gm approx.). This would make that lower link unstable and it may even go down because of the load.

My question is that can this problem occur and if it does, wht can I do to avoid this. I am planning to use 12 V servo. 

Yup this definetely had to appear on the front page again! Thanks a lot, it's really an important reference for many people.

hi,

i hav gone through the code....i want to impliment the same for robotic arm or SCARA.

Actually i am not getting the concept of ''setpoint'' which is used in the programm.

how i will calculate this set point for the robotic arm assembly??

Also in the robotic arm assembly , i am using servo motor and response time of the system will be a concern for me.

So can you please give me some pointer for the same using the PID control???

thank you!!!

The setpoint is where you want the system to be.  The controller will try and maintain the system at this setpoint.  The actual value will be obtained from a sensor, such as a distance, speed or position and will be compared to the setpoint and the controller will try and get the two readings to match. For example, if you have feedback for a joint position from a potentiometer, the controller will move the joint to a position defined by the setpoint.  The setpoint isn't calculated as such, its a value given to the controller for it to try and maintain.

As far as response time goes, this will be defined by the values used for the gains in the controller.  Higher gains will give faster response time but may lead to instability, depending on the application, and may require trial and error to find a good combination of speed vs stability.

 

Hope this helps

I am designing a robot which has 2 motors with differential drive. The motors are 3V and are rated at 90rpm (no load) at this voltage. I have purchased a pair of wheel encoders for my motors. I want the motors to run at say 20 or 30rpm so i guess i will use pwm to slow them down. If the no-load speed is 90rpm, and i want to design a PID controller, wont the actual weight of the chassis + weight of the electronics affect the speed of the motor?

Now if this is so, then how would i go about implementing this PID controller since i would not know the actual speed it is travelling at. I am designing a robot which carries a cup of coffee on it, thus it needs to be move slowly enough to ensure that it does not spill the coffee. How to you determine the loaded speed of a motor by just some sort of inspection? Use the distance formula? I'm not sure if this would be accurate enough.

My initial idea was to assume it goes at 90rpm, use PWM and slow it down to say 30rpm (check experimentally if this speed is suitable - if not slow it down more). Once the acceptable speed is selected, then i will calculate the number of clicks/second of my encoders (using an encoder tool on http://www.societyofrobots.com/encoder_calculator.shtml) and use this as my setpoint/reference.

So when sampling my encoders i will sample them for one second, then use the PID algorithm above to correct the error and increase/decrease the speed.

My goal is to make the robot travel atleast 12m as "straight" as possible.

Any suggestions on this?

Best Regards, Yuveer

Yes, your motors will definitely run more slowly when loaded.

Your encoders will give you the speed that your motors are running at. As per your plan, you'll get a value for encoder counts per second (updated once per second), and from the mechanics of your encoder arrangement you can work out a constant value for your encoder counts per wheel revolution.
Motor speed in revolutions per second is then (counts per second) / (counts per revolution). You can always convert this into RPM, meters/second, radians/second, KPH... whatever is most convenient for you.

Whatever you do, make sure you convert your encoder feedback and setpoint speed so that they end up in the same units. Your error signal that feeds the PID loop will just be the difference between those two values. The output of the PID loop will be the value you use as your PWM duty %.

Most likely you'll have to determine your ideal setpoint speed and your PID factors by experiment.

This is by far the greatest article on PID control on the entire website. Well done!

I am fairly new to PID control and i would like to control my two dc motors just as you have done here.

My problem is that i dont know where to call the doPID() loop. I am unsure of how to adapt this into my code.

I have written a simple program where the user pushes a button and the robot travels forward for 5 seconds. Of course it tends to veer to the left/right, hence the need for the PID controller.

I have a wheel encoder which have 10 clicks on them. I calculated that i should require 12.1 clicks/second at the speed i want. Thus this would be my setpoint.

I am using mikroC Pro for AVR.

Thanks

Yuveer

From above: "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."

If you're grabbing the encoder values at a regular point in your code, you can call doPID() immediately after that.
Otherwise if your encoder values are updated by some sort of background task, then just make sure you call doPID() at regular intervals that are at least long enough apart for the encoder values to update.