拓冰建站拓冰建站
首页 / 资讯中心 / 正文

STM32麦轮小车底盘控制与蓝牙小程序遥控全解析

简介本资源是一套面向嵌入式开发者与机器人爱好者的一体化麦轮小车底盘控制方案聚焦STM32平台下的运动控制实现与小程序远程交互解决多轮协同驱动不丝滑、运动学建模难、PID调参无依据等典型痛点。压缩包含470个文件15.09MB主体为80余个C/H源文件驱动与算法核心、80余个编译中间文件.o/.d、78个调试符号文件.crf及微信小程序端的JS/WXML/WXSS代码覆盖底层外设配置、编码器数据离散化处理、麦轮运动学逆解公式实现、增量式PID闭环控制、上位机指令解析与执行全流程。已有148人学习下载配套博客《如何获得一个丝滑的麦轮底盘》深度剖析运动学推导与代码逻辑所有关键函数均附详细中文注释便于理解底层原理并快速移植调试。 麦轮小车底盘配上STM32做底层控制再搞个小程序当遥控器这套组合在智能车DIY圈子里一直很热。我把整套代码逻辑和控制端方案整理了一下包括底盘运动学拆解、STM32控制代码怎么写、PID闭环怎么调还有小程序端怎么通过蓝牙把指令送到小车把踩过的坑和关键参数都放在里面给准备自己做一台或者正在调车的朋友一个完整的参考。这套方案解决的核心问题就是如何用STM32稳定驱动四个麦克纳姆轮实现平移、旋转、斜向运动这些全向移动能力同时让手机小程序成为低门槛的遥控终端不需要专门做遥控器硬件也不用学复杂的上位机。硬件上就是主控板加电机驱动、编码器电机、蓝牙透传模块代码端分成底盘控制逻辑和通信协议两部分只要按步骤移植配置基本都能跑起来。适合的人群有两类一类是已经会点STM32基础、想做全向底盘但是不知道怎么组织代码的同学另一类是正在做机器人竞赛或项目原型需要快速验证麦轮运动控制同时需要一个方便演示的手机控制端。下面按照整个项目的拆解顺序来写从原理到代码再到排查一步一步来。1. 项目整体设计与思路拆解1.1 为什么选麦轮而不是普通轮子先聊清楚一个基础问题麦轮底盘的优势到底在哪。普通两轮差速底盘靠左右轮速差实现转向前后运动没问题但横向移动做不了想横着走必须倒几把方向。麦轮不同它在轮毂周围斜向分布了一圈无动力辊子辊子与轮轴的夹角通常在45度这样电机驱动轮子转动时地面给轮子的摩擦力方向会和轮子前进方向呈斜角通过四个轮子的不同组合转动就可以让底盘在平面上获得三个自由度前后平移、左右平移、自旋而且这三个动作可以同时叠加实现任意方向的平滑运动。四个麦轮的排布方式需要说明一下。标准配置是四个轮子的辊子方向呈X形或者O形布局常见的是左前轮和右后轮辊子方向一致顺时针右前轮和左后轮方向一致逆时针。控制的时候如果四个轮子同向同速转动车就前后走左前右后正转、右前左后反转车就横移左前左后正转、右前右后反转车就原地旋转。运动学解算的核心就是根据你期望的车体速度vx, vy, omega分别算出四个轮子的目标转速再交给电机去执行。这地方我提醒一句麦轮对地面平整度比较敏感在粗糙地面上辊子磨损快而且四个轮子之间不能有打滑一旦打滑就会产生额外的漂移分量。所以底盘的悬挂和重心分配要尽量对称四个轮子尽量同时着地且压力接近这样才能保证运动学解算出来的速度是准的。1.2 系统架构STM32作为底盘控制核心这个项目的整体分工很明确STM32负责底层闭环控制和运动学解算手机小程序只负责发指令和显示状态。控制器实时性要求高不能有任何延迟抖动所以放到单片机端小程序跑在系统上生态成熟、开发快负责把摇杆或按键操作转成具体的速度数据通过蓝牙透传发给STM32。具体硬件链路是手机小程序设定目标速度和转向数据 → 蓝牙透传模块HC-05/HC-06或BLE模块 → STM32串口接收 → 运动学解算得出四个轮子的目标速度 → 编码器读取当前速度 → PID闭环调节PWM占空比 → 电机驱动模块MOS管H桥或专用驱动芯片 → 直流减速电机。主控我用的STM32F103C8T6也就是最常见的蓝丸板性价比很高。四个电机需要4路PWM输出和4组方向IO再加上4路编码器信号用定时器的编码器模式可以直接捕获正交信号不需要外部中断频繁进中断节省大量CPU时间。选择这个芯片的原因还有一点它可以直接用STM32CubeMX做初始化配置生成HAL库工程省掉自己手写寄存器的麻烦。如果你手头是STM32F407或者G431也没问题逻辑完全兼容只是引脚和定时器资源分布不同。1.3 控制端选型小程序为什么比遥控器更合适控制端我用微信小程序做主方案不是别的就是因为它开发和分发成本最低。小程序不需要安装App微信扫一扫就能打开用蓝牙API直连小车延迟在可接受范围内。相比自己拿2.4G遥控器配合接收机小程序的UI可以做得更丰富——虚拟摇杆、模式切换按键、电池电压显示都能塞进同一个界面改UI不用动底层代码重新编译上传就行。小程序端另外一个独特的优势是跨平台。无论是安卓还是iOS只要微信版本支持蓝牙API就能用不像原生App需要分别开发两套。它调用的是 wx.openBluetoothAdapter、wx.startBluetoothDevicesDiscovery、wx.createBLEConnection 这套蓝牙低功耗BLE接口配合一个BLE转串口透传模块比如JDY-08或HM-10就能实现和STM32串口的数据收发。注意如果用的是HC-05这种经典蓝牙走的是SPP协议小程序不支持经典蓝牙必须用BLE模块。这是我第一次踩坑的地方买模块前一定确认是BLE4.0以上。2. 核心细节解析与实操要点2.1 STM32端控制代码模块化设计拿到一个麦轮小车底盘项目代码千万不要直接梭哈写成一个main.c。按照功能模块拆分开调试的时候会省心很多。我习惯分成这几个模块运动学解算kinematics.c、电机控制motor.c、编码器读取encoder.c、PID控制器pid.c、通信处理protocol.c每个模块职责单一接口清晰。先说运动学解算这个核心模块。它的输入是车体的目标速度vxvyomega输出是四个轮子的目标角速度或线速度具体转换公式是wheel1 vx - vy - omega * (L W) wheel2 vx vy - omega * (L W) wheel3 vx vy omega * (L W) wheel4 vx - vy omega * (L W)注意这里正负号取决于你的麦轮安装方向和辊子朝向排列不同时公式需要调整正负号。L是车体中心到前后轴的距离W是车体中心到左右轮的距离omega乘以(LW)是为了补偿旋转时不同轮子的线速度差异单位要保持一致速度用m/s的话角速度用rad/s。解算完得到的是四个轮子的速度目标值接下来交给PID做速度闭环。电机控制和编码器读取是伴生的两个模块。PWM输出用定时器产生频率我一般设为10kHz左右太高开关损耗变大太低电机会有啸叫。方向IO用普通GPIO控制逻辑电平配合驱动模块的IN1/IN2实现正反转。编码器用定时器的编码器模式STM32的定时器可以直接处理正交编码信号自动计数带方向不需要额外判断相位这样能精确测量每个轮子的实际转速测得的脉冲数经过换算就能得到轮子的线速度。通信处理模块要定义好帧格式。因为蓝牙串口传过来的是字节流如果没有协议接收端很容易出现粘包、丢字节、混乱。我用的协议格式是帧头(0xAA) 命令字 数据长度 数据体 校验和校验用简单累加就行保证传输可靠。在中断里收字节通过状态机判断当前处于帧头、长度、数据还是校验阶段收满一帧之后放到环形缓冲区主循环里解析命令。这样设计的好处是即使发生丢帧或者错位最多丢弃一帧不会影响后续数据。2.2 基于PID的麦轮速度闭环调节麦轮底盘不像普通车那样能跑就行它要全向运动四个轮子的速度必须精确匹配否则就会出现车体歪斜、旋转半径不准确。开环PWM控制温差一大就容易左右不对称所以必须加编码器负反馈做PID速度闭环。PID控制器的标准形式是输出 Kp × 误差 Ki × 误差积分 Kd × 误差微分。在数字系统中是离散化的每个控制周期我一般用10ms执行一次读取编码器速度和目标速度做差得到误差然后累加积分项计算微分项最后输出PWM占空比调整量。调参的时候有个方法先把积分和微分设为0只加比例项让电机空载跑看实测速度是否快速接近目标值有没有震荡。如果震荡就降Kp如果响应慢就升Kp。然后加一点积分项来消除稳态误差注意积分项最容易引起过冲需要设置积分限幅防止积分饱和。微分项对于这种带齿轮箱减速电机来说一般不需要太大如果电机本身阻尼已经比较强Kd可以留0或者给很小的值。另外说个小细节麦轮小车的电机一般减速比在1:30左右减速箱齿轮间隙和皮带或联轴器的弹性会让系统存在滞后。这种机械特性下PID参数不能过于激进否则会出现低速抖动、高速啸叫。实测下来比较稳妥的一组初值Kp在0.5到1.5之间、Ki在0.05到0.2之间、Kd为0或0.01具体要看你的电机驱动增益和编码器线数先用这组数跑起来再微调。2.3 小程序端实现要点与蓝牙通信小程序端从零到能用无非几步初始化蓝牙适配器、扫描设备、连接设备、获取服务和特征值、发送指令、接收数据。需要说明的是微信小程序的BLE API是基于GATT协议的你得知道模块的服务UUID和特征值UUID一般在模块的AT指令文档里有。以JDY-08为例它默认的服务UUID是FFE0特征值UUID是FFE1用这个就能完成读写。扫描设备的时候小程序端可以用wx.startBluetoothDevicesDiscovery开启扫描然后监听onBluetoothDeviceFound事件拿设备列表。每个BLE模块的名字可以在AT指令里配置建议改成一个好识别的名字比如“MecanumCar”这样在设备列表里能快速找到。连接成功后拿到设备的deviceId调用wx.createBLEConnection建立连接之后再用wx.getBLEDeviceServices和wx.getBLEDeviceCharacteristics获取服务特征值最后用wx.writeBLECharacteristicValue发送数据。发送的数据格式要和STM32端协议对应。我会在手机上把虚拟摇杆的x、y分量以及旋转值打包成类似0xAA 0x01 0x06 [vx低字节] [vx高字节] [vy低字节] [vy高字节] [omega低字节] [omega高字节] [checksum]这样的帧每个速度值用int16表示范围-1000到1000对应实际速度范围-1.0到1.0 m/s发送前乘以1000是为了避免编解码小数处理简单也不容易出错。提示小程序请求蓝牙权限时需要用户授权开发调试时要在微信开发者工具里打开蓝牙调试开关在真机上还要确保手机系统蓝牙权限已开启。iOS和安卓对蓝牙权限的处理稍微有点不同安卓有些机型需要开启定位权限才能扫描到蓝牙设备这一点很坑排查了半天。3. 实操过程与核心环节实现3.1 STM32端工程搭建与关键代码实现先搭工程。用STM32CubeMX选择STM32F103C8Tx芯片依次配置时钟树系统时钟设为72MHz、调试接口如果用了PA13/PA14作普通IO需要禁用JTAG否则引脚冲突、定时器引脚、串口和GPIO。这里最容易踩坑的就是引脚复用比如PA15、PB3、PB4这几个引脚默认是JTAG口直接当PWM输出用会失效必须先把AFIO配置里的JTAG关闭只保留SWD。定时器分配我按下面这张表来配置功能定时器/外设通道引脚电机1 PWMTIM2CH1PA0电机2 PWMTIM2CH2PA1电机3 PWMTIM2CH3PA2电机4 PWMTIM2CH4PA3编码器1TIM3CH1/CH2PA6/PA7编码器2TIM4CH1/CH2PB6/PB7编码器3TIM5CH1/CH2PA0/PA1编码器4TIM8CH1/CH2PC6/PC7注意如果编码器用的定时器引脚和PWM冲突需要调整。例如TIM5的CH1/CH2对应PA0/PA1如果你用TIM2输出PWM占了PA0到PA3编码器就得换其他引脚和定时器具体看芯片手册的复用表。我的实际做法是PWM用通用定时器TIM2输出4路PWM编码器分别用TIM3、TIM4等保证互不冲突。生成工程后在代码里初始化编码器模式配置为Encoder Mode TI1 and TI2这意味着两个通道都参与计数分辨率翻倍。然后启动定时器每次计数溢出会产生更新事件可以开一个10ms的中断来读取计数并清零换算成实际转速speed (delta_count / (pulse_per_rev × 4)) × (60 / dt) 得到RPM再乘轮径和减速比算出线速度。我的电机是1:30减速编码器线数13线每圈经过四倍频后每圈脉冲数就是13×4×301560脉冲。用这个数反推速度实测还算准确。电机控制模块里PWM占空比初始设置为0根据PID输出值修改寄存器。方向控制用两个GPIO对应H桥或驱动芯片的IN1和IN2逻辑。注意要加死区防止上下桥直通短路如果用专用驱动芯片如TB6612或DRV8833内部已经处理了死区但用自己搭MOS管H桥就必须自己在代码里控制改变方向时先让PWM为0延时几微秒再切换方向最后恢复PWM。运动学解算和PID都在主循环的10ms定时中断中执行。主循环里只做状态判断和指令解析保证中断里的控制周期固定。中断中按顺序执行读编码器速度 → 算误差 → PID计算 → 运动学解算 → 更新PWM和方向。需要注意的是PID计算和运动学解算的执行顺序我是先把目标速度通过运动学解算转换成四个目标轮速再把每个轮速分别送入PID因为PID的输出对应的是单个轮子的PWM逻辑更清晰。3.2 小程序端代码实现与界面逻辑小程序端的目录结构不复杂核心在index页面里。先在index.wxml里放一个canvas作为摇杆区再放一堆按钮做模式切换。摇杆手势用touchstart、touchmove、touchend事件捕获触点坐标计算相对圆心的偏移量和角度归一化到-1到1之间这个归一化值对应底盘的vx和vy。index.js里关键的是蓝牙连接状态管理。连接流程代码大致是这样wx.openBluetoothAdapter({ success: function (res) { wx.startBluetoothDevicesDiscovery({ allowDuplicatesKey: false, success: function (res) { // 扫描中监听onBluetoothDeviceFound } }); } });扫描到设备后判断设备的name是否等于“MecanumCar”如果是就停止扫描并创建连接。连接成功后再获取服务和特征值同时开启notify监听这样STM32端如果有状态回传小程序能实时收到。发送摇杆数据时要控制发送频率。BLE发送一包数据的耗时大概在10到20ms如果每帧移动事件都发送会造成数据堆积和延迟。我这边做了节流处理在touchmove里每30ms发送一帧在touchend时发送一帧全部为零的停止指令保证松开摇杆后小车能立刻停下。这个细节很多人忽略实际效果差距很大不发停止帧的话小车会因为最后一条移动指令而继续运动很危险。界面布局上左边一个摇杆控制平移右边一个滑块或另一个摇杆控制旋转也可以设计成单摇杆加模式切换默认模式是“平移”打开旋转模式后摇杆控制左右旋转和前后平移。UI尽可能简洁增加一个“连接”按钮和状态指示灯绿点表示已连接红点表示断开。3.3 软硬件联调步骤与测试方法联调的时候不要一上来就装车轮试跑很容易失控撞墙。我习惯按下面这个顺序验证裸机测试先把电机和驱动模块接好STM32下载一个简单的PWM输出程序依次让四个轮子分别正转和反转用万用表或者直接听声音确认驱动正常同时确认各轮方向定义是否符合运动学解算预期。编码器测试写一段程序读取并打印四个编码器的脉冲数手动转动轮子看数值是否增大或减小确认编码器接线和计数方向正确。开环运动学测试先不启用PID直接把目标速度通过运动学解算转成PWM占空比观察小车是否往预期方向运动。比如发送vx0.2、vy0、omega0时小车应该沿x轴正向直行如果出现斜走或自旋检查公式正负号和轮子布局是否匹配。闭环PID测试小车架起来悬空使四个轮子离地启动PID和蓝牙通信用小程序发送各方向速度观察轮子是否快速达到目标速度且稳定。整机地面测试放到地面上试跑先低速再逐步提高速度观察直线度、旋转半径是否准确。如果出现明显偏移可以先检查重心是否对称再微调PID参数和运动学公式里的L、W值。我实测中发现底盘在低速0.2 m/s时方向准确提速到0.6 m/s以上后会有些微偏航原因主要是地面摩擦不均和轮子打滑。做项目演示的话低速完全够了如果要做高速高精度控制得改用全向轮或者加IMU做闭环融合。4. 常见问题与排查技巧实录4.1 电机不转或者只有部分轮子转出现这个问题先分别检查每个轮子对应的PWM信号和方向IO。拿示波器看PWM波形有没有输出如果没有优先怀疑定时器配置或者引脚被复用。比如前面说的PA15、PB3、PB4默认是JTAG功能不关闭JTAG的话PWM信号根本出不来。另外有些电机驱动板要求PWM引脚和方向引脚必须同时配置为复用推挽输出漏掉方向引脚的初始化电机也不会转。如果PWM波形正常但电机还是一动不动用万用表量驱动板输出端有没有电压再量电机的电源电压是否足够。电机启动瞬间电流很大普通的USB供电或者稳压模块撑不住电压一跌落单片机就复位了。建议用2S锂电池7.4V或3S锂电池11.1V给电机单独供电控制板和逻辑电路用单独的5V稳压两边共地但不共电源能有效避免电源干扰。4.2 编码器读数异常、误差大编码器读数跳动或者和实际转速对不上最可能的原因是接线和干扰。编码器信号线要尽量短最好用双绞线或者屏蔽线远离电机电源线和大电流线。另外在信号线上并联一个0.1uF的小电容做硬件滤波可以有效抑制尖峰干扰。还有一种情况是计数方向反了。编码器方向反的表现是PID输出的PWM越加越大因为反馈是反的误差永远不减小。排查方法很简单手动转动轮子观察计数是正还是负如果方向反了可以交换编码器A、B相信号线或者在代码里配置定时器计数方向反转。编码器线数和轮径参数对速度计算影响很大一定要根据自己电机型号仔细核对。某宝买的电机标称13线编码器这个“线”是指单圈脉冲数还是四倍频后的脉冲数不同卖家说法不同建议在代码里加一个打印拿手转轮子数圈看实际计数值差多少按实测值反推不要轻信参数表。4.3 PID调参经验小车抖动与响应迟钝怎么破麦轮小车PID调参最容易出现的问题就是出发时抖动、刹车时振荡。抖动出现在PI参数都偏大的情况下特别是积分项系统启动时误差大积分快速累积导致输出过冲轮子来回抖动。解决办法是给积分项加限幅比如输出范围是-1000到1000那积分项累计结果就限制在-300到300防止积分饱和。另外可以加一个简单的死区目标速度和实际速度差小于某个很小的阈值时误差直接置零避免静止时因为编码器毛刺导致PWM波动。如果小车响应很迟钝按摇杆后过几百毫秒才动通常是Kp太小了加大Kp。但Kp加到一定程度会发现电机有轻微的“嗡嗡”声这是PWM频率和机械系统发生了共振可以试试把PWM频率提高一点或者对PID输出做低通滤波让占空比变化更平滑就不会有那种尖锐的高频噪声了。4.4 小程序蓝牙连不上、频繁断连小程序连不上蓝牙先把手机蓝牙关掉再打开同时把模块断电重启。BLE模块在未配对之前如果上一次连接异常会保持一个半开连接状态导致新设备连不上。建议在程序中每次连接失败时先调用wx.closeBLEConnection关闭之前的连接再做新的连接请求。频繁断连大多数是供电问题。BLE模块本身耗电不大但和STM32共用电源时电机一启动瞬间拉低电压模块掉电重启蓝牙就断了。我给BLE模块单独加了一路3.3V的LDO稳压并且加上一个100uF的电容做储能缓冲电机起步时电压跌落至少不会导致模块复位。通信距离上BLE的穿墙能力弱五六米内没障碍物比较稳定如果距离远或隔着金属就会延迟增大、丢包这个只能换方案比如加ESP32做WiFi UDP透传或者用HC-12的433M无线模块。4.5 小车跑偏、旋转不精确怎么调排除机械安装和重心因素后跑偏基本是四个轮子速度不一致导致。检查每个轮子PID的稳态误差在最简单的地面匀速直行测试时打印四个轮子的实际速度是否一致。如果有某个轮子实测速度偏低首先看那个轮子是不是机械阻力大比如轴承卡滞、轮子压地太紧可以在车架和轮轴之间加垫片调整其次是检查PID参数是否一致应该保证四个轮子的控制器参数完全一样。旋转不精确通常和运动学公式里的L和W有关。这两个值必须测量车体的实际轴距和轮距不是随便填的。L读取不到准确值的话可以把小车放在地面发送ω0.3 rad/s的指令用记号笔标记小车起始朝向测量旋转90度所需时间反过来反推等效的(LW)值用这个校准值替换公式里的参数旋转精度会有明显提升。5. 项目复盘与经验总结整套项目做下来说几个我自己的体会对后来者可能有点用。第一麦轮小车上手容易但做好难。开环控制下看着能跑一旦加编码器做闭环问题就全暴露了轮子速度不均匀、PID参数互相干扰、通信延迟影响控制感。如果有条件建议先把底盘机械部分固定好再写软件不要用胶枪随便粘轮子支架松动、皮带打滑这种机械问题在软件层面怎么调都补不回来。第二通信协议一定要在一开始就设计好别觉得暂时只传几个速度值无所谓。我最早图省事直接发字符串结果蓝牙串口偶尔收半个包解析就崩了。后来改成定制二进制帧格式不仅传输效率高还顺便加了校验排查问题也方便每次收到无效帧能打印出具体错误原因调试效率提升了几倍。第三调试过程中要善用打印和日志。STM32端用串口把每个轮子的目标速度和实际速度周期性地发出来哪怕是发到电脑串口助手也能直观看到PID调节过程。小程序端把蓝牙收发的原始数据包打出来遇到指令没反应就知道是手机没发出去还是单片机没收到。没有这一层数据反馈调整个问题只能靠猜太浪费时间。这个项目后续的扩展空间也不小。底层控制逻辑稳定后可以加上IMU模块做航向锁定让小车走直线不走偏也可以在STM32上移植一个简单的状态机让小车自主执行巡逻、避障等固定动作小程序端还可以接入摄像头画面成为图传遥控终端。核心的底盘控制代码和通信协议可以复用换更大的底盘、换电机驱动板都不用大改这也是模块化设计的好处。希望这篇文章能帮你把麦轮小车跑起来遇到具体问题可以在评论区交流。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门