基于STM32的平衡机器人PID控制系统设计

一、系统概述与核心原理

1. 系统定位

基于STM32的两轮自平衡机器人(Balance Bot)是自动控制理论的经典实践平台。系统通过MPU6050陀螺仪实时监测车身倾角,利用PID算法计算出电机补偿量,驱动直流电机保持车身直立不倒,并实现前进、后退与转向控制。

2. 控制原理

  • 直立控制:基于角度闭环(PD控制),当车身前倾时,电机向前加速;后仰时向后加速。
  • 速度控制:基于编码器闭环(PI控制),抵消直立控制带来的速度波动,实现稳态精度。
  • 方向控制:差速转向,左右轮速度差实现转向。

3. 核心硬件选型

模块 型号 关键参数 接口方式
主控 STM32F103C8T6 72MHz Cortex-M3,3个通用定时器,2路ADC 核心控制器
姿态传感器 MPU6050 3轴陀螺仪+3轴加速度,±2000°/s,I2C接口 I2C1 (PB6/PB7)
电机驱动 TB6612FNG 双H桥,1.2A/路,内置死区控制 IN1-4 (PB0-PB3),PWMA/B (PA8/PA9)
直流电机 520直流电机+霍尔编码器 减速比1:30,编码器分辨率390线/转 编码器A/B相 (PA0/PA1, PA6/PA7)
电源 18650锂电池×2 7.4V/2200mAh,带2A过流保护 7.4V直驱电机,5V降压给MCU

二、硬件设计方案

1. 核心电路连接

STM32F103C8T6
├── MPU6050 (I2C1)
│   ├── SCL = PB6
│   ├── SDA = PB7
│   └── INT = PA0 (数据就绪中断)
├── 电机驱动 (TB6612)
│   ├── 左电机:IN1=PB0, IN2=PB1, PWMA=PA8 (TIM1_CH1)
│   └── 右电机:IN3=PB2, IN4=PB3, PWMB=PA9 (TIM1_CH2)
├── 编码器 (TIM2/TIM3)
│   ├── 左编码器:A=PA0 (TIM2_CH1), B=PA1 (TIM2_CH2)
│   └── 右编码器:A=PA6 (TIM3_CH1), B=PA7 (TIM3_CH2)
└── 按键/指示灯
    ├── 启动/停止按键 = PC0
    └── 状态LED = PC1

2. 机械结构设计要点

  • 重心位置:电池组安装在车体最下端,重心越低,平衡控制越容易(建议重心高度<15cm)。
  • 轮子直径:推荐65-80mm,过大导致惯量增加,过小导致控制精度不足。
  • 电机安装:电机轴线与车身对称轴重合,避免转向力矩不平衡。

三、软件设计与核心PID算法

1. 系统架构(前后台系统)

  • 后台(中断)
    • TIM1更新中断(1ms):执行PID计算,更新电机PWM输出。
    • TIM2/TIM3编码器接口:硬件计数电机转速。
    • MPU6050中断(10ms):读取原始数据,DMP解算姿态角。
  • 前台(主循环):OLED显示状态、按键扫描、蓝牙指令解析。

2. 核心PID算法实现

2.1 直立环PD控制器(最关键)

控制原理:角度偏差 → PD计算 → 电机PWM输出

#include "control.h"

// PID参数结构体
typedef struct {
    float Kp;       // 比例系数(决定响应速度)
    float Ki;       // 积分系数(消除稳态误差)
    float Kd;       // 微分系数(抑制超调/震荡)
    float integral;  // 积分累积
    float prev_error; // 上次误差(用于微分)
} PID_Controller_t;

// 直立环PID(PD控制)
// 输入:target_angle(目标角度,通常0°=直立),current_angle(当前角度)
// 输出:电机PWM值(-1000 ~ +1000)
int16_t Vertical_PID(float target_angle, float current_angle) {
    static PID_Controller_t pid = {
        .Kp = 800.0f,    // 比例系数:800(需根据机械结构调整)
        .Ki = 0.0f,      // 直立环通常不加积分(避免稳态抖动)
        .Kd = 2.5f,      // 微分系数:2.5(抑制车身晃动)
        .integral = 0.0f,
        .prev_error = 0.0f
    };
    
    float error = target_angle - current_angle;  // 角度偏差
    float derivative = error - pid.prev_error;   // 微分项(变化率)
    
    // PD输出 = Kp*误差 + Kd*微分
    int16_t output = (int16_t)(pid.Kp * error + pid.Kd * derivative);
    
    pid.prev_error = error;  // 保存本次误差
    return output;
}

2.2 速度环PI控制器(辅助稳定)

控制原理:编码器速度偏差 → PI计算 → 直立环角度补偿

// 速度环PI控制器
// 输入:target_speed(目标速度),current_speed(当前速度,编码器计数/秒)
// 输出:角度补偿值(叠加到直立环目标角度)
int16_t Velocity_PID(int16_t target_speed, int16_t current_speed) {
    static PID_Controller_t pid = {
        .Kp = 8.0f,     // 比例系数:8
        .Ki = 0.4f,     // 积分系数:0.4(消除速度静差)
        .Kd = 0.0f,     // 速度环不加微分
        .integral = 0.0f,
        .prev_error = 0.0f
    };
    
    int16_t error = target_speed - current_speed;
    pid.integral += error;  // 积分累积
    
    // 积分限幅(防止积分饱和)
    if (pid.integral > 1000) pid.integral = 1000;
    if (pid.integral < -1000) pid.integral = -1000;
    
    // PI输出 = Kp*误差 + Ki*积分
    int16_t output = (int16_t)(pid.Kp * error + pid.Ki * pid.integral);
    return output;
}

2.3 转向环P控制器(差速控制)

// 转向环P控制器(简单比例控制)
// 输入:turn_angle(转向角度,-100~+100,负值左转,正值右转)
// 输出:左右轮速度差
int16_t Turn_PID(int16_t turn_angle) {
    float Kp_turn = 5.0f;  // 转向比例系数
    return (int16_t)(Kp_turn * turn_angle);
}

3. 主控制循环(1ms定时中断)

#include "stm32f10x.h"
#include "mpu6050.h"
#include "encoder.h"
#include "motor.h"

// 全局变量
float current_angle = 0.0f;      // 当前车身角度(来自MPU6050)
int16_t left_speed = 0, right_speed = 0;  // 编码器速度
int16_t vertical_out = 0, velocity_out = 0, turn_out = 0;  // PID输出

// TIM1更新中断(1ms执行一次,控制核心)
void TIM1_UP_IRQHandler(void) {
    if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) {
        // 1. 读取传感器数据
        current_angle = MPU6050_GetAngle();  // 获取车身倾角(DMP解算)
        left_speed = Encoder_GetLeftSpeed();   // 左轮编码器速度
        right_speed = Encoder_GetRightSpeed(); // 右轮编码器速度
        
        // 2. 直立环PID(核心:保持车身直立)
        vertical_out = Vertical_PID(0.0f, current_angle);  // 目标角度0°
        
        // 3. 速度环PID(辅助:消除速度静差)
        int16_t avg_speed = (left_speed + right_speed) / 2;
        velocity_out = Velocity_PID(0, avg_speed);  // 目标速度0(原地平衡)
        
        // 4. 转向环PID(差速控制)
        turn_out = Turn_PID(0);  // 目标转向0(直行)
        
        // 5. 合成最终PWM输出
        int16_t left_pwm = vertical_out + velocity_out - turn_out;
        int16_t right_pwm = vertical_out + velocity_out + turn_out;
        
        // 6. 输出限幅(防止PWM溢出)
        if (left_pwm > 1000) left_pwm = 1000;
        if (left_pwm < -1000) left_pwm = -1000;
        if (right_pwm > 1000) right_pwm = 1000;
        if (right_pwm < -1000) right_pwm = -1000;
        
        // 7. 设置电机PWM
        Motor_SetPWM(left_pwm, right_pwm);
        
        TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
    }
}

4. MPU6050姿态解算(DMP硬件解算)

#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"

// MPU6050初始化与DMP配置
uint8_t MPU6050_Init(void) {
    // 1. 初始化MPU6050
    mpu_init();
    
    // 2. 配置DMP(数字运动处理器)
    dmp_load_motion_driver_firmware();  // 加载DMP固件
    dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));
    dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT | DMP_FEATURE_SEND_RAW_ACCEL | 
                      DMP_FEATURE_SEND_CAL_GYRO | DMP_FEATURE_GYRO_CAL);
    dmp_set_fifo_rate(10);  // 100ms输出一次数据
    
    // 3. 设置陀螺仪量程±2000°/s,加速度计量程±2g
    mpu_set_gyro_range(MPU_GYRO_FS_2000);
    mpu_set_accel_range(MPU_ACCEL_FS_2);
    
    return 0;
}

// 获取车身倾角(通过DMP解算四元数,转换为欧拉角)
float MPU6050_GetAngle(void) {
    short gyro[3], accel[3];
    long quat[4];
    float pitch, roll, yaw;
    
    if (dmp_read_fifo(gyro, accel, quat, &sensor_timestamp) == 0) {
        // 四元数转换为欧拉角
        dmp_get_euler_angles(quat, &pitch, &roll, &yaw);
        return roll;  // 返回车身倾角(roll角)
    }
    return 0.0f;
}

参考代码 stm32 平衡机器人采用PID程序 www.youwenfan.com/contentcst/123511.html

四、PID参数整定指南(核心难点)

1. 整定步骤(必须按顺序执行)

步骤 操作 目标 现象
1. 直立环Kp 从0逐渐增大Kp 车身能短暂直立 车身剧烈震荡,像倒立摆
2. 直立环Kd 从0逐渐增大Kd 抑制震荡,平稳直立 车身不再剧烈晃动,轻微摆动
3. 速度环Kp 从0逐渐增大Kp 消除速度静差 用手推车身,能缓慢回位
4. 速度环Ki 从0逐渐增大Ki 完全消除静差 车身静止不动,无漂移

2. 典型参数参考(需根据实际机械结构调整)

参数 直立环(Kp) 直立环(Kd) 速度环(Kp) 速度环(Ki)
参考值 600~1200 1.5~4.0 5~15 0.2~0.8
过大现象 剧烈震荡 高频抖动 速度突变 积分饱和
过小现象 无法直立 反应迟钝 速度漂移 无法回位

3. 调试技巧

  • 分步调试:先调直立环(速度环Ki=0),再调速度环。
  • 手动辅助:调试时用手扶着车身,防止摔坏电机。
  • 数据监控:通过串口打印角度、PWM值,观察系统响应曲线。

五、系统调试与扩展

1. 调试步骤

阶段 操作 工具
硬件调试 测量电机PWM波形,验证编码器计数方向 示波器、万用表
姿态调试 验证MPU6050角度输出是否与实际倾角一致 串口助手、串口绘图工具
PID整定 按步骤整定直立环、速度环参数 示波器观察角度响应曲线
功能测试 测试前进、后退、转向功能 实际场地测试

2. 扩展功能

  • 蓝牙遥控:添加HC-05蓝牙模块,通过手机APP控制平衡车移动。
  • 超声波避障:添加HC-SR04超声波,实现自动避障功能。
  • OLED显示:实时显示角度、速度、电池电压等信息。
  • 自动充电:添加红外寻线传感器,实现自动回充功能。

六、总结

基于STM32的平衡机器人通过MPU6050+DMP实现精准姿态解算,采用“直立环PD+速度环PI”的串级控制结构,确保车身稳定直立。

posted @ 2026-04-16 09:23  晃悠人生  阅读(85)  评论(0)    收藏  举报