从零到一:基于STM32与PID算法的两轮自平衡小车实战指南

张开发
2026/4/18 5:58:20 15 分钟阅读

分享文章

从零到一:基于STM32与PID算法的两轮自平衡小车实战指南
1. 两轮自平衡小车的基本原理第一次看到两轮自平衡小车时很多人都会觉得它像变魔术一样神奇。两个轮子怎么就能稳稳地立在那里呢其实这背后的原理并不复杂。想象一下你站在平衡板上保持平衡的过程当身体前倾时你会下意识地向前移动脚步后仰时又会向后调整。自平衡小车的工作方式与此类似只不过它用传感器代替了我们的内耳用电机代替了我们的双腿。核心的平衡控制主要依赖三个关键部分姿态检测、控制算法和电机驱动。MPU6050传感器就像小车的内耳能实时感知车体的倾斜角度和角速度。STM32微控制器则相当于大脑通过PID算法计算出需要给电机发送的指令。最后电机驱动模块负责执行这些指令通过调整两个轮子的转速来保持平衡。这里有个很有意思的现象自平衡小车其实是个倒立摆系统。就像用手指顶着一根直立的木棍需要不断移动手指来保持平衡。小车也是通过不断调整轮子位置来维持直立状态。这种系统在控制理论中被称为不稳定系统任何微小的扰动都会导致失衡因此需要快速、精确的控制。2. 硬件选型与电路设计2.1 主控芯片的选择STM32F103C8T6是我最推荐的选择江湖人称蓝莓派。这款芯片价格亲民约10元性能却相当强悍72MHz主频、64KB Flash、20KB RAM完全能满足自平衡小车的需求。更重要的是它的生态系统非常完善资料多、例程丰富遇到问题很容易找到解决方案。我在早期尝试时用过Arduino虽然开发简单但性能确实有限特别是做卡尔曼滤波时明显感觉吃力。后来换用STM32不仅运行流畅还能留出足够资源做蓝牙遥控和数据显示。对于初学者建议直接选择带USB接口的核心板调试会方便很多。2.2 传感器模块的注意事项MPU6050是姿态检测的核心但新手常在这里踩坑。首先要注意安装位置必须固定在车体中心线上且尽量靠近轮轴高度。我曾在车顶安装传感器结果小车像喝醉酒一样左右摇摆调试半天才发现是安装位置不当导致的。接线时特别注意I2C总线的上拉电阻必不可少通常4.7kΩ很多廉价的MPU6050模块省掉了这个导致通信不稳定。另外传感器的Z轴应该与车体前进方向一致否则采集的数据需要做坐标变换。建议先用现成的模块等熟悉后再考虑自己画板子。2.3 电机与驱动电路电机选型直接影响平衡效果。N20减速电机是个折中的选择体积小、扭矩适中、价格便宜约15元/个。但要注意选择带编码器的版本虽然初期可以不用编码器做平衡控制但后续做速度环时会需要。TB6612FNG驱动芯片比常用的L298N效率高很多发热小支持PWM调速。接线时特别注意电机电源和逻辑电源要分开供电共地即可。我有次把两者混用结果电机一启动STM32就复位折腾了好久才发现是电源干扰问题。3. 软件架构与核心算法3.1 姿态解算的三种方法获取准确的倾角是平衡控制的基础。最简单的方法是直接使用加速度计数据但车辆运动时会产生额外加速度导致数据波动很大。陀螺仪积分可以平滑跟踪角度变化但存在漂移问题。因此实际工程中多采用传感器融合算法互补滤波计算简单适合入门// 简单互补滤波示例 angle 0.98*(angle gyro*dt) 0.02*acc_angle;卡尔曼滤波效果更好但实现复杂// 卡尔曼预测步骤 P[0][0] dt*(dt*P[1][1] - P[0][1] - P[1][0] Q_angle); P[0][1] - dt*P[1][1]; P[1][0] - dt*P[1][1]; P[1][1] Q_gyro*dt;Mahony滤波折中方案适合资源有限的场合实测下来对于自平衡小车互补滤波已经能满足基本需求。如果想追求更好效果可以尝试简化版的卡尔曼滤波。我整理了一个开源的卡尔曼滤波库特别针对STM32做了优化需要的可以私信我。3.2 PID控制的实现技巧PID控制器是平衡系统的核心但很多新手对它的理解有误区。实际上我们需要三个独立的PID环直立环最外层保持车身垂直速度环中间层控制移动速度转向环最内层处理转向指令// 典型的三环PID结构 float balance_output Balance_PID(0, current_angle, gyro); float speed_output Speed_PID(target_speed, encoder_diff); float turn_output Turn_PID(target_turn, gyro_z); // 最终输出合成 left_motor balance_output speed_output - turn_output; right_motor balance_output speed_output turn_output;调试时切记要逐个环来调先调直立环等能稳定站立后再加速度环最后才是转向环。我见过有人一次性调三个环结果小车像抽风一样乱抖这就是典型的错误示范。4. 调试过程中的常见问题4.1 小车根本站不起来这是新手遇到最多的问题。首先检查硬件确保电池电量充足至少7V以上电机接线正确用手转动应该能感觉到阻力。然后用串口把角度数据打印出来看看静止时是否接近0度±2度内。如果硬件没问题多半是PID参数设置不当。直立环的Kp可以从10开始尝试每次增加5直到小车能短暂站立。Kd参数一般设为Kp的1/10左右用于抑制震荡。记住Ki参数在直立环中可以暂时设为0。4.2 站立后剧烈抖动这说明微分增益Kd太大了。逐步减小Kd直到抖动消失。同时检查MPU6050的数据是否有噪声可以增加简单的滑动平均滤波#define FILTER_NUM 5 float filter_buf[FILTER_NUM]; float filter(float new_val) { static int index 0; filter_buf[index] new_val; if(index FILTER_NUM) index 0; float sum 0; for(int i0; iFILTER_NUM; i) { sum filter_buf[i]; } return sum/FILTER_NUM; }4.3 小车总是向一边偏首先做传感器校准将小车放在绝对水平面上运行校准程序记录偏移量。如果还是偏可能是电机性能不一致导致的。可以在代码中给两个电机设置不同的补偿系数// 电机补偿系数 #define LEFT_MOTOR_COMPENSATE 1.05 #define RIGHT_MOTOR_COMPENSATE 0.98 left_motor * LEFT_MOTOR_COMPENSATE; right_motor * RIGHT_MOTOR_COMPENSATE;5. 进阶优化与功能扩展当小车能稳定站立后就可以考虑增加更多有趣的功能了。蓝牙遥控是最实用的扩展我用HC-05模块实现了简单的手机控制// 蓝牙指令处理示例 void Bluetooth_Handler(uint8_t cmd, uint16_t value) { switch(cmd) { case 0x01: // 速度控制 target_speed map(value, 0, 255, -100, 100); break; case 0x02: // 转向控制 target_turn map(value, 0, 255, -50, 50); break; } }还可以增加OLED显示屏实时显示状态信息或者添加超声波模块实现避障功能。我最近给小车加了个摄像头做视觉巡线效果相当酷炫。不过要注意STM32F103的资源有限复杂功能可能需要升级到F4系列芯片。电源管理也是容易被忽视的一点。通过降低STM32的主频比如从72MHz降到36MHz可以显著降低功耗。我测试过在36MHz下小车依然能稳定运行而电池续航时间能延长30%以上。

更多文章