Implementing a PID Controller Algorithm in Python
2024-10-28 | By Maker.io Staff
In control systems engineering, arguably no algorithm is more effective and widely used than the proportional-integral-derivative (PID) controller. PID control is used to regulate all kinds of systems, including temperature, flow, pressure, speed, etc. PID control is particularly useful in embedded and sensor-laden systems, which take inputs from the real world and use that data to manipulate the environment.
To help demonstrate the working mechanisms of PID control, this article will demonstrate how to implement a simple PID controller using Python.
PID Control Theory
At the highest level, control systems work to decrease the difference between a variable's current state, known as the process variable, and a desired final state, known as the set point. This difference is known as the error signal. These systems are considered closed-loop systems because they continuously monitor the process variable, compare it to the set point, and adjust the control inputs based on the error signal to minimize this difference, thereby maintaining the desired system performance despite disturbances or changes in the environment.
For example, consider a heater that starts at 24C (i.e., process variable) but wants to reach 100C (i.e., set point). In this case, the original error signal is 76C. The control system will work to minimize this error signal by bringing the system’s actual temperature as close to 100C as possible.
Block diagram of a PID control system.
PID control operates on the principle of modulating an output control signal based on the error signal at present, as well as how the error signal is changing over time. More specifically, there are three components to a PID controller: a proportional (P) term, an integral (I) term, and a derivative (D) term, where the P term is a measure of the current error signal, the I term is the sum of the error signal over time, and the D term is the instantaneous rate of change of the error signal.
The standard mathematical form of a PID controller is given by the following equation
Where
- u(t) is the control output.
- Kp is the proportional gain.
- Ki is the integral gain.
- Kd is the derivative gain.
- e(t) is the error signal, defined as the difference between the setpoint r(t) and the process variable y(t):
- e(t) = r(t)- y(t)
- is the integral of the error over time.
- is the derivative of the error with respect to time.
Python Implementation
We will now implement a simple PID controller in Python.
Step 1: Importing Libraries
import time import matplotlib.pyplot as plt
In this segment, we import the necessary libraries. The time library provides various time-related functions, which are used for introducing delays (time.sleep) in the simulation. The matplotlib.pyplot library is used for plotting graphs, allowing us to visualize the process variable (PV), setpoint, and control output over time.
Step 2: PID Controller Function
def pid_controller(setpoint, pv, kp, ki, kd, previous_error, integral, dt): error = setpoint - pv integral += error * dt derivative = (error - previous_error) / dt control = kp * error + ki * integral + kd * derivative return control, error, integral
This function implements the core logic of the PID controller. It takes the setpoint, current process variable (PV), PID gains (kp, ki, kd), previous error, integral of the error, and the time step (dt) as inputs. It computes the current error as the difference between the setpoint and the PV. The integral term accumulates the error over time, while the derivative term estimates the rate of change of the error. The control output is calculated by combining these three terms, each scaled by their respective gains (kp, ki, kd). The function returns the control output, current error, and updated integral.
Step 3: Main Simulation Function
def main(): setpoint = 100 # Desired setpoint pv = 0 # Initial process variable kp = 1.0 # Proportional gain ki = 0.1 # Integral gain kd = 0.05 # Derivative gain previous_error = 0 integral = 0 dt = 0.1 # Time step
The main function initializes the parameters required for the simulation. The setpoint is the desired value we want the PV to reach. The initial PV is set to 0. The PID gains (kp, ki, kd) are set to values that aim to stabilize the system. The previous_error and integral are initialized to 0. The dt parameter represents the time step for each iteration of the simulation.
Step 4: Data Storage Initialization
time_steps = [] pv_values = [] control_values = [] setpoint_values = []
Here, we initialize lists to store data that will be used for plotting. time_steps will store the time points at each iteration, pv_values will store the PV at each time step, control_values will store the control output at each time step, and setpoint_values will store the setpoint value at each time step.
Step 5: Simulation Loop
for i in range(100): # Simulate for 100 time steps control, error, integral = pid_controller(setpoint, pv, kp, ki, kd, previous_error, integral, dt) pv += control * dt # Update process variable based on control output (simplified) previous_error = error time_steps.append(i * dt) pv_values.append(pv) control_values.append(control) setpoint_values.append(setpoint) time.sleep(dt)
The loop runs for 100 iterations, simulating the control process over time. In each iteration, the pid_controller function is called to compute the control output, current error, and updated integral. The PV is then updated based on the control output (simplified by multiplying control by dt). The previous error is updated to the current error for the next iteration. The current time, PV, control output, and setpoint values are appended to their respective lists. The time.sleep(dt) function introduces a delay to simulate real-time behavior.
Step 6: Plotting the Results
plt.figure(figsize=(12, 6)) plt.subplot(2, 1, 1) plt.plot(time_steps, pv_values, label='Process Variable (PV)') plt.plot(time_steps, setpoint_values, label='Setpoint', linestyle='--') plt.xlabel('Time (s)') plt.ylabel('Value') plt.title('Process Variable vs. Setpoint') plt.legend() plt.subplot(2, 1, 2) plt.plot(time_steps, control_values, label='Control Output') plt.xlabel('Time (s)') plt.ylabel('Control Output') plt.title('Control Output over Time') plt.legend() plt.tight_layout() plt.show()
In this segment, we use matplotlib to create plots of the simulation results. We create a figure with two subplots. The first subplot displays the PV and setpoint over time, showing how the PV approaches the setpoint. The second subplot shows the control output over time, illustrating how the controller adjusts the output to minimize the error. Labels, titles, and legends are added to make the plots informative and clear. The plt.tight_layout() function adjusts the spacing between subplots to prevent overlap, and plt.show() displays the plots.
Step 7: Entry Point
if __name__ == "__main__": main()
This segment ensures that the main function is called when the script is executed. The if __name__ == "__main__": statement checks whether the script is being run as the main program and not being imported as a module in another script. If true, it calls the main function to start the simulation.
Plot Results and Fixes
When running this script for the first time, the resultant plot should look like the following.
What we see is that the plot shows a significant overshoot in the process variable (PV) with a slow correction toward the set point. This indicates that the PID controller may be experiencing some degree of underdamping or an aggressive tuning, where the proportional gain might be set too high, causing the system to overshoot before eventually stabilizing at the desired value. To fix this, we’ll try modifying the parameters to achieve a more stable response. Specifically, we’ll change
- kp (Proportional gain) reduced to 0.6.
- ki (Integral gain) increased to 0.3.
- kd (Derivative gain) increased to 0.1.
Now running our plots, we should receive the following output.
This demonstrates that the values of the PID coefficients have a significant impact on the performance of the control system. There are many methods of determining the PID coefficients, which we will discuss in a future article!
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum