Accelerometer calibration efficiency using magneto 1.4 #16

Open
opened 2026-04-05 17:51:37 +02:00 by MrUnknownDE · 0 comments
Owner

Originally created by @brightproject on 12/25/2025

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:

6cd29c7cea/src/sensors/mpu9250sensor.cpp (L350)

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

*Originally created by @brightproject on 12/25/2025* 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. <img width="557" height="560" alt="Image" src="https://github.com/user-attachments/assets/9f221fe5-95c2-4af5-bfb1-da4f18d98068" /> The magneto algorithm is ideal for the magnetometer, but I'm having trouble calibrating the accelerometer. I got the code from here: > https://github.com/SlimeVR/SlimeVR-Tracker-ESP/blob/6cd29c7cea33f250e356ba09b238d911d86c0adc/src/sensors/mpu9250sensor.cpp#L350 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](https://github.com/user-attachments/assets/25b638b9-9bbd-4fdd-8737-e3fcdcf65eae) I would like an explanation of the calibration algorithm as it applies to the accelerometer, because in my experience, it has been inaccurate🙂 ```c++ // 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
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/SlimeVR-Tracker-ESP#16