尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

智能车从跑飞到跑稳:PID闭环控制与差速转弯实战调参指南

智能车从跑飞到跑稳:PID闭环控制与差速转弯实战调参指南 做智能车尤其是参加竞赛或者自己捣鼓着玩最头疼的问题往往不是车跑不快而是跑不稳。直线跑歪、过弯甩尾、起步抖成筛子这些问题背后基本都绕不开两个关键词PID控制和差速转弯。我见过不少新手把车架装得很漂亮摄像头架得也很稳结果一下赛道就跑飞最后查来查去问题就出在控制逻辑和转向策略上。这篇内容就是给智能车新手准备的入门实操总结。我会把PID怎么让电机听话、差速怎么让车优雅过弯这两件事拆开讲清楚再合到一起给出可以直接抄的代码示例和调参流程。无论是准备全国大学生智能车竞赛还是自己在STM32上做一辆玩这篇文章都能帮你少走很多弯路。全程用大白话讲原理给的是可复现的代码和实测过的参数思路学完你至少能把车从“乱跑”调教到“规矩跑直线、稳定过弯”。1. 为什么小车跑不直先搞懂PID和差速转弯分别解决什么问题1.1 开环控制的坑你以为给了PWM轮子就会按你想的转很多新手第一次让小车动起来用的都是开环控制直接给电机一个固定的PWM占空比比如左轮给500右轮也给500然后就觉得车应该往前走。但事实是车跑起来不是往左偏就是往右偏速度越快偏得越离谱。原因很简单两个电机不可能完全一样就算型号相同绕组阻抗、碳刷磨损、机械阻力也会有差异。更麻烦的是电池电压会随着放电下降PWM给的占空比相同实际电机转速也会掉。还有地面摩擦力、轮胎打滑、重心偏移这些因素都会让“给多少PWM”和“实际转多快”之间产生偏差。开环控制等于闭着眼睛开车你告诉轮子“你该转这么快”但没有反馈确认它到底转了多快。所以要跑稳第一步就是把“开环”变成“闭环”。闭环的意思就是给电机加上反馈——通过编码器测出轮子实际转速然后和目标转速比较有误差就调整输出。而PID就是做这个“调整输出”的核心算法。1.2 PID管速度差速转弯管方向两者要配合PID负责的是“电机转速听不听话”它解决的是速度控制的精度问题。而差速转弯解决的是“车子往哪儿走”的问题通过让左右轮有速度差实现转向。这两件事看起来独立实际是强耦合的——如果PID没调好差速转弯时轮子速度响应慢车就会推头如果差速逻辑没设计好PID再好车也会在弯里画龙。打个比方PID像一个人的肌肉反应能力差速转弯像大脑的转向决策。肌肉反应快大脑下指令转30度车就能快速跟上大脑决策差该转大弯的时候只给了很小的轮速差反应再快也转不过来。反过来大脑给了足够的轮速差但肌肉反应迟钝轮速半天提不上去车还是会冲出赛道。所以这篇内容的思路就是先让肌肉听话再教大脑怎么转向。把速度环PID调稳再设计差速转弯策略配合起来就能让车既“听话”又“走位准确”。2. PID控制的核心思想与代码落地方案2.1 PID三兄弟P、I、D分别在干什么PID是比例Proportional、积分Integral、微分Derivative三个环节的合称。理解它的最好方式是把自己想象成在控制水温的人。比例P负责“看误差有多大”水温偏差10度你就把火力调大一点偏差3度就调小一点。P越大对误差的反应越猛但太大了会在目标值附近来回震荡水温忽高忽低。对应到电机上P太大会导致电机转速在目标附近上下抖小车运行时能听到明显的“嗡嗡”声。积分I负责“消除静差”如果只靠P水温到了99度差1度上不去因为这时P给的那点火力刚好和散热相等永远差这1度。I会把过去的误差累加起来只要一直有误差输出就不断增加直到把最后这点误差吃掉。但I太大容易超调水温冲到101度再回来对应到电机上就是转速冲过头再回落。微分D负责“看误差变化的速度”水温正在快速上升即使现在还有偏差D也会提前收火力防止冲过头相当于“刹车”或“阻尼”。D能显著抑制震荡但太大会放大噪声另一个问题是对编码器信号质量敏感稍微有点毛刺输出就乱跳。用公式表达位置式PID的输出是u(k) Kp * e(k) Ki * Σe(i) Kd * [e(k) - e(k-1)]这个公式后面写代码就是照它来的。2.2 位置式PID和增量式PID怎么选PID实现方式主要有两种位置式和增量式。两者的区别一句话就能说清位置式算的是“当前应该输出多少”的绝对值增量式算的是“这次比上次多输出多少”的变化量。增量式PID的输出是Δu(k) Kp * [e(k) - e(k-1)] Ki * e(k) Kd * [e(k) - 2*e(k-1) e(k-2)]实际输出为 u(k) u(k-1) Δu(k)增量式的好处是执行器收到的是增量变化不会出现大幅跳变对电机这种执行机构更友好而且就算PID暂时出问题输出也只是在小范围内变化不会直接给满PWM。它还有一个实用优点天然带积分截断效应系统只需要暂存最近两三次误差计算量小在STM32这种单片机上跑毫无压力。我的建议是智能车电机速度环用增量式因为输出是叠加式的起步柔和不冲转向环如果要用PID比如根据赛道偏差计算目标速度差位置式更方便因为你要的是一个明确的转向力度值。下面代码里我会把两种都写出来你直接按用途挑。2.3 从公式到代码一个可以直接抄的电机速度环直接上一个实用的增量式PID实现。前提你的车至少要有编码器能测速常见的接法是STM32定时器编码器模式读TIMx-CNT就能拿到脉冲数。typedef struct { float Kp; // 比例系数 float Ki; // 积分系数 float Kd; // 微分系数 int16_t err_now; // 当前误差 int16_t err_last; // 上一次误差 int16_t err_prev; // 上上次误差 int16_t output; // 本次应叠加的输出量 int16_t output_add; // 累计输出最终给PWM用的值 int16_t output_max; // 输出限幅 } IncrementalPID_t; void IncrementalPID_Init(IncrementalPID_t *pid, float kp, float ki, float kd, int16_t max) { pid-Kp kp; pid-Ki ki; pid-Kd kd; pid-err_now 0; pid-err_last 0; pid-err_prev 0; pid-output 0; pid-output_add 0; pid-output_max max; } int16_t IncrementalPID_Process(IncrementalPID_t *pid, int16_t target, int16_t actual) { pid-err_now target - actual; // 增量式PID公式 pid-output (int16_t)(pid-Kp * (pid-err_now - pid-err_last) pid-Ki * pid-err_now pid-Kd * (pid-err_now - 2 * pid-err_last pid-err_prev)); pid-output_add pid-output; // 输出限幅防止PWM给满或反向 if (pid-output_add pid-output_max) pid-output_add pid-output_max; if (pid-output_add -pid-output_max) pid-output_add -pid-output_max; // 误差移位 pid-err_prev pid-err_last; pid-err_last pid-err_now; return pid-output_add; }调用方式在定时器中断里读取编码器脉冲数作为实际转速然后调用IncrementalPID_Process得到输出值直接作为PWM占空比。注意输出限幅要根据你的PWM周期来比如PWM周期是999限幅就给800左右留点余量别在低速时就把PWM加满。位置式PID的实现更简单typedef struct { float Kp; float Ki; float Kd; int16_t err_now; int16_t err_last; float integral; int16_t output_max; } PositionalPID_t; int16_t PositionalPID_Process(PositionalPID_t *pid, int16_t target, int16_t actual) { pid-err_now target - actual; pid-integral pid-err_now; if (pid-integral pid-output_max) pid-integral pid-output_max; if (pid-integral -pid-output_max) pid-integral -pid-output_max; pid-output (int16_t)(pid-Kp * pid-err_now pid-Ki * pid-integral pid-Kd * (pid-err_now - pid-err_last)); pid-err_last pid-err_now; return pid-output; }位置式PID里积分项用的是误差累加和所以必须限幅否则积分饱和后车会疯掉——比如车堵住了误差一直很大积分累到一千多等障碍清除后车猛窜出去就是积分饱和的典型表现。3. 差速转弯的实现方法与转向策略3.1 差速转弯的几种做法固定比例、动态比例、PID外环差速转弯最常见的实现是打角的时候给左轮和右轮不同的目标速度。比如目标速度是600脉冲/控制周期要右转时左轮给700右轮给500。问题在于比例怎么定。固定的做法最简单写死偏置量。右转时左轮目标基础速度偏置右轮目标基础速度-偏置。优点是代码量少缺点是速度越快转弯越呆——低速时偏置可能过大导致转弯过猛高速时偏置又不够导致转不过弯。动态比例的做法是让偏置随基础速度变化高速时偏置加大低速时偏置减小。更精细一点可以按当前赛道曲率来算偏置。这个方案是多数智能车竞赛队伍的基础策略既能过弯又不至于在直道上乱抖。PID外环的做法是把差速转弯做成一个控制器摄像头识别赛道后算出当前位置偏差比如中线偏左多少个像素然后把这个偏差当作PID的输入输出作为左右轮的速度差。这个方案最灵活也是很多摄像头组强队的标准做法。后面章节会给这个“转向PID”的代码思路。3.2 常见赛道元素的转向策略直线、直角弯、回环、十字不同赛道元素其实需要不同的差速策略这是新手比较容易忽略的。直线保持左右轮目标速度一致误差修正交给PID自身的调节能力。不要在直道上还叠加转向PID否则车会在中线附近来回摆跑成“蛇形”。直角弯需要较大的轮速差和提前降速。直角弯路径很短如果不预先降速靠差速转向根本拉不过来车会直接冲出去。一般策略是检测到弯道特征后提前降低基础速度到原来的50%~60%同时把差速偏置拉大。回环环形弯轮的差速可以保持恒定但要考虑回环半径。回环半径小差速要加大半径大差速可以稍小。如果回环时车身明显向外甩优先加大差速而不是更大幅度降速因为降速太多会影响整体圈速。十字路口一般不需要特别处理差速保持直行即可。但如果车从斜侧进入十字可以稍微给一点纠偏差速把车身拉正。这些判断在代码里本质是图像处理状态机的事。这里先给结论差速策略必须配合赛道识别一起设计单独调PID没法解决所有弯道问题。3.3 速度环和转向环怎么配串级/级联思路很多参赛队用的“级联PID控制”其实就是串级PID外环是转向PID负责根据赛道偏差计算目标轮速差内环是速度PID负责让电机实际转速跟踪目标转速。外环输出作为内环目标的一部分。用代码表达就是// 转向外环输入赛道偏差输出轮速差 speed_diff PositionalPID_Process(steer_pid, 0, track_error); // 速度分配基础速度 转向补偿 left_target base_speed speed_diff; right_target base_speed - speed_diff; // 内环分别用两个速度PID控制左右电机 left_pwm IncrementalPID_Process(left_speed_pid, left_target, left_actual); right_pwm IncrementalPID_Process(right_speed_pid, right_target, right_actual);串级的好处是分工明确外环只操心“往哪儿走”内环只操心“走多快”互不干扰。新手最常犯的错误是只做一个速度环然后把转向命令直接叠加到PWM上结果转向PID输出稍大轮子PWM就变了速度环拼命去纠正两个环打起来车就抖了。正确的结构就是上面这样转向PID只改变目标速度不直接改PWM。目标速度变了速度环会去追自然而然完成差速这样两个环是父子关系而不是竞争关系整辆车才稳。4. PID调参实战从跑飞到跑稳的完整流程4.1 准备工作上位机、串口打印、底盘标定调参之前建议先把工具准备好。很多新手上来就盲调车跑起来看两眼觉得“差不多了”实际上差得很远。我的习惯是所有调参过程必须能“看到数据”。首选工具是VOFA或者匿名上位机这样的串口调试软件。把设定速度、实际速度、PID输出值这三个量通过串口以协议或者CSV格式发到上位机就能画出实时曲线。PID调试时看到曲线判断P、I、D该加该减一是直观二是少折腾车。对新手来说曲线对比目标值和实际值超调、稳态误差、响应慢这些信息一眼就看出来了。另外先做一个底盘标定把车用一个固定的PWM驱动读取编码器实际速度至少标5个点占空比20%、40%、60%、80%、100%。这样你能知道PWM和转速之间的近似关系比如目标转速800大概给多少PWMPID调参时的初始值心里有底。4.2 调参顺序和方法先P后I再D临界比例法调PID没有一步到位的公式但有固定的顺序先调P再调I最后调D。下面是我实测比较顺手的一套流程。第一步Ki和Kd先设为0只调Kp。从一个较小的值开始比如0.2或0.3设定一个目标转速看曲线。如果实际转速长时间够不到目标加大Kp如果实际转速在目标附近来回震荡减小Kp。找到“实际转速能快速逼近目标、但会有轻微震荡”的Kp值记为临界值。第二步保持Kp为临界值的60%~70%开始加Ki。Ki负责消除稳态误差。观察曲线如果实际转速稳定之后和目标有固定的偏差那就加大Ki。Ki加到“偏差消失、且不出现明显超调”为止。如果Ki太大曲线会明显冲过目标再回来反复一两次才能稳定这就是超调要减小。第三步加Kd。如果曲线在高频震荡或者响应太快导致轮子抖动Kd能帮上忙把曲线压平。Kd一般从较小的值开始加通常不会超过Kp的四分之一。如果编码器信号有毛刺Kd加大会适得其反这种情况需要先处理信号后面章节会讲。下面给一组我常用的速度环PID参考值适合编码器周期20ms、脉冲目标范围0-1000的场合参数经验范围作用说明Kp0.3~1.0决定响应速度过大会震荡Ki0.01~0.05消除稳态误差过大会超调Kd0.02~0.1抑制震荡过大会放大噪声输出限幅700/999防止PWM饱和打满这只是起步范围不同底盘、编码器分辨率、控制周期都会有差异。千万不要死记这些数要用上位机看曲线来定。4.3 几天实测总结的调参注意事项和坑调参这件事上手和踩坑是绑定的。我把个人实际调车过程中踩过的坑列出来新手能避开就直接绕开。第一坑控制周期不稳定。PID要求控制周期尽量固定否则参数没法收敛。新手容易把PID放在主循环里跑主循环里有图像处理、OLED扫描时间波动很大。正确的做法是放到定时器中断里或者用RTOS的固定周期任务保证每10ms或者20ms执行一次PID运算。第二坑编码器没滤波。我踩过这个坑编码器原始数据毛刺很大D项一加输出就开始乱跳。解决办法是加一个滑动平均滤波对最近5~10次的脉冲值取平均。滤波会带来一点延迟但对速度环来说这点延迟完全可以接受换来的是稳定输出。第三坑左右轮参数不一样。左右电机的PID参数最好分开标定因为两个电机的特性总有差异。先单独给左轮调一套再给右轮调一套最后上车联调。这样做虽然麻烦但直道跑偏的概率会大大降低。第四坑只用目测判断效果。记得你调的不是外观是数据。调完一组参数至少要让车跑三个来回看上位机的曲线确认无明显超调、稳态误差在可接受范围内、响应速度够快才算这组参数合格。5. 实战中常见问题与排查技巧记录5.1 小车一启动就抖或者嗡嗡响这是Kp太大或者D项异常的典型表现。判断方法是看PWM输出值如果输出在目标值两侧快速来回变大概率是Kp过大尝试把Kp直接砍半看效果。如果砍半还抖检查编码器数据先看波形是不是毛刺太多。还有一种情况是控制周期太短。如果控制周期只有5ms电机的机械惯性还没跟上PID就把误差当成响应不足继续加大输出造成抖振。这种情况要加长控制周期到10ms或20ms。5.2 直道始终跑偏怎么调都调不正先别急着改PID参数。直道跑偏的原因可能是两个电机特性不一致、重心偏左或者偏右、轮子安装有倾角。排查顺序是先静态推车看四个轮子是否都顺畅转动再用同一个PWM给左右轮看编码器的速度是否一致。如果开环状态下速度就不一样那是机械问题如果开环一致但闭环跑偏才是PID参数问题。另外检查左右轮的PID参数是否对称。我见过很多跑偏的车是因为左右PID调的精度不一样一个超调、一个响应慢方向就跑偏了。把左右参数尽量统一跑直道问题基本能解决。5.3 转弯推头或者甩尾推头转向不足的原因是过弯时轮速差不够大或者降速不够。处理办法加大差速偏置或者提高转向PID的Kp让转向环更积极地响应赛道偏差。甩尾转向过度则相反差速偏置过大导致后轮侧滑需要减小差速偏置或者降低入弯速度。速度不能一味降低否则圈速不行。正解是找到“当前速度下能稳定过弯的最小差速”——差速太小推头太大甩尾中间那段就是适合这辆车的窗口。这个窗口要靠实测不同弯道半径、不同路面材料窗口都不太一样。5.4 代码和参数记录的一些建议调参过程中最怕“这次调得好下次重启全忘了”。建议在代码里做一个参数结构体一组一组的存通过串口命令下发不用每次改代码烧录。比如从串口发送“P1.2 I0.02 D0.05”程序解析后直接把PID参数改掉这样调参效率会高很多。另一个技巧是加一个参数打印命令把当前所有PID参数、目标值、实际值、输出值一次性打印出来。每次跑完收车用日志工具保存下来下次对比参数效果这比靠记忆靠谱一万倍。我用这个方法最快的一次一个晚上就把新车从跑飞调到稳定过弯。6. 用PID模拟器快速积累手感再上真车如果你还没有实车或者不想每次都拆电池充电我强烈建议先用PID模拟器练手感。这类工具网上有不少有网页版的也有手机App功能都是模拟一个系统让你调Kp、Ki、Kd三个滑块实时观察响应曲线变化。这个练习方式特别适合新手建立参数直觉你会直观地看到“调大Kp曲线变快但震荡”“调大Ki消除静差但超调”“调大Kd压住震荡但噪声敏感”。这些感觉在真车上要试很多次才能建立但在模拟器上半小时就够了。上真车之后先用模拟器里比较接近的一套参数做起点再结合前面讲的“先P后I再D”流程微调。很多人问我为什么调参快其实很大程度是模拟器练出来的手感——看到曲线就知道下一步该动哪个参数、往哪个方向动。最后分享一个我个人的调参体会做智能车调PID心态比技术更重要。我的体会是不要追求一次调好接受“调参是一个逐步逼近的过程”。每次改一个参数跑到稳定记录再改下一个。一次只动一个参数是铁律同时动两个出了问题你根本不知道是哪个改坏的。还有一个习惯每次到一个新的场地先不要急着跑全赛道。先只跑直线确认直道稳定再只跑一个直角弯确认过弯不飘最后才拼全赛道。分段测试出问题能精确定位。这些习惯比任何PID公式都有用是真正能让车“跑得更稳”的东西。
返回列表