Proportional-Integral-Derivative (PID) Controller

PID Intro:

The heart of any real control system has a feedback controller.  When the system’s process is unknown or hard to model, a Proportional-Integral-Derivative (PID) controller is an efficient method for control.  If the system’s process is known, a custom controller will yield higher efficiency.  However, modeling complex systems in attempt to design a custom controller may result in a much higher development time and cost than can be afforded.  In both cases, a PID controller is a very efficient method for controlling all types of systems.

thanks to wikipedia.org for the diagram

PID Theory:

PID controllers can be understood(partially) without an in depth lecture on control theory. PID controllers use 3 sub-controllers combined into 1 controller using a simple sum. The 3 controllers are:

  • Proportional:
    The proportional section of a PID controller is a basic intuitive approach to feedback control. A naive approach to feedback control would say, the farther away from perfect the system is, the more it should work to get perfect. In a perfect world without friction, momentum, etc., this system alone would work great! This is proportional control. However, our world is imperfect and we need to add smarter feedback compensation.
  • Integral:
    The integral section of a PID controller compensates environment imperfections such as friction, wind, and other such imperfections that would resist the system to reach its perfect state. An integral controller works by keeping a sum of all the error the system has seen. In calculus, this is equivalent to the area underneath the curve up to the current point. The controller increases its control signal as the summed error gets larger.
  • Derivative:
    The derivative section of a PID controller compensates environment imperfections such as momentum which causes the system to overshoot its perfect state. The derivative controller lessens its control signal as the speed in which it is achieving its perfect state increases. In calculus, this is the slope of the error signal.

Example:

Let’s consider an example to show how a PID controller could be used. Our example will be an airborne GPS navigation system in a helicopter. The aircraft knows where it is and where it is being told to be. Using basic subtraction, it can figure out the distance to the desired location. This is the error signal. It indicates how far from perfect it is.

Lets say that the PID controller is controlling the forward thrust of the helicopter and that the direction is automatically set by something else (in other words, the helicopter always points the direction it should).

The proportional controller would just set the thrust according to the distance away from the target location. This is a simple approach but most likely will not work by itself. As the helicopter gains momentum, it will become harder to slow down. Using proportional control only, the helicopter will overshoot its target and possibly oscillate around the target location. Another issue is wind. The thrust controller should compensate for wind because a tail wind could cause an positional overshoot and a head wind might cause it to never get there.

The integral controller continues to sum the error it incurs and adjusts appropriately. In the head wind example, the thrust would increase until the aircraft could reach its target destination.

The derivative controller measures the speed in which the error signal is changing, which for the helicopter is simply the relative ground velocity. As the helicopter approaches its destination the derivative controller reduces the thrust allowing the helicopter not to overshoot its target position. In the event of tail wind, it reduces the thurst even more so that it can’t be pushed past the target.

For the helicopter example, all 3 sub-controllers must be used. To use all of them, you just sum the control signals of all 3.

Implementation:

If you think this sounds hard to implement, you are wrong. PID controllers were designed to be generic and easily adapted to all systems. As mentioned before, PID controllers have 3 sub-controllers. Each controller has a parameter that must be tuned, called ‘gain’. To add a PID controller to a system, you just need to attach the generic PID controller and tune the 3 values.

The following C code is an efficient PID controller.

typedef struct {
    double windup_guard;
    double proportional_gain;
    double integral_gain;
    double derivative_gain;
    double prev_error;
    double int_error;
    double control;
} PID;

void pid_zeroize(PID* pid) {
    // set prev and integrated error to zero
    pid->prev_error = 0;
    pid->int_error = 0;
}

void pid_update(PID* pid, double curr_error, double dt) {
    double diff;
    double p_term;
    double i_term;
    double d_term;

    // integration with windup guarding
    pid->int_error += (curr_error * dt);
    if (pid->int_error < -(pid->windup_guard))
        pid->int_error = -(pid->windup_guard);
    else if (pid->int_error > pid->windup_guard)
        pid->int_error = pid->windup_guard;

    // differentiation
    diff = ((curr_error - pid->prev_error) / dt);

    // scaling
    p_term = (pid->proportional_gain * curr_error);
    i_term = (pid->integral_gain     * pid->int_error);
    d_term = (pid->derivative_gain   * diff);

    // summation of terms
    pid->control = p_term + i_term + d_term;

    // save current error as previous error for next iteration
    pid->prev_error = curr_error;
}

Windup Guard:

As you may have noticed, the code has a feature called windup guard. This is a critical feature that must be used in most control systems. Windup guarding is simply just setting a cap on the maximum value that the integrated error can be. This is typically most needed for startup conditions and situations for switching in and out of control. Let’s look at our helicopter example again. Consider the situation where the helicopter can be piloted by a person or the PID autonomous controller. If the human operator had a target destination only a few feet away from the current position but held the helicopter still, the integral portion of the PID controller would continue to sum the error seen. Eventually this error would grow very large. If the pilot then switched to autonomous mode, the controller’s output thrust signal would be huge, most likely causing a wreck. There are two solutions to this problem. The first is using a cap for the maximum absolute value of the integrated value. This is the windup guard. Another solution would be to call the pid_zeroize function each time the GPS target is set and each time the autonomous control system is enabled. In either case, setting a safe maximum value using a windup guard is good practice.

Optimization:

This code can be optimized if the pid_update function is called at the exact same rate every time. In this case, all references to ‘dt’ can be removed. This will change the optimal values for the integral and derivative gains but once tuned, will respond the same way. In this code, this optimization only removes one multiplication operation and one division operation.
It is possible to change this code to run on fixed-point arithmetic rather than floating-point. This dramatically increases the efficiency but system limits and precision may be compromised. Only use fixed-point if you are sure that you are using enough precision.

EDIT: fixed bug on line 31. changed multiply to divide.

    • Bigney
    • July 24th, 2011

    It’s hard to find knowledgeable people on this topic, but you sound like you know what you’re talking about! Thanks

    • Ong Chin Hui
    • October 28th, 2011

    Good work!!

    However, should it be a divide operation rather than multiplication at line 31:

    ie.

    diff = ((curr_error – pid->prev_error) / dt);

    instead of

    diff = ((curr_error – pid->prev_error) * dt);

    • Great catch! Consider it changed. Thanks.

    • Muddi
    • December 16th, 2012

    Hi,
    I am designing a PID controller to control lateral and longitudinal stability of a helicopter. Do you know the MATLAB code for it??

    If you could provide that I shall be very thankful to you.

    Please respond.

      • nic
      • December 17th, 2012

      You should be able to take the PID function above and port it to MATLAB. The best thing about PID controllers is that it doesn’t matter what you are controlling, the PID function is always the same. The settings for the 3 gains are the only tuning needed.

      Let me know if you have any problems porting the C code to MATLAB. I’d be glad to help.

        • Muddi
        • January 5th, 2013

        Hi nic,
        Well I might sound a complete dumb person right now but the truth is that I have failed to port the pid function to MATLAB. My MATLAB version does not have pid function in it. I am using R2009b. I have tried in 2007 and 2011 versions as well but all in vain. Also, I am not very good at using MATLAB so you can imagine how hard would it be to port it for me..

        It has been 3 weeks now I am trying to figure it out but no gain. Is there anyway you could help me with?? I will really appreciate your time and help.
        and thanks for your quick response.
        waiting for another one.🙂

      • Ok, check out this post. I hope it helps

    • Ahmed Thabet
    • December 21st, 2012

    Hey nic, I am designing a real time quadcopter, and I wanted to do a simulink PID control to simulate its stability. Is there any more tutorials on this in specific or any kind of advice or documents I could read to implement this?

      • nic
      • December 22nd, 2012

      The hardest part about simulating a PID controller is determining how to simulate the system being controlled. PID controllers were developed for situations where the transfer function of the system is unknown or very complex. If you actually found the transfer function of a quadcopter, you’d probably discover a better feedback control system than a PID controller.

  1. Hi Nic,
    I’m building a quadcopter with a RaspberryPi – your post is the clearest I’ve found on the PID purpose and code, thanks. Just a couple (three actually) naive questions:

    1. I assume there is an independent PID algorithm for each of the X and Y planes, but that’s not necessary for the Z plane as there are no motors to control that way?

    2. I assume P derives directly from an acclerometer and D from a gyroscope but from where is I derived? Is this the roll of a magnetometer to show absolute position (or even GPS)

    3. I assume dt is simply the time span since the last time the PID algorithm was called (told you it was naive!)

    Thanks,

    Andy

    http://www.pistuffing.co.uk

  2. Hove :
    Your comment is awaiting moderation.
    Hi Nic,
    I’m building a quadcopter with a RaspberryPi – your post is the clearest I’ve found on the PID purpose and code, thanks. Just a couple (three actually) naive questions:
    1. I assume there is an independent PID algorithm for each of the X and Y planes, but that’s not necessary for the Z plane as there are no motors to control that way?
    2. I assume P derives directly from an acclerometer and D from a gyroscope but from where is I derived? Is this the roll of a magnetometer to show absolute position (or even GPS)
    3. I assume dt is simply the time span since the last time the PID algorithm was called (told you it was naive!)
    Thanks,
    Andy
    http://www.pistuffing.co.uk

    Oops, a little more thought made me realize all this tied into the accelerometer – it’s the PID which accounts for speed / gravity / position / wind factors. Just the proportional, intergral and differential aspects will compenstate for gravity, wind, momentum etc

    Cheers for the great article.

    Hove

      • nic
      • February 25th, 2013

      Hove,
      Take a look at the diagram on this post:
      https://nicisdigital.wordpress.com/2011/05/17/software-design/

      The sensor fusion algorithm should fuse all the sensor data into one measurement, aircraft attitude, or basically the tilt of the quadcopter. You should have a PID controller for any axis (or dimension) being controlled by your software. The inputs are: the desired value, and the current value. The PID controller will output a control signal. This will then drive your motors.

      You need to view each stage independently. Good luck!

      -Nic

      • Thanks Nic,

        That’s what I’ve coded once I’d finally realized how the PID(s) worked (hugely appreciated, thanks, to the extent I’ve included a back-reference on my site); so I have 3 PIDs, representing the target G-force in each dimension, and therefore the PIDs each return the necessary PWM power change to resolve the difference between the sensor and the target both statically, dynamically and accounting for external noise.

        Cheers,

        Hove

      • Thanks, finally think I understand – I was using the PID outputs for each of the X, Y, and Z dimensions as changes to the current output settings rather than absolute values for the output settings. So this rapidly got out of control (only in simulation luckily).

        Cheers,

        Andy

        http://www.pistuffing.co.uk

    • AWK
    • April 11th, 2015

    There is one think I did not understand. How do we choose proportional_gain , integral_gain, double derivative_gain and dt?

    Thanks

    • Hi Awk, great question! This is the hardest thing about PID controllers. There are better ways to make feedback controllers than PID controllers, but they require you to understand the dynamics of your system. There are a few ways you can tune your PID controller, but the best, most formal way is called the Ziegler Nichols method (look it up on Wikipedia). The basic idea is set P, I, and D to zero, then very slowly ramp up the P value until the system oscillates with a constant amplitude. You then use the amplitude and frequency of oscillates to set the P, I, and D gains based on a desired control style.

  1. January 17th, 2012
  2. January 11th, 2013
  3. February 24th, 2013
  4. November 24th, 2015

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: