1. 项目概述
作为一名嵌入式开发者,我一直对平衡车这类自平衡控制系统充满兴趣。最近我完成了一个基于STM32和MPU6050的双轮平衡车项目,通过PID算法实现了稳定的自平衡控制。这个项目不仅让我深入理解了姿态解算和运动控制的原理,也积累了丰富的实战经验。现在我将完整分享这个项目的实现过程,希望能帮助更多对嵌入式控制和物联网感兴趣的开发者。
这个平衡车系统的核心是通过MPU6050传感器获取车身姿态数据,经过滤波处理后得到准确的俯仰角(Pitch),然后通过串级PID控制器计算出电机控制量,驱动两个直流电机保持车身平衡。整个系统运行在FreeRTOS实时操作系统上,确保控制任务的实时性和稳定性。
2. 硬件设计与选型
2.1 核心硬件组件
在选择硬件时,我主要考虑了性能、成本和易用性三个因素。以下是最终确定的硬件清单:
-
主控制器:STM32F103C8T6最小系统板
- 72MHz主频,64KB Flash,20KB RAM
- 丰富的定时器和外设接口
- 性价比高,开发资源丰富
-
姿态传感器:MPU6050模块
- 集成3轴加速度计和3轴陀螺仪
- 内置DMP(数字运动处理器),可直接输出姿态角
- I2C接口,使用方便
-
电机驱动:L298N双H桥驱动模块
- 最大驱动电流2A
- 可同时驱动两个直流电机
- 内置续流二极管,保护电路
-
执行机构:25GA370直流减速电机(带编码器)
- 减速比1:30
- 额定电压6V,空载转速200RPM
- 内置11线霍尔编码器
-
电源系统:
- 2节18650锂电池(7.4V)
- LM2596降压模块(7.4V转5V)
- AMS1117-3.3V稳压芯片
2.2 电路设计要点
在设计电路时,有几个关键点需要特别注意:
-
电源设计:
- 电机驱动和主控需要分开供电
- 使用大容量电容(1000μF)滤除电机干扰
- 添加电源指示灯和开关
-
信号隔离:
- PWM信号线上串联100Ω电阻
- 编码器信号线使用双绞线
- 所有数字信号线加上拉电阻
-
保护电路:
- 电机输出端并联续流二极管
- 添加保险丝和反接保护
- 关键信号线添加TVS二极管
3. 软件架构设计
3.1 系统框架
整个软件系统采用分层架构设计:
-
硬件抽象层(HAL):
- 外设驱动(I2C、PWM、编码器等)
- 传感器数据采集
- 电机控制接口
-
算法层:
- 姿态解算算法
- PID控制算法
- 滤波算法
-
应用层:
- 任务调度
- 人机交互
- 系统监控
3.2 FreeRTOS任务划分
为了确保实时性,系统运行在FreeRTOS上,主要任务如下:
-
姿态采集任务(优先级2)
- 10ms周期
- 读取MPU6050数据
- 执行互补滤波
-
PID计算任务(优先级3)
- 5ms周期
- 计算角度环和速度环PID
- 输出PWM控制量
-
电机控制任务(优先级3)
- 5ms周期
- 更新电机PWM输出
- 读取编码器速度
-
人机交互任务(优先级1)
- 100ms周期
- OLED显示刷新
- 按键扫描处理
4. 核心算法实现
4.1 姿态解算
MPU6050输出的原始数据需要经过处理才能得到准确的姿态角。我采用了互补滤波算法:
c复制void ComplementaryFilter(float acc[3], float gyro[3], float *pitch, float *roll)
{
// 加速度计解算角度
float acc_pitch = atan2(acc[0], sqrt(acc[1]*acc[1] + acc[2]*acc[2])) * 180/PI;
float acc_roll = atan2(acc[1], acc[2]) * 180/PI;
// 陀螺仪积分角度
static float gyro_pitch = 0, gyro_roll = 0;
gyro_pitch += gyro[1] * dt;
gyro_roll += gyro[0] * dt;
// 互补滤波融合
*pitch = 0.98 * (*pitch + gyro[1] * dt) + 0.02 * acc_pitch;
*roll = 0.98 * (*roll + gyro[0] * dt) + 0.02 * acc_roll;
}
4.2 PID控制器
系统采用串级PID控制结构:
-
角度环(内环)
- 输入:目标角度(0°)与实际角度偏差
- 输出:目标速度
-
速度环(外环)
- 输入:目标速度与实际速度偏差
- 输出:PWM占空比
PID算法的实现如下:
c复制typedef struct {
float Kp, Ki, Kd;
float error, last_error, integral;
float output;
} PID;
void PID_Init(PID *pid, float Kp, float Ki, float Kd)
{
pid->Kp = Kp;
pid->Ki = Ki;
pid->Kd = Kd;
pid->error = pid->last_error = pid->integral = 0;
}
float PID_Calculate(PID *pid, float target, float actual, float dt)
{
pid->error = target - actual;
pid->integral += pid->error * dt;
// 抗积分饱和
if(pid->integral > 1000) pid->integral = 1000;
if(pid->integral < -1000) pid->integral = -1000;
float derivative = (pid->error - pid->last_error) / dt;
pid->output = pid->Kp * pid->error + pid->Ki * pid->integral + pid->Kd * derivative;
pid->last_error = pid->error;
return pid->output;
}
5. 系统调试与优化
5.1 PID参数整定
PID参数的整定是平衡车能否稳定运行的关键。我采用以下步骤:
-
角度环整定:
- 先设置Ki=0,Kd=0
- 逐渐增大Kp直到系统开始振荡
- 然后加入Kd抑制振荡
- 最后加入Ki消除静差
-
速度环整定:
- 在角度环稳定的基础上进行
- 采用同样的步骤
- 注意速度环参数要比角度环小一个数量级
5.2 常见问题解决
在调试过程中遇到的一些典型问题及解决方法:
-
电机抖动:
- 检查电源是否充足
- 降低PWM频率(1kHz左右)
- 增加死区补偿
-
角度漂移:
- 重新校准MPU6050
- 检查滤波算法参数
- 确保传感器安装牢固
-
响应迟钝:
- 检查控制周期是否足够短
- 适当增大Kp
- 检查电机驱动能力
6. 项目扩展与改进
完成基础功能后,可以考虑以下扩展:
-
无线控制:
- 添加蓝牙或WiFi模块
- 实现手机APP控制
- 增加状态监控功能
-
路径规划:
- 添加超声波或红外传感器
- 实现自动避障
- 开发简单的路径跟踪算法
-
性能优化:
- 改用更高效的滤波算法(如卡尔曼滤波)
- 实现参数自整定
- 添加自适应控制
7. 开发心得
通过这个项目,我深刻体会到几个关键点:
-
机械结构的重要性:
- 重心位置直接影响控制难度
- 电机安装要牢固,减少振动
- 车轮摩擦力要适中
-
实时性的保证:
- 关键控制任务必须高优先级
- 避免在中断中执行复杂计算
- 合理分配任务周期
-
调试技巧:
- 分模块调试,先硬件后软件
- 使用OLED或串口实时显示关键参数
- 做好数据记录和分析
这个项目不仅让我掌握了嵌入式系统开发的完整流程,也让我对控制理论有了更深入的理解。希望我的经验能对正在开发类似项目的朋友有所帮助。
