Skip to content

Acceleration z-axis offset is incorrect after using CalibrateAccel function #103

@amsjntz

Description

@amsjntz

I've written a small sketch for an ESP32 that calls mpu.getMotion6() repeatedly, and calculates the average values over the last 400 samples:

#include "MPU6050.h"

#define IMU_SDA_PIN D4
#define IMU_SCL_PIN D5

#define NUM_SAMPLES 400

int16_t accel_x[NUM_SAMPLES];
int16_t accel_y[NUM_SAMPLES];
int16_t accel_z[NUM_SAMPLES];

int16_t gyro_x[NUM_SAMPLES];
int16_t gyro_y[NUM_SAMPLES];
int16_t gyro_z[NUM_SAMPLES];

size_t sample_idx = 0;

MPU6050 mpu;

void setup() {
    Serial.begin(115200);

    // IMU initialization
    Wire.begin(IMU_SDA_PIN, IMU_SCL_PIN, 400000);
    mpu.initialize();
    Serial.println("testing mpu connection");
    if (mpu.testConnection()) {
        delay(500);
        Serial.println("MPU6050 connected");

        mpu.setXGyroOffset(0);
        mpu.setYGyroOffset(0);
        mpu.setZGyroOffset(0);
        mpu.setXAccelOffset(0);
        mpu.setYAccelOffset(0);
        mpu.setZAccelOffset(0);

        mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_4);
        mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_250);

        Serial.println("calibrating IMU...");

        mpu.CalibrateAccel(60);
        mpu.CalibrateGyro(60);

        Serial.println("Done calibrating");
    } else {
        Wire.end();
        Serial.println("no MPU6050 found");
    }
}

void loop() {
    mpu.getMotion6(&accel_x[sample_idx], &accel_y[sample_idx], &accel_z[sample_idx], &gyro_x[sample_idx], &gyro_y[sample_idx], &gyro_z[sample_idx]);

    sample_idx++;
    if (sample_idx >= NUM_SAMPLES) {
        sample_idx = 0;

        int64_t accel_x_sum = 0;
        int64_t accel_y_sum = 0;
        int64_t accel_z_sum = 0;
        int64_t gyro_x_sum = 0;
        int64_t gyro_y_sum = 0;
        int64_t gyro_z_sum = 0;
        
        for (size_t i = 0; i < NUM_SAMPLES; i++) {
            accel_x_sum += accel_x[i];
            accel_y_sum += accel_y[i];
            accel_z_sum += accel_z[i];
            gyro_x_sum += gyro_x[i];
            gyro_y_sum += gyro_y[i];
            gyro_z_sum += gyro_z[i];
        }

        float average_ax = accel_x_sum / (float) NUM_SAMPLES;
        float average_ay = accel_y_sum / (float) NUM_SAMPLES;
        float average_az = accel_z_sum / (float) NUM_SAMPLES;

        float average_gx = gyro_x_sum / (float) NUM_SAMPLES;
        float average_gy = gyro_y_sum / (float) NUM_SAMPLES;
        float average_gz = gyro_z_sum / (float) NUM_SAMPLES;

        Serial.printf("ax: %f, ay: %f, az: %f, gx: %f, gy: %f, gz: %f\n", average_ax, average_ay, average_az, average_gx, average_gy, average_gz);
    }

    delay(5);
}

With the sensor completely still and upright, an example output of the sketch looks like this:
ax: -167.300003, ay: -2.940000, az: 16364.785156, gx: 2.967500, gy: 0.482500, gz: 3.402500

Note that we should actually expect az to be approximately 8192 for the 4G range setting, which it clearly is not. It is definetly an issue with the generated offsets from mpu.CalibrateAccel(), as the output changes to something like this when pointing the sensor straight down:
ax: 110.449997, ay: -216.229996, az: -403.950012, gx: 4.822500, gy: 2.887500, gz: 1.022500

Now, az is somewhat close to zero, while we expect it to be at around -8192.

I tried to fix the offset by including this code snippet after the calls to the calibration functions:

int16_t old_z_offset = mpu.getXAccelOffset();
int16_t new_z_offset = old_z_offset + 8192;
mpu.setZAccelOffset(new_z_offset);

This only made things worse though. The only successful way to get at least somewhat correct values out of this was by doing a manual calibration like this:

// do z accel calibration separately because otherwise its not accurate for some reason:
int64_t sum = 0;
for (unsigned int i = 0; i < 100; i++) {
    sum += mpu.getAccelerationZ();
    delay(10);
}
int16_t avg_z = (int16_t) (sum / 100);
int16_t expected_z = 8192; // 4G range -> 8192 is 1G
manual_z_offset = expected_z - avg_z; // manually add this value to measured accel_z values to make them more correct

I sadly was not able to find any more info on this problem, so I hope I can get some support on the matter by opening an issue. I also couldn't rule out a hardware issue yet, as I have no another MPU6050 module to test this with.

Also, a proper calibration would of course make use of the IMU_Zero sketch from the examples. I don't think this would change anything in my case though.

Many thanks for providing this library - I hope we can improve it together :)

Metadata

Metadata

Assignees

Labels

BugSomething isn't workingFeedbackImprovements or additions

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions