1. 平衡单车控制的核心挑战与串级PID的引入
搞过智能车平衡组的朋友都知道,让一个两轮小车站起来,本质上是在和物理定律做对抗。而当我们把场景换成“平衡单车”时,这个挑战的难度直接上了一个数量级。传统的两轮平衡车,重心低、轮距宽,姿态恢复的容错空间相对较大。但平衡单车呢?它只有一个前轮提供动力和转向,整个车体的平衡完全依赖于一个绕前轮轴旋转的自由度,重心高,惯性大,稍微一点扰动就可能让车体像倒立的钟摆一样无可挽回地倒下。这不再是简单的“不倒翁”问题,而是一个典型的不稳定、非线性系统控制难题。
为什么串级PID会成为解决这个问题的首选架构?这得从我们手头的传感器和控制目标说起。在平衡单车项目中,最核心的传感器通常是MPU6050这类六轴陀螺仪加速度计。它能给我们提供车体相对于惯性空间的角速度和加速度信息。我们的控制目标有两个层次:最内层、最紧急的是保持车体直立,也就是控制“俯仰角”;在这个基础上,我们还需要控制单车的前进、后退以及转向,以实现循迹等功能。这两个目标对控制器的响应速度和精度要求是不同的。直立控制要求极快的响应,任何微小的角度偏差都必须被立刻纠正,否则就是“秒倒”。而速度控制则相对缓和,它需要的是一个平滑、稳定的输出,避免因为速度环的剧烈波动干扰到脆弱的平衡环。
串级PID的精妙之处就在于,它将这两个环“嵌套”了起来。内环(通常是角度环)作为“保镖”,专注于以最高优先级维持车体不倒,它的输出直接作为外环(通常是速度环)的“期望值”的一部分。外环则负责实现更上层的运动意图。这种结构就像一个经验丰富的飞行员:他的大脑(外环)在规划飞行路线(目标速度),但他的双手(内环)会以毫秒级的反应去微调操纵杆,对抗气流扰动(角度偏差),确保飞机(车体)始终稳定在正确的姿态上。内环的快速响应为外环的稳定控制提供了一个坚实的基础平台。
在实际调车时,我深切体会到,理解串级PID中“串”的含义,比死记硬背PID公式重要得多。它不是两个独立PID的简单叠加,而是一个有严格主从关系的控制系统。内环的任何一个参数变动,都会直接影响到整个系统的动态性能。很多新手调参时觉得车“很神经质”,一会抖一会倒,往往就是因为没有理清内外环的职责边界,导致内环响应太慢撑不住车,或者外环指令太猛把内环搞崩溃了。
2. 从传感器数据到控制量:姿态解算与环路的建立
拿到MPU6050的原始数据(三轴加速度、三轴角速度)后,我们离能用的“角度”还有一段距离。这段路就是姿态解算。对于平衡单车,我们最关心的是俯仰角(Pitch)。直接用加速度计计算角度行吗?理论上可以,因为静止时,重力加速度在车体坐标系Z轴的分量与俯仰角有三角函数关系。但车子一动起来,特别是加速、减速时,会产生额外的线性加速度,这会严重污染加速度计的数据,导致计算出的角度严重失真。所以,单纯靠加速度计是绝对不行的。
这时就需要陀螺仪登场了。陀螺仪测量的是角速度,通过对角速度积分,理论上可以得到角度变化。但陀螺仪有零漂,积分会累积误差,时间一长,角度就会漂到天涯海角去。因此,实际工程中普遍采用互补滤波或更复杂的姿态解算算法(如Mahony、Madgwick滤波,或直接使用DMP库)。其核心思想是:用加速度计的数据来修正陀螺仪积分产生的长期漂移,用陀螺仪的数据来抑制加速度计在运动时的短期噪声。以最简单的互补滤波为例,它的代码可能就几行:
// 假设 gyro_y 是陀螺仪Y轴角速度(经过标定和单位转换),accel_angle 是由加速度计计算出的俯仰角 float dt = 0.001; // 控制周期,假设1ms float filter_k = 0.98; // 滤波系数,通常取0.98左右 // 陀螺仪积分得到角度 gyro_angle += gyro_y * dt; // 互补滤波融合 pitch_angle = filter_k * (pitch_angle + gyro_y * dt) + (1 - filter_k) * accel_angle;这个filter_k参数就是权衡信任谁的关键。取值越接近1,越信任陀螺仪(动态性能好,但会漂移);越接近0,越信任加速度计(静态准,但动态差)。对于平衡单车,因为需要快速响应,通常会更偏向陀螺仪一些(比如取0.98),同时依赖控制环本身来抑制残余的漂移。
得到可靠的俯仰角pitch_angle和俯仰角速度gyro_y后,我们就可以构建串级PID了。典型的平衡单车串级控制结构如下:
外环(速度环):
- 输入(反馈量):编码器测得的前轮实际转速
speed_real。 - 输入(设定值):期望的前轮转速
speed_target(可能来自遥控器指令或循迹算法)。 - 输出:一个“目标俯仰角”
pitch_target_speed。这个值的物理意义是:为了达到或维持某个速度,车体需要向前或向后倾斜的角度。比如,想让车加速前进,就需要让车体稍微前倾,利用重力的分力来提供加速度。
内环(角度环):
- 输入(反馈量):融合得到的实际俯仰角
pitch_angle和角速度gyro_y(角速度通常作为微分项D的输入,也可单独构成PD控制)。 - 输入(设定值):由外环输出的
pitch_target_speed加上一个可能存在的“平衡零点角”pitch_balance(即车体完全直立静止时的角度,可能不是0度)。 - 输出:最终的控制量,通常是PWM占空比,直接驱动电机。
整个数据流和控制流是:期望速度 -> 速度PID控制器 -> 目标角度 -> 角度PID控制器 -> 电机PWM。内环的运算频率通常要求比外环更高,因为姿态变化更快。例如,角度环1ms计算一次,速度环可以5ms或10ms计算一次。
3. 内环(角度环)PID的整定:快速与稳定的博弈
内环是平衡单车的“生命线”,它的调参直接决定了车能不能站起来,以及站起来后“稳不稳”。角度环通常使用PD控制,或者PID全用。其中,角速度gyro_y作为微分项D的输入,是抑制震荡、提高阻尼的关键,被称为“阻尼项”。
P(比例)项:P_out = Kp * (pitch_target - pitch_angle)这是恢复力。Kp越大,车体对角度偏差的纠正力就越强。但Kp太大,会导致车体在平衡点附近高频抖动,甚至引发共振直接翻车。调Kp时,我的经验是先把Ki和Kd设为0,用手扶着车,给一个小的角度偏差,观察电机是否产生正确的纠正力矩(车往前倒,电机应该正转使车轮往前追,试图把车拉回来)。然后慢慢增大Kp,直到松手后车能勉强站住,但可能会来回摆动(欠阻尼震荡)。
D(微分)项:D_out = Kd * (gyro_y_target - gyro_y),通常gyro_y_target为0。 这是阻尼力。它的作用是预测角度变化的趋势并施加反方向的力来抑制变化。Kd是抑制震荡的“神器”。当车体开始摆动时,角速度不为零,Kd会产生一个与摆动方向相反的力矩,让车体慢下来。Kd太小,车会摇摆不停;Kd太大,系统会变得“迟钝”,响应变慢,而且会放大陀螺仪的高频噪声,可能引起电机高频啸叫。调Kd就是在Kp已经能让车站住但摆动的基础上,逐渐增加Kd,直到摆动迅速平息,车体稳稳地锁定在平衡点。一个常见的技巧是,如果硬件支持,可以对陀螺仪数据进行低通滤波,以减少噪声对微分项的干扰。
I(积分)项:在角度环中,积分项Ki的使用需要非常谨慎。它的作用是消除静态误差。但对于平衡单车,其“平衡点”本身可能不是一个固定角度(比如为了维持速度需要轻微前倾),而且积分项会引入相位滞后,可能破坏稳定性。很多时候,角度环仅用PD控制就足够了。如果确实存在无法消除的微小角度偏差(比如由于电机死区或机械不对称),可以引入一个很小的Ki,但必须配合积分限幅,防止积分饱和导致控制失控。
注意:调内环参数时,务必确保车体机械结构紧固,轮胎抓地力良好,电池电量充足。一个松动的螺丝或打滑的轮胎,会让任何参数调试都失去意义。另外,一定要在软件里做好PWM输出限幅,防止参数设置错误时产生极大的输出烧坏电机驱动。
实测中的意外情况处理:有时你会发现,按照理论调出的PD参数,车在平地上很稳,但一到赛道起伏处或者启动加速时就倒了。这可能是因为Kd项依赖于角速度。在通过坡道时,车体角速度会有一个突变,如果Kd很大,可能会产生一个过大的反向力矩,反而破坏了平衡。这时可能需要根据实际情况动态调整Kd,或者在角速度信号进入D项前做更细致的滤波和处理。
4. 外环(速度环)PID的整定:赋予单车“目的性”
当内环调稳,单车能像不倒翁一样原地站稳后,我们就要赋予它“行动能力”,这就是外环——速度环的职责。速度环的输入是编码器测得的电机转速,输出是内环角度环的设定值偏移量。
速度环的核心作用:将抽象的速度指令,转化为具体的车身姿态调整。例如:
- 目标速度 > 实际速度:速度环PID输出一个正的角度偏移量,告诉内环:“请让车身稍微前倾”。车身前倾后,重力会产生一个向前的分力,驱动车轮加速,从而提升实际速度。
- 目标速度 < 实际速度:输出一个负的角度偏移量,让车身后仰,利用重力减速。
- 目标速度 = 实际速度 = 0:输出为0,内环只维持静态平衡角。
速度环PID调参要点:
先P后I,慎用D:速度环通常使用PI控制就够了。微分项D对速度噪声非常敏感,容易引入抖动。先从较小的
Kp_speed开始。Kp_speed决定了你想改变速度的“意愿”有多强。Kp_speed太大,会导致车体为了追速度而过度前倾/后仰,从而干扰内环的平衡,甚至直接拉倒整车。表现就是车在平衡点附近“前后窜动”。Kp_speed太小,则车速响应迟钝,加速慢。积分项I的重要性:速度环的积分项
Ki_speed非常关键。它的作用是消除稳态误差。比如,地面有轻微的坡度阻力,仅靠P项,可能需要一个永久的姿态角才能维持速度,这增加了内环的负担。加入Ki_speed后,它可以累积速度误差,输出一个持续的角度偏移,最终在某个特定的姿态角下,车的驱动力刚好抵消阻力,实现无静差的速度跟踪。调Ki_speed时,要观察车从静止加速到目标速度,以及稳速运行的过程,速度是否能够平稳且无静差地跟上。内外环的耦合与带宽:这是串级调参最精髓也最困难的部分。外环的响应速度必须显著慢于内环。这是稳定性要求。你可以把内环想象成一个反应极快的仆人,外环是下命令的主人。如果仆人反应慢(内环带宽低),主人下一个命令他半天才动,系统效率低下。但如果主人命令变得太快、太频繁(外环带宽高),仆人就会手忙脚乱,甚至执行了上一个命令的一半就去执行下一个,导致系统崩溃。
- 如何判断?如果调速度环参数时,原本稳定的单车开始出现高频抖动或周期性摇摆,这很可能是外环(速度环)的响应过快,其输出的角度指令变化频率接近甚至超过了内环(角度环)能稳定跟踪的带宽,引发了震荡。这时必须降低速度环的
Kp_speed和Ki_speed,让它的输出更“平滑”。 - 一个实用的调试技巧:先让速度环只输出一个很小的固定值(相当于给一个固定的倾角指令),看单车是否能稳定地匀速运动。如果能,再接入真实的PI控制器,从小参数开始慢慢加大。
- 如何判断?如果调速度环参数时,原本稳定的单车开始出现高频抖动或周期性摇摆,这很可能是外环(速度环)的响应过快,其输出的角度指令变化频率接近甚至超过了内环(角度环)能稳定跟踪的带宽,引发了震荡。这时必须降低速度环的
5. 上位机调试与参数整定实战流程
“盲调”PID参数是极其低效的。借助上位机软件(如VOFA+、SerialPlot、自己写的QT程序等)实时可视化关键数据,是智能车调试的“眼睛”。我们需要通过串口将单片机内的数据发送到电脑。
需要发送的关键波形包括:
- 实际俯仰角与目标俯仰角:观察内环的跟踪效果。
- 实际角速度:观察微分项的效果和噪声。
- 实际速度与目标速度:观察外环的跟踪效果。
- 最终PWM输出:观察控制量是否饱和。
- PID各分项输出(P_out, I_out, D_out):高级调试时用于分析哪个环节出了问题。
基于波形的调参实战步骤:
阶段一:内环(角度环)粗调
- 将速度环目标设为0,输出限幅设为一个很小的值(防止车冲出去)。
- 扶住车,用手施加一个小扰动然后松开,通过上位机观察角度恢复的曲线。
- 调
Kp_angle:目标是让车在松手后能往回走,即使有超调和震荡。曲线应表现出明显的恢复趋势。 - 调
Kd_angle:目标是抑制Kp引起的震荡。观察曲线,震荡次数应减少,回复过程变得更“干脆”,接近临界阻尼。
阶段二:内环细调与抗扰测试
- 让车在平衡点附近稳定。
- 用手轻轻、快速地推一下车(施加阶跃扰动)。
- 观察波形:车体角度偏离后,是否能快速、平稳地回到平衡点,且没有持续震荡或明显的过冲?如果不是,微调
Kp和Kd。 - 测试在不同初始角度放手时,车是否都能稳定站住。
阶段三:外环(速度环)引入
- 保持内环参数不变,将速度环
Kp_speed和Ki_speed设为0。 - 给一个很小的目标速度(比如0.1 m/s)。
- 调
Kp_speed:观察车是否开始缓慢而稳定地移动,实际速度能否跟随目标速度变化。如果车开始剧烈前后抖动,立即减小Kp_speed。 - 调
Ki_speed:让车在平地上匀速运行,观察实际速度与目标速度的稳态误差。逐渐增加Ki_speed直到稳态误差被消除。注意观察积分项是否在合理范围内累积,防止饱和。
阶段四:联合调试与性能优化
- 进行加速、减速、匀速测试。
- 观察在速度变化过程中,车体俯仰角的变化是否平滑?有没有因为速度环指令变化太快导致内环失稳?
- 尝试在赛道上跑动,观察过弯、上下坡时的表现。可能需要根据不同的运动状态(如转向时),对速度环的目标值或PID参数进行动态调整或前馈补偿。
踩坑实录:我曾遇到过车在直道很稳,但一到弯道就内侧倒的情况。通过上位机发现,在转向时,由于差速和离心力,车体实际姿态角会发生复杂变化。单纯的速度-角度串级控制无法处理这种耦合扰动。后来在速度环的输出上,叠加了一个与转向角速度相关的微小前馈补偿量,相当于提前给了一个抵抗离心力倾覆的“预瞄”指令,才解决了问题。这说明,串级PID是基础框架,但在复杂场景下,往往需要结合前馈、模糊控制等策略进行增强。
6. 超越基础串级PID:应对复杂场景的策略
当基础的串级PID能让你的平衡单车在平地上稳稳跑起来后,你会很快发现它在应对真实赛道时的局限性:启动加速太慢、刹车点头、过弯侧翻、坡道调节不力。这时就需要引入更高级的策略。
前馈控制(Feedforward):这是提升响应速度的利器。串级PID是反馈控制,它基于“误差”来行动,总是慢半拍。而前馈是“预测”控制。例如,在知道目标速度将从0突变到V时,我们可以直接给速度环的输出(即角度环的设定值)加上一个与V成正比的阶跃信号。这个信号不是基于当前速度误差算出来的,而是基于我们“知道”要加速这个命令。这相当于在反馈控制还没反应过来的时候,就提前让车体摆出了加速所需的倾角,极大地减少了加速延迟和超调。同理,在刹车、转向时也可以加入相应的前馈量。
变参数PID与模糊PID:一套固定的PID参数很难在所有工况下都表现最优。比如,高速运行时可能需要更“柔和”的参数来保证平稳,而低速或静止时需要更“强硬”的参数来对抗扰动。我们可以根据车速、姿态角误差大小等状态量,设计简单的规则来动态切换或插值计算PID参数。模糊PID则将专家的调参经验(如“如果误差为正且较大,则增大P”)规则化,用模糊逻辑在线计算参数,适应能力更强。
转向平衡耦合处理:这是平衡单车独有的难题。传统两轮车转向靠差速,对俯仰平衡影响较小。但单车转向时,车把转动会直接改变整车质心的投影位置,强烈耦合进俯仰动力学中。简单的处理方法是:在转向时,根据转向角速度,给角度环的设定值一个动态的补偿偏移,或者临时微调角度环的Kp、Kd参数,以增强抗侧倾能力。更高级的做法是建立包含转向自由度的动力学模型,进行解耦控制。
能量管理与防饱和:平衡单车是一个能量敏感系统。猛加速或上坡时,电机可能持续输出大PWM,导致电池电压骤降,进而影响控制芯片和传感器供电,形成恶性循环。需要在软件中加入能量管理策略,例如对总输出PWM进行限幅,或者根据电池电压动态缩放PID输出。同时,积分项的饱和(Windup)问题必须妥善处理,必须对积分项的输出进行限幅,并在某些条件下(如输出已饱和)停止积分,防止系统“失控”。
调车到最后,我个人的体会是,PID控制就像骑自行车本身,理论告诉你平衡的原理,但真正的“手感”需要在无数次摔倒和调整中获得。串级PID提供了一个清晰、强大的框架,但它不是万能的公式。最重要的永远是理解你的被控对象——你的这辆平衡单车——它独特的机械结构、传感器特性、电机响应。通过上位机仔细观察它的每一次“呼吸”和“颤抖”,理解数据曲线背后的物理意义,你才能从“调参数”进化到“与车对话”,最终让它不仅站得稳,更能跑得顺、转得灵,从容应对赛道上的一切挑战。