first commit

This commit is contained in:
rangang
2026-08-12 17:40:45 +08:00
commit 84b2bdb35d
12 changed files with 1958 additions and 0 deletions
+145
View File
@@ -0,0 +1,145 @@
# controllers.py
import os, sys, time
def _pid_log(msg: str):
"""PID 内部日志,直接写文件 + 刷盘"""
try:
log_dir = os.path.join(os.path.dirname(sys.executable), "logs")
os.makedirs(log_dir, exist_ok=True)
log_file = os.path.join(log_dir, "control_debug.log")
with open(log_file, "a", encoding="utf-8") as f:
f.write(f"[{time.strftime('%H:%M:%S.%f')[:-3]}] [PID] {msg}\n")
f.flush()
os.fsync(f.fileno())
except Exception:
pass
class IncrementalPID:
"""增量式PID控制器"""
def __init__(self, kp: float, ki: float, kd: float, dt: float,
out_min: float, out_max: float, xa_full: float = 1062.5):
# PID参数
self.kp = kp
self.ki = ki
self.kd = kd
self.dt = dt # 默认50HZ执行周期防止除零
self.motor_max = 300.0
self.du_max = self.motor_max * self.dt
self.dead_area = 240.0
self.xa_full = xa_full # 总限幅(最大行程)
# self.kp = 1.392
# self.ki = 30.2
# self.kd = 0.000485
# self.dt = 0.0059
# 限幅设置
self.out_min = out_min
self.out_max = out_max
# 输入输出
self.target_pressure = 0.0 # 参考值(设定压力大小)
self.current_pressure = 0.0 # 反馈值
self.error = 0.0 # 当前误差
# 计算系数
self.a0 = 0.0
self.a1 = 0.0
self.a2 = 0.0
self._calculate_coefficients()
# 控制器状态
self.prev_error = 0.0 # 前次误差 e(k-1)
self.prev_error2 = 0.0 # 前前次误差 e(k-2)
self.output = 0.0 # 控制器总输出
def _calculate_coefficients(self):
"""重新计算增量式PID系数"""
if self.dt <= 0:
return
self.a0 = self.kp + (self.ki * self.dt / 2.0) + (2.0 * self.kd / self.dt)
self.a1 = -self.kp + (self.ki * self.dt / 2.0) - (4.0 * self.kd / self.dt)
self.a2 = (2.0 * self.kd) / self.dt
def update_pressure_values(self, current_pressure, target_pressure):
"""更新当前压力和目标压力值"""
self.current_pressure = current_pressure
self.target_pressure = target_pressure
def update(self, du_max=None):
# 计算当前误差
self.error = -(self.target_pressure - self.current_pressure)
# if abs(self.error) < 1:
# return self.output # 误差过小,直接返回当前输出
# 计算控制增量
delta = (self.a0 * self.error + self.a1 * self.prev_error + self.a2 * self.prev_error2)
if du_max is not None:
self.du_max = du_max
else:
self.du_max = self.get_du_max(self.target_pressure)
# 纯 Python 限幅(替代 np.clip
if delta > self.du_max:
delta = self.du_max
elif delta < -self.du_max:
delta = -self.du_max
# 计算新输出
new_output = self.output + delta
# print(f"output:{self.output}, delta:{delta}, new_output:{new_output}")
# 应用输出限幅
new_output = max(self.out_min, min(self.out_max, new_output))
# 更新历史状态
self.prev_error2 = self.prev_error
self.prev_error = self.error
self.output = new_output
return new_output
def reset(self):
"""重置PID控制器状态(保留参数)"""
self.prev_error = 0.0
self.prev_error2 = 0.0
self.output = 0.0
def update_parameters(self, kp: float, ki: float, kd: float):
self.kp = kp
self.ki = ki
self.kd = kd
self._calculate_coefficients()
def set_du_max(self, value):
"""设置 du_max(供外部模块通过方法调用设置,避免跨 .pyd 属性写入 crash)"""
self.du_max = value
def get_du_max(self, target_pressure):
"""根据目标压力计算 PID 最大增量限幅(纯 Python 线性插值)"""
x = float(target_pressure)
dt = float(self.dt)
if x <= 0.0:
val = 500.0 * dt
elif x >= 200.0:
val = 250.0 * dt
elif x <= 100.0:
# 0~100:从 500 线性下降到 300
val = (500.0 - 2.0 * x) * dt
else:
# 100~200:从 300 线性下降到 250
val = (350.0 - 0.5 * x) * dt
return val
def init_v(self, position_x):
v = (self.xa_full - position_x) / (self.xa_full - self.dead_area) * 100
return v