Roll Pitch Yaw steady output

hi

i searched a lot to solve this problem and found a few interesting things but not the solution:

Hardware: ESP32C6 with QMI8658

if i understood this right i have to calibrate (because its a 6DOF) the magnetic things with the programm magneto 1.2. So i found this: GitHub - michaelwro/accelerometer-calibration: A general method (with Python scripts) for calibrating accelerometer sensors.

That seems to be nice and working. But where i’m still confused. I want to have a code where i can than use this correctional data.

So i found the code from @jremington with this lines:

// vvvvvvvvvvvvvvvvvv  VERY VERY IMPORTANT vvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//These are the previously determined offsets and scale factors for accelerometer and gyro for
// a particular example of an MPU-6050. They are not correct for other examples.
//The AHRS will NOT work well or at all if these are not correct

float A_cal[6] = {265.0, -80.0, -700.0, 0.994, 1.000, 1.014}; // 0..2 offset xyz, 3..5 scale xyz
float G_off[3] = { -499.5, -17.7, -82.0}; //raw offsets, determined for gyro at rest
#define gscale ((250./32768.0)*(PI/180.0))  //gyro default 250 LSB per d/s -> rad/s

// ^^^^^^^^^^^^^^^^^^^ VERY VERY IMPORTANT ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

So it seems that this and the megneto programm corresponds - but how? The output is one 3 values and 2 times 3 rows with 3 values. So the question where tu put what?

I tried a lot of programs but nothing gives me steady roll pitch yaw angles.

Could anyone give me a hint where to find the explanation from going with the magneto callibration values in an Arduino filter code to get rid of the steady changing values?

the nearest code to the problem which works (i get values but these values are not stable and also in the wrong range (roll between -29.7 and +30.7 and pitch between -27.1 and 30.1 and Yaw between -179.9 and +179.9) so YAW seems to work.

The code (i knew that there is only a simple low pass filter):

/*
  QMI8658 Advanced Example
  
  This example demonstrates advanced features of the QMI8658 library:
  - Motion detection
  - Data filtering
  - Orientation calculation
  - Calibration
  
  Hardware connections:
  - VCC to 3.3V
  - GND to GND
  - SDA to pin 21 (ESP32) or A4 (Arduino)
  - SCL to pin 22 (ESP32) or A5 (Arduino)
  
  Author: [Your Name]
*/

#include <QMI8658.h>
#include <math.h>

QMI8658 imu;

// Pin definitions (adjust for your board)
#define SDA_PIN 18  // ESP32 default
#define SCL_PIN 19  // ESP32 default

// Motion detection variables
float accelThreshold = 2.0;  // m/s² threshold for motion detection
bool motionDetected = false;
unsigned long lastMotionTime = 0;

// Calibration variables
float accelOffsetX = 0, accelOffsetY = 0, accelOffsetZ = 0;
float gyroOffsetX = 0, gyroOffsetY = 0, gyroOffsetZ = 0;
bool calibrated = false;

// Filter variables (simple low-pass filter)
float filteredAccelX = 0, filteredAccelY = 0, filteredAccelZ = 0;
float filteredGyroX = 0, filteredGyroY = 0, filteredGyroZ = 0;
const float alpha = 0.1; // Filter coefficient (0-1, lower = more filtering)

float min_roll, min_pitch, min_yaw;
float max_roll, max_pitch, max_yaw;

void setup() {
    Serial.begin(115200);
    while (!Serial) delay(10);
    
    Serial.println("QMI8658 Advanced Example");
    Serial.println("========================");
    
    // Initialize IMU
    if (!imu.begin(SDA_PIN, SCL_PIN)) {
        Serial.println("❌ Failed to initialize QMI8658!");
        Serial.println("Check connections and try again.");
        while (1) delay(1000);
    }
    
    Serial.println("✅ QMI8658 initialized successfully!");
    Serial.print("Device ID: 0x");
    Serial.println(imu.getWhoAmI(), HEX);
    
    // Configure sensor
    Serial.println("\n🔧 Configuring sensor...");
    imu.setAccelRange(QMI8658_ACCEL_RANGE_8G);
    imu.setAccelODR(QMI8658_ACCEL_ODR_1000HZ);
    imu.setGyroRange(QMI8658_GYRO_RANGE_512DPS);
    imu.setGyroODR(QMI8658_GYRO_ODR_1000HZ);
    
    // Set units
    imu.setAccelUnit_mps2(true);  // m/s²
    imu.setGyroUnit_rads(false);  // degrees per second
    
    // Enable sensors
    imu.enableSensors(QMI8658_ENABLE_ACCEL | QMI8658_ENABLE_GYRO);
    
    Serial.println("✅ Configuration complete!");
    
    // Perform calibration
    performCalibration();
    
    Serial.println("\n📊 Starting sensor readings...");
    Serial.println("Time(ms)\tMotion\tRoll\tPitch\tYaw\tAccel_Mag\tGyro_Mag\tTemp(°C)");
    Serial.println("-------------------------------------------------------------------------");
}

void loop() {
    QMI8658_Data data;
    
    if (imu.readSensorData(data)) {
        // Apply calibration offsets
        float accelX = data.accelX - accelOffsetX;
        float accelY = data.accelY - accelOffsetY;
        float accelZ = data.accelZ - accelOffsetZ;
        
        float gyroX = data.gyroX - gyroOffsetX;
        float gyroY = data.gyroY - gyroOffsetY;
        float gyroZ = data.gyroZ - gyroOffsetZ;
        
        // Apply low-pass filter
        filteredAccelX = alpha * accelX + (1 - alpha) * filteredAccelX;
        filteredAccelY = alpha * accelY + (1 - alpha) * filteredAccelY;
        filteredAccelZ = alpha * accelZ + (1 - alpha) * filteredAccelZ;
        
        filteredGyroX = alpha * gyroX + (1 - alpha) * filteredGyroX;
        filteredGyroY = alpha * gyroY + (1 - alpha) * filteredGyroY;
        filteredGyroZ = alpha * gyroZ + (1 - alpha) * filteredGyroZ;
        
        // Calculate orientation (roll, pitch, yaw)
        float roll, pitch, yaw;
        calculateOrientation(filteredAccelX, filteredAccelY, filteredAccelZ,
                           filteredGyroX, filteredGyroY, filteredGyroZ,
                           roll, pitch, yaw);
        
        // Motion detection
        float accelMagnitude = sqrt(accelX*accelX + accelY*accelY + accelZ*accelZ);
        float gyroMagnitude = sqrt(gyroX*gyroX + gyroY*gyroY + gyroZ*gyroZ);
        
        //checkMotion(accelMagnitude, gyroMagnitude);

        if (min_roll > roll) {min_roll = roll;}
        if (min_pitch > pitch) {min_pitch = pitch;}
        if (min_yaw > yaw) {min_yaw = yaw;}
        if (max_roll < roll) {max_roll = roll;}
        if (max_pitch < pitch) {max_pitch = pitch;}
        if (max_yaw < yaw) {max_yaw = yaw;}

        // Print results
        // Serial.print(millis());
        // Serial.print("\t");
        // Serial.print(motionDetected ? "YES" : "NO");
        // Serial.print("\t");
        Serial.print("roll: ");
        Serial.print(roll, 1);
        Serial.print("\t");
        Serial.print("pitch: ");
        Serial.print(pitch, 1);
        Serial.print("\t");
        Serial.print("yaw: ");
        Serial.print(yaw, 1);
        // Serial.print("\t");
        // Serial.print("temperature: ");
        // Serial.println(data.temperature, 1);
        Serial.println();
        
        // Check for calibration command
        if (Serial.available()) {
            String command = Serial.readString();
            command.trim();
            if (command == "cal" || command == "calibrate") {
                Serial.println("\n🔄 Recalibrating...");
                performCalibration();
            }
            if (command == "max" || command == "min") {
                Serial.print("\n min_roll  :");
                Serial.print(min_roll);
                Serial.print("\n min_pitch :");
                Serial.print(min_pitch);
                Serial.print("\n min_yaw   :");
                Serial.print(min_yaw);
                Serial.print("\n max_roll  :");
                Serial.print(max_roll);
                Serial.print("\n max_pitch :");
                Serial.print(max_pitch);
                Serial.print("\n max_yaw   :");
                Serial.println(max_yaw);
                delay(50000);
            }
        }
    }
    
    delay(50); // 20Hz update rate
}

void performCalibration() {
    Serial.println("\n🎯 Starting calibration...");
    Serial.println("Place the sensor on a flat, stable surface.");
    Serial.println("Calibration will start in 3 seconds...");
    
    for (int i = 3; i > 0; i--) {
        Serial.print(i);
        Serial.println("...");
        delay(1000);
    }
    
    Serial.println("📈 Collecting calibration data...");
    
    const int numSamples = 1000;
    float accelSumX = 0, accelSumY = 0, accelSumZ = 0;
    float gyroSumX = 0, gyroSumY = 0, gyroSumZ = 0;
    int validSamples = 0;
    
    for (int i = 0; i < numSamples; i++) {
        QMI8658_Data data;
        if (imu.readSensorData(data)) {
            accelSumX += data.accelX;
            accelSumY += data.accelY;
            accelSumZ += data.accelZ;
            
            gyroSumX += data.gyroX;
            gyroSumY += data.gyroY;
            gyroSumZ += data.gyroZ;
            
            validSamples++;
        }
        
        if (i % 100 == 0) {
            Serial.print(".");
        }
        
        delay(10);
    }
    
    if (validSamples > 0) {
        // Calculate offsets
        accelOffsetX = accelSumX / validSamples;
        accelOffsetY = accelSumY / validSamples;
        accelOffsetZ = (accelSumZ / validSamples) - 9.81; // Remove gravity
        
        gyroOffsetX = gyroSumX / validSamples;
        gyroOffsetY = gyroSumY / validSamples;
        gyroOffsetZ = gyroSumZ / validSamples;
        
        calibrated = true;
        
        Serial.println("\n✅ Calibration complete!");
        Serial.print("Accel offsets: ");
        Serial.print(accelOffsetX, 3); Serial.print(", ");
        Serial.print(accelOffsetY, 3); Serial.print(", ");
        Serial.println(accelOffsetZ, 3);
        
        Serial.print("Gyro offsets: ");
        Serial.print(gyroOffsetX, 3); Serial.print(", ");
        Serial.print(gyroOffsetY, 3); Serial.print(", ");
        Serial.println(gyroOffsetZ, 3);
        
        Serial.println("💡 Type 'cal' to recalibrate anytime.");
    } else {
        Serial.println("\n❌ Calibration failed! No valid samples collected.");
    }
}

void calculateOrientation(float ax, float ay, float az, 
                         float gx, float gy, float gz,
                         float &roll, float &pitch, float &yaw) {
    // Calculate roll and pitch from accelerometer
    //roll = atan2(ay, sqrt(ax * ax + az * az)) * 180.0 / M_PI;
    roll = atan2(ay , az) * 57.3;
    //pitch = atan2(-ax, sqrt(ay * ay + az * az)) * 180.0 / M_PI;
    pitch = atan2((- ax) , sqrt(ay * ay + az * az)) * 57.3;
    
    // Simple yaw integration from gyroscope (not accurate for long term)
    static float yawIntegrated = 0;
    static unsigned long lastTime = 0;
    
    unsigned long currentTime = millis();
    if (lastTime > 0) {
        float dt = (currentTime - lastTime) / 1000.0; // Convert to seconds
        yawIntegrated += gz * dt;
    }
    lastTime = currentTime;
    
    yaw = yawIntegrated;
    
    // Keep yaw in range [-180, 180]
    while (yaw > 180) yaw -= 360;
    while (yaw < -180) yaw += 360;
}

void checkMotion(float accelMag, float gyroMag) {
    // Check if current acceleration deviates significantly from gravity
    float accelDeviation = abs(accelMag - 9.81);
    
    if (accelDeviation > accelThreshold || gyroMag > 10.0) {
        if (!motionDetected) {
            Serial.println("\n🚶 Motion detected!");
        }
        motionDetected = true;
        lastMotionTime = millis();
    } else {
        // No motion for 2 seconds
        if (motionDetected && (millis() - lastMotionTime > 2000)) {
            Serial.println("🛑 Motion stopped.");
            motionDetected = false;
        }
    }
}

A 6DOF sensor cannot measure the absolute yaw angle. A magnetometer is usually used for that.

The Magneto program outputs a 9 parameter correction matrix and 3 offsets. To apply those corrections to the raw accelerometer data requires matrix multiplication. Example code can be extracted from that for a 9DOF sensor, for example the ICM-20948.

Excerpt for just the accelerometer:


//Accelerometer correction

float A_B[3]
{   79.60,  -18.56,  383.31};

float A_Ainv[3][3]
{ {  1.00847,  0.00470, -0.00428},
  {  0.00470,  1.00846, -0.00328},
  { -0.00428, -0.00328,  0.99559}
};

...

// subtract offsets and correction matrix to accel and mag data

void get_scaled_IMU(float Axyz[3], float Mxyz[3]) {
  byte i;
  float temp[3];
  Axyz[0] = imu.agmt.acc.axes.x;  //get raw data
  Axyz[1] = imu.agmt.acc.axes.y;
  Axyz[2] = imu.agmt.acc.axes.z;
  
  //apply offsets (bias) and scale factors from Magneto
  for (i = 0; i < 3; i++) temp[i] = (Axyz[i] - A_B[i]);
  
  Axyz[0] = A_Ainv[0][0] * temp[0] + A_Ainv[0][1] * temp[1] + A_Ainv[0][2] * temp[2];
  Axyz[1] = A_Ainv[1][0] * temp[0] + A_Ainv[1][1] * temp[1] + A_Ainv[1][2] * temp[2];
  Axyz[2] = A_Ainv[2][0] * temp[0] + A_Ainv[2][1] * temp[1] + A_Ainv[2][2] * temp[2];

hi

ah ok therefor i read a few things where the 9DOF is mentioned. Thats interesting i will put this in my programm and look if the result will be better.

thx a lot

hape

one more question:

so i have done it but the pitch doesn’t work:

max_pitch :88.88
min_pitch :-74.56

is that because i have not the 9DOF? Its really a bit curious for me.

I have done the magneto calculations twice (other results) but its the same overall. The roll and yaw looks very good to me the pitch is not correct.

here is my code (with the magneto input).

/*
  QMI8658 Advanced Example
  
  This example demonstrates advanced features of the QMI8658 library:
  - Motion detection
  - Data filtering
  - Orientation calculation
  - Calibration
  
  Hardware connections:
  - VCC to 3.3V
  - GND to GND
  - SDA to pin 21 (ESP32) or A4 (Arduino)
  - SCL to pin 22 (ESP32) or A5 (Arduino)
  
  Author: [Your Name]
*/

#include <QMI8658.h>
#include <math.h>

QMI8658 imu;

// Pin definitions (adjust for your board)
#define SDA_PIN 18  // ESP32 default
#define SCL_PIN 19  // ESP32 default

// Motion detection variables
float accelThreshold = 2.0;  // m/s² threshold for motion detection
bool motionDetected = false;
unsigned long lastMotionTime = 0;

// Calibration variables
float accelOffsetX = 0, accelOffsetY = 0, accelOffsetZ = 0;
float gyroOffsetX = 0, gyroOffsetY = 0, gyroOffsetZ = 0;
bool calibrated = false;

// Filter variables (simple low-pass filter)
float filteredAccelX = 0, filteredAccelY = 0, filteredAccelZ = 0;
float filteredGyroX = 0, filteredGyroY = 0, filteredGyroZ = 0;
const float alpha = 0.1; // Filter coefficient (0-1, lower = more filtering)

float Axyz[3];

float A_B[3]
{   0.188590,  0.188590,  0.437335};

float A_Ainv[3][3]
{ {  0.968288,  0.008160, -0.021019},
  {  0.008160,  2.455807, 0.001729},
  { -0.021019, 0.001729,  2.256662}
};

float min_roll, min_pitch, min_yaw;
float max_roll, max_pitch, max_yaw;

int il = 1;

void setup() {
    Serial.begin(115200);
    while (!Serial) delay(10);
    
    Serial.println("QMI8658 Advanced Example");
    Serial.println("========================");
    
    // Initialize IMU
    if (!imu.begin(SDA_PIN, SCL_PIN)) {
        Serial.println("❌ Failed to initialize QMI8658!");
        Serial.println("Check connections and try again.");
        while (1) delay(1000);
    }
    
    Serial.println("✅ QMI8658 initialized successfully!");
    Serial.print("Device ID: 0x");
    Serial.println(imu.getWhoAmI(), HEX);
    
    // Configure sensor
    Serial.println("\n🔧 Configuring sensor...");
    imu.setAccelRange(QMI8658_ACCEL_RANGE_8G);
    imu.setAccelODR(QMI8658_ACCEL_ODR_1000HZ);
    imu.setGyroRange(QMI8658_GYRO_RANGE_512DPS);
    imu.setGyroODR(QMI8658_GYRO_ODR_1000HZ);
    
    // Set units
    imu.setAccelUnit_mps2(true);  // m/s²
    imu.setGyroUnit_rads(false);  // degrees per second
    
    // Enable sensors
    imu.enableSensors(QMI8658_ENABLE_ACCEL | QMI8658_ENABLE_GYRO);
    
    Serial.println("✅ Configuration complete!");
    
    // Perform calibration
    performCalibration();
    
    Serial.println("\n📊 Starting sensor readings...");
    Serial.println("Time(ms)\tMotion\tRoll\tPitch\tYaw\tAccel_Mag\tGyro_Mag\tTemp(°C)");
    Serial.println("-------------------------------------------------------------------------");
}

void loop() {
    QMI8658_Data data;
    
    il += 1;

    if (imu.readSensorData(data)) {
        // Apply calibration offsets
        // float accelX = data.accelX - accelOffsetX;
        // float accelY = data.accelY - accelOffsetY;
        // float accelZ = data.accelZ - accelOffsetZ;
        
        float gyroX = data.gyroX - gyroOffsetX;
        float gyroY = data.gyroY - gyroOffsetY;
        float gyroZ = data.gyroZ - gyroOffsetZ;

        // float accelX = data.accelX;
        // float accelY = data.accelY;
        // float accelZ = data.accelZ;
        
        // float gyroX = data.gyroX;
        // float gyroY = data.gyroY;
        // float gyroZ = data.gyroZ;
                
        Axyz[0] = data.accelX;  //get raw data
        Axyz[1] = data.accelY;
        Axyz[2] = data.accelZ;
        
        //apply offsets (bias) and scale factors from Magneto.
        byte i;
        float temp[3];
        for (i = 0; i < 3; i++) temp[i] = (Axyz[i] - A_B[i]);
        
        filteredAccelX = A_Ainv[0][0] * temp[0] + A_Ainv[0][1] * temp[1] + A_Ainv[0][2] * temp[2];
        filteredAccelY = A_Ainv[1][0] * temp[0] + A_Ainv[1][1] * temp[1] + A_Ainv[1][2] * temp[2];
        filteredAccelZ = A_Ainv[2][0] * temp[0] + A_Ainv[2][1] * temp[1] + A_Ainv[2][2] * temp[2];
        
        // Apply low-pass filter
        // filteredAccelX = alpha * accelX + (1 - alpha) * filteredAccelX;
        // filteredAccelY = alpha * accelY + (1 - alpha) * filteredAccelY;
        // filteredAccelZ = alpha * accelZ + (1 - alpha) * filteredAccelZ;
        
        filteredGyroX = alpha * gyroX + (1 - alpha) * filteredGyroX;
        filteredGyroY = alpha * gyroY + (1 - alpha) * filteredGyroY;
        filteredGyroZ = alpha * gyroZ + (1 - alpha) * filteredGyroZ;
        
        // Calculate orientation (roll, pitch, yaw)
        float roll, pitch, yaw;
        calculateOrientation(filteredAccelX, filteredAccelY, filteredAccelZ,
                           filteredGyroX, filteredGyroY, filteredGyroZ,
                           roll, pitch, yaw);
        
        // Motion detection
        // float accelMagnitude = sqrt(accelX*accelX + accelY*accelY + accelZ*accelZ);
        // float gyroMagnitude = sqrt(gyroX*gyroX + gyroY*gyroY + gyroZ*gyroZ);
        
        //checkMotion(accelMagnitude, gyroMagnitude);

        if (min_roll > roll) {min_roll = roll;}
        if (min_pitch > pitch) {min_pitch = pitch;}
        if (min_yaw > yaw) {min_yaw = yaw;}
        if (max_roll < roll) {max_roll = roll;}
        if (max_pitch < pitch) {max_pitch = pitch;}
        if (max_yaw < yaw) {max_yaw = yaw;}

        // Print results
        // Serial.print(millis());
        // Serial.print("\t");
        // Serial.print(motionDetected ? "YES" : "NO");
        // Serial.print("\t");
        Serial.print("roll: ");
        Serial.print(roll, 1);
        Serial.print("\t");
        Serial.print("pitch: ");
        Serial.print(pitch, 1);
        Serial.print("\t");
        Serial.print("yaw: ");
        Serial.print(yaw, 1);
        Serial.print("\t");
        // Serial.print("temperature: ");
        // Serial.println(data.temperature, 1);
        // Serial.print(il);
        // Serial.print("\t");
        // Serial.print(accelX);
        // Serial.print("\t");
        // Serial.print(accelY);
        // Serial.print("\t");
        // Serial.print(accelZ);
        // Serial.print("\t");
        Serial.println();
        
        // Check for calibration command
        if (Serial.available()) {
            String command = Serial.readString();
            command.trim();
            if (command == "cal" || command == "calibrate") {
                Serial.println("\n🔄 Recalibrating...");
                performCalibration();
            }
            if (command == "max" || command == "min") {
                Serial.print("\n min_roll  :");
                Serial.print(min_roll);
                Serial.print("\n min_pitch :");
                Serial.print(min_pitch);
                Serial.print("\n min_yaw   :");
                Serial.print(min_yaw);
                Serial.print("\n max_roll  :");
                Serial.print(max_roll);
                Serial.print("\n max_pitch :");
                Serial.print(max_pitch);
                Serial.print("\n max_yaw   :");
                Serial.println(max_yaw);
                delay(50000);
            }
        }
    }
    
    delay(50); // 20Hz update rate

    // if (il > 1000) {
    //     Serial.println("ending");
    //     delay(100000);
    //     exit(0);
    // }

}

void performCalibration() {
    Serial.println("\n🎯 Starting calibration...");
    Serial.println("Place the sensor on a flat, stable surface.");
    Serial.println("Calibration will start in 3 seconds...");
    
    for (int i = 3; i > 0; i--) {
        Serial.print(i);
        Serial.println("...");
        delay(1000);
    }
    
    Serial.println("📈 Collecting calibration data...");
    
    const int numSamples = 1000;
    float accelSumX = 0, accelSumY = 0, accelSumZ = 0;
    float gyroSumX = 0, gyroSumY = 0, gyroSumZ = 0;
    int validSamples = 0;
    
    for (int i = 0; i < numSamples; i++) {
        QMI8658_Data data;
        if (imu.readSensorData(data)) {
            accelSumX += data.accelX;
            accelSumY += data.accelY;
            accelSumZ += data.accelZ;
            
            gyroSumX += data.gyroX;
            gyroSumY += data.gyroY;
            gyroSumZ += data.gyroZ;
            
            validSamples++;
        }
        
        if (i % 100 == 0) {
            Serial.print(".");
        }
        
        delay(10);
    }
    
    if (validSamples > 0) {
        // Calculate offsets
        accelOffsetX = accelSumX / validSamples;
        accelOffsetY = accelSumY / validSamples;
        accelOffsetZ = (accelSumZ / validSamples) - 9.81; // Remove gravity
        
        gyroOffsetX = gyroSumX / validSamples;
        gyroOffsetY = gyroSumY / validSamples;
        gyroOffsetZ = gyroSumZ / validSamples;
        
        calibrated = true;
        
        Serial.println("\n✅ Calibration complete!");
        Serial.print("Accel offsets: ");
        Serial.print(accelOffsetX, 3); Serial.print(", ");
        Serial.print(accelOffsetY, 3); Serial.print(", ");
        Serial.println(accelOffsetZ, 3);
        
        Serial.print("Gyro offsets: ");
        Serial.print(gyroOffsetX, 3); Serial.print(", ");
        Serial.print(gyroOffsetY, 3); Serial.print(", ");
        Serial.println(gyroOffsetZ, 3);
        
        Serial.println("💡 Type 'cal' to recalibrate anytime.");
    } else {
        Serial.println("\n❌ Calibration failed! No valid samples collected.");
    }
}

void calculateOrientation(float ax, float ay, float az, 
                         float gx, float gy, float gz,
                         float &roll, float &pitch, float &yaw) {
    // Calculate roll and pitch from accelerometer
    //roll = atan2(ay, sqrt(ax * ax + az * az)) * 180.0 / M_PI;
    roll = atan2(ay , az) * 57.3;
    //pitch = atan2(-ax, sqrt(ay * ay + az * az)) * 180.0 / M_PI;
    pitch = atan2((- ax) , sqrt(ay * ay + az * az)) * 57.3;
    
    // Simple yaw integration from gyroscope (not accurate for long term)
    static float yawIntegrated = 0;
    static unsigned long lastTime = 0;
    
    unsigned long currentTime = millis();
    if (lastTime > 0) {
        float dt = (currentTime - lastTime) / 1000.0; // Convert to seconds
        yawIntegrated += gz * dt;
    }
    lastTime = currentTime;
    
    yaw = yawIntegrated;
    
    // Keep yaw in range [-180, 180]
    while (yaw > 180) yaw -= 360;
    while (yaw < -180) yaw += 360;
}

void checkMotion(float accelMag, float gyroMag) {
    // Check if current acceleration deviates significantly from gravity
    float accelDeviation = abs(accelMag - 9.81);
    
    if (accelDeviation > accelThreshold || gyroMag > 10.0) {
        if (!motionDetected) {
            Serial.println("\n🚶 Motion detected!");
        }
        motionDetected = true;
        lastMotionTime = millis();
    } else {
        // No motion for 2 seconds
        if (motionDetected && (millis() - lastMotionTime > 2000)) {
            Serial.println("🛑 Motion stopped.");
            motionDetected = false;
        }
    }
}

I could calculate the middle of the min and max and multiply with 180 the pitch result or there is another approach to get rid of this problem.

Any suggestions are very welcome.

thx in advance

hape

That is quite a hodgepodge of code, and most of it isn't doing you any good.

The smoothing filters aren't needed and the following "calibration" is completely wrong for the accelerometer. it could actually invalidate the offsets calculated by Magneto.

    for (int i = 0; i < numSamples; i++) {
        QMI8658_Data data;
        if (imu.readSensorData(data)) {
            accelSumX += data.accelX;
            accelSumY += data.accelY;
            accelSumZ += data.accelZ;
            
...            
            validSamples++;
        }
        
        if (i % 100 == 0) {
            Serial.print(".");
        }
        
        delay(10);
    }
    
    if (validSamples > 0) {
        // Calculate offsets
        accelOffsetX = accelSumX / validSamples;
        accelOffsetY = accelSumY / validSamples;
        accelOffsetZ = (accelSumZ / validSamples) - 9.81; // Remove gravity

The extremely large discrepancy in the diagonal terms of the correction matrix (1 : 2.5 : 2.3) suggest a serious problem with the calibration or the sensor. The diagonal values should be within about 10% of each other.

float A_Ainv[3][3]
{ {  0.968288,  0.008160, -0.021019},
  {  0.008160,  2.455807, 0.001729},
  { -0.021019, 0.001729,  2.256662}
}

For reasonable values of pitch and roll, you probably don't even need to calibrate the accelerometer. Try these expressions on the raw accelerometer data instead:

    // Calculate roll and pitch from accelerometer
    roll = atan2(ay , az) * 57.3;
    pitch = atan2((- ax) , sqrt(ay * ay + az * az)) * 57.3;

Something missing here?

Correction - my fault not reading the full statement. Sorry

i will test tomorrow but

pitch = atan2((- ax) , sqrt(ay * ay + az * az)) * 57.3;

seems correct.

You can write “(-ax” , or “((- ax) ,” its the same i think.

I will test the thoughts from @jremington this seems a point what he mentioned.

hape

so i test a bit more:

i have taken another from my 5 bought QMI8658. The testdata made from the raw output looks the same and also the output from Magneto is more or less the same.

@jremington what you mentioned is not done in my code because this lines are only commented lines:

// float accelX = data.accelX - accelOffsetX;
// float accelY = data.accelY - accelOffsetY;
// float accelZ = data.accelZ - accelOffsetZ;

So there must be as you said another problem:

the data for correction from magneto is now

float A_B[3]{   -0.114370,  -0.275384,  0.402837};
float A_Ainv[3][3]
{{  0.690899,  -0.002012, 0.045327},  
{  -0.002012,  2.064582, 0.001882},  
{ 0.045327, 0.001882,  1.944492}};

So one more question:

if i put out the raw-data with FastIMU i got this lines in front:

Accel biases X/Y/Z:
0.08, 0.05, -0.00
Gyro biases X/Y/Z:
-0.84, 1.49, -0.08

the code for the output:

  Serial.println("Accel biases X/Y/Z: ");
  Serial.print(calib.accelBias[0]);
  Serial.print(", ");
  Serial.print(calib.accelBias[1]);
  Serial.print(", ");
  Serial.println(calib.accelBias[2]);
  Serial.println("Gyro biases X/Y/Z: ");
  Serial.print(calib.gyroBias[0]);
  Serial.print(", ");
  Serial.print(calib.gyroBias[1]);
  Serial.print(", ");
  Serial.println(calib.gyroBias[2]);

in the gyro there is at second position a real large number. Did anyone know what this number means - i have searched for the calib. array but did not found any idea.

Should i subtract this number from magneto?

Any ideas are very welcome

thx in advance

hape

Something seems to wrong with the sensor or the raw data used to calibrate it.

Please post the code used to collect the raw data, and the data file used for input to Magneto.

here is the program to output the data:

#include "FastIMU.h"
#include <Wire.h>

#define IMU_ADDRESS 0x6B    //Change to the address of the IMU
#define PERFORM_CALIBRATION //Comment to disable startup calibration
QMI8658 IMU;               //Change to the name of any supported IMU! 

// Currently supported IMUS: MPU9255 MPU9250 MPU6886 MPU6500 MPU6050 ICM20689 ICM20690 BMI055 BMX055 BMI160 LSM6DS3 LSM6DSL QMI8658

calData calib = { 0 };  //Calibration data
AccelData accelData;    //Sensor data
GyroData gyroData;
MagData magData;
int il = 0;

void setup() {
  Wire.begin(18, 19);
  Wire.setClock(400000); //400khz clock
  Serial.begin(115200);
  while (!Serial) {
    ;
  }

  int err = IMU.init(calib, IMU_ADDRESS);
  if (err != 0) {
    Serial.print("Error initializing IMU: ");
    Serial.println(err);
    while (true) {
      ;
    }
  }
  
#ifdef PERFORM_CALIBRATION
  Serial.println("FastIMU calibration & data example");
  if (IMU.hasMagnetometer()) {
    delay(1000);
    Serial.println("Move IMU in figure 8 pattern until done.");
    delay(3000);
    IMU.calibrateMag(&calib);
    Serial.println("Magnetic calibration done!");
  }
  else {
    delay(5000);
  }

  delay(5000);
  Serial.println("Keep IMU level.");
  delay(5000);
  IMU.calibrateAccelGyro(&calib);
  Serial.println("Calibration done!");
  Serial.println("Accel biases X/Y/Z: ");
  Serial.print(calib.accelBias[0]);
  Serial.print(", ");
  Serial.print(calib.accelBias[1]);
  Serial.print(", ");
  Serial.println(calib.accelBias[2]);
  Serial.println("Gyro biases X/Y/Z: ");
  Serial.print(calib.gyroBias[0]);
  Serial.print(", ");
  Serial.print(calib.gyroBias[1]);
  Serial.print(", ");
  Serial.println(calib.gyroBias[2]);
  if (IMU.hasMagnetometer()) {
    Serial.println("Mag biases X/Y/Z: ");
    Serial.print(calib.magBias[0]);
    Serial.print(", ");
    Serial.print(calib.magBias[1]);
    Serial.print(", ");
    Serial.println(calib.magBias[2]);
    Serial.println("Mag Scale X/Y/Z: ");
    Serial.print(calib.magScale[0]);
    Serial.print(", ");
    Serial.print(calib.magScale[1]);
    Serial.print(", ");
    Serial.println(calib.magScale[2]);
  }
  delay(5000);
  IMU.init(calib, IMU_ADDRESS);
#endif

  //err = IMU.setGyroRange(500);      //USE THESE TO SET THE RANGE, IF AN INVALID RANGE IS SET IT WILL RETURN -1
  //err = IMU.setAccelRange(2);       //THESE TWO SET THE GYRO RANGE TO ±500 DPS AND THE ACCELEROMETER RANGE TO ±2g
  
  if (err != 0) {
    Serial.print("Error Setting range: ");
    Serial.println(err);
    while (true) {
      ;
    }
  }
}

void loop() {
  il += 1;
  IMU.update();
  IMU.getAccel(&accelData);
  Serial.print(accelData.accelX);
  Serial.print("\t");
  Serial.print(accelData.accelY);
  Serial.print("\t");
  Serial.print(accelData.accelZ);
  Serial.print("\t");
  // IMU.getGyro(&gyroData);
  // Serial.print(gyroData.gyroX);
  // Serial.print("\t");
  // Serial.print(gyroData.gyroY);
  // Serial.print("\t");
  // Serial.print(gyroData.gyroZ);
  // if (IMU.hasMagnetometer()) {
  //   IMU.getMag(&magData);
  //   Serial.print("\t");
  //   Serial.print(magData.magX);
  //   Serial.print("\t");
  //   Serial.print(magData.magY);
  //   Serial.print("\t");
  //   Serial.print(magData.magZ);
  // }
  // if (IMU.hasTemperature()) {
	//   Serial.print("\t");
	//   Serial.println(IMU.getTemp());
  // }
  // else {
  //   Serial.println();
  // }
  Serial.println();
  delay(50);
  if (il>450) {
    delay(1000000);
  }
}

and data:

-0.00.-0.00.-1.00.
-0.00.-0.00.-1.00.
-0.00.-0.00.-1.00.
-0.01.-0.00.-1.00.
-0.01.-0.00.-1.00.
-0.01.-0.00.-1.00.
-0.00.0.00.-1.00.
-0.01.-0.00.-1.01.
-0.01.-0.02.-1.01.
0.00.0.02.-1.01.
0.00.0.03.-1.01.
0.05.0.02.-1.00.
0.11.0.05.-1.05.
0.03.0.10.-0.92.
0.17.0.08.-1.01.
0.25.0.09.-1.07.
0.08.0.02.-0.95.
0.16.0.06.-0.99.
0.18.0.09.-0.94.
0.20.0.11.-1.11.
0.17.0.08.-0.93.
0.16.0.08.-1.00.
0.14.0.13.-1.07.
-0.04.0.10.-0.95.
-0.15.0.09.-1.01.
-0.29.0.11.-0.92.
-0.40.0.09.-0.89.
-0.50.0.07.-0.94.
-0.55.0.04.-0.84.
-0.71.0.03.-0.70.
-0.81.-0.02.-0.61.
-0.82.-0.03.-0.50.
-0.91.-0.03.-0.29.
-1.02.-0.07.-0.22.
-0.97.-0.05.-0.04.
-0.98.-0.02.0.18.
-1.06.-0.09.0.20.
-0.85.-0.02.0.35.
-0.87.-0.02.0.49.
-0.85.-0.06.0.48.
-0.74.-0.02.0.63.
-0.76.-0.00.0.71.
-0.72.-0.04.0.75.
-0.60.-0.01.0.80.
-0.54.-0.03.0.81.
-0.58.-0.00.0.95.
-0.43.0.00.0.85.
-0.34.0.03.0.89.
-0.38.0.02.1.00.
-0.26.0.05.0.97.
-0.24.0.04.1.02.
-0.15.0.05.1.01.
-0.09.0.03.0.99.
0.05.0.03.1.02.
0.18.0.03.0.98.
0.22.0.06.1.00.
0.27.0.04.0.93.
0.33.0.04.0.90.
0.35.0.03.0.93.
0.44.0.03.0.91.
0.43.0.03.0.91.
0.40.0.03.0.91.
0.46.0.03.0.93.
0.42.0.02.1.00.
0.36.0.02.1.01.
0.18.-0.01.0.99.
0.09.0.03.1.02.
-0.00.0.05.1.03.
-0.11.-0.03.1.13.
-0.23.0.00.0.92.
-0.34.-0.03.0.95.
-0.43.-0.02.0.85.
-0.56.0.00.0.83.
-0.64.0.01.0.79.
-0.70.0.03.0.71.
-0.83.0.02.0.63.
-0.79.0.03.0.54.
-0.87.0.03.0.47.
-0.87.0.06.0.36.
-0.95.0.10.0.26.
-1.03.0.12.0.17.
-1.01.0.15.0.07.
-0.95.0.16.-0.08.
-1.06.0.19.-0.14.
-0.90.0.17.-0.31.
-0.88.0.16.-0.34.
-1.02.0.20.-0.49.
-0.79.0.17.-0.53.
-0.80.0.17.-0.59.
-0.77.0.17.-0.67.
-0.64.0.15.-0.73.
-0.62.0.15.-0.79.
-0.52.0.14.-0.85.
-0.46.0.12.-0.93.
-0.37.0.12.-0.97.
-0.20.0.09.-0.99.
-0.13.0.07.-1.00.
0.01.0.06.-1.02.
0.11.0.03.-1.01.
0.23.-0.01.-0.96.
0.30.-0.02.-1.01.
0.37.-0.01.-0.88.
0.47.-0.06.-0.89.
0.59.-0.11.-0.80.
0.54.-0.09.-0.73.
0.66.-0.16.-0.69.
0.79.-0.18.-0.75.
0.79.-0.16.-0.63.
0.85.-0.16.-0.58.
0.82.-0.13.-0.48.
0.93.-0.16.-0.41.
0.95.-0.13.-0.27.
1.04.-0.17.-0.12.
1.06.-0.18.-0.05.
0.96.-0.15.0.12.
0.91.-0.17.0.21.
0.92.-0.19.0.33.
0.94.-0.19.0.33.
0.83.-0.22.0.53.
0.76.-0.21.0.20.
0.86.-0.17.0.53.
0.71.-0.15.0.73.
0.71.-0.12.0.71.
0.44.-0.09.0.67.
0.40.-0.04.0.90.
0.45.-0.00.0.97.
0.38.0.02.0.99.
0.20.0.02.0.96.
0.11.0.03.0.89.
0.20.0.02.1.10.
-0.18.0.01.0.93.
-0.10.0.02.1.11.
-0.32.-0.01.0.86.
-0.31.0.01.1.03.
-0.60.-0.03.0.74.
-0.56.0.02.0.83.
-0.57.0.05.0.75.
-0.84.0.06.0.65.
-0.77.0.07.0.56.
-0.98.0.07.0.37.
-0.76.0.04.0.62.
-0.88.0.03.0.27.
-0.71.0.02.0.25.
-0.96.0.09.0.25.
-1.08.0.09.0.09.
-0.98.0.21.0.59.
-0.76.0.15.0.50.
-1.08.0.18.0.18.
-0.88.0.18.0.48.
-0.87.0.09.0.53.
-0.90.0.11.0.40.
-0.92.0.10.0.69.
-0.75.-0.10.0.76.
-0.82.0.01.0.54.
-1.11.0.11.0.49.
-0.76.0.03.0.62.
-1.02.-0.09.0.30.
-0.95.-0.15.0.52.
-1.04.-0.19.0.08.
-1.19.-0.19.0.33.
-1.11.-0.17.-0.24.
-0.75.-0.16.0.08.
-0.62.-0.23.-0.69.
-0.89.-0.09.-0.25.
-1.08.-0.06.-0.33.
-0.32.-0.13.-0.39.
-0.64.-0.02.-0.70.
-0.78.0.16.-1.07.
-0.46.0.11.-0.87.
-0.30.0.06.-1.07.
-1.26.0.13.-0.92.
0.71.0.13.-0.83.
-0.43.-0.00.-0.99.
-0.04.-0.02.-0.95.
0.09.-0.00.-1.20.
-0.04.0.01.-1.07.
0.14.-0.02.-1.17.
0.16.-0.02.-0.92.
0.21.-0.03.-0.93.
-0.01.-0.05.-0.90.
-0.44.0.06.-1.12.
-0.59.-0.03.-0.80.
-0.50.0.00.-0.76.
-0.76.-0.02.-0.92.
-0.77.-0.07.-0.51.
-0.85.-0.05.-0.63.
-0.92.-0.06.-0.26.
-0.94.-0.08.-0.14.
-1.02.-0.01.-0.42.
-1.03.-0.01.0.22.
-0.96.-0.02.0.23.
-1.04.-0.04.0.12.
-0.94.-0.00.0.38.
-0.86.-0.04.0.45.
-0.82.-0.03.0.49.
-0.71.-0.00.0.77.
-0.69.0.02.0.83.
-0.59.-0.03.0.92.
-0.25.-0.00.0.86.
-0.07.-0.01.1.15.
-0.16.-0.02.0.93.
0.28.-0.03.0.99.
0.47.-0.06.0.94.
0.44.-0.07.0.83.
0.58.-0.09.0.89.
0.74.-0.09.0.59.
0.77.-0.11.0.58.
0.75.-0.13.0.61.
0.86.-0.14.0.40.
0.92.-0.15.0.34.
0.96.-0.15.0.24.
0.86.-0.17.0.15.
1.12.-0.17.0.08.
0.92.-0.17.0.02.
1.03.-0.19.-0.11.
0.99.-0.18.-0.22.
0.91.-0.19.-0.28.
1.01.-0.18.-0.35.
0.74.-0.18.-0.47.
0.87.-0.21.-0.55.
0.74.-0.20.-0.57.
0.52.-0.17.-0.70.
0.91.-0.05.-0.67.
0.61.-0.11.-1.11.
0.59.-0.15.-0.62.
0.12.-0.16.-0.88.
0.13.-0.15.-1.15.
0.23.-0.16.-0.89.
-0.44.-0.21.-0.87.
-0.14.-0.17.-1.03.
-0.66.-0.23.-0.90.
-0.43.-0.22.-0.75.
-0.64.-0.21.-0.92.
-0.86.-0.19.-0.34.
-1.02.-0.22.-0.29.
-0.96.-0.22.-0.39.
-1.11.-0.22.-0.01.
-0.85.-0.23.0.40.
-0.60.-0.32.0.57.
-0.84.-0.21.0.57.
-0.61.-0.11.0.79.
-0.62.-0.10.0.67.
-0.77.-0.11.0.90.
-0.24.-0.09.1.06.
-0.07.-0.09.0.81.
0.30.-0.11.1.20.
0.22.-0.15.0.94.
0.50.-0.17.0.75.
0.58.-0.20.0.78.
0.74.-0.21.0.69.
0.94.-0.22.0.57.
0.75.-0.23.0.41.
1.02.-0.25.0.23.
0.95.-0.24.0.05.
0.90.-0.27.-0.03.
1.01.-0.26.-0.03.
0.91.-0.27.-0.23.
0.92.-0.26.-0.23.
0.88.-0.26.-0.41.
0.83.-0.25.-0.55.
0.67.-0.26.-0.81.
0.50.-0.25.-0.83.
0.28.-0.24.-0.94.
0.31.-0.24.-0.84.
0.25.-0.23.-0.97.
0.26.-0.19.-0.83.
0.29.-0.12.-1.07.
0.63.-0.17.-0.64.
0.56.-0.13.-0.70.
0.90.-0.11.-0.91.
0.69.-0.10.-0.50.
0.75.-0.05.-0.41.
0.96.-0.03.-0.25.
0.82.-0.01.0.04.
1.04.0.06.0.28.
0.68.0.08.0.78.
0.71.0.15.0.90.
0.48.0.18.0.87.
0.16.0.11.1.23.
-0.15.0.13.1.05.
-0.54.0.06.0.95.
-0.49.-0.01.0.96.
-0.85.-0.12.0.50.
-0.72.-0.20.0.62.
-1.06.-0.29.0.29.
-0.94.-0.39.0.28.
-0.71.-0.46.-0.12.
-0.82.-0.56.-0.37.
-1.06.-0.46.-0.14.
-0.78.-0.75.-0.50.
-0.88.-0.62.-0.53.
-0.69.-0.66.-0.43.
-0.59.-0.75.-0.49.
-0.66.-0.81.0.11.
0.17.-0.91.-0.01.
0.07.-1.03.0.12.
-0.03.-1.01.-0.01.
0.05.-1.00.0.03.
0.14.-0.99.-0.00.
0.25.-0.96.-0.03.
0.39.-0.90.0.02.
0.49.-0.85.-0.15.
0.69.-0.85.-0.01.
0.51.-0.73.-0.11.
0.61.-0.62.-0.12.
0.93.-0.42.-0.33.
1.19.-0.41.-0.12.
1.21.-0.34.-0.03.
1.63.-0.37.-0.11.
1.14.-0.48.0.12.
1.07.-0.20.-0.25.
0.48.-0.52.0.20.
-0.06.-0.52.-0.77.
0.30.-0.91.0.09.
-0.55.-0.74.-0.37.
-0.34.-0.89.-0.09.
-0.57.-0.74.-0.37.
-0.69.-0.69.-0.43.
-0.78.-0.51.-0.62.
-0.91.-0.42.-0.87.
-1.03.-0.44.-0.72.
-0.35.-0.45.0.02.
-0.80.-0.06.-0.01.
-1.21.0.08.-0.91.
-0.26.0.14.0.17.
-0.88.0.50.0.01.
-1.41.0.65.-0.63.
-0.62.0.68.0.00.
-0.54.0.82.0.06.
-0.63.0.96.-0.27.
-0.54.1.05.-0.41.
-0.14.1.03.0.23.
-0.20.1.13.-0.09.
0.27.1.29.-0.47.
-0.40.1.17.0.24.
0.30.1.05.-0.37.
-0.07.0.97.-0.24.
-0.12.0.73.0.19.
-0.41.0.97.-0.24.
-0.04.1.09.-0.30.
-0.21.1.24.0.38.
-0.12.1.36.-0.26.
-0.38.1.40.0.17.
-0.44.1.21.-0.25.
-0.70.1.01.0.31.
-0.46.0.85.-0.20.
-1.42.0.59.0.16.
-0.77.0.65.0.07.
-0.67.0.13.-0.02.
-1.00.-0.19.0.27.
-0.75.-0.33.-0.11.
-0.10.-0.71.-0.17.
-0.65.-0.81.0.20.
-0.48.-0.89.-0.53.
-0.13.-1.02.0.07.
-0.76.-0.93.-0.32.
0.41.-0.74.-0.08.
0.21.-0.86.-0.44.
0.14.-0.86.-0.02.
0.56.-0.39.-0.47.
0.31.-0.10.-0.02.
1.00.0.11.1.27.
1.24.-0.06.0.40.
0.96.0.28.0.91.
0.67.0.20.0.64.
0.52.0.33.0.56.
1.04.0.52.0.66.
0.77.0.74.0.83.
0.65.0.52.0.60.
0.58.0.60.0.39.
0.60.0.59.0.29.
0.69.0.62.0.30.
0.61.0.60.0.35.
0.49.0.79.0.28.
0.44.0.75.0.32.
0.39.1.03.0.21.
0.57.0.75.0.16.
0.39.1.15.0.02.
0.39.0.97.-0.04.
0.00.0.90.0.22.
0.21.0.89.0.08.
0.69.1.12.-0.25.
-0.32.0.92.-0.29.
-0.40.1.04.-0.00.
0.64.1.03.-0.15.
-0.23.1.03.-0.30.
-0.26.1.01.-0.13.
-0.42.0.97.0.11.
-0.42.0.90.-0.36.
-0.63.0.86.-0.34.
-0.82.0.99.-0.03.
-0.62.0.85.-0.24.
-0.72.0.74.-0.47.
-0.93.0.67.0.04.
-0.90.0.54.-0.14.
-0.92.0.31.-0.37.
-0.70.0.20.0.21.
-0.74.0.10.-0.37.
-0.27.0.12.-0.32.
-0.24.0.23.-0.21.
-0.18.0.67.-0.80.
-0.30.1.07.-1.00.
-0.56.1.70.-0.64.
-0.33.1.27.-0.34.
0.14.1.15.-0.51.
0.64.1.06.-0.83.
0.75.0.72.-0.62.
0.88.0.84.0.14.
0.75.0.47.0.12.
1.27.0.69.0.71.
0.63.0.50.0.84.
0.54.0.26.0.52.
0.64.-0.05.0.25.
0.46.-0.24.0.79.
0.65.-0.18.0.99.
0.46.-0.34.0.87.
0.81.-0.52.-0.09.
0.76.-0.51.0.46.
0.27.-0.55.1.02.
0.61.-0.46.0.27.
0.81.-0.58.0.39.
1.03.-0.56.0.21.
0.69.-0.64.0.28.
0.65.-0.71.0.22.
0.67.-0.62.0.17.
1.07.-0.58.0.21.
0.39.-0.61.0.36.
1.07.-0.55.0.13.
0.95.-0.59.0.17.
0.50.-0.51.0.26.
0.81.-0.46.-0.37.
0.36.-0.44.-0.55.
0.76.-0.44.-0.82.
0.66.-0.20.-0.64.
-0.29.-0.20.-0.74.

thx for helping me and giving me your time - thats very nice @jremington

hape

As I suspected, those aren't raw sensor data. Raw data are integer values.

Some sort of calibration, correction and scaling is being performed by the library you are using, and it is not correct.

ah ok than i will dig in this direction - thx hape

@jremington ok after investing a lot of time and asking a lot of people i have to say that nobody has ever get roll pitch and yaw out of this chip in a stable and usable way. So i gave up and have a board which is useless for finding the correct angles. Its very disappointing but sometimes you buy a good hardware but without any help from the vendor or someone else there is no chance to get a solution. So at this point i’m out of the QMI8658**.**

thx for trying to help

hape

I've used a number of IMUs but have never heard of the QMI8658. Thanks for the heads up!

Adafruit, Sparkfun and Pololu (among other reputable hobby suppliers) sell modern 9DOF sensors that work well. They also provide libraries that support most, if not all of the features.

The sensors all perform similarly. The ICM-20948 seems to be easiest to use but is now obsolete.