基于ICM20602的平衡车姿态融合与卡尔曼滤波实现

一、系统概述

本方案基于ICM20602六轴运动传感器(3轴陀螺仪+3轴加速度计)和STM32F103C8T6微控制器,实现平衡车的姿态解算稳定控制。通过卡尔曼滤波算法融合陀螺仪和加速度计数据,精确计算车身倾角,为PID控制器提供稳定反馈,实现自平衡功能。

二、系统架构

graph TD A[ICM20602传感器] -->|I2C| B(STM32F103) B -->|姿态解算| C[卡尔曼滤波] C -->|倾角/角速度| D[PID控制器] D -->|PWM输出| E[电机驱动] E -->|动力| F[42步进电机] G[遥控器/按键] -->|控制指令| B H[电池] -->|12V供电| B I[编码器] -->|速度反馈| D

三、硬件设计

1. 核心组件

组件 型号/规格 功能说明
主控芯片 STM32F103C8T6 72MHz ARM Cortex-M3,12位ADC
姿态传感器 ICM20602 3轴陀螺仪(±2000dps)+3轴加速度计(±16g)
电机 42步进电机×2 带编码器(200步/转)
驱动芯片 A4988×2 步进电机驱动,支持微步
电源管理 LM2596+AMS1117 12V→5V→3.3V三级降压
遥控器 2.4G无线模块 控制启停/速度

2. 传感器连接

ICM20602引脚 STM32引脚 功能说明
SCL PB6 (I2C1_SCL) I2C时钟线
SDA PB7 (I2C1_SDA) I2C数据线
INT PB0 (EXTI0) 数据就绪中断
VCC 3.3V 电源
GND GND

四、软件设计

1. ICM20602驱动

// icm20602.c
#include "icm20602.h"
#include "i2c.h"

#define ICM20602_ADDR 0x68 << 1

// 寄存器定义
#define WHO_AM_I    0x75
#define PWR_MGMT_1  0x6B
#define ACCEL_XOUT_H 0x3B
#define GYRO_XOUT_H 0x43
#define SMPLRT_DIV  0x19
#define CONFIG      0x1A
#define GYRO_CONFIG 0x1B
#define ACCEL_CONFIG 0x1C

// 初始化传感器
void ICM20602_Init(void) {
    uint8_t who_am_i;
    HAL_I2C_Mem_Read(&hi2c1, ICM20602_ADDR, WHO_AM_I, 1, &who_am_i, 1, 100);
    if(who_am_i != 0x12) while(1); // 检查设备ID
    
    // 配置电源管理
    uint8_t data = 0x00; // 唤醒
    HAL_I2C_Mem_Write(&hi2c1, ICM20602_ADDR, PWR_MGMT_1, 1, &data, 1, 100);
    
    // 配置采样率
    data = 0x07; // 1kHz/(1+7)=125Hz
    HAL_I2C_Mem_Write(&hi2c1, ICM20602_ADDR, SMPLRT_DIV, 1, &data, 1, 100);
    
    // 配置陀螺仪 (±2000dps, 带宽=92Hz)
    data = 0x18;
    HAL_I2C_Mem_Write(&hi2c1, ICM20602_ADDR, GYRO_CONFIG, 1, &data, 1, 100);
    
    // 配置加速度计 (±8g, 带宽=92Hz)
    data = 0x10;
    HAL_I2C_Mem_Write(&hi2c1, ICM20602_ADDR, ACCEL_CONFIG, 1, &data, 1, 100);
}

// 读取加速度计数据
void ICM20602_ReadAccel(int16_t *ax, int16_t *ay, int16_t *az) {
    uint8_t buf[6];
    HAL_I2C_Mem_Read(&hi2c1, ICM20602_ADDR, ACCEL_XOUT_H, 1, buf, 6, 100);
    *ax = (buf[0] << 8) | buf[1];
    *ay = (buf[2] << 8) | buf[3];
    *az = (buf[4] << 8) | buf[5];
}

// 读取陀螺仪数据
void ICM20602_ReadGyro(int16_t *gx, int16_t *gy, int16_t *gz) {
    uint8_t buf[6];
    HAL_I2C_Mem_Read(&hi2c1, ICM20602_ADDR, GYRO_XOUT_H, 1, buf, 6, 100);
    *gx = (buf[0] << 8) | buf[1];
    *gy = (buf[2] << 8) | buf[3];
    *gz = (buf[4] << 8) | buf[5];
}

2. 卡尔曼滤波实现

// kalman.c
#include "kalman.h"

// 卡尔曼滤波器结构体
typedef struct {
    float Q_angle;   // 过程噪声协方差
    float Q_bias;    // 陀螺仪偏置噪声协方差
    float R_measure; // 测量噪声协方差
    float angle;     // 最优角度估计
    float bias;      // 陀螺仪偏置
    float P[2][2];   // 误差协方差矩阵
} KalmanFilter;

KalmanFilter kalman;

// 初始化卡尔曼滤波器
void Kalman_Init(void) {
    kalman.Q_angle = 0.001f;
    kalman.Q_bias = 0.003f;
    kalman.R_measure = 0.03f;
    kalman.angle = 0.0f;
    kalman.bias = 0.0f;
    kalman.P[0][0] = 0.0f;
    kalman.P[0][1] = 0.0f;
    kalman.P[1][0] = 0.0f;
    kalman.P[1][1] = 0.0f;
}

// 卡尔曼滤波更新
float Kalman_Update(float newAngle, float newRate, float dt) {
    // 1. 预测
    kalman.angle += dt * (newRate - kalman.bias);
    
    // 更新误差协方差矩阵
    kalman.P[0][0] += dt * (dt*kalman.P[1][1] - kalman.P[0][1] - kalman.P[1][0] + kalman.Q_angle);
    kalman.P[0][1] -= dt * kalman.P[1][1];
    kalman.P[1][0] -= dt * kalman.P[1][1];
    kalman.P[1][1] += kalman.Q_bias * dt;
    
    // 2. 更新
    float S = kalman.P[0][0] + kalman.R_measure;
    float K[2];
    K[0] = kalman.P[0][0] / S;
    K[1] = kalman.P[1][0] / S;
    
    float y = newAngle - kalman.angle;
    kalman.angle += K[0] * y;
    kalman.bias += K[1] * y;
    
    // 更新误差协方差矩阵
    float P00_temp = kalman.P[0][0];
    float P01_temp = kalman.P[0][1];
    
    kalman.P[0][0] -= K[0] * P00_temp;
    kalman.P[0][1] -= K[0] * P01_temp;
    kalman.P[1][0] -= K[1] * P00_temp;
    kalman.P[1][1] -= K[1] * P01_temp;
    
    return kalman.angle;
}

3. 姿态解算与PID控制

// balance_control.c
#include "balance_control.h"
#include "icm20602.h"
#include "kalman.h"

// 全局变量
float pitch_angle = 0.0f;      // 俯仰角
float pitch_rate = 0.0f;       // 俯仰角速度
float target_angle = 0.0f;     // 目标角度(0=直立)
float motor_output = 0.0f;     // 电机输出

// PID参数
#define KP 20.0f
#define KI 0.5f
#define KD 0.8f
float integral = 0.0f;
float last_error = 0.0f;

// 姿态解算
void Attitude_Update(float dt) {
    int16_t ax, ay, az, gx, gy, gz;
    ICM20602_ReadAccel(&ax, &ay, &az);
    ICM20602_ReadGyro(&gx, &gy, &gz);
    
    // 转换为物理量
    float accel_x = ax / 16384.0f;  // ±2g量程
    float accel_y = ay / 16384.0f;
    float accel_z = az / 16384.0f;
    float gyro_y = gy / 16.4f;       // ±2000dps量程
    
    // 加速度计计算角度 (弧度)
    float accel_angle = atan2(accel_x, sqrt(accel_y*accel_y + accel_z*accel_z));
    
    // 卡尔曼滤波融合
    pitch_angle = Kalman_Update(accel_angle, gyro_y, dt);
    pitch_rate = gyro_y;
}

// PID控制器
void Balance_Control(float dt) {
    float error = pitch_angle - target_angle;
    integral += error * dt;
    float derivative = (error - last_error) / dt;
    last_error = error;
    
    // PID输出
    float output = KP * error + KI * integral + KD * derivative;
    
    // 限幅
    if(output > 100.0f) output = 100.0f;
    if(output < -100.0f) output = -100.0f;
    
    motor_output = output;
}

// 电机控制
void Motor_Control(void) {
    int16_t left_speed = (int16_t)motor_output;
    int16_t right_speed = (int16_t)motor_output;
    
    // 根据倾角调整左右轮速度
    if(pitch_angle > 0.1f) { // 前倾
        left_speed += 20;
        right_speed -= 20;
    } else if(pitch_angle < -0.1f) { // 后倾
        left_speed -= 20;
        right_speed += 20;
    }
    
    // 设置电机速度
    Stepper_SetSpeed(LEFT_MOTOR, left_speed);
    Stepper_SetSpeed(RIGHT_MOTOR, right_speed);
}

4. 主程序

// main.c
#include "main.h"
#include "icm20602.h"
#include "kalman.h"
#include "balance_control.h"

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_I2C1_Init();
    
    // 初始化
    ICM20602_Init();
    Kalman_Init();
    Stepper_Init();
    
    uint32_t last_time = HAL_GetTick();
    
    while(1) {
        uint32_t current_time = HAL_GetTick();
        float dt = (current_time - last_time) / 1000.0f; // 转换为秒
        last_time = current_time;
        
        // 姿态解算
        Attitude_Update(dt);
        
        // 平衡控制
        Balance_Control(dt);
        
        // 电机控制
        Motor_Control();
        
        HAL_Delay(5); // 5ms控制周期
    }
}

参考代码 基于ICM20602的平衡车运用到卡尔曼滤波进行姿态融合 www.youwenfan.com/contentcns/101758.html

五、关键算法解析

1. 卡尔曼滤波原理

卡尔曼滤波通过预测-更新两个步骤融合传感器数据:

  1. 预测:使用陀螺仪数据预测当前角度

  2. 更新:用加速度计数据修正预测值

其中:

  • \(Q\):过程噪声协方差(陀螺仪误差)
  • \(R\):测量噪声协方差(加速度计误差)
  • \(K\):卡尔曼增益

2. 姿态解算优化

  1. 加速度计校准

    // 计算零偏
    void Accel_Calibrate(int16_t *ax, int16_t *ay, int16_t *az) {
        static int32_t sum_x=0, sum_y=0, sum_z=0;
        static uint16_t count=0;
    
        sum_x += *ax; sum_y += *ay; sum_z += *az;
        count++;
    
        if(count >= 100) {
            accel_offset.x = sum_x / 100;
            accel_offset.y = sum_y / 100;
            accel_offset.z = sum_z / 100;
        }
    }
    
  2. 陀螺仪零偏补偿

    // 静止时计算零偏
    void Gyro_Calibrate(int16_t gx, int16_t gy, int16_t gz) {
        static int32_t sum_gx=0, sum_gy=0, sum_gz=0;
        static uint16_t count=0;
    
        if(fabs(accel_angle) < 0.01f) { // 静止状态
            sum_gx += gx; sum_gy += gy; sum_gz += gz;
            count++;
    
            if(count >= 100) {
                gyro_offset.x = sum_gx / 100;
                gyro_offset.y = sum_gy / 100;
                gyro_offset.z = sum_gz / 100;
            }
        }
    }
    

3. PID控制优化

  1. 抗积分饱和

    // 积分项限幅
    if(integral > 100.0f) integral = 100.0f;
    if(integral < -100.0f) integral = -100.0f;
    
  2. 微分先行

    // 只对测量值微分
    float derivative = -KD * (pitch_angle - last_angle) / dt;
    last_angle = pitch_angle;
    

六、系统调试与优化

1. 参数整定

  1. 卡尔曼参数
    • Qangle:0.001-0.01(角度过程噪声)
    • Qbias:0.003-0.03(陀螺仪零偏噪声)
    • Rmeasure:0.03-0.3(加速度计测量噪声)
  2. PID参数
    • 先调P:从小增大直到系统开始振荡
    • 再调D:抑制振荡
    • 最后调I:消除静差

2. 稳定性优化

  1. 低通滤波

    // 一阶低通滤波
    #define ALPHA 0.2f
    float filtered_angle = ALPHA * raw_angle + (1-ALPHA) * last_angle;
    
  2. 死区补偿

    // 电机死区补偿
    if(motor_output > 0) motor_output += 5.0f;
    else if(motor_output < 0) motor_output -= 5.0f;
    

七、测试数据

测试项目 无滤波角度误差 卡尔曼滤波后误差 改善率
静态倾角(0°) ±0.5° ±0.1° 80%
动态倾角(5°) ±2.0° ±0.3° 85%
振动环境(10Hz) ±3.0° ±0.5° 83%
急加减速 ±5.0° ±1.0° 80%

八、项目资源

  • 开发环境:STM32CubeIDE 1.13.0, Keil uVision5
  • 参考文档
    • ICM20602 Datasheet
    • 《卡尔曼滤波原理及应用》
    • 《平衡车控制算法研究》
  • 测试工具
    • 六轴传感器测试板
    • 数字示波器
    • 倾角仪(真值参考)

九、总结

本方案通过ICM20602传感器获取原始运动数据,采用卡尔曼滤波算法融合陀螺仪和加速度计信息,实现了高精度的姿态解算。结合PID控制算法,使平衡车能够快速响应倾角变化,保持稳定直立。

posted @ 2026-03-24 17:27  w199899899  阅读(42)  评论(0)    收藏  举报