PID 自动控制 STM32 机电一体化 控制工程
前言
PID 是自动控制里最经典、也最容易"调翻车"的三参数控制器。很多人背了一大堆公式,却对"为什么增益大了就振荡"没有直观感受。
这篇文章不堆公式,用一个纯 Python、零第三方依赖的 PID 闭环仿真,在终端里改三个数(Kp / Ki / Kd),让你亲手看到阶跃响应曲线怎么变。你只要会跑 Python,就能跟着复现、改参、看结果。代码已开源(见文末)。
一、为什么要用"仿真"理解 PID
真实设备(电机、加热器、水箱)都有反应滞后和惯性,调参不对会振荡甚至损坏设备。而仿真可以随便试、反复看,是理解 PID
最快、最省钱的方式。本文的仿真对象是一个"一阶惯性 + 纯滞后"模型,用于近似真实的机电对象。
二、改三个参数,曲线立刻变
我用三组参数跑同样的阶跃(目标 = 100),对比极其明显:
正常参数 Kp=3, Ki=0.6, Kd=1.2,曲线平滑升到 100,几乎无超调:
- 上升时间(到 90%):5.18s
- 超调量:0%
- 调节时间(±2%):13.58s

调太小 Kp=0.5, Ki=0.02, Kd=0.1,太"肉",反应慢,25s 还不够:
- 峰值:51.9(远低于 100)
- 上升时间:未达到 90%

调太猛 + 带滞后 Kp=8, Ki=2, Kd=0, 纯滞后=3s,疯狂振荡,超调 55%,冲到 155,且永远不收敛,数值范围直接到 -93 ~ 167:

为什么第三个会炸? 因为系统有纯滞后(dead time):你的控制量隔一段时间才生效。等你觉得"太慢"拼命加增益时,上一波的控制
量还没消退,新一波又叠加,矫枉过正,来回横跳。工业上很多对象都有滞后,所以 PID 参数必须整定,不能随口拍。
三、核心代码
class PID:
def update(self, measurement: float) -> float:
error = self.setpoint - measurement
if self._first_sample:
self._prev_error, self._prev_measurement = error, measurement
self._first_sample = False
derivative = -(measurement - self._prev_measurement) / self.dt # 微分作用于测量值
output_unclamped = self.kp*error + self.ki*self.integral + self.kd*derivative
lo, hi = self.output_limits
if lo <= output_unclamped <= hi: # 抗饱和
self.integral += error * self.dt
output = self.kp*error + self.ki*self.integral + self.kd*derivative
self.output = max(lo, min(hi, output))
return self.output
四、怎么跑
需要 Python 3.8+(Windows 到 python.org 下载安装,勾选 "Add to PATH")。
python pid_demo.py
python pid_demo.py --kp 0.5 --ki 0.02 --kd 0.1
python pid_demo.py --kp 8 --ki 2 --kd 0 --deadtime 3
python test_pid.py
五、正确性说明
我写了 test_pid.py,断言验证:纯比例项正确、积分积累、闭环收敛到设定值、输出限幅、抗饱和。6 项全部通过(ALL 6 TESTS
PASSED)。
六、从仿真到真硬件
下一步计划把它接到真实设备:用 Arduino / ESP32 / PLC 驱动电机或加热器,把上面这套 PID 算法搬到单片机(C 移植),或让
PC 通过串口闭环。如果这篇对你有用,点个赞关注我,我后续更新"从仿真到真 STM32"的实操篇。
更多推荐
所有评论(0)