Guide to Designing a PID Controller Part 1

The Proportional Integral Derivative (PID) controller and the lesser control system such as Proportional (P), Proportional Integral (PI), and Proportional Derivative (PD) have been with us for a long time. Proportional control stretches all the way back to the 18th century to James Watt and his mechanical fly-ball governor for the steam engine. This rudimentary mechanical automation system shares attributes with the latest microcontroller or Programmable Logic Controller (PLC) solution as all implementations monitor and then respond to the output of their respective machine or process being controlled (referred to as a “plant” in automation and control literature). This is an inhibiting negative feedback process. If the feedback is lost, the plant will be driven to full power with the danger of catastrophic failure.

Introducing the PID

We will explore a servomotor PID application as shown in Figure 1. This mechanism is built on a PORTENTA Pro C33 microcontroller plus PORTENTA pro break out board. It also features a Pololu #4754 DC motor and a Seeed MDD3A motor controller. This combination provides an excellent test bed from which to explore the P, PI, PD, and PID controllers. It’s a responsive system with human-observable outputs. We can hear, see, and feel the motor’s response as the system is developed and tuned.

Figure 1: Picture of the servomotor-based PID controller test bed including the Arduino C33, PORTENTA breakout board, Seeed MDD3A motor drive, and the Pololu 4754 brush type DC motor.

Video 1: Servomotor in operation completing one complete turn and then returning to the starting position.

Tech Tip: PID is an umbrella term. Lesser controllers such as a simple Proportional, Proportional Derivative (PD) or Proportional Integral (PI) are generally included as subcategories of the PID controller. A PID controller may easily be converted into a P, PI, or a PD controller by turning off the unused functionality by setting the associate gain values to zero. For example, a PID controller may be converted to a PI controller by setting the D gain to zero.

Author’s motivation for writing this article

Nearly 20 years ago I wrote a three-part PID Article featured in Nuts & Volts. Looking back, I’d say it was a good attempt. However, since then, I’ve had the opportunity to apply the PID in many different situations including some not so obvious applications. More importantly, I’ve had the opportunity to guide many successful student projects. This is a difficult learning process as it incorporates ideas from many different classes. It’s one thing to complete a control theory class and learn about PID and related math-intensive controllers. It’s a very different experience to implement those ideas into a responsive real-world system especially an embedded system with all the constraints and complexities of a microcontroller.

This brief serves as a starting point for blending the topics of control systems and microcontrollers. It is biased toward the practical aspects of simply getting the system to work. Once you have the working system and have gained some experience empirically tuning the PID gains and timing parameters, you can go back and explore the mathematics. The final product is shown in Video 1. Here the servomotor is completing a single revolution and then returning to the original position.

Objectives of this PID article

Thousands of books and articles have been written about the P, PI, PD, and PID controllers since their original introduction. Chances are high that you have already read a few of these articles, and are now looking for practical advice for implementing and improving the stability of your project. Rather than rehash the old theoretical material, this engineering brief is focused on a practical application of the PID controller. For convenience, we leverage your foundation in the Arduino Microcontroller with a brief exploration of FreeRTOS to assist with integrating the PID into a large ecosystem.

The specific objectives of this article are:

  • to provide a PID code framework biased toward education. For example, the individual PID gain elements are explored as percentages.

  • to provide a real-time interface that allows observation of the individual PID contributions.

  • to set limits on the individual PID contributions. As an example, this allows the D contribution to be observed when it would otherwise be hidden by the P contribution.

  • to leverage the Arduino education base and then expand the application to include a real time operating system running on advanced hardware.

  • to demonstrate prototyping techniques with modern high performance microcontrollers such as the featured Arduino PORTENTA C33 which facilitates the future use of Ethernet and Bluetooth.

  • to leverage the flexibility of the multitasking FreeRTOS

In summary, we avoid the well documented theoretical aspects of the PID and focus on a robust implementation with interactive empirical tuning. The technique will help your grok the PID allowing you to design, commission, and troubleshoot control systems.

Note that several prerequisite articles have already been posted to the DigiKey Tech forum. Please take the time to review these articles as they represent a critical foundation upon which this brief rests. From this point forward we assume you are already familiar with the topics:

Motion and Control

Arduino PORTENTA Pro

Tech Tip: The PID controller may be designed for high programmatic efficiency suitable for operation on an 8-bit microcontroller. For example, the program can be optimized to use fast integer math as opposed to floating point calculation. No attempt is made to optimize the PID featured in this article as it makes exclusive use of floating-point numbers. This education-biased implementation is mitigated by using a powerful modern 32-bit microcontroller with a Floating-Point Unit (FPU).

What is a PID controller used for?

The Proportional Integral Derivative (PID) controller is a widely used process control algorithm. The term “process” describes a system designed for extended or continuous operation at some stable setpoint. Common examples include regulating water pressure, maintaining a fixed temperature, or maintaining a fixed velocity of a machine.

The concept of the PID extends to dedicated PID hardware modules which may be analog or digital in nature. It may also describe code running on a microcontroller of Programmable Logic Controller (PLC). For our purposes we will explore the software side of the PID and the supporting microcontroller structures. If there is interest, we could explore industrial PID hardware modules or PLC software implementation of the PID.

What are the inputs and outputs of a PID controller?

The PID controller has two inputs and one output as shown in Figure 2. The inputs include an analog representation of where the plant is (feedback) and where the plant should be (setpoint). The output is used to control the plant to minimize the difference between the feedback and setpoint signals. In an ideal world the plant will precisely follow the setpoint. In the real world this is not an easy task especially when the physical plant has kinetic and potential energy.

How does the classical PID algorithm work?

The PID controller is a mathematical model that may be implemented in the real world using analog circuitry or digital methods. As the name suggests, the core algorithm consists of a combination of three mathematic operations including:

  • Proportional – control action based on how far the plant’s measured feedback is from the desired setpoint. The greater the error, the greater the corrective control action. From a time-based perspective, the proportional term acts on the here and now.

  • Integral – control action based on the time integral of the error. A small error accumulated over a large time leads to a large control action. From a time-based perspective, the integral is acting on past information as we have accumulated all past errors. In some respects, the integral acts as a low pass filter as it is relatively immune to noise.

  • Derivative – control action based on time rate of change describing how fast the plant’s output is changing. The derivative term works in opposition to proportional integral. A quickly moving plant leads to a large control action to slow down the system. From a time-based perspective, the derivative is action on the future as a system that is quickly moving will soon overshoot the target. In some respects, the derivative acts as a high pass filter it is very sensitive to noise and timing jitter.

The classical PID algorithm is shown in Figure 2. Observe that the individual P, I, and D terms are based on the error. Where error is the difference between the setpoint and the plant feedback. The strength of the P, I, and D contributions is determined by the respective kP, kI, and kD gains. Finally, the individual P, I, and D terms are combined to produce the plant drive signal.

Figure 2: Block diagram of the traditional (academic) PID controller. The P, I, and D terms are based on the error signal (difference between setpoint and feedback).

The core PID operation may be described using this short snippet of C code. For clarity the variable declarations have been omitted along with and setters and getters. Observe that the code is a direct representation of the Figure 2 block diagram.

Tech Tip: There is an implicit time component to the sampled PID control system as indicated by the clock in Figure 2. The PID update method shown below must be called at regular time intervals. For example, a motor control system may require an update at 10 ms time intervals. Variations in this time interval appear as noise which degrades the derivative performance of the PID controller.

float PIDController::update(float feedback) {  // Must be called at regular time intervals
    error = setpoint - feedback;
    P = error * kP;                            // now
    I += error * kI;                           // backwards looking accumulation of all previous errors
    D = (error - last_error) * kD;             // forward looking based on current trend (slow down a fast moving system)
    last_error = error;
    PID_output = P + I + D;
   return PID_output;
}

If you are a student, you may also recognize the PID by the time-domain and discrete time equations. Without explanation, the traditional PID equations are:

u(t) = K_p \cdot e(t) + K_i \cdot \int_{0}^{t} e(\tau) \, d\tau + K_d \cdot \frac{d}{dt} e(t)

u[k] = K_p \cdot e[k] + K_i \cdot \sum_{i=0}^{k} e[i] \cdot \Delta t + K_d \cdot \frac{e[k] - e[k-1]}{\Delta t}

We have just explored several different ways to describe the traditional PID controller. While these are all true and valid descriptions, they are of limited use for real-world implementation where we are faced by nonlinear system responses and noise. For example, in an ideal system the associate plant may provide unlimited power in response to an unbounded PID command. In practice devices such as a Pulse Width Modulator (PWM) driven motor controller are bounded by physical saturation limits - once the PWM is at 100% there can be no additional power added to the system. Noise is an unavoidable attribute encountered in all feedback measuring systems, including the quadrature encoder featured in this article. Noise is also introduced by variations in the PID update time.

How is the traditional PID controller modified to improve real-word response?

A responsive real-world PID controller includes code or circuitry to prevent problems associated with the integral and derivative contributions. As shown in Figure 3 this includes a mechanism to prevent integral windup, predictable limiters, derivative input taken directly from the feedback, and a low pass filter for the derivative input.

As we continue this discussion, know that each limiter block is set to +/- 100. Consequently, we can talk about the contributions of the P, I, and D terms in terms of a percentage. For example, our servomotor-based plant can be driven 100% CW or 100% CCW. If we command a large move such as 10 turns in a CW direction, the P component will immediately saturate and drive the plant 100 % CW.

Figure 3: A practical modified PID controller includes saturation blocks for the individual P, I, and D contribution. A lockout mechanism is included to prevent integral windup. A Low Low-Pass Filter (LPF) is also included for the D term, which in turn is derived from feedback to prevent derivative kick.

What is Integral Windup?

Integral windup is an undesirable condition where the integral term builds to a large value. As an example, let’s assume a change to the servomotor setpoint commands a 10 turn CW move. Such a motion will take several second to complete. Without intervention, the integral would build (accumulate the large error) likely growing to well over 1,000 percent drive. This will cause system instability with a long-term oscillation before settling to a final value – or not settling at all.

The saturation block immediately following the integrator will limit the maximum value to 100%. This will help, but overshoot and oscillation remain. The lockout block will help as it impedes the accumulation process while the system is saturated by the P terms. Stated another way, the I component is frozen until the motor approaches the commanded setpoint. The combined action provides a significant reduction in overshoot leading to faster settling times.

What is derivative kick?

Derivative kick is undesirable derivative action when the setpoint of a PD or PID controller is changed. Looking back to Figure 2 we see that the derivative term is based on the error while Figure 3 shows an association with the feedback signal itself. For the first error-based situation, a large change in setpoint would cause a large change (kick) in the D contribution. With the feedback-based improvement, the derivative contribution is 100% determined by the plant with no kick in response to a change in setpoint.

Figure 3 also includes a Low Pass Filter (LPF) for the derivative term. This is a simple running average filter used to eliminate noise. This includes noise from the measurement process as well as jitter induced noise form the sampling process. Configuring this filter is part of the tuning process as we select the number of samples to be included in the average.

Code for a responsive PID controller

The code for the modified PID is shown in this listing. Notice that the saturation blocks are completed using the fLimit( ) function. This limits each P, I, and D contribution to +/- 100. The Integral lockout is a rudimentary check based on the P term. If P is saturated, the integral is held at its current value. The derivative is driven by the feedback with a running average filter composed of DSamplesAveraged.

float PIDController::update(float feedback) {
  error = setpoint - feedback;
  lastSetpoint = setpoint;

  P = error * kP;
  P = fLimit(P, -100.0, 100.0);

  if(fabs(P) != 100) {
      I += error * kI;
  } else {
     ;                        // Hold on I if the P term is saturated.
  }
  I = fLimit(I, -100, 100);

  float runAvgFeedback = runningAverage(feedback, DSamplesAveraged);
  D = ( runAvgFeedback - last_feedback) * kD;
  D = fLimit(D, -100, 100);
  last_feedback = runAvgFeedback;

  PID_output = P + I - D;
  PID_output = fLimit(PID_output, -100, 100);

  return PID_output;

}

Parting thoughts

Future installments of this series delve deeper into the modified PID code and the supporting microcontroller structures. We will also backtrack and fill in some of the necessary language associate with control systems. This will lead to a better understanding of stability. Until then, may I recommend this practical PID article.

Please leave your comments and suggestion below. While I cannot make any promises, I will attempt to address your questions in future installments.

Best Wishes,

APDahlen

Please follow this link for related Arduino education content.

About this author

Aaron Dahlen, LCDR USCG (Ret.), serves as an application engineer at DigiKey. He has a unique electronics and automation foundation built over a 27-year military career as a technician and engineer which was further enhanced by 12 years of teaching (partially interwoven with military experience). With an MSEE degree from Minnesota State University, Mankato, Dahlen has taught in an ABET-accredited EE program, served as the program coordinator for an EET program, and taught component-level repair to military electronics technicians. Dahlen has returned to his Northern Minnesota home and thoroughly enjoys researching and writing educational articles about electronics and automation.

Highlighted Experience

Dahlen is an active contributor to the DigiKey TechForum. At the time of this writing, he has created over 145 unique posts and provided an additional 475 forum posts. Dahlen shares his insights on a wide variety of topics including microcontrollers, FPGA programming in Verilog, and a large body of work on industrial controls. A collection of Dahlen’s Arduino educational articles can be found at Arduino education content.