1. 项目概述
两轮平衡车作为典型的倒立摆控制系统,一直是控制理论和嵌入式开发的经典实践项目。基于STM32F103C8的方案因其性价比高、开发资源丰富而成为入门者的首选。这个项目将带你从零开始构建完整的平衡车系统,重点在于卡尔曼滤波的姿态解算和PID控制算法的工程实现。
我最初接触平衡车是在大三的课程设计,当时用51单片机勉强实现了站立功能,但抗干扰能力极差。后来在工作中接触到工业级平衡车方案,才发现传感器数据处理和控制算法的重要性。这次分享的STM32F103C8方案,正是结合了教学级和工业级的优点。
2. 硬件系统设计
2.1 核心器件选型
主控选用STM32F103C8T6最小系统板,这款72MHz的Cortex-M3内核MCU具有:
- 64KB Flash + 20KB RAM
- 3个USART和2个SPI接口
- 16通道12位ADC
- 7通道DMA控制器
MPU6050作为姿态传感器,其DMP功能可以输出四元数,但我们会直接使用原始数据自行解算。电机驱动采用TB6612FNG双H桥芯片,相比L298N具有:
- 更低导通电阻(0.4Ω vs 1.2Ω)
- 更高效率(91% vs 70%)
- 内置保护电路
2.2 关键电路设计
电源部分需要特别注意:
c复制// 锂电池管理电路
[锂电保护IC] -> [3.3V LDO] -> MCU
-> [5V Buck] -> 电机驱动
MPU6050的I2C接口要加上拉电阻(4.7kΩ),并尽量缩短走线长度。电机驱动PWM频率建议设置在10-20kHz,既能避免可闻噪声,又能保证响应速度。
3. 软件架构设计
3.1 实时控制流程
mermaid复制graph TD
A[传感器数据采集] --> B[卡尔曼滤波]
B --> C[PID计算]
C --> D[电机控制]
D --> A
这个闭环控制在STM32上通过定时器中断实现,建议控制周期在5-10ms。太短会增加计算负担,太长会影响控制效果。
3.2 任务优先级安排
- 电机控制中断(最高优先级)
- 姿态解算任务
- 无线通信任务(如蓝牙调试)
- 状态显示任务
4. 卡尔曼滤波实现
4.1 状态方程建立
对于两轮平衡车,我们建立以下状态变量:
- 角度θ
- 角速度θ'
- 加速度a
状态转移矩阵:
code复制F = [1, dt, 0
0, 1, -dt
0, 0, 1]
4.2 具体实现代码
c复制typedef struct {
float q_angle; // 过程噪声协方差
float q_bias;
float r_measure; // 测量噪声协方差
float angle; // 计算出的角度
float bias; // 陀螺仪偏置
float P[2][2]; // 误差协方差矩阵
} Kalman;
float Kalman_update(Kalman* k, float newAngle, float newRate, float dt) {
// 预测步骤
k->angle += dt * (newRate - k->bias);
k->P[0][0] += dt * (dt*k->P[1][1] - k->P[0][1] - k->P[1][0] + k->q_angle);
k->P[0][1] -= dt * k->P[1][1];
k->P[1][0] -= dt * k->P[1][1];
k->P[1][1] += k->q_bias * dt;
// 更新步骤
float y = newAngle - k->angle;
float S = k->P[0][0] + k->r_measure;
float K[2];
K[0] = k->P[0][0] / S;
K[1] = k->P[1][0] / S;
k->angle += K[0] * y;
k->bias += K[1] * y;
float P00_temp = k->P[0][0];
float P01_temp = k->P[0][1];
k->P[0][0] -= K[0] * P00_temp;
k->P[0][1] -= K[0] * P01_temp;
k->P[1][0] -= K[1] * P00_temp;
k->P[1][1] -= K[1] * P01_temp;
return k->angle;
}
4.3 参数整定经验
- q_angle:影响系统对加速度计数据的信任程度,建议0.001-0.01
- q_bias:陀螺仪偏置的变化率,建议0.003-0.03
- r_measure:测量噪声,建议0.3-3.0
实际调试时,可以先用互补滤波确定大致范围,再微调卡尔曼参数。
5. PID控制算法
5.1 串级PID结构
code复制外环(角度环) -> 内环(速度环) -> 电机输出
角度环保证车身直立,速度环实现速度控制。两个环的PID输出需要合理限幅。
5.2 代码实现
c复制typedef struct {
float kp, ki, kd;
float integral;
float prev_error;
float out_max;
float out_min;
} PID;
float PID_update(PID* pid, float error, float dt) {
// 比例项
float p_out = pid->kp * error;
// 积分项
pid->integral += error * dt;
float i_out = pid->ki * pid->integral;
// 微分项
float d_out = pid->kd * (error - pid->prev_error) / dt;
pid->prev_error = error;
// 总和输出
float output = p_out + i_out + d_out;
// 输出限幅
if(output > pid->out_max) output = pid->out_max;
if(output < pid->out_min) output = pid->out_min;
return output;
}
5.3 参数整定步骤
- 先调角度环P,使车能勉强站立但抖动
- 加入角度环D,抑制抖动
- 最后加入角度环I,消除稳态误差
- 速度环参数一般比角度环小一个数量级
典型参数范围:
- 角度P:20-50
- 角度D:0.5-2
- 角度I:0.1-0.5
- 速度P:1-5
- 速度I:0.01-0.1
6. 系统调试技巧
6.1 传感器校准
MPU6050需要先进行静止状态下的校准:
c复制// 陀螺仪零偏校准
for(int i=0; i<1000; i++) {
gyro_offset += gyro_raw;
delay(1);
}
gyro_offset /= 1000;
6.2 无线调试方法
通过蓝牙模块发送关键数据到上位机:
code复制角度,角速度,PID输出
可以用串口绘图工具直观观察系统响应。
6.3 常见问题解决
- 车身持续往一边偏:检查MPU6050安装是否水平
- 高频抖动:增加微分项或降低P值
- 反应迟钝:检查控制周期是否过长
- 电机异常发热:检查PWM频率和死区设置
7. 进阶优化方向
- 加入编码器实现闭环速度控制
- 使用RTOS管理多任务
- 实现手机蓝牙遥控功能
- 添加OLED显示状态信息
- 改用FOC算法驱动无刷电机
这个项目最让我有成就感的是看到小车从摇摇欲坠到稳稳站立的过程。建议先用现成的平衡车套件验证算法,再自己设计PCB,这样能避免同时处理硬件和软件问题。
