“STM32F103 与 MPU6050 和 HMC5883L 集成中的偏航漂移问题”

问题描述 投票:0回答:1

我将 STM32F103RT6TR 与 MPU6050 和 HMC5883L 集成,以计算加速度、陀螺仪、俯仰、滚动和偏航值。虽然其他一切工作正常,但偏航值正在漂移。有人可以帮我解决这个问题吗?


void MPU6050_Calibrate(I2C_HandleTypeDef *hi2c)
{
    uint8_t rawData[14];
    int16_t accel_raw[3], gyro_raw[3];
    int samples = 2000;

    printf("Calibrating...\n");

    for (int i = 0; i < samples; i++)
    {
        HAL_I2C_Mem_Read(hi2c, MPU6050_ADDR, ACCEL_XOUT_H, 1, rawData, 14, HAL_MAX_DELAY);

        accel_raw[0] = (int16_t)(rawData[0] << 8 | rawData[1]);
        accel_raw[1] = (int16_t)(rawData[2] << 8 | rawData[3]);
        accel_raw[2] = (int16_t)(rawData[4] << 8 | rawData[5]);
        gyro_raw[0] = (int16_t)(rawData[8] << 8 | rawData[9]);
        gyro_raw[1] = (int16_t)(rawData[10] << 8 | rawData[11]);
        gyro_raw[2] = (int16_t)(rawData[12] << 8 | rawData[13]);

        accel_offset[0] += accel_raw[0];
        accel_offset[1] += accel_raw[1];
        accel_offset[2] += accel_raw[2];
        gyro_offset[0] += gyro_raw[0];
        gyro_offset[1] += gyro_raw[1];
        gyro_offset[2] += gyro_raw[2];

        //printf("Calibration %d\n",i);
    }

    // Average offsets
    for (int i = 0; i < 3; i++)
    {
        accel_offset[i] /= samples;
        gyro_offset[i] /= samples;
    }
    accel_offset[2] -= ACCEL_SCALE;  // Gravity adjustment
    printf("Calibration Done...\n");
}
// Read all data from MPU6050
void MPU6050_Read_All(I2C_HandleTypeDef *hi2c, float *accel, float *gyro, float *angles)
{
    uint8_t rawData[14];
    int16_t accel_raw[3], gyro_raw[3];
    float accel_angle[2];  // Roll and Pitch from accelerometer

    uint32_t current_time = HAL_GetTick();
    float dt = (current_time - last_time)/1000.0;  // time difference in seconds

    if(dt == 0)
        dt = 0.01; // fallback for very fast loops

    // Read accelerometer and gyroscope data
    HAL_I2C_Mem_Read(hi2c, MPU6050_ADDR, ACCEL_XOUT_H, 1, rawData, 14, HAL_MAX_DELAY);

    // Convert raw data
    accel_raw[0] = (int16_t)(rawData[0] << 8 | rawData[1]);
    accel_raw[1] = (int16_t)(rawData[2] << 8 | rawData[3]);
    accel_raw[2] = (int16_t)(rawData[4] << 8 | rawData[5]);
    gyro_raw[0] = (int16_t)(rawData[8] << 8 | rawData[9]);
    gyro_raw[1] = (int16_t)(rawData[10] << 8 | rawData[11]);
    gyro_raw[2] = (int16_t)(rawData[12] << 8 | rawData[13]);

    // Scale the values
    accel[0] = (accel_raw[0] - accel_offset[0]) / ACCEL_SCALE;
    accel[1] = (accel_raw[1] - accel_offset[1]) / ACCEL_SCALE;
    accel[2] = (accel_raw[2] - accel_offset[2]) / ACCEL_SCALE;

    gyro[0] = (gyro_raw[0] - gyro_offset[0]) / GYRO_SCALE;
    gyro[1] = (gyro_raw[1] - gyro_offset[1]) / GYRO_SCALE;
    gyro[2] = (gyro_raw[2] - gyro_offset[2]) / GYRO_SCALE;

    // Calculate angles from accelerometer
    accel_angle[0] = atan2f(accel[1], sqrtf(accel[0] * accel[0] + accel[2] * accel[2])) * 180.0 / M_PI;  // Roll
    accel_angle[1] = atan2f(-accel[0], sqrtf(accel[1] * accel[1] + accel[2] * accel[2])) * 180.0 / M_PI;  // Pitch

    // Apply Kalman filter for roll and pitch
    angles[0] = Kalman_Filter(accel_angle[0], gyro[0], dt, &roll_state, &roll_bias);
    angles[1] = Kalman_Filter(accel_angle[1], gyro[1], dt, &pitch_state, &pitch_bias);

    float magnetometer_yaw = atan2f(mag_y, mag_x) * 180.0 / M_PI;  // Magnetometer-based yaw
    yaw = 0.98 * (yaw + gyro[2] * dt) + 0.02 * magnetometer_yaw;  // Complementary filter
    angles[2] = yaw;

    last_time = current_time;


}

void HMC5883L_Read_Mag(void)
{
    uint8_t mag_data[6];
    int16_t raw_x, raw_y, raw_z;

    // Read magnetometer data
    HAL_I2C_Mem_Read(&hi2c1, HMC5883L_ADDR, HMC5883L_DATA_X_MSB, 1, mag_data, 6, HAL_MAX_DELAY);

    // Combine high and low bytes
    raw_x = (int16_t)(mag_data[0] << 8 | mag_data[1]);
    raw_z = (int16_t)(mag_data[2] << 8 | mag_data[3]);
    raw_y = (int16_t)(mag_data[4] << 8 | mag_data[5]);

    // Convert to Gauss (apply scale if necessary)
    mag_x = (float)raw_x * MAG_SCALE;
    mag_y = (float)raw_y * MAG_SCALE;
}
// Kalman filter implementation
float Kalman_Filter(float accel_angle, float gyro_rate, float dt, float *state, float *bias)

{
    static float P[2][2] = { {1, 0}, {0, 1} };  // Initial error covariance
    const float Q_angle = 0.001, Q_bias = 0.003, R_measure = 0.03;  // Tuning parameters

    float rate = gyro_rate - *bias;
    *state += dt * rate;

    // Predict error covariance
    P[0][0] += dt * (dt * P[1][1] - P[0][1] - P[1][0] + Q_angle);
    P[0][1] -= dt * P[1][1];
    P[1][0] -= dt * P[1][1];
    P[1][1] += Q_bias * dt;

    // Kalman gain
    float S = P[0][0] + R_measure;
    float K[2] = { P[0][0] / S, P[1][0] / S };

    // Update state with measurement
    float y = accel_angle - *state;  // Measurement residual
    *state += K[0] * y;
    *bias += K[1] * y;

    // Update error covariance
    float P00_temp = P[0][0];
    float P01_temp = P[0][1];
    P[0][0] -= K[0] * P00_temp;
    P[0][1] -= K[0] * P01_temp;
    P[1][0] -= K[1] * P00_temp;
    P[1][1] -= K[1] * P01_temp;

    return *state;
}
 

main
功能中,我初始化MPU6050和HMC5883L,然后校准MPU6050。在
while
循环内,我先调用
HMC5883L_Read_Mag()
,然后调用
MPU6050_Read_All(&hi2c1, accel, gyro, angles)

embedded stm32 gyroscope mpu6050
1个回答
0
投票

SO 并不是推荐库,但与 6axis 相关的数学比简单的方程复杂得多。 集成来自许多 MEMS 传感器的数据并不是一件容易的事。

正在成功使用https://www.st.com/en/embedded-software/x-cube-mems1.html.

© www.soinside.com 2019 - 2024. All rights reserved.