1. 项目背景与核心原理
两轮自平衡小车是嵌入式开发领域的经典练手项目,它完美融合了微控制器编程、传感器数据处理和自动控制理论三大核心技术。使用STM32F103C8T6这款性价比极高的Cortex-M3内核芯片作为主控,配合MPU6050六轴传感器获取姿态数据,通过PID算法实时调整电机转速,最终实现小车的自主平衡。
这个项目的独特魅力在于:从硬件电路焊接、传感器调试到控制算法优化,每个环节都充满挑战。我花了整整三周时间才让小车稳稳立住,期间经历了无数次的参数调整和代码重构。下面就把这些实战经验毫无保留地分享给大家。
2. 硬件设计与关键器件选型
2.1 主控芯片:STM32F103C8T6的三大优势
选择这款72MHz主频的ARM芯片主要基于三点考虑:
- 丰富的外设接口:自带3个USART、2个SPI和2个I2C接口,完美适配各类传感器
- 充足的运算能力:单周期乘法和硬件除法指令,满足实时控制的计算需求
- 成本优势:相比Arduino方案,价格仅为1/3但性能提升5倍以上
注意:务必购买正版ST芯片,市面上有些打磨翻新货会导致PWM输出异常
2.2 运动感知核心:MPU6050的配置要点
这个集成三轴加速度计+陀螺仪的模块需要特别注意:
- I2C通信建议使用400kHz高速模式
- 安装位置要尽量靠近小车重心
- 必须做传感器校准(具体方法见3.2节)
实测发现,在MPU6050底部粘贴3M双面胶能有效减少电机振动带来的噪声干扰。
2.3 电机驱动方案对比
测试了三种常见方案后,最终选择TB6612FNG驱动模块:
code复制L298N : 发热量大(需加散热片), 效率60%
DRV8833 : 体积小但电流不足(1A持续)
TB6612FNG: 效率90%, 1.2A持续电流
电机建议选用带编码器的N20减速电机(减速比1:30),编码器分辨率直接影响控制精度。
3. 软件架构与核心算法实现
3.1 系统任务划分
在Keil MDK中建立如下任务结构:
- 高频任务(1kHz)
- MPU6050数据采集
- 姿态解算(互补滤波)
- 中频任务(200Hz)
- PID计算
- 电机控制
- 低频任务(10Hz)
- 蓝牙调试信息发送
- 电池电压检测
3.2 传感器校准实战
必须执行的校准步骤:
- 静止校准加速度计
c复制for(int i=0; i<500; i++){ ax_sum += accel_x; delay(2); } ax_offset = ax_sum / 500; - 陀螺仪零偏校准(放置水平桌面10秒)
- 安装角度补偿(用手机水平仪测量实际安装倾角)
3.3 姿态解算的三种方案对比
实测数据表明:
- 纯互补滤波:响应快但存在漂移
- 卡尔曼滤波:精度高但计算量大
- Mahony算法:平衡性最佳(最终采用)
姿态解算关键代码片段:
c复制void MahonyUpdate(float gx, float gy, float gz, float ax, float ay, float az){
float recipNorm;
float vx, vy, vz;
float ex, ey, ez;
// 加速度归一化
recipNorm = 1.0/sqrt(ax*ax + ay*ay + az*az);
ax *= recipNorm;
ay *= recipNorm;
az *= recipNorm;
// 计算误差
vx = 2*(q1*q3 - q0*q2);
vy = 2*(q0*q1 + q2*q3);
vz = q0*q0 - q1*q1 - q2*q2 + q3*q3;
ex = (ay*vz - az*vy);
ey = (az*vx - ax*vz);
ez = (ax*vy - ay*vx);
// 积分误差
exInt += Ki * ex;
eyInt += Ki * ey;
ezInt += Ki * ez;
// 补偿陀螺仪
gx += Kp*ex + exInt;
gy += Kp*ey + eyInt;
gz += Kp*ez + ezInt;
// 四元数更新
q0 += (-q1*gx - q2*gy - q3*gz)*0.5*dt;
q1 += (q0*gx + q2*gz - q3*gy)*0.5*dt;
q2 += (q0*gy - q1*gz + q3*gx)*0.5*dt;
q3 += (q0*gz + q1*gy - q2*gx)*0.5*dt;
}
4. PID控制器的调参技巧
4.1 参数整定顺序
必须严格按以下步骤调试:
- 先调直立环(P参数)
- 从3.0开始逐步增加,直到出现小幅振荡
- 取振荡临界值的60%作为最终值
- 再调速度环(I参数)
- 从0.001开始,每次增加50%
- 观察小车能否抵抗轻微推力
- 最后加转向环(D参数)
- 通常取P值的1/10到1/5
4.2 抗积分饱和处理
在电机达到最大输出时停止积分:
c复制if((output>max_output && error>0) ||
(output<-max_output && error<0)){
integral = integral; // 保持原值
} else {
integral += error * dt;
}
4.3 实测最佳参数范围
根据20组实验数据统计:
code复制直立P : 25.0~35.0
速度I : 0.08~0.15
转向D : 2.5~4.0
5. 电源管理的五个关键细节
- 锂电池选型:推荐2S 7.4V 1200mAh,续航可达4小时
- 电压检测电路:
c复制float battery_voltage = (float)adc_value/4096*3.3*11; - 低电量保护:电压<6.8V时逐渐降低控制频率
- 电机与MCU分开供电,避免电压波动导致重启
- 在STM32的VBAT引脚接纽扣电池,保持RTC运行
6. 常见故障排查指南
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 小车往一边倾斜 | MPU6050安装不水平 | 重新校准传感器 |
| 高频抖动 | D参数过大 | 减小D值10% |
| 反应迟钝 | 控制频率过低 | 检查定时器配置 |
| 突然倒下 | 电源接触不良 | 检查XT60插头 |
| 蓝牙断连 | 天线被电机干扰 | 增加物理距离 |
7. 进阶优化方向
- 加入OLED显示实时参数
- 通过手机APP调节PID参数
- 实现路径跟踪功能(需加装编码器)
- 改用FOC电机驱动提升能效
- 移植到FreeRTOS实现多任务管理
调试过程中最深的体会是:平衡车的参数没有标准答案,每个硬件组合都需要重新调参。建议准备一个详细的数据记录本,每次修改参数都要记录变化效果。当看到小车终于稳稳立住的那一刻,所有的熬夜调试都值得了。