项目概述

本项目设计并实现了一款基于 STM32F4 和 FreeRTOS 的两轮自平衡小车,采用串级 PID 控制算法,能够在 200ms 内完成自平衡启动,最大行进速度可达 1.5m/s。

系统架构

平衡小车系统架构图

系统说明

  1. 上层应用:蓝牙遥控、速度指令、状态显示
  2. FreeRTOS 任务层:4 个任务(控制/传感器/通信/显示)
  3. 硬件抽象层:GPIO、TIM、ADC、I2C、UART
  4. 硬件层: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 滤波电路

电源电容作用
VDD10uF 钽电容 → GND低频滤波
VDD0.1uF 陶瓷电容 → GND高频去耦
I2C 总线4.7kΩ → 3.3V上拉电阻

电机驱动去耦

电源电容作用
VM100uF 电解电容 → GND储能
VM0.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 控制

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 微分项过大 + 编码器噪声

解决

  1. 降低 Kd 参数
  2. 编码器数据加入低通滤波
  3. 增加 PWM 死区补偿

问题 2:启动摔倒

现象:上电后无法自平衡,直接摔倒

原因:初始角度偏差过大

解决

  1. 增加 2 秒校准时间
  2. 校准期间锁定电机
  3. 校准后清零角度偏移

问题 3:转向过冲

现象:转向时超调严重

原因:转向 PID 参数过强

解决

  1. 降低转向环 Kp
  2. 增加转向速率限制
  3. 加入前馈补偿

性能测试

平衡性能

测试项目结果
静止平衡±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 站调试视频参考

相关推荐

总结

本项目完整实现了平衡小车的硬件设计、软件开发和调试优化。通过串级 PID 控制和 FreeRTOS 实时调度,达到了良好的平衡效果。项目代码开源,可作为学习嵌入式控制的实践案例。


项目耗时:3 周 | 代码量:5000 行 | 版本:v1.2