PID without a PhD
Editor's Note: Tim Wescott's "PID without a PhD" was originally published Embedded Systems Programming in October 2000. The article became a huge hit over the years and was "repurposed" by other sites, such as EE Times India, and linked to by many sites, such as Wikipedia. We knew this was a popular article and it remained so up until it became unavailable when we redesigned our site in July 2010. The staff at Embedded.com is working diligently to restore all our old content and make never-before-posted content available soon.
Here is the full original PDF of the article "PID without a PhD."
Note: This article PDF is under copyright to Embedded Systems Design magazine and may not be reposted elsewhere without permission. The original article text is owned by Tim Wescott and may not be used without permission of the author. Please link to the article, instead.
Below is the HTML version of the article.
Contact us for further information or requests:
Managing Editor, ESD magazine
PID Without a PhD
PID (proportional, integral, derivative) control is not as complicated as it sounds. Follow these simple implementation steps for quick results.
At work, I am one of three designated "servo guys," and the only one who implements control loops in software. As a result, I often have occasion to design digital control loops for various projects. I have found that while there certainly are control problems that require all the expertise I can bring to bear, a great number of control problems can be solved with simple controllers, without resorting to any control theory at all. This article will tell you how to implement and tune a simple controller without getting into heavy mathematics and without requiring you to learn any control theory. The technique used to tune the controller is a tried and true method that can be applied to almost any control problem with success.
PID stands for "proportional, integral, derivative." These three terms describe the basic elements of a PID controller. Each of these elements performs a different task and has a different effect on the functioning of a system.
In a typical PID controller these elements are driven by a combination of the system command and the feedback signal from the object that is being controlled (usually referred to as the "plant"). Their outputs are added together to form the system output.
Figure 1 shows a block diagram of a basic PID controller. In this case the derivative element is being driven only from plant feedback. The plant feedback is subtracted from the command signal to generate an error. This error signal drives the proportional and integral elements. The resulting signals are added together and used to drive the plant. I haven't described what these elements do yet-we'll get to that later. I've included an alternate placement for the proportional element (dotted lines)-this can be a better location for the proportional element, depending on how you want the system to respond to commands.
Each of these systems has different characteristics and each one requires a different control strategy to get the best performance.
Motor and gear
A DC motor driven by a voltage wants to go at a constant speed that is proportional to the applied voltage. Usually the motor armature has some resistance that limits its ability to accelerate, so the motor will have some delay between the change in input voltage and the resulting change in speed. The gear train takes the movement of the motor and multiplies it by a constant. Finally, the potentiometer measures the position of the output shaft.
Figure 3 shows the step response of the motor and gear combination. I'm using a time constant value of t0 = 0.2s. The step response of a system is just the behavior of the output in response to an input that goes from zero to some constant value at time t = 0. Since we're dealing with fairly generic examples here I've shown the step response as a fraction of full scale, so it goes to 1. Figure 3 shows the step input and the motor response. The response of the motor starts out slowly due to the time constant, but once that is out of the way the motor position ramps at a constant velocity.
You might expect to see this sort of mechanism stabilizing an element of an optical system, or locating some other piece of equipment or sensor. Figure 4 shows such a system. Software commands the current in the coil. This current sets up a magnetic field that exerts a force on the magnet. The magnet is attached to the stage, which moves with an acceleration proportional to the coil current. Finally, the stage position is monitored by a non-contact position transducer.
With this arrangement, the force on the magnet is independent of the stage motion. Fortunately this isolates the stage from external effects. Unfortunately the resulting system is very "slippery," and can be a challenge to control. In addition, the electrical requirements to build a good current-output amplifier and non-contact transducer interface can be challenging. You can expect that if you are doing a project like this you are a member of a fairly talented team (or you're working on a short-lived project).
The equations of motion for this system are fairly simple. The force on the stage is proportional to the drive command alone, so the acceleration of the system is exactly proportional to the drive. The step response of this system by itself is a parabola, as shown in Figure 5. As we will see later this makes the control problem more challenging because of the sluggishness with which the stage starts moving, and its enthusiasm to keep moving once it gets going.
Thermal systems tend to have very complex responses. I'm going to ignore quite a bit of detail and give a very approximate model. Unless your performance requirements are severe, an accurate model isn't necessary.
Figure 7 shows the step response of the system to a change in Vd. I've used time constants of t1 = 0.1s and t2 = 0.3s. The response tends to settle out to a constant temperature for a given drive, but it can take a great deal of time doing it. Also, without lots of insulation, thermal systems tend to be very sensitive to outside effects. This effect is not shown in the figure, but we'll be investigating it later in the article.
I'm going to assume a function call as shown below. As the discussion evolves, you'll see how the data structure and the internals of the function shapes up.
double UpdatePID(SPid * pid,
The reason I pass the error to the PID update routine instead of passing the command is that sometimes you want to play tricks with the error. Leaving out the error calculation in the main code makes the application of the PID more universal. This function will get used like this:
Figure 8 shows what happens when you add proportional feedback to the motor and gear system. For small gains (kp = 1) the motor goes to the correct target, but it does so quite slowly. Increasing the gain (kp = 2) speeds up the response to a point. Beyond that point (kp = 5, kp = 10) the motor starts out faster, but it overshoots the target. In the end the system doesn't settle out any quicker than it would have with lower gain, but there is more overshoot. If we kept increasing the gain we would eventually reach a point where the system just oscillated around the target and never settled out-the system would be unstable.
The motor and gear start to overshoot with high gains because of the delay in the motor response. If you look back at Figure 2, you can see that the motor position doesn't start ramping up immediately. This delay, plus high feedback gain, is what causes the overshoot seen in Figure 8. Figure 9 shows the response of the precision actuator with proportional feedback only. Proportional control alone obviously doesn't help this system. There is so much delay in the plant that no matter how low the gain is, the system will oscillate. As the gain is increased, the frequency of the output will increase but the system just won't settle.
Figure 10 shows what happens when you use pure proportional feedback with the temperature controller. I'm showing the system response with a disturbance due to a change in ambient temperature at t = 2s. Even without the disturbance you can see that proportional control doesn't get the temperature to the desired setting. Increasing the gain helps, but even with kp = 10 the output is still below target, and you are starting to see a strong overshoot that continues to travel back and forth (this is called ringing).
As the previous examples show, a proportional controller alone can be useful for some things, but it doesn't always help. Plants that have too much delay, like the precision actuator, can't be stabilized with proportional control. Some plants, like the temperature controller, cannot be brought to the desired set point. Plants like the motor and gear combination may work, but they may need to be driven faster than is possible with proportional control alone. To solve these control problems you need to add integral or differential control or both.
The code to implement an integrator is shown below. The integrator state, iState is the sum of all the preceding inputs. The parameters iMin and iMax are the minimum and maximum allowable integrator state values.
Integral control by itself usually decreases stability, or destroys it altogether. Figure 11 shows the motor and gear with pure integral control (pGain = 0). The system doesn't settle. Like the precision actuator with proportional control, the motor and gear system with integral control alone will oscillate with bigger and bigger swings until something hits a limit. (Hopefully the limit isn't breakable.)
Figure 12 shows the temperature control system with pure integral control. This system takes a lot longer to settle out than the same plant with proportional control (see Figure 10), but notice that when it does settle out, it settles out to the target value-even with the disturbance added in. If your problem at hand doesn't require fast settling, this might be a workable system.
Figure 12 shows why we use an integral term. The integrator state "remembers" all that has gone on before, which is what allows the controller to cancel out any long term errors in the output. This same memory also contributes to instability-the controller is always responding too late, after the plant has gotten up speed. To stabilize the two previous systems, you need a little bit of their present value, which you get from a proportional term.
Figure 13 shows the motor and gear with proportional and integral (PI) control. Compare this with Figures 8 and 11. The position takes longer to settle out than the system with pure proportional control, but it will not settle to the wrong spot.
Figure 14 shows what happens when you use PI control on the heater system. The heater still settles out to the exact target temperature, as with pure integral control (see Figure 12), but with PI control, it settles out two to three times faster. This figure shows operation pretty close to the limit of the speed attainable using PI control with this plant.
Before we leave the discussion of integrators, there are two more things I need to point out. First, since you are adding up the error over time, the sampling time that you are running becomes important. Second, you need to pay attention to the range of your integrator to avoid windup.
The rate that the integrator state changes is equal to the average error multiplied by the integrator gain multiplied by the sampling rate. Because the integrator tends to smooth things out over the long term you can get away with a somewhat uneven sampling rate, but it needs to average out to a constant value. At worst, your sampling rate should vary by no more than ±20% over any 10-sample interval. You can even get away with missing a few samples as long as your average sample rate stays within bounds. Nonetheless, for a PI controller I prefer to have a system where each sample falls within ±1% to ±5% of the correct sample time, and a long-term average rate that is right on the button.
If you have a controller that needs to push the plant hard, your controller output will spend significant amounts of time outside the bounds of what your drive can actually accept. This condition is called saturation. If you use a PI controller, then all the time spent in saturation can cause the integrator state to grow (wind up) to very large values. When the plant reaches the target, the integrator value is still very large, so the plant drives beyond the target while the integrator unwinds and the process reverses. This situation can get so bad that the system never settles out, but just slowly oscillates around the target position.
Figure 15 illustrates the effect of integrator windup. I used the motor/controller of Figure 13, and limited the motor drive to ±0.2. Not only is controller output much greater than the drive available to the motor, but the motor shows severe overshoot. The motor actually reaches its target at around five seconds, but it doesn't reverse direction until eight seconds, and doesn't settle out until 15 seconds have gone by.
The easiest and most direct way to deal with integrator windup is to limit the integrator state, as I showed in my previous code example. Figure 16 shows what happens when you take the system in Figure 15 and limit the integrator term to the available drive output. The controller output is still large (because of the proportional term), but the integrator doesn't wind up very far and the system starts settling out at five seconds, and finishes at around six seconds.
Note that with the code example above you must scale iMin and iMax whenever you change the integrator gain. Usually you can just set the integrator minimum and maximum so that the integrator output matches the drive minimum and maximum. If you know your disturbances will be small and you want quicker settling, you can limit the integrator further.