基于STM32的麦克纳姆轮全向移动小车:运动解算与闭环控制实战 1. 从四个轮子的转向逻辑说起为什么偏偏选麦克纳姆轮很多人做遥控小车第一反应是买一套普通的橡胶轮加差速转向底盘。便宜、好买、资料多听起来没什么毛病。但只要你真的把车放到地板上跑两圈就会发现一个很别扭的事想让车原地转个身得让左右轮反向转车是转了可它同时也在往前或往后画弧想让它像坦克一样原地打转普通轮子做不到。更别提横着平移这种动作了普通轮子想都别想。麦克纳姆轮解决的正是这个问题。它的轮毂上斜着装了一圈小辊子辊子轴线跟轮子平面成45度角。当轮子转动时地面给辊子的反作用力会分解成两个方向一个沿轮子前进方向一个垂直于轮子前进方向。四个轮子按特定方式组合就能把这四个方向的力叠加或抵消最终合成出任意方向的运动矢量。说白了它让底盘变成了一个可以全向移动的平台。我选它做这个项目核心动机有三个。第一全向移动本身就是个很有意思的运动学问题值得动手验证一遍。第二麦克纳姆轮小车的控制逻辑比普通差速车复杂正好用来练手嵌入式控制和运动解算。第三它做出来之后确实好玩横着走、斜着走、原地旋转视觉冲击力比普通小车强太多。但这里要先泼一盆冷水麦克纳姆轮不是没有代价的。它的辊子跟地面是点接触摩擦力比普通轮子小越障能力差稍微有点门槛或者地毯就卡住。而且辊子磨损快地面不平整时车会抖。所以它适合平整硬质地面比如瓷砖、木地板、水泥地。你要是想拿它去草地或者砂石路撒野趁早换方案。提示买轮子的时候注意区分左旋和右旋。麦克纳姆轮分左右两种一套四个轮子通常是两左两右装反了车会完全不受控。收到货先在地上滚一下看辊子斜向确认配对。2. 底盘机械结构从轮距轴距到辊子接触角2.1 车架尺寸怎么定别拍脑袋车架尺寸不是随便切块板子就完事。麦克纳姆轮的运动解算依赖轮距和轴距这两个参数它们直接影响速度合成关系。我建议先定轮子直径再反推车架。假设你用的是直径60mm的麦克纳姆轮那车架长度至少要能容纳前后轮中心距。我一般让轴距前后轮中心距离和轮距左右轮中心距离尽量接近这样四个轮子的受力比较均衡解算也简单。我的第一版车架是120mm×120mm的方形底板轴距和轮距都控制在90mm左右轮子边缘离板边留15mm余量避免转向时轮子蹭到车架。底板材料我用的是3mm厚的亚克力板。为什么不用铝板铝板强度好但加工麻烦要钻孔攻丝而且重。亚克力用激光切割或者手工锯都能搞定重量轻对电机负载小。缺点是脆螺丝拧太紧会裂所以我在螺丝孔位置加了橡胶垫圈缓冲。电机选型上我用的是TT马达加编码器版本。TT马达便宜、扭矩够、转速适中配1:48减速比空载转速大概200RPM。四个轮子独立驱动每个轮子一个电机。编码器用来做速度闭环后面控制部分会讲为什么这个很重要。2.2 电机座和轮子的装配细节电机座我用3D打印件因为TT马达的安装孔位是标准的网上有现成模型。打印的时候填充率给到40%以上不然电机一转起来座子会软。装配顺序是先把电机座固定在底板上再把电机卡进座子最后装轮子。这里有个坑麦克纳姆轮的轮毂孔位跟TT马达的输出轴不一定匹配。TT马达输出轴是双D形轴直径约5.5mm而很多麦克纳姆轮的轮毂孔是圆孔或者六角孔。我的做法是买轮子的时候直接选配TT马达适配的轮毂或者用联轴器转接。联轴器会增加轴向长度装的时候注意四个轮子伸出长度一致不然车会跑偏。轮子装好之后用手拨一下确认每个轮子都能自由转动没有卡顿。然后通电让电机慢速转观察四个轮子的转向。从车顶往下看左前轮和右后轮应该是一组右前轮和左后轮是另一组。具体转向关系后面运动解算会详细说。2.3 电源和配重的位置安排电源我用的是2节18650锂电池串联标称7.4V容量2500mAh。电池放在底板正中央偏后位置用电池盒固定。为什么偏后因为TT马达和轮子集中在四角中间偏后放电池可以让重心稍微靠后增加后轮抓地力减少急加速时前轮打滑。底板上还要放主控板和电机驱动模块。主控板我放在电池前方驱动模块放在主控板两侧。整体布局原则是重的组件电池放低放中间轻的组件主控、传感器放上层。如果空间允许可以加一层亚克力板做双层结构下层放电池和驱动上层放主控和扩展模块。配重这件事很多人忽略。麦克纳姆轮对重量分布很敏感四个轮子受力不均会导致某些轮子打滑运动解算出来的速度就不准。装完之后用手按一下四个角感受一下弹力是否一致。如果不一致挪一下电池位置或者加配重块。3. 运动学解算四个轮子转速到底怎么算3.1 先搞清楚车体坐标系和轮子编号在写代码之前必须先把坐标系定死。我定义车体坐标系X轴指向车头前方Y轴指向车体左侧原点在车体几何中心。四个轮子编号如下左前轮LF位于X正、Y正象限右前轮RF位于X正、Y负象限左后轮LR位于X负、Y正象限右后轮RR位于X负、Y负象限每个轮子的辊子方向决定了它转动时产生的力方向。标准麦克纳姆轮布局中左前轮和右后轮的辊子方向相同右前轮和左后轮的辊子方向相同两组互为镜像。3.2 速度合成公式的推导思路假设车体想要的速度是Vx前后方向、Vy左右方向、ω自转角度速度。每个轮子的线速度由三部分组成Vx分量、Vy分量、ω分量。因为辊子成45度所以Vx和Vy在轮子上的投影会有一个根号2的关系。我直接给最终公式推导过程网上很多但要注意符号约定。以左前轮为例V_LF Vx - Vy - ω * (L W)其中L是半轴距W是半轮距。其他三个轮子类似只是符号不同。完整公式V_LF Vx - Vy - ω*(LW) V_RF Vx Vy ω*(LW) V_LR Vx Vy - ω*(LW) V_RR Vx - Vy ω*(LW)这个公式的物理意义是每个轮子的转速是车体三个运动分量的线性组合。Vx让所有轮子同向转Vy让左前和右后反向、右前和左后反向ω让对角线轮子同向。注意不同资料里的符号约定可能不同关键是你要自己验证一遍。我的验证方法是假设Vx1Vy0ω0四个轮子应该同速正转车往前走。假设Vy1Vx0ω0左前和右后应该正转右前和左后反转车往左平移。如果实际转向不对把对应轮子的符号取反即可。3.3 从线速度到PWM占空比的换算算出来的是轮子线速度单位是米每秒。但电机需要的是PWM占空比。换算关系是PWM (V_wheel / (π * D)) * 60 / RPM_max * 100%其中D是轮子直径RPM_max是电机最大转速。比如轮子直径60mm电机最大转速200RPM想要轮子线速度0.2m/s那PWM大概是0.2 / (3.14 * 0.06) * 60 / 200 * 100% ≈ 31.8%实际写代码的时候我会把最大速度归一化到-100到100的整数范围然后映射到PWM的0到255。这样上层控制只需要给归一化速度底层负责换算。3.4 编码器闭环为什么不能省开环控制也能跑但麦克纳姆轮对速度一致性要求高。四个TT马达即使同型号实际转速也会有差异开环跑直线会慢慢偏。加了编码器之后每个轮子做PID速度闭环把实际转速反馈回来修正PWM四个轮子转速一致了车才能走直。我的PID参数是Kp0.8Ki0.15Kd0.05。这个参数不是通用的跟电机特性、轮子负载有关。调参的时候先把Ki和Kd设0慢慢加Kp直到轮子响应快但不振荡然后加Ki消除稳态误差最后加Kd抑制超调。编码器读数我用的是定时器正交解码模式每10ms读一次计数换算成转速。TT马达的编码器一般是11线减速比1:48所以轮子转一圈编码器输出11*48528个脉冲。这个数用来算转速。4. 主控与驱动电路从原理图到焊接4.1 主控板选型为什么不用Arduino UnoArduino Uno只有6个PWM引脚四个电机每个需要2个PWM方向调速一共8个不够用。而且Uno的中断资源有限四路编码器解码会吃力。我选的是STM32F103C8T6最小系统板也就是常说的“蓝板”。它有4个定时器支持正交解码PWM引脚也够多价格跟Uno差不多。如果你手头只有Arduino可以用Mega2560PWM和中断都够。或者用ESP32性能更强还带WiFi后面想加遥控扩展也方便。我选STM32是因为想顺便练一下寄存器配置和HAL库。4.2 电机驱动模块L298N还是TB6612L298N便宜、好买、资料多但压降大7.4V供电实际到电机可能只有6V左右而且发热严重。TB6612压降小、效率高、体积小但价格贵一点。我两版都做过第一版用L298N跑十分钟驱动板烫手后来换TB6612温度明显低很多。TB6612每个模块驱动两路电机四个电机需要两个模块。接线逻辑是VM接电池正极VCC接5V逻辑电源GND共地。每个模块的AIN1、AIN2、BIN1、BIN2接主控GPIO控制方向PWMA、PWMB接主控PWM引脚调速。STBY引脚接高电平使能。注意TB6612的VM和VCC要分别供电VM接7.4VVCC接5V。如果只接VM不接VCC模块不工作。我第一次就忘了接VCC查了半天以为模块坏了。4.3 电源分配和稳压电池是7.4V电机驱动直接接电池。主控需要3.3V或5V我用一个LM2596降压模块从7.4V降到5V给主控和编码器供电。LM2596效率一般但便宜好用。注意降压模块的输出电流要够主控加编码器大概200mALM2596标称3A绰绰有余。电源开关我放在电池和降压模块之间用一个自锁按钮。充电接口用XT60或者DC头看电池类型。18650电池盒我选的是带引线的焊接的时候注意正负极不要接反反接会烧降压模块。4.4 接线检查和上电测试焊接完成之后先不要装车把电路摊在桌上测试。步骤是万用表测电池电压确认7.4V左右不接主控只接驱动和电机给驱动使能信号看电机是否转接主控下载一个简单的PWM测试程序看四个电机能否独立调速接编码器读计数手动转轮子看计数是否变化全部正常后再装车这个顺序能帮你快速定位问题。如果电机不转先查驱动使能和PWM信号如果编码器不计数查接线和定时器配置。别一上来就装车拆起来麻烦。5. 遥控方案与操控手感调校5.1 遥控器选型PS2手柄还是手机APPPS2手柄便宜、手感好、按键多接收器是SPI接口接线简单。我用的是PS2手柄因为它的摇杆输出是模拟量适合做速度控制。手机APP方案需要加蓝牙或WiFi模块开发量大但界面灵活。如果你只是想快速跑起来PS2手柄是最省事的。PS2接收器接线DAT接主控MISOCMD接MOSICS接片选CLK接时钟VCC接3.3VGND共地。注意PS2接收器是3.3V逻辑接5V会烧。我第一版直接接5V接收器当场冒烟。5.2 摇杆映射到运动矢量PS2手柄有两个摇杆左摇杆控制前后左右平移右摇杆控制自转。映射逻辑是左摇杆Y轴 - Vx前后左摇杆X轴 - Vy左右右摇杆X轴 - ω自转摇杆输出范围是0到255中值128。我先减去128归一化到-128到127再除以128得到-1到1的浮点数最后乘以最大速度。死区设10避免摇杆回中不准导致车自己动。5.3 操控手感调校加速度限制和速度曲线直接映射摇杆到速度车会非常窜稍微推一点摇杆就猛冲。我加了两个处理一是速度曲线把线性映射改成二次曲线小摇杆量时速度变化慢大摇杆量时速度变化快。二是加速度限制每10ms更新速度时实际速度向目标速度逼近最大变化量限制在5%以内。这两个处理让操控手感好很多尤其是做精细平移的时候。你可以根据自己喜好调曲线参数和加速度限制值。我的经验是加速度限制在3%到8%之间比较合适太小了响应迟钝太大了还是窜。5.4 失控保护和急停遥控器信号丢失时车必须停下来。我在主控里加了信号超时检测超过200ms没收到手柄数据就把所有电机PWM设为0。另外手柄上设一个急停按键按下直接切断电机使能。这个功能看着简单但实际很重要。我测试的时候有一次手柄电池没电车直接冲出去撞墙轮子都撞歪了。加了失控保护之后就没再出过这种事。6. 实测中的坑与调优经验6.1 车走不直先查机械再查代码车走不直是最常见的问题。我的排查顺序是先看四个轮子是否都着地用手按四个角感受弹力再看轮子是否装正有没有歪斜然后看编码器读数是否正常四个轮子转速是否一致最后才查代码里的解算公式。我遇到的一次走不直原因是右后轮电机座打印件有点变形轮子跟地面不是垂直的跑起来往右偏。换了打印件就好了。所以机械精度比代码更重要别一上来就怀疑算法。6.2 平移时车头偏转轮距轴距参数不准横着平移的时候如果车头会慢慢偏转说明轮距和轴距参数跟实际不符。解算公式里的L和W必须用实际测量值不能拍脑袋填。我的做法是用卡尺量前后轮中心距和左右轮中心距精确到毫米然后填进代码。如果参数对了还是偏那就是四个轮子转速不一致。用编码器读数对比一下哪个轮子慢了就调它的PID参数或者加补偿系数。6.3 电机发热和电池续航TT马达连续跑十分钟以上会发热这是正常的但烫手就不正常了。发热原因一般是负载太大或者PWM频率太低。TT马达建议PWM频率在1kHz到5kHz之间太低会有啸叫和发热。我设的是2kHz。续航方面2500mAh电池跑跑停停大概能用40分钟。如果一直全速跑可能只有20分钟。想延长续航可以换更大容量电池或者降低最大速度。但注意电池重量增加会影响操控。6.4 地面材质对麦克纳姆轮的影响前面说过麦克纳姆轮挑地面。我实测下来瓷砖地面最好摩擦力适中辊子滚动顺畅。木地板也不错但要注意别刮花。水泥地摩擦力大但辊子磨损快。地毯直接卡死根本走不动。如果非要在摩擦力小的地面跑可以给辊子加一点硅胶涂层增加摩擦但会加速磨损。我的建议是就在平整硬质地面玩别为难它。7. 后续可以折腾的扩展方向这个底盘跑通之后能扩展的东西很多。我列几个我试过或者打算试的方向。第一个是加传感器做自动避障。超声波加红外配合全向移动避障路径比普通车灵活很多。第二个是加摄像头做视觉巡线麦克纳姆轮可以横着走巡线策略比差速车丰富。第三个是加IMU做姿态闭环让车在受扰动时自动修正方向。第四个是换更好的电机和轮子提升速度和精度。代码层面可以把运动解算封装成独立模块上层只给速度指令底层负责解算和闭环。这样换底盘或者换电机时上层代码不用动。我现在的代码结构就是这样移植性很好。最后说一个我踩过的坑不要一开始就追求完美。我的第一版车架是用纸板做的轮子用热熔胶粘的跑起来歪歪扭扭但它让我验证了解算逻辑和电路。第二版才换亚克力。先跑通再优化比一开始就精雕细琢效率高得多。