simple-pid
simple-pid is a Python library that provides a simple and easy-to-use PID controller. It is designed to be robust and operate without external dependencies, making it suitable for various control system applications. The library is actively maintained, with the current version being 2.0.1, and new major versions released approximately every 2-3 years, supplemented by minor and patch releases as needed.
Warnings
- breaking Official support for Python 2 was dropped in version 2.0.0. While the code might still function, it is no longer tested against Python 2 environments, and no guarantees are provided for its compatibility or future functionality.
- gotcha Integral windup is a common issue in PID controllers where the integral term accumulates error even when the controller output is saturated. simple-pid mitigates this by automatically clamping the integral term when `output_limits` are set. Failing to set appropriate `output_limits` can lead to this problem and unstable control.
- gotcha The derivative term can cause a 'derivative kick' (a sharp output spike) on sudden setpoint changes if calculated on the error. By default, `simple-pid` calculates the derivative on the measurement (`differential_on_measurement=True`) to avoid this. If classic derivative-on-error behavior is desired, explicitly set `differential_on_measurement=False` during initialization.
- gotcha The accuracy of time-based calculations (integral and derivative terms) depends on reliable time measurements. `simple-pid` defaults to `time.monotonic()`, but if you override `PID.time_fn` or manually set `dt` (especially if `sample_time` is `None`), ensure your custom time source provides consistent and monotonic time to avoid calculation errors.
- gotcha When switching a system from manual control to PID auto mode, or starting PID on a system already at its setpoint, the PID might initially output zero (causing a 'bump') as its internal state is zero. Version 2.0.0 introduced `starting_output` for a smoother transition, and `auto_mode=True` can take a `last_output` value.
Install
-
pip install simple-pid
Imports
- PID
from simple_pid import PID
Quickstart
import time
from simple_pid import PID
# A dummy controlled system for demonstration
class ControlledSystem:
def __init__(self, initial_value=0.0):
self.value = initial_value
self.time_step = 0.1
def update(self, control_input):
# Simulate system response, e.g., a simple first-order system
self.value += (control_input - self.value) * (self.time_step * 0.5)
return self.value
# Initialize PID controller: Kp, Ki, Kd, setpoint
# Here, a setpoint of 10 is desired.
pid = PID(2.0, 0.5, 0.2, setpoint=10.0)
# Configure PID parameters
pid.sample_time = 0.1 # Update every 0.1 seconds
pid.output_limits = (-10, 10) # Limit output to avoid integral windup
# Initialize the controlled system
system = ControlledSystem(initial_value=0.0)
print(f"Initial system value: {system.value:.2f}")
# Run the control loop for a few iterations
for i in range(100):
# Compute new output from the PID according to the system's current value
control_output = pid(system.value)
# Feed the PID output to the system and get its current value
system_value = system.update(control_output)
# Optional: Print current state
if i % 10 == 0:
print(f"Iteration {i}: Setpoint={pid.setpoint:.2f}, System Value={system_value:.2f}, Control Output={control_output:.2f}")
time.sleep(pid.sample_time)
print(f"Final system value: {system.value:.2f}")
# Expected output will show the system value approaching 10.0