项目概述
本项目设计并实现了一款基于 STM32F4 和 FreeRTOS 的两轮自平衡小车,采用串级 PID 控制算法,能够在 200ms 内完成自平衡启动,最大行进速度可达 1.5m/s。
系统架构
系统说明:
- 上层应用:蓝牙遥控、速度指令、状态显示
- FreeRTOS 任务层:4 个任务(控制/传感器/通信/显示)
- 硬件抽象层:GPIO、TIM、ADC、I2C、UART
- 硬件层:STM32F407 + MPU6050 + 电机驱动 + 编码器
核心技术指标
| 指标 | 参数 |
|---|---|
| 控制周期 | 1ms (1kHz) |
| 平衡角度范围 | ±15° |
| 最大速度 | 1.5m/s |
| 启动时间 | <200ms |
| 续航时间 | 60 分钟 |
| 负载能力 | 500g |
硬件设计
核心器件选型
MCU: STM32F407VGT6
- 主频:168MHz
- Flash: 1MB, SRAM: 192KB
- 定时器:12 个(含 4 个高级定时器)
- 编码器接口:硬件正交解码
IMU: MPU6050
- 6 轴:加速度计 + 陀螺仪
- I2C 接口:400kHz
- 量程:±2g / ±2000°/s
电机驱动: TB6612FNG
- 双 H 桥驱动
- 持续电流:1.2A
- PWM 频率:20kHz
电机: N20 减速电机
- 减速比:1:100
- 编码器:11PPR (脉冲/转)
- 额定电压:6V
关键电路设计
MPU6050 滤波电路
| 电源 | 电容 | 作用 |
|---|---|---|
| VDD | 10uF 钽电容 → GND | 低频滤波 |
| VDD | 0.1uF 陶瓷电容 → GND | 高频去耦 |
| I2C 总线 | 4.7kΩ → 3.3V | 上拉电阻 |
电机驱动去耦
| 电源 | 电容 | 作用 |
|---|---|---|
| VM | 100uF 电解电容 → GND | 储能 |
| VM | 0.1uF 陶瓷电容 → GND | 高频噪声 |
软件架构
任务划分
// 任务优先级定义
#define TASK_PRIORITY_CONTROL 5 // 最高
#define TASK_PRIORITY_SENSOR 4
#define TASK_PRIORITY_COMM 3
#define TASK_PRIORITY_DISPLAY 2
// 任务栈大小
#define TASK_STACK_CONTROL 512
#define TASK_STACK_SENSOR 256
#define TASK_STACK_COMM 256
#define TASK_STACK_DISPLAY 128
控制任务 (1kHz)
void vControlTask(void *pvParameters) {
TickType_t xLastWakeTime = xTaskGetTickCount();
for (;;) {
// 1. 读取姿态数据
get_attitude(&roll, &pitch, &yaw);
// 2. 计算平衡控制量 (串级 PID)
float angle_out = pid_angle(&pid_angle_ctrl, target_angle, roll);
float speed_out = pid_speed(&pid_speed_ctrl, target_speed, motor_speed);
// 3. 合成最终 PWM 输出
float pwm_l = angle_out + speed_out;
float pwm_r = angle_out - speed_out;
// 4. 限制 PWM 范围
pwm_l = constrain(pwm_l, -MAX_PWM, MAX_PWM);
pwm_r = constrain(pwm_r, -MAX_PWM, MAX_PWM);
// 5. 更新电机
motor_set_pwm(pwm_l, pwm_r);
// 精确延时 1ms
vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1));
}
}
串级 PID 控制
直立环 (外环):
- 输入:目标角度 vs 实际角度
- 输出:目标速度
- 参数:Kp=15.0, Ki=0.02, Kd=8.0
速度环 (内环):
- 输入:目标速度 vs 实际速度
- 输出:PWM 占空比
- 参数:Kp=2.5, Ki=0.01, Kd=0.5
PID 代码实现:
typedef struct {
float Kp, Ki, Kd;
float integral;
float last_error;
float output_max;
} PID_TypeDef;
float pid_calc(PID_TypeDef *pid, float target, float measure) {
float error = target - measure;
// 比例项
float p_term = pid->Kp * error;
// 积分项 (带限幅)
pid->integral += error;
pid->integral = constrain(pid->integral, -100, 100);
float i_term = pid->Ki * pid->integral;
// 微分项
float d_term = pid->Kd * (error - pid->last_error);
pid->last_error = error;
float output = p_term + i_term + d_term;
return constrain(output, -pid->output_max, pid->output_max);
}
姿态解算
互补滤波
#define ALPHA 0.98f // 滤波系数
void complementary_filter(float *roll, float *pitch) {
// 加速度计解算角度
float accel_roll = atan2f(ay, az) * RAD2DEG;
float accel_pitch = atan2f(-ax, sqrtf(ay*ay + az*az)) * RAD2DEG;
// 陀螺仪积分角度
gyro_roll += gx * dt;
gyro_pitch += gy * dt;
// 互补滤波融合
*roll = ALPHA * (gyro_roll) + (1.0f - ALPHA) * accel_roll;
*pitch = ALPHA * (gyro_pitch) + (1.0f - ALPHA) * accel_pitch;
}
卡尔曼滤波 (进阶)
typedef struct {
float Q_angle; // 过程噪声协方差
float Q_gyro; // 陀螺仪噪声协方差
float R_angle; // 加速度计噪声协方差
float P[2][2]; // 误差协方差矩阵
float K[2]; // 卡尔曼增益
} Kalman_TypeDef;
float kalman_filter(Kalman_TypeDef *k, float newAngle, float newRate, float dt) {
// 预测
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_gyro * dt;
// 更新
float S = k->P[0][0] + k->R_angle;
k->K[0] = k->P[0][0] / S;
k->K[1] = k->P[1][0] / S;
float y = newAngle - k->P[0][0];
k->P[0][0] -= k->K[0] * k->P[0][0];
k->P[0][1] -= k->K[0] * k->P[0][1];
k->P[1][0] -= k->K[1] * k->P[0][0];
k->P[1][1] -= k->K[1] * k->P[0][1];
return k->K[0] * y;
}
调试经验
问题 1:电机抖动
现象:静止时电机高频抖动
原因:PID 微分项过大 + 编码器噪声
解决:
- 降低 Kd 参数
- 编码器数据加入低通滤波
- 增加 PWM 死区补偿
问题 2:启动摔倒
现象:上电后无法自平衡,直接摔倒
原因:初始角度偏差过大
解决:
- 增加 2 秒校准时间
- 校准期间锁定电机
- 校准后清零角度偏移
问题 3:转向过冲
现象:转向时超调严重
原因:转向 PID 参数过强
解决:
- 降低转向环 Kp
- 增加转向速率限制
- 加入前馈补偿
性能测试
平衡性能
| 测试项目 | 结果 |
|---|---|
| 静止平衡 | ±2° |
| 抗干扰恢复 | <500ms |
| 斜坡平衡 | 最大 10° |
| 连续运行 | 60 分钟无漂移 |
运动性能
| 测试项目 | 结果 |
|---|---|
| 最大速度 | 1.5m/s |
| 加速度 | 0.8m/s² |
| 转向响应 | <100ms |
| 定位精度 | ±5cm |
源码与资料
项目资源
| 资源类型 | 链接 | 说明 |
|---|---|---|
| GitHub 源码 | https://github.com/topics/balancing-robot | 开源平衡小车项目合集 |
| 原理图下载 | https://oshwhub.com/ | 立创 EDA 开源平台 |
| 固件编译 | 参考源码自行编译 | 需 STM32CubeIDE |
| 调试视频 | https://space.bilibili.com/search/平衡小车 | B 站调试视频参考 |
相关推荐
- 开源项目: cchost/balancing-robot
- 教程参考: 野火 STM32 平衡小车教程
- 视频教学: B 站 - 平衡小车制作
总结
本项目完整实现了平衡小车的硬件设计、软件开发和调试优化。通过串级 PID 控制和 FreeRTOS 实时调度,达到了良好的平衡效果。项目代码开源,可作为学习嵌入式控制的实践案例。
项目耗时:3 周 | 代码量:5000 行 | 版本:v1.2