Skip to content

Accelerometer calibration efficiency using magneto 1.4 #508

@brightproject

Description

@brightproject

Unfortunately, I don't expect to receive any responses, as this repository and issue are used for tracking developer issues, not for users of this library.
In this case, I would like to ask you to open DISCUSSIONS.
Otherwise, the purpose of a community for this repo is lost, IMHO🙄

I'm testing the calibration algorithm for the ICM45686 and QMC6309 sensors.

Image

The magneto algorithm is ideal for the magnetometer, but I'm having trouble calibrating the accelerometer.
I got the code from here:

magneto_acc->current_calibration(A_BAinv);

But usually, the accelerometer is simply fixed along the X, Y, and Z axes and the sign is changed, resulting in six measurements.
And with a magnetometer, should the magnetometer calibration also be performed in a stationary state, or what?
In any case, we move the accelerometer sensor, and accelerations involuntarily occur, no matter how carefully we try to move the axes along the table.
Values ​​obtained after calibration:

Image

I would like an explanation of the calibration algorithm as it applies to the accelerometer, because in my experience, it has been inaccurate🙂

// ACCELEROMETER CALIBRATION (stationary positions)
AccelCalibration calibrateAccelerometer(const vector<Vector3f>& accelData) {
    /*
      * The accelerometer is calibrated in STILL positions!
      * Expected positions (in g units):
      * 1. Z up: (0, 0, 1)
      * 2. Z down: (0, 0, -1)
      * 3. Y up: (0, 1, 0)
      * 4. Y down: (0, -1, 0)
      * 5. X up: (1, 0, 0)
      * 6. X down: (-1, 0, 0)
     */
    
    int n = accelData.size();
    if (n < 6) {
        cerr << "Error: At least 6 measurements are required to calibrate the accelerometer" << endl;
        return AccelCalibration();
    }
    
    // Least-squares method for the accelerometer
    // Equation: S * (raw - bias) = ​​reference
    // where reference is the known gravity vector (0, 0, ±1g, etc.)
    
    // We assume that the data is already split into positions
    // In reality, you need to transmit data separately for each position
    
    // Simplified method: calibrating only the offset and scale
    Vector3f minVal(10000, 10000, 10000);
    Vector3f maxVal(-10000, -10000, -10000);
    
    for (const auto& point : accelData) {
        for (int i = 0; i < 3; i++) {
            if (point[i] < minVal[i]) minVal[i] = point[i];
            if (point[i] > maxVal[i]) maxVal[i] = point[i];
        }
    }
    
    AccelCalibration result;
    
    // Bias - midpoint of range
    result.bias = (minVal + maxVal) / 2.0f;
    
    // Scale factors
    // Range should correspond to ±1g = ±9.8 m/s²
    Vector3f range = maxVal - minVal;
    
    // Assume full range = 2g (from -1g to +1g)
    // If the accelerometer sensitivity is, for example, 16384 LSB/g
    result.scale = Matrix3f::Identity();
    result.scale(0,0) = 2.0f / range.x(); // To convert to g
    result.scale(1,1) = 2.0f / range.y();
    result.scale(2,2) = 2.0f / range.z();
    
    result.invScale = result.scale.inverse();
    
    return result;
}

I would be happy to discuss the project and my question @Eirenliel

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions