
做机器人小车有些年头了说实话“跑偏”这个毛病是新手问得最多的问题也是我自己早年调车时最头疼的问题。一辆小车放在地上让它直线往前走结果它总往一边画弧你以为是电机坏了换一个还是偏你以为是程序bug改了半天还是偏。最后折腾一晚上才发现是轮子直径差了那么一点或者左右两边的PWM占空比压根不一样。这篇文章就围绕“机器人小车总跑偏”这个具体症状把背后常见的几个环节挨个拆开讲清楚。核心围绕四层机械结构、电机驱动、控制算法、传感器反馈外加一套常用的调试工具链。无论你是刚入手STM32智能车、树莓派小车还是在做麦克纳姆轮底盘、差速转向底盘这套排查思路基本都通用。我会按排查顺序走一遍每层都会说明现象特征、判断方法、以及实操中容易忽略的细节帮你少走几趟弯路。先给出一个判断框架跑偏不等于某一个环节坏了而是多个环节叠加的结果。下面这张表是这几年调试中积累的“现象→嫌疑环节”快速索引后面每一条都会展开细讲。跑偏表现优先排查环节备选排查点起步瞬间猛拐一下然后慢慢直电机加速曲线、PWM死区电源瞬时压降、驱动板电流限制始终匀速画大弧方向固定轮径差异、重心偏移左右电机转速-占空比特性不一致直线走几秒后越来越偏编码器反馈不一致、PID积分未整定IMU零漂、里程计误差累积抖动跑偏声音“滋滋”响PID比例系数过大控制周期不稳定、滤波延迟过大转向后恢复直线出现回摆积分饱和、目标速度阶跃过大底盘运动学换算错误1. 机械结构天生的“长短腿”问题很多人一上来就怀疑程序但实际上机械层面的不对称是最容易被忽略、却最致命的跑偏源头。你可以把小车想象成人两条腿不一样长再怎么学走路也走不直。对小车来说“两条腿”就是左右驱动轮、底盘重心、悬挂和轮轴阻力这几个机械因素。1.1 轮子直径差异最隐蔽的“画弧元凶”同一个底盘左边轮子直径 65mm右边 66mm你可能觉得差 1mm 无所谓。实际跑起来转速相同的情况下直径大的轮子线速度更大单位时间走的距离更远小车自然向直径小的一侧转弯。我测试过一个两驱小车左右轮直径差了 1mm在 1 米长的直道上偏移了差不多 15 厘米。当时还以为是编码器问题后来用游标卡尺量了轮子才找到原因。怎么排查把左右驱动轮拆下来用游标卡尺测轮子外径重点测轮子接触地面的那一圈实际滚动直径。如果误差超过 0.5mm建议直接换同批次轮子。橡胶轮胎还有老化变形的问题新的和旧的混用跑偏更是必然。另一个细节是轮轴和轴承的阻力。左右轮轴承一个顺滑、一个涩滞即使电机转速指令相同阻力大的那侧实际转速也会被拖慢。判断方法把车悬空用手拨动两个轮子感受旋转阻力是否一致再把车放地上不供电沿直线推动如果它自己会偏向某侧说明机械阻力已经不对称了。1.2 重心偏移慢慢“压”出来的跑偏重心问题往往不会让新车一上电就偏但会在运行过程中逐渐显现。比如电池固定的位置偏左或者车身上加了摄像头、超声波模块却没有对称安装重心就不在几何中心上。重心偏移后左右轮的压地力不同摩擦力也产生差异跑起来会像“拖着一条腿走路”稳定跑偏。尤其底盘两侧有独立悬挂四个轮子都有避震时重心偏了一侧该侧弹簧被压缩更多底盘高度变化又会改变轮子的有效直径和接触角跑偏会更明显。排查方法把小车放在水平桌面上用手指轻轻压在车体中心位置试着推动车头观察车身是否“歪着走”。更量化的方法是分别抬起左右侧用电子秤称一下轮子对地的压力如果差异超过 10%就得重新布置电池和电路板的位置。1.3 底盘安装与车架变形一票否决项我见过一个同学的亚克力底盘装好电池和驱动板用了半年底盘中间那块板已经明显下凹。车架变形直接改变轮距和悬挂几何里外都调不好。还有底盘螺丝松紧不一致的问题。固定电机的螺丝一边拧得特别紧、另一边偏松电机的安装位置会出现微小位移齿轮啮合阻力也不同跑起来会有轻微的周期性跑偏。所以机械层的排查顺序建议是先目测车架是否水平、螺丝是否对称紧固再量轮径和轴距最后检查重心和轮轴阻力。这几步全都不涉及代码五分钟做完却可能解决一半以上的跑偏问题。2. 电机驱动左右手劲不一样大机械结构查完没问题下一个环节就是电机和驱动板。这层的问题核心是左右电机在相同的控制指令下实际输出转速却不一样。原因又可以细分为 PWM 占空比标定、死区差异、驱动板通道差异、电源压降几个方向。2.1 左右电机转速-占空比特性开环标定的必经之路同一个型号的直流电机参数也有离散性。它们在相同电压和 PWM 占空比下的空载转速可能相差 5% 甚至更多。如果你不接编码器直接给左右两个轮子相同的占空比比如 50%理论上期望它们转速一致实际上常常一边快一边慢。所以做底盘驱动时第一步要做的是“开环标定测试”接通电路后用串口调试助手或者简单控制程序分别给左轮和右轮施加一组 PWM 占空比从 10% 到 90%间隔 10%同时用编码器测量或者用测速仪测每个占空比下的实际转速记录成表格PWM占空比左轮转速rpm右轮转速rpm偏差30%1251185.6%50%2102033.3%70%2962921.4%从这张表就能看出低速段左右偏差明显偏大高速段反而接近。这就是低速时跑偏严重、高速时反而好一点的原因之一。解决方法有两种。一是软件补偿在程序里建立一张“占空比→目标转速”的映射表让两边各自按表输出不同的 PWM。二是上闭环给左右轮分别装编码器用 PID 速度闭环直接让左右轮转速等于目标值。第二种是工程上最靠谱的方案后面控制算法部分会详细讲。2.2 PWM 死区低速时左右手劲不一致的放大器直流电机存在启动死区——PWM 占空比太低时电机力矩不足以克服静摩擦和转子惯性根本不会转。这个死区阈值对于左右电机来说很可能不一样。比如左轮 15% 占空比就能转右轮要 18% 才转。那么你在程序里给一个 15% 的极小速度指令期望两边慢慢前进结果左轮动、右轮不动车直接原地画弯。这种现象在缓慢行走模式、原地转向微调时特别明显。排查时在开环标定测试里记录“最小启动占空比”如果两边差异超过 3 个百分点要么更换电机要么在软件里做一个“死区补偿”低于阈值的指令直接映射到阈值保证两边动作一致。还要留意电机减速箱的齿轮润滑状态润滑不良会让死区阈值变大。2.3 驱动板与电源压降看着是软件问题实则是硬件问题驱动板的两个通道输出能力也会有差异。同样用 TB6612、DRV8833 这类驱动芯片两个 H 桥的 MOS 管导通电阻、散热条件不完全一样大电流时产生的压降就不同左右电机实际电压也就不同。更常见的坑是电源线和接线端子。左右电机的电源线一根长一根短或者端子接触不良大电流时线路压降差异会非常明显。我试过一次跑偏排查所有东西都没问题最后发现是电池到驱动板的一根杜邦线内部折断了连接着右电机供电接触电阻忽大忽小车一会儿直一会儿偏。排查建议用万用表分别量驱动板输出端给左右电机的实际电压尤其是在电机堵转或大电流时对比。或者把左右电机驱动线对调如果偏向反过来了说明硬件通道问题坐实。3. 控制算法PID 不是“抄参数”就完事机械和驱动都正常左右轮也能精确输出相同转速了这时候还跑偏问题就转移到控制算法上。很多新手拿到 PID 直接网上抄一组参数结果车不是振荡就是“画龙”第三件事就是怀疑传感器坏了。其实玩转 PID三句话就能归纳Kp 管“则”不跑偏Ki 管“残余误差”Kd 管“别过头”。3.1 PID 调试顺序从比例开始一步步来我给小车调速度闭环时习惯先全部清零只设一个非常小的 Kp比如 0.1然后给一个固定目标速度比如 0.2m/s观察响应。如果转速达不到目标且有明显稳态误差——比如实测只有 0.15m/s——就加大 Kp。Kp 越大转速越接近目标但超过临界值后转速就开始围绕目标值来回振荡甚至发出尖锐的电机鸣叫声。这时候再加 Ki。Ki 的作用是消除稳态误差Kp 已把速度拉到接近目标但差一点Ki 会一点点补足这个差值让误差归零。Ki 在爬坡、负载变化时特别关键但也最容易引起“超调回摆”——速度越过目标后又冲回来来回几次才稳定车走起来像喝醉了。Kd 是速度环里用得最少的因为编码器反馈本身有噪声Kd 一大会放大噪声效果适得其反。如果你用的是陀螺仪/IMU 航向闭环Kd 才有实际的阻尼价值。调试时有个技巧用串口调试助手把目标转速、实测转速、PID 输出这三个变量以固定频率打印出来。观察曲线比肉眼盯着车跑要准确得多。3.2 积分饱和为什么一松手就转圈积分饱和是个极容易踩的坑。假设小车被卡住或者正以大力矩加速目标速度 0.3m/s实际却一直达不到PID 的积分项会持续累计一个很大的值。等障碍解除或车动起来后这个大积分输出一送车会猛地冲出去甚至原地打转。解决积分饱和的标准做法是限幅给积分项设一个最大最小值比如最大 20最小 -20或者做“积分钳位”只有输出在限幅范围内时积分才累加。对于跑偏问题积分饱和体现为直线走得好好的突然收到一个转向指令再松开车会朝一个方向额外多转一点——这就是积分项没有清零导致的“余尾”。所以做小车转向控制时转向执行完记得把该轴的积分项清零做速度闭环时给目标突变前也应把积分项复位。3.3 差速运动学换算直线不是“左右 PWM 相同”那么简单很多人在做差速小车时以为“直行 左右轮 PWM 相同”。这个想法在低速均匀负载下勉强成立实际中却不一定。因为转向时给定的角速度、线速度需要换算到左右轮各自的目标转速换算公式是左轮目标速度 线速度 - 角速度 * 轮距 / 2 右轮目标速度 线速度 角速度 * 轮距 / 2如果你的目标速度换算错了或者轮距写错直行时就等于给左右轮设了不同的目标速度车自然跑偏。轮距要用“左右轮中心到中心”的距离差一厘米长时间运行累积的偏向会特别明显。这里最容易踩的坑是用麦克纳麦轮全向轮时也要做运动学分解但公式和普通差速不一样。直行时四个轮子的转速”合成”后才能保证直线任意一个轮子的映射关系写错就会出现斜着走甚至原地旋转的诡异表现。4. 传感器反馈测不准才是原罪如果你已经确认机械没问题、驱动一致、PID 也调好了剩下的跑偏源头十有八九是传感器“测不准”。对跑偏影响最大的两个感知设备轮速编码器和航向传感器陀螺仪/IMU。4.1 霍尔编码器极对数配错导致测速差一倍霍尔编码器常见的有 13 极对、20 极对等规格代码里CPR参数每圈脉冲数写错的话实际测出来的转速就会和真实值相差数倍。左右轮如果配置错误会导致一边看起来转得快、一边转得慢PID 就会拼命调整真实转速去迁就错误测量车自然跑不直。有一个更隐蔽的坑编码器 A/B 相接线反了。虽然很多程序可以反向计数但如果你没做方向适配左右轮一个加数一个减数PID 控制直接紊乱。排查时先把车悬空用手慢慢转动左轮和右轮用串口助手打印编码器计数。两个轮子的数值应同方向增加且大小和手转速度线性匹配。4.2 陀螺仪/IMU 安装位置和数据滤波如果小车有航向闭环比如用陀螺仪维持直线那 IMU 的安装位置就特别讲究。芯片必须尽量靠近车体几何中心且 Z 轴垂直于底盘平面。装歪哪怕几度航向角输出就会有常数偏差小车会朝着一个固定方向慢慢转弯。传感器数据如果不做滤波波形会带毛刺。但滤波太激进又会导致相位延迟控制上表现为“转过了才发现偏了”的滞后跑偏。折中方案是滑动窗口平均窗口大小选 10~20 个数据点或者用轻量级低通滤波截止频率选 20~30Hz兼顾平滑和实时性。我踩过的一个坑是 IMU 供电电压不稳。陀螺仪对电源纹波很敏感电压波动会在航向角上叠加周期性噪声车走起来像“蛇形前进”。给 IMU 单独加 LDO 或滤波电容后现象立刻消失。4.3 里程计标定跑得越远偏差越大没有航向传感器的小车走直线靠的是左右轮编码器计数一致。但编码器本身也有误差加上轮子打滑、轮径误差里程计会随时间累积漂移。表现为刚启动时走得很直跑十几米后渐渐偏离。解决方法是做“里程计标定”让小车跑一段已知长度的直线比如 10 米用卷尺量实际位移与编码器累计位移算出一个比例系数。把左右轮的比例系数分别标定到一致能显著延长“走直线”的有效距离。更高级的做法是用 UWB、视觉标签或者磁条做全局修正这个属于后续扩展方向但初级阶段的里程计标定绝对值得做好。5. 调试工具链用对工具才能定位问题写代码、调小车这些年靠肉眼去“看”跑偏效率极低。真正高效的做法是利用串口、波形、日志等调试工具把看不见的数据“拉”出来看。这套工具链的熟练程度决定了你排查跑偏问题的速度。5.1 串口调试助手最基础也最刚需排查跑偏时我用串口助手打印四个关键数据左右轮目标转速、左右轮实测转速、PID 输出、航向角如果有。打印频率 50~100Hz 即可别太高否则串口会阻塞主循环。打印格式建议带时间戳和标头方便后期分析[100ms] L_target:20.0 L_real:19.6 R_target:20.0 R_real:20.4 L_PID:12.5 R_PID:-8.2 yaw:0.05串口助手里SSCOM、正点原子串口助手这类软件都够用。注意波特率、换行符\r\n还是\n要跟单片机打印格式一致否则显示乱码。数据量大时不要用“显示模式”肉眼看打开“保存到文件”功能事后用 Excel 或 Python 画曲线分析。有一段时间我用 win11 的 windbg 双机调试调试上位机程序也踩过波特率配置不一致导致调试失效的坑。5.2 上位机波形从“看现象”到“看数据”的思维转变串口助手适合打印数值但看趋势和波动不够直观。这时候需要用上位机绘图工具。我常用的方案里VOFA 是免费且好上手的它的“JustFloat”协议可以把单片机发来的 float 数组实时画成波形左右轮速度曲线、PID 输出曲线一目了然。具体做法是在单片机里按固定格式发送数据帧比如帧头 左轮速度 float 右轮速度 float PID 输出 float。VOFA 收到后自动绘图。这样跑偏时一眼就能看出是“左轮 PI D输出爆了”还是“右轮反馈一直跟不上”还是“两个轮子都在正常响应但车还是偏”。我印象很深的一次调一辆四驱麦克纳姆轮小车出发时是直的跑 3 秒后开始斜向漂移。用 VOFA 看四个轮子的转速才发现其中一个轮子的反馈信号周期性跌落原因是编码器焊点虚焊。这种问题用肉眼观察车体几乎不可能定位但波形极其明显。5.3 仿真与在线调试工具别直接照搬参数现在网上有不少“PID 在线调试网站”和仿真工具用虚拟模型演示 PID 参数变化对系统响应的影响。这类工具对理解 PID 的“脾气”很有帮助建议第一次接触 PID 的人先去点一点直观感受比例、积分、微分各自的效果。但一定注意仿真参数不能直接照搬到真车。真车有电机力矩饱和、底盘柔性、编码器噪声、通信时延仿真里完美稳定的参数上实车可能直接振荡。仿真的价值在于“理解规律”实车调参还得靠串口和波形。另一个工具方向是系统日志回放。比如在 Linux 小车树莓派、Jetson 系列上可以把传感器数据和控制输出写入日志文件跑一圈回来再离线分析。跑偏问题通常偶尔出现一次抓不住现场的话日志回放就是最好的“事后监控”手段。最后再分享一个小经验把所有改动记录成版本号每次只改一个变量。这句话听起来像废话但踩坑多了就明白它的分量。我曾经调一辆两驱小车同时改了 PID 参数、换了新轮子、又调整了重心位置结果车还是跑偏我根本没法判断到底哪个改动起了反作用。后来老老实实回到“每次只改一项改完立刻验证”的节奏问题很快定位到姿态传感器安装角度上。跑偏排查的本质不是找到“一个原因”而是把机械、驱动、控制、反馈这四个环节当成一根链条逐个排除。机械上看轮径和重心驱动上看 PWM 和电源控制上看 PID 和运动学换算反馈上看编码器和 IMU。配合串口助手观察数据、上位机绘制波形跑偏这个问题其实是机器人调试里最容易“系统化解决”的。如果你也正好卡在某辆小车跑偏的问题上照着这个顺序过一遍大概率能省下好几个晚上。