nnspike.utils.pid
PID (Proportional-Integral-Derivative) controller implementation for control systems.
This module provides a discrete-time PID controller class designed for real-time control applications in robotics, automation, and other feedback control systems. The implementation focuses on practical usage with features like output limiting, time-aware calculations, and integral windup prevention.
Methodology: The PID controller implements the standard control algorithm:
output = Kp * error + Ki * ∫error*dt + Kd * d(error)/dt
Where: - Kp (Proportional): Reacts to current error magnitude - Ki (Integral): Eliminates steady-state error by accumulating past errors - Kd (Derivative): Dampens oscillations by predicting future error trends
Results: The controller produces smooth, stable control signals suitable for: - Motor speed and position control - Temperature regulation - Line following in robotics - Steering correction systems - Process control applications
Conclusion: This implementation provides a robust foundation for feedback control systems with proper time handling and output constraints. Users should focus on proper parameter tuning (Kp, Ki, Kd) for their specific application to achieve optimal performance and system stability.
Example
Basic usage for a line-following robot:
>>> from nnspike.utils.pid import PIDController
>>>
>>> # Create steering controller (setpoint = 0 means centered)
>>> steering_pid = PIDController(kp=1.2, ki=0.05, kd=0.8, setpoint=0.0)
>>> steering_pid.set_output_limits((-1.0, 1.0)) # Limit steering range
>>>
>>> # Control loop
>>> while robot.is_running():
... line_position = robot.get_line_position() # -1 to 1 range
... steering_correction = steering_pid.update(line_position)
... robot.set_steering(steering_correction)
... time.sleep(0.01) # 100Hz control frequency
- Classes:
PIDController: Main PID controller implementation with output limiting.
- Dependencies:
time: For delta time calculations between updates.
Classes
|
A PID (Proportional-Integral-Derivative) controller for closed-loop control systems. |
- class nnspike.utils.pid.PIDController(kp, ki, kd, setpoint, output_limits=(None, None))[source]
A PID (Proportional-Integral-Derivative) controller for closed-loop control systems.
This class implements a discrete-time PID controller that continuously calculates an error value as the difference between a desired setpoint and a measured process variable. The controller applies proportional, integral, and derivative corrections to minimize this error over time, making it suitable for robotic control systems, motor speed regulation, and other feedback control applications.
Methodology: The PID controller uses three distinct parameters: - Proportional (P): Provides output proportional to the current error - Integral (I): Accumulates past errors to eliminate steady-state error - Derivative (D): Predicts future error based on the rate of change
The control output is calculated as: output = Kp * error + Ki * integral + Kd * derivative
where error = setpoint - measured_value
Results: The controller produces a continuous control signal that drives the system towards the desired setpoint. Output can be constrained within specified limits to prevent actuator saturation or system damage.
Conclusion: This implementation provides time-aware PID control with integral windup prevention through output limiting. The controller maintains internal state between updates, making it suitable for real-time control applications. Note that proper tuning of Kp, Ki, and Kd parameters is crucial for optimal performance and system stability.
- kp
Proportional gain coefficient.
- Type:
float
- ki
Integral gain coefficient.
- Type:
float
- kd
Derivative gain coefficient.
- Type:
float
- setpoint
Target value that the system should achieve.
- Type:
float
- output_limits
Min/max output constraints.
- Type:
tuple[float | None, float | None]
Example
>>> # Create PID controller for steering control >>> pid = PIDController(kp=1.0, ki=0.1, kd=0.05, setpoint=0.0) >>> pid.set_output_limits((-1.0, 1.0)) >>> >>> # Update control loop >>> measured_position = get_sensor_reading() >>> control_output = pid.update(measured_position) >>> apply_control_signal(control_output)
- __init__(kp, ki, kd, setpoint, output_limits=(None, None))[source]
Initializes the PIDController with specified parameters.
Sets up the PID controller with the given gain values, target setpoint, and optional output constraints. Initializes internal state variables for time tracking and error accumulation.
- Parameters:
kp (float) – Proportional gain coefficient. Higher values increase responsiveness but may cause overshoot.
ki (float) – Integral gain coefficient. Eliminates steady-state error but may cause instability if too high.
kd (float) – Derivative gain coefficient. Reduces overshoot and improves stability but sensitive to noise.
setpoint (float) – Target value that the controller should achieve.
output_limits (tuple[float | None, float | None], optional) – Minimum and maximum output bounds. Use None for unbounded limits. Defaults to (None, None).
Example
>>> # Create PID for temperature control >>> pid = PIDController( ... kp=2.0, ki=0.5, kd=0.1, setpoint=25.0, output_limits=(-100, 100) ... )
- set_output_limits(new_output_limits)[source]
Updates the output limits for the PID controller.
Modifies the minimum and maximum bounds for the controller output. This helps prevent actuator saturation and integral windup.
- Parameters:
new_output_limits (tuple[float, float]) – New minimum and maximum output limits as (min_limit, max_limit).
- Return type:
None
Example
>>> pid.set_output_limits((-50.0, 50.0)) # Limit output to ±50
- update(measured_value)[source]
Computes the PID control output based on current measurement.
Calculates the control signal by combining proportional, integral, and derivative terms. Updates internal state for the next iteration and applies output limits if specified.
- Parameters:
measured_value (float) – Current value of the process variable being controlled (e.g., current position, temperature, speed).
- Returns:
Control output signal, typically used for actuator control (e.g., motor commands, valve positions). Value is constrained within the specified output limits.
- Return type:
float
Note
The first call may have reduced accuracy for the derivative term due to lack of previous time reference.
Example
>>> current_temp = thermometer.read() >>> heater_power = pid.update(current_temp) >>> heater.set_power(heater_power)