面向机器人控制系统的 PID 控制器模拟器
在这个 PID 控制器模拟器里,一边整定比例、积分和微分三个增益,一边把系统的响应、误差、饱和与扰动都画出来观察。
- 类别
- 控制系统
- 时长
- 60–120 分钟
- 平台
- 浏览器 · Arduino
01 / 从这里开始
简介
PID 控制贯穿整个机器人领域:轮速、航向、关节位置、温度和平衡系统都依赖反馈。这个项目把控制器变成一个看得见的实验。改变一个增益,扰动一下被控对象,再把由此得到的曲线与能在 Arduino 或嵌入式控制器上运行的代码联系起来。
Live lab / Deterministic sampled control loop
PID controller simulator
Drive a second-order plant toward a setpoint. Tune each gain, inject a load, and watch response, error, and control effort in real time.
Three stacked plots share a scrolling time axis: measured output against the setpoint line, tracking error around zero, and control effort inside the shaded actuator-limit band.
- Setpoint
- 1.00
- Measured
- 0.000
- Error
- 1.000
- Control
- 0.000
- Overshoot
- 0%
- Steady-state error
- 1.000
Keyboard: focus the plots, then use Space to run/pause, N to step, R to reset, G to toggle the load, and F for full screen.
控件
模拟器开放设定点、比例增益、积分增益、微分增益、采样间隔、执行器限幅和扰动幅值这几项参数。对齐的图表会显示设定点、测量输出、误差和控制输出。重置会清空控制器的记忆,让各次实验之间保持可比。
原理
反馈控制器用设定点减去测量值来算误差。比例作用立即响应,积分作用累积持续存在的误差,微分作用响应的则是变化率。三者之和就是执行器指令。
控制器的性能受被控对象所限。采样太慢会把运动藏起来;驱动超过执行器限幅就会饱和;而带噪声的测量会让未经滤波的微分项变得不稳定。因此调参是一场同时涉及控制器和被控对象的实验。
算法
- 按固定间隔读取测量值并计算误差。
- 用实际的时间步长累积一个有界的积分项。
- 由测量值或误差估计微分项,并施加相应的滤波。
- 把三项加权结果相加,并限制到执行器范围内。
- 施加指令、保存上一个样本,并记录各项指标。
- 当控制模式或被控对象发生明显变化时,重置积分项和历史记录。
源代码
这个实现包含一个简单的抗积分饱和条件:
float updatePid(float setpoint, float measured, float dt) {
const float error = setpoint - measured;
const float derivative = (error - previousError) / dt;
const float candidateIntegral = integral + error * dt;
const float raw = kp * error + ki * candidateIntegral + kd * derivative;
const float output = constrain(raw, outputMin, outputMax);
if (raw == output) integral = candidateIntegral;
previousError = error;
return output;
}
产品级的控制器还会为无效测量、定时器溢出、模式切换和执行器故障定义相应的行为。
假设与硬件差异
这里的被控对象是一个干净的二阶模型,质量、阻尼和延迟都由滑块设定——而不是一台带摩擦、带死区、扭矩随转速衰减、驱动器还会发热的真实电机。采样在构造上就是固定的,因此微分项始终表现良好;可是在 Arduino 上,delay() 或其他阻塞式工作会让间隔产生抖动,即使增益一点没改,D 项也会出问题。执行器饱和被建模为硬限幅并提供了抗饱和,但真实系统还有电流限制、电源压降和温升,它们会在运行中改变这个上限。先在这里把形状调好,再到硬件上去验证——在那里被控对象只是近似已知。
电路图
反馈传感器报告的是实际输出;它不能替代限流或硬件安全停机。控制器把设定点与调理后的传感器读值作比较,然后通过一个按负载额定选型的 PWM 级去驱动执行器。
引导实验
读到超调,跟刻意把超调造出来不是一回事。下面每个实验 都只需要几分钟,而且各自只隔离一个效应。
1. 找出临界增益
把 Ki 和 Kd 设为零。提高 Kp,直到输出以恒定幅度振荡——
既不增大也不衰减。记下增益(Ku)和振荡周期(Tu)。
首次整定只需要这两个数字:
| 控制器 | Kp |
Ki |
Kd |
|---|---|---|---|
| PID(经典) | 0.6 Ku |
1.2 Ku / Tu |
0.075 Ku Tu |
| PID(无超调) | 0.2 Ku |
0.4 Ku / Tu |
0.066 Ku Tu |
把这些值填进去对比。经典那一行很激进,会超调 20–40%;第二行落得稳而且不带超调,只是花的时间更长。两者都不算“正确”——它们是对不同要求给出的不同答案,而这正是重点。
2. 亲眼看积分饱和发生
把执行器限幅设得很低——大约在量程的 20%——然后给一个很大的设定点阶跃。 观察控制输出曲线:它立刻饱和并停在那里,而积分项还在不断累积它根本无力施加的误差。当输出终于到达设定点时,那些储存下来的作用力一次性释放出来,系统会冲过很远。
现在提高执行器限幅,用同样的增益再跑一遍。超调基本上消失了。 控制器本身一点没变——这就是要点。饱和是控制器与饱和执行器之间相互作用的属性,而不是增益的属性。
3. 证明杀死回路的是滞后而不是噪声
保持增益不变,把采样间隔从最低值开始逐级提高。响应在图表看起来还 不算噪声的时候就先变差了:超调变大,然后出现振荡,接着变得不稳定。
| 采样间隔 | 用原本不错的整定会看到 |
|---|---|
| 5 ms | 干净,跟整定一致 |
| 20 ms | 超调略多 |
| 50 ms | 出现明显振铃 |
| 100 ms | 持续振荡 |
| 200 ms | 不稳定 |
这就是为什么把机器人回路里的一个 delay() 去掉,往往比任何程度的调参都更能改善跟踪性能。过期的信息无法靠增益找回来。
4. 往微分项里灌噪声
先在 Kd 为零时提高扰动幅值,再提高 Kd。控制输出曲线在输出曲线
之前很久就变得参差不齐——你看到的就是微分运算在放大高频成分,它本来就该如此。
正是这种行为让人得出“D 项没用”的结论并把它设成零。真正的修法在上游: 对测量值做滤波,或者对微分项本身做滤波。
你应该观察到什么
| 设置 | 预期形状 | 如果你看到的不是这样 |
|---|---|---|
只用 Kp,取值低 |
缓慢上升,稳定在设定点之下 | — |
只用 Kp,取值高 |
超调、振铃、衰减 | 振荡不断增大说明你已经越过 Ku |
Kp + Kd |
快速上升,超调很小,稳态偏差很小 | 输出参差说明 D 项在放大噪声 |
Kp + Ki |
精确到达设定点,较慢 | 冲过头说明存在饱和或 Ki 太大 |
| 完整 PID | 快,超调极小,无偏差 | — |
只有 P、D 而没有 I 时的稳态偏差值得刻意造出来看一次。它最清楚地 演示了积分项到底是为了什么:比例作用必须有一个非零误差才能产生任何输出, 所以它必然会停在稍微差一点的位置。
硬件落地
在这里找到的增益是一个起点,而不是可以直接搬运的东西。能够完美搬运的是 整套流程;搬不过去的是那些数字,因为它们描述的是这里的被控对象。
| 这个实验台 | 真实机器人 |
|---|---|
| 采样间隔是精确的 | 除非你测量 dt 并把它传进去,否则会有抖动 |
| 被控对象是干净的二阶模型 | 摩擦、死区、随转速衰减的扭矩 |
| 执行器限幅是硬限幅 | 还有电流限制、电源压降和温升 |
| 不加就有传感器噪声 | 永远有噪声,而且很少是高斯的 |
| 被控对象永远不变 | 电池电压、负载和温度都会改变它 |
最后一行在实际中造成的困惑最多。一组在全新电池上完美的整定,到了快没电的 电池上就会变得迟钝,因为同一条指令现在产生的扭矩更少了。这并不是方法失效—— 增益是被控对象的属性,而被控对象变了。专业的做法是在下面加一层速度环, 或者做增益调度。把如何整定 PID 控制器的完整流程 走一遍,然后把它带到循迹实验台去,在那里被控对象会反击。
硬件清单
元器件
- 带稳定定时器的单片机
- 可测量的被控对象,例如直流电机或舵机
- 编码器、电位器或其他反馈传感器
- 按执行器额定值选型的输出驱动器
- 稳压电源和急停开关
探索关联图谱
哪里用到这个模拟器
以这个实验台为基础的项目、学习路线和教程。
继续搭建
下载资源
完成项目时可以参考本页上的这些资料。可下载的项目包只会在其源文件和版本发布之后才会添加。
常见问题
常见问题解答
应该先整定哪一项?
先把积分增益和微分增益设为零。提高比例增益,直到响应够用但带有振荡,然后加入微分阻尼。最后才加积分增益,而且只在仍然存在可重复的稳态误差时才加。一条常用的经验法则是:P 带来速度,D 减少超调,I 消除偏差——按这个顺序,一次加一项。
如何防止 PID 控制器超调?
超调通常来自过强的比例或积分作用。先降低比例增益,再提高微分增益,让趋近过程得到阻尼。如果超调只在执行器达到极限之后才出现,那么原因是积分饱和而不是增益,你应该对积分项做限幅。
为什么我的 PID 控制器会振荡?
持续的振荡几乎总是意味着比例增益对这个回路来说太高,或者微分项太弱,不足以提供阻尼。把比例增益降低大约一半,再加入微分增益。振荡也可能来自运行太慢或间隔不稳定的控制回路,这会让微分项变得不可靠。
什么是积分饱和,如何防止?
积分饱和发生在执行器已经饱和——电机全速运转、阀门全开——而累积的积分误差却还在不断增大的时候,于是当误差最终反向时,控制器会严重超调。防止的方法有限幅法(在输出饱和期间停止累加积分)和反算法(利用请求输出与实际输出之差,把积分值逐步泄放下来)。
PID 回路需要跑多快?
回路的采样速度应该比它所控制的系统快好几倍,而且间隔要稳定。在单片机上,要避免长时间的阻塞延迟:即使增益不变,间隔多变或过慢的回路也会改变实际起作用的积分项和微分项,这是整定效果差的一个常见隐藏原因。
PID 可以只用 P 和 D 两项吗?
可以。当可以接受很小的稳态误差、又想避免积分饱和时,PD 控制(不含积分)很常见;而 PI 控制(不含微分)适合信号噪声大的场合,因为微分项会放大噪声。只使用问题真正需要的那几项,而不是一律运行完整的 PID。
手动整定和 Ziegler–Nichols 法有什么区别?
手动整定是一边观察响应、一边一次调整一个增益,直观又安全,适合学习。Ziegler–Nichols 是一种基于公式的方法,它根据持续振荡的临界点推导出增益;它更快,但往往偏激进,所以它给出的结果通常只是一个起点,还要再手动微调。
延伸阅读
参考资料
权威资料,帮助你越过本模拟器有限的教学模型,进一步深入学习。