line-follow-pid / pid_controller.py
samuellimabraz's picture
Implement real-time line detection application with Streamlit and OpenCV. Features include webcam input, interactive HSV color adjustment, multiple line detection algorithms (Hough, Adaptive Hough, Rotated Rectangle, Fit Ellipse, RANSAC), customizable region of interest, and confidence estimation. Includes necessary modules for color detection, line detection, and PID control.
1b7bc37 unverified
import time
import math
class PIDController:
def __init__(
self, kp=1.0, ki=0.0, kd=0.0, setpoint=0.0, min_output=-100, max_output=100
):
# PID constants
self.kp = kp # Proportional gain
self.ki = ki # Integral gain
self.kd = kd # Derivative gain
# Control variables
self.setpoint = setpoint # Desired target value
self.prev_error = 0.0 # Previous error for derivative calculation
self.integral = 0.0 # Accumulated error for integral calculation
self.last_time = time.time() # Time of last update
self.last_input = float("nan") # Store the last process variable
# Output constraints
self.min_output = min_output
self.max_output = max_output
# For visualization/debugging
self.p_term = 0.0
self.i_term = 0.0
self.d_term = 0.0
def compute(self, process_variable):
"""Calculate PID output value based on current process variable"""
# Store the current input value
self.last_input = process_variable
# Handle non-numeric or invalid input
if math.isnan(process_variable):
return 0.0, 0.0, 0.0, 0.0
# Calculate time delta
current_time = time.time()
dt = current_time - self.last_time
if dt <= 0:
dt = 0.001 # Avoid division by zero
# Calculate error
error = self.setpoint - process_variable
# Proportional term
self.p_term = self.kp * error
# Integral term - with anti-windup
self.integral += error * dt
self.i_term = self.ki * self.integral
# Derivative term - on measurement, not error
if dt > 0:
self.d_term = self.kd * (error - self.prev_error) / dt
else:
self.d_term = 0.0
# Calculate output
output = self.p_term + self.i_term + self.d_term
# Constrain output
output = max(self.min_output, min(self.max_output, output))
# Save state
self.prev_error = error
self.last_time = current_time
return output, self.p_term, self.i_term, self.d_term
def reset(self):
"""Reset the controller state"""
self.prev_error = 0.0
self.integral = 0.0
self.last_time = time.time()
self.p_term = 0.0
self.i_term = 0.0
self.d_term = 0.0
self.last_input = float("nan") # Reset the last input to NaN