平衡小车工程全解析:硬件选型、PID控制与循迹扩展 简介面向自动控制学习者和嵌入式开发者的平衡小车完整工程包源自控制系统理论实践覆盖姿态检测、PID调节、卡尔曼滤波等核心环节适合正在学习STM32、Arduino等平台平衡控制算法的读者也可为相关课程设计提供参考。压缩包内共1420个文件以C源码与头文件为主——包含439个.c与379个.h另有汇编启动文件、链接脚本、Keil工程配置文件以及TXT/HTML说明文档整体大小36.17MB目录结构按工程模块划分便于快速定位逻辑。已有1742人浏览/下载在同类资源中较受关注。内容不仅包含完整工程源码还有图纸、说明文档和编译中间文件可直接打开工程对照学习也可提取底层驱动或控制算法模块复用。通过梳理这些资料能直观理解传感器数据融合、PID参数整定以及电机驱动信号生成的完整链路适合作为进阶练习的起点。1. 从压缩包看平衡小车的项目全貌1.1 一个平衡小车工程通常包含哪些模块看到平衡小车car--葛凤佩.rar这种命名习惯的压缩包我的第一反应是别急着解压、双击编译、烧录一气呵成——先静下心看目录。这种文件名十有八九是课程设计或者竞赛项目打包后的产物里面藏着一个完整的小车工程该有的所有东西但摆放得整不整齐直接决定了你后续要花多少时间。一个规范的平衡小车工程压缩包里通常有这么几类内容一是主控芯片的工程源码最常见的是Keil MDK工程也就是带着.uvprojx后缀那一套二是硬件设计文件原理图和PCB格式可能是AD或立创EDA三是外设驱动代码MPU6050姿态传感器、电机编码器、OLED显示屏这些器件的驱动基本都会单独成文件四是文档类调参记录、设计报告、演示视频运气好还能看到作者手写的调试笔记。我之所以强调先看目录是因为平衡小车这个项目的代码耦合度相当高。姿态解算要吃加速度计和陀螺仪的原始数据控制环要把解算出来的角度变成PWM占空比而PWM又要和编码器测速配合形成速度闭环。这三个环节只要中间断一条线整个工程就跑不起来。所以拿到代码后第一件事是分清哪些文件负责传感器读取、哪些文件负责控制计算、哪些文件负责电机输出。就算你后面打算完全推翻重写这个分类也能帮你快速定位问题。1.2 平衡小车与平衡循迹小车的定位差异热门词里带了平衡循迹小车这其实是平衡小车的进阶形态也是很多人做完基础版之后自然而然想走的方向。纯平衡小车只需要解决一个问题站稳。控制目标非常单纯让车身倾角稳定在零位附近轮子根据倾角前后移动来保持重心落在支撑面内。而平衡循迹小车要在这个基础上多解决一个问题往哪走。循迹模块识别赛道上的黑线把横向偏差折算成目标速度或目标转向角最终通过左右轮差速实现转弯。听起来只是加一个模块的事但我拆过的项目包多了之后发现绝大多数人恰恰折在这里。为什么因为循迹不是简单地在平衡控制代码里加两行if判断而是要在直立环、速度环之外再叠加一个转向环。三个环的响应速度完全不一样直立环最快毫秒级速度环次之几十毫秒级转向环最慢百毫秒级。如果三个环全写在一个大循环里串行执行整个系统会明显发僵转向动作迟钝、车身来回晃。这个道理你在后面调参的时候会反复体会。2. 硬件平台选型主控、传感器、驱动器的搭配原则2.1 主控芯片STM32与Arduino的取舍先聊主控。我在市面上看到的平衡小车课程设计绝大多数用STM32F103C8T6就是常说的蓝色药丸开发板。72MHz主频硬件I2C、定时器编码器模式都有价格便宜、资料铺天盖地用来做平衡小车属于杀鸡用牛刀但恰好趁手。Arduino Uno这类AVR平台不是说不行但16MHz的主频要同时跑姿态解算、PID控制、OLED刷新外加蓝牙或循迹扩展CPU占用会非常紧张后期加功能时捉襟见肘。从选型的角度我特别建议关注一点编码器接口。平衡小车的速度环必须知道轮子转速而编码器测速最省CPU的做法是利用定时器的编码器模式让硬件自己数脉冲主控只负责定时读寄存器。STM32的通用定时器基本都支持这个功能而Arduino Uno要实现同样的效果得靠外部中断软件模拟一边跑控制一边频繁进中断实时性就差一截。你要做平衡循迹小车的话这个差距会被进一步放大。2.2 MPU6050姿态传感器安装位置与数据质量姿态传感器这块入门几乎是清一色的MPU6050。它内置三轴加速度计和三轴陀螺仪通过I2C接口输出原始数据成本十来块钱精度对自平衡这种应用场景完全够用。那些用更高端传感器做出来的效果更好吗未必很多时候是调参功夫到位不是硬件堆出来的。真正容易被忽略的是传感器的安装位置和方向。我见过不少实物MPU6050用杜邦线悬空飞线连接电机一启动回传的角度波形抖成一团。正确做法是传感器尽量靠近车体的几何中心用螺丝或热熔胶固定死不能有丝毫悬空供电走主控板上的3.3VI2C线越短越好。传感器放在底盘正中间还有一个好处车模原地旋转的时候向心加速度对它的影响会降到最小。这些看着都是细节但决定了你的原始数据干不干净而原始数据不干净后面PID调出花来也没用。2.3 电机与驱动减速比和电流余量电机选型表面上简单其实最容易埋坑。平衡小车一般用带霍尔编码器的N20或MG513电机减速比常见1:30、1:50甚至1:90。我自己的实测经验是1:30更适合做平衡车响应快转向敏捷1:90速度太慢转向迟钝调转向环的时候会明显感觉车头拧不过来。当然具体还得看你用的轮子直径和整车重量这两个因素变化时最佳减速比也会变。驱动芯片我强烈推荐TB6612比L298N好用太多。TB6612体积小、压降小、PWM频率可以给到20kHz以上而L298N的管内压降太大电池电压稍微掉一点电机端的实际电压就跟着掉反映到控制上就是同样占空比下转速漂移PID参数在一个电量区间调好了换个电量又不稳。电源方面千万记得分开供电电机用电池直供主控和传感器用降压后的5V或3.3V别让电机启动瞬间的电流冲击把主控拉复位。这个问题在电池快没电时尤其明显小车上电一瞬间直接黑屏重启十有八九是供电没分开。3. 姿态解算与PID控制环让小车站起来的关键3.1 姿态解算互补滤波与零偏处理MPU6050输出的原始数据不能直接用这是个新手容易卡住的地方。加速度计能测倾角但它对振动极其敏感电机一转动加速度计输出就全是噪声陀螺仪积分得到的角度短时间很稳定但会随时间累积漂移一分钟不校准就偏出好几度。单独的谁都不可信所以要做融合也就是姿态解算。平衡小车这个场景互补滤波完全够用代码短、计算量小STM32跑起来毫无压力。核心公式不复杂angle 0.98 * (angle gyro_y * dt) 0.02 * acc_angle0.98和0.02就是权重工程上可以根据实际振动情况微调振动大就减小加速度计的权重。比起四元数加卡尔曼滤波互补滤波牺牲的那点精度在平衡车这种场景里根本感知不到却把代码复杂度和调试难度降了一个量级。这里必须强调一个细节陀螺仪零偏。MPU6050的陀螺仪输出不是完美的0上电静止时读出来可能有个几十到几百的偏移量这个偏移量不消除积分出来的角度会匀速漂移。正确做法是上电后静止采样几百次取平均值作为零偏后续每次读数都减去这个值。我见过太多小车出现慢速往一个方向跑、怎么调参数都静不下来的现象最后发现就是少了这一步。3.2 三个控制环的叠加顺序控制部分直立环一般用PD控制输出 Kp * angle Kd * gyro_y这里直接用陀螺仪的角速度当微分项比用角度差分再经过低通滤波平滑得多这是几乎所有平衡车代码的标准写法。速度环用PI控制作用是让小车以目标速度前进或者保持静止它的输出叠加到直立环的最终PWM上。转向环也是PD控制输入是Z轴陀螺仪积分出的偏航角输出是左右轮的PWM差。三个环的叠加顺序是关键。先说直立环它是内环保证小车不倒再说速度环它是中间层让小车不溜车最后转向环修正量一加一减分别作用到左右轮让小车转向。叠加时先算直立环再算速度环两者相加得到基础PWM最后把转向环的修正量加到左右轮上。顺序反了比如把速度环输出直接替换掉直立环输出小车会立刻倒地。这个部分最开始我犯过的错就是想当然地把三个环结果求平均结果是三个环互相打架车在原地疯狂点头。3.3 调参顺序与现场翻车记录调参是平衡车项目里最磨人、也是最见功夫的环节。我总结一个经过多次验证的顺序先只调直立环把Kp从小往大加加到小车能快速回正但又不震荡的位置再微调Kd来抑制高频抖动直立站稳后加速度环Kp先给一个很小的值观察轮子是否慢慢回中最后才加转向环。这个过程里我翻过最大的车是Kp加太猛。有一次想当然地把Kp从80直接调到200小车当场趴下然后高速原地打转电池瞬间跌到保护电压关机。后来我学乖了把所有参数写入EEPROM每次只改一个参数改完从串口打印角度和PWM波形看稳了再动下一个。记住一次只动一个参数这个习惯能帮你省掉大量定位问题的时间。4. 代码组织与调试手段从能跑到跑稳4.1 前后台结构与定时器中断的任务划分平衡小车的控制周期通常取5ms或10ms对应100Hz或200Hz的控制频率。裸机环境下最经典的做法是把整个控制循环放进一个定时器中断里主循环只负责非实时任务比如OLED刷新、按键扫描、串口打印。这样控制频率严格稳定不会因为主循环里某个显示函数耗时过长导致控制周期抖动。控制周期一抖PID微分项的输出就会剧烈波动直观表现是电机发出断断续续的嗡嗡声。写代码时有个细节很容易忽略中断服务函数里尽量只做计算和PWM赋值不要做耗时的I2C读取。MPU6050通过I2C读一次数据大概几百微秒如果控制周期只有5ms这占的比例就不小了。而且如果I2C是用软件模拟的GPIO翻转遇到干扰还可能卡在等待应答的死循环里。我的习惯是MPU6050的读取也放在定时器中断里但保证这个读取函数没有阻塞式等待并且用DMA或快速读寄存器的方式把耗时压到最短。4.2 串口波形调参法调试平衡小车光靠眼睛盯着车看它晃不晃远远不够。你需要数据当前角度、角速度、PWM输出、编码器速度这些数值能告诉你车为什么晃。最廉价的方案是串口打印到PC配合匿名上位机或VOFA这类波形软件把目标角度、实际角度、直立环输出画在同一个坐标系里几乎是调参的标配。波形带给你的信息量远超肉眼观察。如果实际角度围绕目标角度高频抖动说明Kd不够或者传感器噪声大如果实际角度缓慢偏离目标角度说明零偏没去干净或速度环没稳住如果PWM波形长时间顶在限幅值上说明控制力不够得检查电池电压或者机械卡涩。没有波形调参就像蒙着眼睛开车凭感觉调出来的参数换一个场地可能就失效了。4.3 电压补偿、死区与限幅还有几个工程细节代码量都不大但就是这些懒得多写几行的小地方决定了小车是站3秒还是站3分钟。第一个是电池电压补偿。锂电池从满电4.2V放到3.7V电压变化接近15%如果不做补偿同一个PID参数在满电时表现正常低电量时却会明显变软。简单做法是ADC采样电池电压估算一个补偿系数叠加到PWM输出上。第二个是PWM死区。电机和驱动电路存在一个最低启动占空比比如5%以下电机根本不转。PID输出在这个死区附近时电机时而转时而停控制效果非常差。处理方式是检测到输出绝对值低于死区阈值时直接按0处理或者叠加一个前馈量跨过死区。第三个是输出限幅。直立环的PWM输出必须限幅否则在突然受到外力干扰时积分项叠加会让PWM瞬间饱和电机猛冲反而把小车推倒。限幅值一般设在满载的70%到80%既保证有足够余量纠正姿态又避免饱和失控。5. 从平衡到循迹扩展方向与典型坑5.1 循迹模块的加入与控制切换做完纯平衡很多人会自然想进阶到平衡循迹小车。循迹模块最常用的是灰度传感器或红外对管阵列装在车头下方通过检测黑白反光差异来识别赛道黑线。控制逻辑上把传感器读到的线位置偏差映射成一个转向量再叠加到原有的控制输出上。这里的关键点在于循迹的偏差处理不要直接覆盖转向环的输出而是应该给转向环一个目标偏航角。也就是说你仍然让直立环和速度环正常工作只是根据循迹结果不断调整小车该朝哪个方向转。这样设计的好处是循迹代码和平衡控制代码的耦合度最低两者可以独立调试。我见过有人把循迹偏差直接加到最终PWM上结果小车左右剧烈摆头因为循迹信号本身带噪声直接叠加等于给控制环灌入了高频干扰。关于控制切换循迹和手动遥控之间要留一个平滑过渡。最简单的办法是做一个模式变量同一个控制周期根据模式选择不同的转向目标来源而不是在中断服务函数里做长时间阻塞逻辑切换。切换瞬间可以先清零速度环的积分项防止切换时积分残留导致小车突然加速。5.2 机械结构与重心带来的隐性影响最后聊机械这部分是最容易背锅也最容易被忽视的。代码调得再好机械结构不行也是白搭。平衡小车的重心要尽量低且居中这是硬道理。我做过对比测试把电池竖着绑在支架上方PID参数怎么调都感觉软绵绵响应慢半拍把电池平放到底盘上之后同样的参数立刻稳住了。重心一高等效摆长变长系统固有频率变低控制难度成倍增加。轮子间距和轮胎摩擦力对转向环的影响也很大。摩擦力太小的轮子在小半径转向时容易打滑打滑瞬间编码器读数会突然跳变速度环接收到错误的高速度值会误判并输出错误的控制量。另外很多小车在硬质桌面试得好好的放到地毯上就站不住多半就是轮胎打滑改变了速度环的工作点。遇到这种情况先别急着改PID参数先检查机械摩擦环节再回头看代码。平衡小车这个项目我的切身体会是算法占三成硬件占三成耐心调参占四成。那些最后跑得稳的项目包无一例外都留有完整的调参记录哪怕只是几行潦草的参数和日期也比事后靠回忆强得多。你如果正在做这个项目从第一天开始就随手记录每次修改的参数和对应现象等调完回头看这份记录会比代码本身更值钱。本文还有配套的精品资源点击获取