3. 基础回顾:运动控制核心——PID控制器原理与调参
聊导航调参之前,咱们得先把运动控制的老底子翻出来晒晒。PID控制器,说白了就是机器人底盘最底层的"肌肉反射"。导航规划层告诉它"往左转30度,跑1米",但具体怎么让轮子转、转多快、转稳不稳,全是PID在干。
我个人习惯把PID比作一个"纠偏员"。你给它一个目标值,它盯着实际值,一有偏差就动手往回拉。拉得太猛会过头,拉得太慢又跟不上。嗯,调参就是在找那个"刚刚好"的平衡点。
3.1 PID的数学本质:三个"纠偏动作"
先看公式,别怕,就一行:
u(t) = Kp * e(t) + Ki * ∫e(τ)dτ + Kd * de(t)/dt
拆开来看,三个分量各管一摊事:
| 分量 | 符号 | 它管什么 | 我见过的典型问题 |
|---|---|---|---|
| 比例 | Kp | 当前偏差有多大,就拉多大力 | Kp太小,机器人"懒洋洋";Kp太大,抖得像筛糠 |
| 积分 | Ki | 把过去的偏差攒起来,消除静差 | Ki过大,系统"记仇"过头,来回震荡 |
| 微分 | Kd | 预判偏差的变化趋势,提前刹车 | Kd太敏感,噪声一吹就乱跳 |
比例项是主力。偏差大就猛拉,偏差小就轻拉。但光靠它,系统永远到不了目标——因为到了目标附近,拉动力和阻力刚好抵消,就停在那了。这就是所谓的"静差"。
积分项就是来解决这个问题的。它把过去所有偏差加起来,哪怕偏差很小,时间一长积分值也够大,能推最后一把。但这里有个坑——积分饱和。我在项目里遇到过机器人启动时积分疯狂累积,结果冲过头好几米才刹住。后来加了积分限幅和条件积分,才算稳住。
微分项最有意思。它不看偏差大小,看偏差变化快慢。偏差在快速增大?它提前给反向力。偏差在快速减小?它收力防止过冲。说白了就是个"预见性刹车"。但微分对噪声极其敏感,传感器抖一下,微分项就炸了。所以我一般会在微分通道前加个低通滤波。
核心理解:三个分量不是独立工作的。它们像三个性格各异的队友——比例是"实干派",积分是"记仇派",微分是"谨慎派"。调参就是让这三个队友配合默契。
3.2 位置式PID vs 增量式PID
写代码的时候,你会遇到两种实现方式。我刚开始做运动控制时也纠结过,后来发现选哪个取决于你的执行器。
- 位置式PID:直接算出一个完整的控制量(比如PWM占空比)。输出和过去所有状态都有关,一旦积分饱和,输出可能飞到天上去。
- 增量式PID:只算当前控制量的变化量(Δu)。输出只和最近几次偏差有关,不会累积历史错误。电机驱动、舵机控制里用得最多。
给你看段我常用的增量式PID代码,简洁实用:
// 增量式PID,适合电机速度环
float pid_incremental(float target, float current) {
float error = target - current;
float delta_u = Kp * (error - last_error)
+ Ki * error
+ Kd * (error - 2*last_error + last_last_error);
last_last_error = last_error;
last_error = error;
return delta_u; // 返回的是增量,不是值
}
为什么我喜欢用增量式?因为它的输出天然带限幅保护。你想想看,每次只加一点点变化量,就算参数调得再离谱,输出也不会瞬间爆炸。这对机器人底盘来说太重要了——我可不想看到机器人突然原地起飞。
我的经验:速度环用增量式PID,位置环用位置式PID。速度环要求平滑响应,增量式天然抗积分饱和;位置环要求无静差,位置式积分项更直接。
3.3 调参方法论:从"抖"到"稳"的四个步骤
调参这事儿,网上有各种玄学。什么"先调Kp,再调Kd,最后调Ki",听起来像菜谱。但实际干活的时候,你得有套路。我总结了一套"四步法",在AGV和四轮差速底盘上都验证过:
- 先让系统动起来:Ki和Kd先置零,Kp从0慢慢往上加。加到系统开始出现等幅振荡(持续抖动),记下这个Kp值,叫临界增益Ku。同时记下振荡周期Tu。
- 引入微分压震荡:把Kp降到Ku的60%左右,然后加Kd。Kd从0开始加,直到系统抖动明显减弱。注意,Kd加太多会引入高频噪声,适得其反。
- 积分消除静差:Ki从0开始加,每次加一点,观察稳态误差是否消失。Ki加到系统开始出现低频振荡就停下,然后往回退20%。
- 微调收尾:给系统加个阶跃信号(比如突然给个目标速度),看超调量和调节时间。如果超调太大,加Kd或减Kp;如果响应太慢,加Kp或减Kd。
我曾经在一个差速底盘上遇到过死活调不稳的情况。Kp加到10就开始抖,Kd加到0.5就噪声爆炸。后来发现是编码器分辨率太低,微分项算出来的变化率全是噪声。换了高分辨率编码器,问题迎刃而解。所以调参之前,先确认你的传感器够不够格。
避坑指南:千万不要在系统还没稳定的时候就同时调三个参数。我曾经图省事,Kp、Ki、Kd一起改,结果系统直接发散,电机啸叫,差点烧了驱动器。一次只动一个参数,改完观察至少3个振荡周期。
3.4 PID与导航系统的"接口"
导航系统(比如ROS的move_base)输出的是速度指令——线速度v和角速度ω。而PID控制的是电机转速。这中间有个转换关系:
// 差速底盘:从v, ω 到左右轮转速
float v_left = (v - ω * wheel_base / 2) / wheel_radius;
float v_right = (v + ω * wheel_base / 2) / wheel_radius;
// 然后每个轮子各自跑PID速度环
float pwm_left = pid_incremental(v_left, current_left_speed);
float pwm_right = pid_incremental(v_right, current_right_speed);
这里有个容易被忽略的点:导航系统输出的v和ω是"期望值",但底盘实际能不能跟上,全看PID的响应速度。如果PID调得太慢,导航规划层以为机器人已经转弯了,实际还在直行——路径跟踪就崩了。
我一般要求速度环的响应时间在50ms以内,位置环在100ms以内。这样导航系统的控制周期(通常100ms)才能和底层运动控制合拍。
关键认知:导航调参和运动控制调参不是两件事。导航的路径跟踪精度,上限由运动控制的响应速度决定。你花三天调导航参数,不如花一天把PID调利索。
3.5 一张图看懂PID在导航中的位置
下面这张图是我自己画的,把PID放在整个导航-控制链路里看,你就明白它有多重要了:
从这张图你能看到,PID控制器是连接"导航大脑"和"底盘肌肉"的神经中枢。全局规划画好路线,局部规划算出速度,PID负责把速度指令变成实实在在的电机转动。任何一个环节掉链子,机器人就跑偏。
3.6 几个实战调参技巧
最后分享几个我在项目里摸爬滚打总结出来的技巧,不一定写在教科书上,但很管用:
- 先调空载,再调带载:空载时调好的参数,满载后Kp可能要加20%-30%。因为负载大了,系统惯性变大,同样的Kp拉不动。
- 用示波器看曲线:别光靠耳朵听电机声音。把目标值和实际值通过串口打印出来,画成曲线图。一眼就能看出超调、振荡、静差。
- 积分分离:偏差大的时候关掉积分,等偏差小了再开。这样既避免了积分饱和,又能消除静差。代码实现就一行if判断。
- 微分先行:只对反馈信号做微分,不对目标值做微分。这样目标值突变时,微分项不会产生冲击。我几乎所有项目都这么用。
一个小工具推荐:ROS的rqt_reconfigure可以动态调参。把Kp、Ki、Kd暴露成可调参数,一边跑一边调,实时看效果。比改代码→编译→运行快十倍。
好了,PID的基础就复习到这儿。记住一句话:PID调好了,导航调参才有意义。底盘不稳,再好的规划算法也是空中楼阁。