Click here to Skip to main content
14,240,705 members

PID process control, a “Cruise Control” example

Rate this:
4.83 (46 votes)
Please Sign up or sign in to vote.
4.83 (46 votes)
14 May 2009CPOL
Example of a PID (Proportional, Integral, Derivative) control, used when processes change due to inertia.


This code is a working example of a PID (Proportional, Integral, Derivative) control. This type of a control is used when processes change due to inertia. (A car's cruise control is a PID controller.) The PID algorithm is surprisingly simple, and can be implemented in five lines of code. There are three constants that must be determined in order to shape the control's output. The three constants as well as the set point and sampling interval can be changed in real time. The resulting shape of the output will be displayed in a strip chart.


How are PID loops used?

Many real world processes build up over time. When you step on the accelerator, your car moves slowly, then faster, and faster still, until you let off the gas pedal. As you speed up, you press the gas pedal less, then a little less, then even less, until you reach the speed limit. Unlike the digital world where things are either “on” (1) or “off” (0), real processes have varying degrees of “on”. In the driving example, how much the accelerator is turned “on” depends on the car's current inertia and how different the car's speed is from the speed limit. Controlling such a process with inertia can be done with only five lines of code. But, just like learning to drive, it takes practice to know if you are starting too quickly, or if you'll overshoot the speed limit.

Cruise control is one example of a PID control loop. To calculate the output, it needs three factors. The first, (P), is the difference between the current speed and the desired speed. The second, (I), is the sum of the differences over time. And, the third, (D), is the rate of change between sampled differences. Each factor is scaled by a gain constant; they are refered to as Kp, Ki, and Kd. The value of these gain constants determines how responsive the output will be. If the Kp, Ki, and Kd values are too high, the output (car's speed) will far exceed the set point (speed limit). Set too low, the output may never reach the set point (like driving 40mph on the highway).

Code implementation

In the real world, a process updates constantly. In order to simulate this action, a timer is used to run an equation that models the process. From a second timer, the PID control algorithm samples the process value at a rate slower than the process model updates. The “Process Value” or PV timer should run at least twice as faster than the “PID control” timer. In the application, the PV timer runs every 17ms, and the PID timer runs every 100ms.

The PV timer (tmrPV) tick event handler runs the following code:

//This timer updates the process data. it needs to be the fastest
// interval in the system.
private void tmrPV_Tick(object sender, EventArgs e)
   /* this is my version of cruise control. 
    * PV = PV + (output * .2) - (PV*.10);
    * The equation contains values for speed, efficiency,
    * and wind resistance.
    * Here 'PV' is the speed of the car.
    * 'output' is the amount of gas supplied to the engine.
    * (It is only 20% efficient in this example)
    * And it looses energy at 10% of the speed. (The faster the 
    * car moves the more PV will be reduced.)
    * Noise is added randomly if checked, otherwise noise is 0.0
    * (Noise doesn't relate to the cruise control, but can be useful
    * when modeling other processes.)
   PV = PV + (output * 0.20) - (PV * 0.10) + noise;
   // change the above equation to fit your application.

The PID control timer (tmrPID_Ctrl) tick event handler runs:

/* This represents the speed at which electronics could actually 
* sample the process values.. and do any work on them.
* [most industrial batching processes are SLOW, on the order of minutes.
* but were going to deal in times 10ms to 1 second. 
* Most PLC's have relatively slow data buses, and would sample
* temperatures on the order of 100's of milliseconds. So our 
* starting time interval is 100ms]
private void tmrPID_Ctrl_Tick(object sender, EventArgs e)
{ /*
   * Pseudo code (source Wikipedia)
     previous_error = 0
     integral = 0 
     error = setpoint – PV [actual_position]
     integral = integral + error*dt
     derivative = (error - previous_error)/dt
     output = Kp*error + Ki*integral + Kd*derivative
     previous_error = error
     goto start
   // calculate the difference between
   // the desired value and the actual value
  error = setpoint - PV; 
   // track error over time, scaled to the timer interval
  integral = integral + (error * Dt);
   // determine the amount of change from the last time checked
  derivative = (error - preError) / Dt; 
   // calculate how much to drive the output in order to get to the 
   // desired setpoint. 
  output = (Kp * error) + (Ki * integral) + (Kd * derivative);
   // remember the error for the next time around.
  preError = error; 

Take a look at some typical output shapes

In the images below, the green line is the set point, the blue line is the input (or process value), and the red line is the output (or manipulated value).


Correct control signal. All three gain constants are set correctly.


Overshoot. Integral constant too high.


Undershoot. Integral constant too low.


Ringing. Integral and Proportional gain constants too low.


Noise (under control). All three constants are set correctly.


Noise (not controlled). Derivative gain constant too high.

Code modifications you might consider

This example works for modeling any process that has inertia. The process being modeled here is a car's cruise control. In order to adapt the code to model a process other than cruise control, the equation in the PV timer tick event handler should be changed.

I use PID loops for electric furnace control. In furnace control, thermal mass is measured by sampling temperature. Better PID loop tuning results in efficient energy use. The code currently in the PV timer tick event handler is pretty close to a furnace equation. You can modify the equation to fit the system you want to model. As a rule of thumb, use the following equation:

ProcessValue = ProcessValue + (output * efficiency) – loss

In a real cruise control, there are limits on how much the output can change from sample to sample. This example does not include any way to limit the output's magnitude of the change. Such code might look like:

if ( (output – outputLast) > maxChange) 
  output = outputLast + maxChange;
else if ( (outputLast – output) > maxChange)  
  output = outputLast – maxChange;
outputLast = output;

The noise that can be added to the signal is not representative of anything your car might encounter. (It is really just a model of electrical noise.) Noise to a car's cruise control might be something like a hill, or a gust of wind. Both of those examples have a lower frequency than our noise. Since the noise is created in its own timer event handler, you can change the interval of the noise to change its frequency. You could also change the noise equation to model the effects of a hill, or even a chilling arctic blast.


  • 2009 - 05 - 14 - Article submitted.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

United States United States
No Biography provided

Comments and Discussions

Questionintegral variable gets out of hand Pin
Member 872248315-Aug-13 3:09
memberMember 872248315-Aug-13 3:09 
Questionintegral variable gets out of hand Pin
Member 872248315-Aug-13 2:23
memberMember 872248315-Aug-13 2:23 
QuestionPID control for heater Pin
vebi100031-Jul-13 4:05
membervebi100031-Jul-13 4:05 
QuestionVery neat application Pin
Sergey Chepurin25-Jun-13 22:13
memberSergey Chepurin25-Jun-13 22:13 
QuestionJust something that I don't understand Pin
Martin Asenov18-Mar-13 5:36
memberMartin Asenov18-Mar-13 5:36 
GeneralMy vote of 5 Pin
LeoBro24-Dec-12 3:01
memberLeoBro24-Dec-12 3:01 
QuestionUsing a negative SetPoint Pin
jnilson_9910-Oct-12 11:41
memberjnilson_9910-Oct-12 11:41 
AnswerRe: Using a negative SetPoint Pin
jnilson_9910-Oct-12 12:00
memberjnilson_9910-Oct-12 12:00 
GeneralMy vote of 5 Pin
Member 944192519-Sep-12 7:22
memberMember 944192519-Sep-12 7:22 
QuestionPV Equation Pin
CRMATTHIEU18-Jan-12 6:01
memberCRMATTHIEU18-Jan-12 6:01 
AnswerRe: PV Equation Pin
oswaldfig7-Feb-12 8:46
memberoswaldfig7-Feb-12 8:46 
Questiontransfer function of the process ? Pin
oswaldfig29-Nov-11 11:49
memberoswaldfig29-Nov-11 11:49 
GeneralMy vote of 5 Pin
smurariu7-Feb-11 23:53
membersmurariu7-Feb-11 23:53 
Generalvery good article Pin
mnch7817-Oct-09 7:40
membermnch7817-Oct-09 7:40 
QuestionCan this be done with fixed point math? Pin
s_mack8-Sep-09 14:53
members_mack8-Sep-09 14:53 
AnswerRe: Can this be done with fixed point math? Pin
lcady8-Sep-09 18:29
memberlcady8-Sep-09 18:29 
GeneralRe: Can this be done with fixed point math? [modified] Pin
s_mack8-Sep-09 19:07
members_mack8-Sep-09 19:07 
GeneralRe: Can this be done with fixed point math? Pin
s_mack8-Sep-09 20:37
members_mack8-Sep-09 20:37 
GeneralRe: Can this be done with fixed point math? Pin
lcady9-Sep-09 7:27
memberlcady9-Sep-09 7:27 
GeneralRe: Can this be done with fixed point math? Pin
s_mack9-Sep-09 8:08
members_mack9-Sep-09 8:08 
GeneralRe: Can this be done with fixed point math? Pin
lcady10-Sep-09 3:37
memberlcady10-Sep-09 3:37 
GeneralRe: Can this be done with fixed point math? Pin
s_mack10-Sep-09 4:03
members_mack10-Sep-09 4:03 
Generalpid controller Pin
johngholton18-Aug-09 4:23
memberjohngholton18-Aug-09 4:23 
GeneralRe: pid controller Pin
Owen Lawrence19-Aug-09 8:39
memberOwen Lawrence19-Aug-09 8:39 
GeneralExcellent! Pin
sajmon4425-May-09 11:13
membersajmon4425-May-09 11:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Posted 14 May 2009


91 bookmarked