1. 项目概述
两轮自平衡车是嵌入式系统开发的经典项目,它完美融合了传感器技术、控制算法和机电一体化设计。作为一个从零开始搭建的平衡车系统,本项目采用STM32F103C8T6作为主控芯片,通过MPU6050姿态传感器实时采集车体倾角,结合PID控制算法实现自主平衡。整套系统包含车体硬件、遥控器和上位机调试工具三大部分,完整实现了从理论建模到实际部署的全流程开发。
这个项目最吸引我的地方在于它涵盖了嵌入式开发的完整技术栈:从底层的PWM电机驱动、编码器信号采集,到中层的无线通信协议栈、传感器数据处理,再到上层的控制算法实现。通过这个项目,开发者可以系统性地掌握嵌入式硬件设计、实时控制系统开发以及机电系统集成等核心技能。
2. 硬件设计详解
2.1 主控板选型与设计
我们选用STM32F103C8T6作为主控芯片,这款Cortex-M3内核的MCU具有72MHz主频、64KB Flash和20KB RAM,完全满足平衡车对实时性的要求。其丰富的外设资源包括:
- 4个通用定时器(用于PWM生成和编码器接口)
- 2个SPI接口(分别连接NRF24L01无线模块和MPU6050)
- 3个USART(用于蓝牙模块和调试输出)
- 12位ADC(用于电池电压检测)
硬件设计经验:在PCB布局时,将MPU6050尽量靠近主控芯片放置,并确保其安装方向与车体坐标系一致。我们采用4层板设计,中间两层分别为GND和VCC平面,有效降低高频噪声干扰。
2.2 传感器模块集成
姿态检测采用MPU6050六轴传感器,它集成了3轴加速度计和3轴陀螺仪,通过I2C接口与主控通信。在实际使用中需要注意:
- 传感器需安装在车体重心附近,避免振动干扰
- 采样率设置为200Hz(寄存器0x19写入0x04)
- 启用DLPF(数字低通滤波器)配置为5Hz(寄存器0x1A写入0x06)
编码器选用增量式光电编码器(500线/转),通过TIM2和TIM3的编码器接口模式进行四倍频计数,实现2000脉冲/转的分辨率。电机驱动采用TB6612FNG双H桥芯片,相比传统的L298N具有更高效率(最高达95%)和更低发热量。
2.3 电源系统设计
电源管理是平衡车稳定运行的关键,我们的设计方案:
- 主电源:2节18650锂电池(7.4V)
- 5V稳压:AMS1117-5.0(为MCU和传感器供电)
- 3.3V稳压:SPX3819(为无线模块供电)
- 电压检测:电阻分压+ADC采样(R1=10kΩ,R2=3.3kΩ)
电池保护电路采用DW01+组合,提供过充(4.25V±0.05V)、过放(2.5V±0.1V)和短路保护。实测表明,这套电源系统在满载情况下可提供4小时的连续工作时间。
3. 软件架构设计
3.1 实时控制流程
系统采用前后台架构,关键任务在定时器中断中执行:
c复制// 1ms定时器中断服务函数
void TIM4_IRQHandler(void)
{
static uint8_t cnt = 0;
if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
{
// 姿态数据采集(200Hz)
if(++cnt >= 5) {
cnt = 0;
MPU6050_GetData(&mpu_data);
Kalman_Filter(&kalman, mpu_data.Accel, mpu_data.Gyro);
}
// PID计算与控制输出(100Hz)
Balance_PID_Calc();
Motor_Output();
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
}
}
3.2 多传感器数据融合
为获得准确的姿态角度,我们采用卡尔曼滤波算法融合加速度计和陀螺仪数据:
c复制typedef struct {
float Q_angle; // 过程噪声协方差
float Q_gyro; // 过程噪声协方差
float R_angle; // 测量噪声协方差
float x_bias; // 陀螺仪偏置
float P[2][2]; // 误差协方差矩阵
} Kalman_Filter;
void Kalman_Filter_Update(Kalman_Filter *kf, float accel, float gyro, float dt)
{
// 预测步骤
kf->x_bias = gyro - kf->x_bias;
kf->P[0][0] += dt * (dt*kf->P[1][1] - kf->P[0][1] - kf->P[1][0] + kf->Q_angle);
kf->P[0][1] -= dt * kf->P[1][1];
kf->P[1][0] -= dt * kf->P[1][1];
kf->P[1][1] += kf->Q_gyro * dt;
// 更新步骤
float y = accel - kf->x_bias;
float S = kf->P[0][0] + kf->R_angle;
float K[2] = {kf->P[0][0]/S, kf->P[1][0]/S};
kf->x_bias += K[0] * y;
kf->P[0][0] -= K[0] * kf->P[0][0];
kf->P[0][1] -= K[0] * kf->P[0][1];
kf->P[1][0] -= K[1] * kf->P[0][0];
kf->P[1][1] -= K[1] * kf->P[0][1];
}
3.3 无线通信协议
遥控器与车体采用NRF24L01模块通信,自定义协议格式如下:
| 字节 | 内容 | 说明 |
|---|---|---|
| 0 | 模式标志 | 0x01请求状态,0x00控制 |
| 1 | LH摇杆值 | -100~100 |
| 2 | LV摇杆值 | -100~100 |
| 3 | RH摇杆值 | -100~100 |
| 4 | RV摇杆值 | -100~100 |
| 5 | 按键状态1 | 每位对应一个按键 |
| 6 | 按键状态2 | 每位对应一个按键 |
为提高通信可靠性,我们实现了以下机制:
- 自动重传(设置ARC=3,ARD=500us)
- 动态调整发射功率(0dBm~-18dBm)
- 数据包CRC校验(使能EN_CRC和CRCO)
4. 控制算法实现
4.1 串级PID控制器设计
系统采用角度环(外环)和速度环(内环)的串级PID结构:
c复制typedef struct {
float Target; // 目标值
float Kp, Ki, Kd; // PID参数
float Error; // 当前误差
float Integral; // 积分项
float LastError; // 上次误差
float Out; // 输出值
} PID_TypeDef;
void PID_Calc(PID_TypeDef *pid, float feedback, float dt)
{
pid->Error = pid->Target - feedback;
pid->Integral += pid->Error * dt;
// 积分限幅
if(pid->Integral > 500) pid->Integral = 500;
else if(pid->Integral < -500) pid->Integral = -500;
pid->Out = pid->Kp * pid->Error
+ pid->Ki * pid->Integral
+ pid->Kd * (pid->Error - pid->LastError)/dt;
pid->LastError = pid->Error;
}
4.2 参数整定方法
通过MATLAB仿真确定PID初值后,实际调试采用"先角度后速度"的步骤:
-
角度环调试(保持速度环参数为0)
- 先设Ki=0,Kd=0,逐渐增大Kp直到车体出现小幅振荡
- 加入微分项Kd抑制振荡(典型值0.1~0.5)
- 最后加入小量Ki消除静差(典型值0.001~0.01)
-
速度环调试
- 固定角度环参数
- 重复上述过程,但Kp取值通常比角度环小一个数量级
实测最优参数(单位:角度-度,速度-转/分钟):
c复制AnglePID.Kp = 25.0, AnglePID.Ki = 0.5, AnglePID.Kd = 0.3;
SpeedPID.Kp = 0.8, SpeedPID.Ki = 0.02, SpeedPID.Kd = 0.01;
4.3 转向控制实现
转向控制通过差速实现,算法核心:
c复制// 在平衡控制循环中加入转向处理
void Motor_Output(void)
{
float balance_out = AnglePID.Out + SpeedPID.Out;
float turn_out = TurnPID.Out;
// 左右轮差速输出
PWML = balance_out - turn_out;
PWMR = balance_out + turn_out;
// 输出限幅(PWM占空比±100%)
PWML = constrain(PWML, -100, 100);
PWMR = constrain(PWMR, -100, 100);
// 设置电机输出
Motor_SetPWM(MOTOR_L, PWML);
Motor_SetPWM(MOTOR_R, PWMR);
}
5. 系统调试与优化
5.1 常见问题排查
-
车体无法保持平衡
- 检查MPU6050安装方向(Y轴应与车体前进方向一致)
- 验证传感器数据符号(前倾时角度应为正)
- 确认电机极性(正转应使车体前倾角度减小)
-
出现剧烈振荡
- 降低角度环Kp(每次减小20%)
- 增加微分项Kd(每次增加0.05)
- 检查机械结构是否松动
-
遥控响应延迟
- 测量NRF24L01的CE引脚波形(应有500us脉冲)
- 检查SPI时钟速率(不应超过8MHz)
- 尝试更换2.4G信道(避开WiFi干扰)
5.2 性能优化技巧
-
降低控制延迟
- 将MPU6050的INT引脚连接到MCU外部中断
- 使用DMA方式读取传感器数据
- 优化PID计算代码(启用FPU加速)
-
提高无线可靠性
- 在PCB上为NRF24L01设计π型匹配网络
- 添加钽电容(10uF)稳定电源
- 实现自适应跳频算法(每10秒更换信道)
-
能耗优化
- 动态调整CPU频率(平衡时72MHz,待机时8MHz)
- 关闭未使用的外设时钟
- 采用PWM斩波方式降低电机驱动功耗
6. 进阶开发方向
6.1 上位机调试工具
基于Qt开发的上位机可实现:
- 实时显示姿态数据波形
- 动态调整PID参数
- 记录运行数据用于分析
通信协议采用自定义二进制格式:
code复制帧头(0xAA 0x55) + 长度(1B) + 命令(1B) + 数据(NB) + CRC16(2B)
6.2 路径规划算法
在现有系统上增加超声波或TOF传感器后,可以实现:
- 基于A*算法的静态避障
- 人工势场法的动态避障
- 惯性导航与里程计融合定位
6.3 机器学习应用
通过采集大量运行数据,可以尝试:
- 使用LSTM网络预测车体运动状态
- 基于强化学习自动优化PID参数
- 神经网络替代传统PID控制器
这个平衡车项目从硬件选型到算法实现,处处体现了嵌入式系统开发的精髓。在实际调试过程中,最深的体会是:理论计算只是起点,真正的优化永远来自对实际系统的观察和思考。比如我们发现车体机械谐振频率在8Hz左右,于是在控制算法中特意避开了这个频段,最终使稳定性提升了40%。