Help with LIS3MDL custom calibration

Hello every one.

I am using the Arduino Due, with I2C connect to the 9 DOF IMU (Adafruit LSM6DS3TRC + LIS3MDL).

I am also using the AdaFruit library for the sensor.

The problem is I do not want to use the MotionCal software to calibrate the Magnetometer.

I found some code on GitHub, where the the Mag is calibrated by moving the sensor in a figure 8 pattern

void magcalMPU9250(float * dest1, float * dest2) 
 {
 uint16_t ii = 0, sample_count = 0;
 int32_t mag_bias[3] = {0, 0, 0}, mag_scale[3] = {0, 0, 0};
 int16_t mag_max[3] = {-32767, -32767, -32767}, mag_min[3] = {32767, 32767, 32767}, mag_temp[3] = {0, 0, 0};

 Serial.println("Mag Calibration: Wave device in a figure eight until done!");
 delay(4000);

// shoot for ~fifteen seconds of mag data
if(MPU9250Mmode == 0x02) sample_count = 128;  // at 8 Hz ODR, new mag data is available every 125 ms
if(MPU9250Mmode == 0x06) sample_count = 1500;  // at 100 Hz ODR, new mag data is available every 10 ms
for(ii = 0; ii < sample_count; ii++) {
MPU9250readMagData(mag_temp);  // Read the mag data   
for (int jj = 0; jj < 3; jj++) {
  if(mag_temp[jj] > mag_max[jj]) mag_max[jj] = mag_temp[jj];
  if(mag_temp[jj] < mag_min[jj]) mag_min[jj] = mag_temp[jj];
}
if(MPU9250Mmode == 0x02) delay(135);  // at 8 Hz ODR, new mag data is available every 125 ms
if(MPU9250Mmode == 0x06) delay(12);  // at 100 Hz ODR, new mag data is available every 10 ms
}


// Get hard iron correction
 mag_bias[0]  = (mag_max[0] + mag_min[0])/2;  // get average x mag bias in counts
 mag_bias[1]  = (mag_max[1] + mag_min[1])/2;  // get average y mag bias in counts
 mag_bias[2]  = (mag_max[2] + mag_min[2])/2;  // get average z mag bias in counts

 dest1[0] = (float) mag_bias[0]*MPU9250mRes*MPU9250magCalibration[0];  // save mag biases in G for main program
 dest1[1] = (float) mag_bias[1]*MPU9250mRes*MPU9250magCalibration[1];   
 dest1[2] = (float) mag_bias[2]*MPU9250mRes*MPU9250magCalibration[2];  
   
// Get soft iron correction estimate
 mag_scale[0]  = (mag_max[0] - mag_min[0])/2;  // get average x axis max chord length in counts
 mag_scale[1]  = (mag_max[1] - mag_min[1])/2;  // get average y axis max chord length in counts
 mag_scale[2]  = (mag_max[2] - mag_min[2])/2;  // get average z axis max chord length in counts

 float avg_rad = mag_scale[0] + mag_scale[1] + mag_scale[2];
 avg_rad /= 3.0;

 dest2[0] = avg_rad/((float)mag_scale[0]);
 dest2[1] = avg_rad/((float)mag_scale[1]);
 dest2[2] = avg_rad/((float)mag_scale[2]);

 Serial.println("Mag Calibration done!");
 }

I then adapted the code to the following function

bool CalibrateMag(void)
{ 
    int16_t mag_max[3] = {-32767, -32767, -32767}, mag_min[3] = {32767, 32767, 32767}, mag_temp[3] = {0, 0, 0};
    float Average_Rad = 0;
    uint16_t InnerLoop = 0, Sample_Count = 128, OutterLoop = 0;
    int32_t MBias[3] = { 0, 0, 0 };
    int32_t Mag_Scale[3] = {0, 0, 0};

    for(OutterLoop = 0; OutterLoop < Sample_Count; OutterLoop++)
    {
      sensors_event_t Magnets;

      MagnetoMeter2->getEvent(&Magnets);

      SerialUSB.println("   ");
      SerialUSB.print("Magnets X = ");SerialUSB.print(Magnets.magnetic.x, 4); SerialUSB.print("   ");
      SerialUSB.print("Magnets Y = ");SerialUSB.print(Magnets.magnetic.y, 4); SerialUSB.print("   ");
      SerialUSB.print("Magnets Z = ");SerialUSB.print(Magnets.magnetic.z, 4); SerialUSB.print("   ");
      SerialUSB.println("   ");

      mag_temp[0] = (int16_t) Magnets.magnetic.x;
      mag_temp[1] = (int16_t) Magnets.magnetic.y;
      mag_temp[2] = (int16_t) Magnets.magnetic.z;

      for(InnerLoop = 0; InnerLoop < 3; InnerLoop++)
      {
        if(mag_temp[InnerLoop] > mag_max[InnerLoop]) mag_max[InnerLoop] = mag_temp[InnerLoop];
        if(mag_temp[InnerLoop] < mag_min[InnerLoop]) mag_min[InnerLoop] = mag_temp[InnerLoop];
      }

      digitalWrite(RedLED, HIGH);
      delay(162);
      digitalWrite(RedLED, LOW);
      delay(162);

    }
              //Calculate  - Hard iron correction 
    MBias[0] = ((mag_max[0] + mag_min[0])/2);
    MBias[1] = ((mag_max[1] + mag_min[1])/2);
    MBias[2] = ((mag_max[2] + mag_min[2])/2);  

    MyMag_HardIron[0] = (float) (MBias[0]) * Mag_sensitivity;
    MyMag_HardIron[1] = (float) (MBias[1]) * Mag_sensitivity;
    MyMag_HardIron[2] = (float) (MBias[2]) * Mag_sensitivity;

    Mag_Scale[0] = ((mag_max[0] - mag_min[0])/2);
    Mag_Scale[1] = ((mag_max[1] - mag_min[1])/2);
    Mag_Scale[2] = ((mag_max[2] - mag_min[2])/2);  
    
    Average_Rad = (Mag_Scale[0]+ Mag_Scale[1] + Mag_Scale[2]);
     
    Average_Rad /= 3.0;

    MyMag_SoftIron[0] = (Average_Rad / (float)Mag_Scale[0]);
    MyMag_SoftIron[1] = (Average_Rad / (float)Mag_Scale[1]);
    MyMag_SoftIron[2] = (Average_Rad / (float)Mag_Scale[2]);

}

The problem is the values of Magnets.magnetic.x, Magnets.magnetic.y and Magnets.magnetic.z do not change they stay the same. Even with a magnet moved close to the Magnetometer the values do not change

I am also not sure what the value of Mag_sensitivity should be#define Mag_sensitivity 1.499389499 in the Github code that how its defined, for the MPU9250. Does the value stay the same for the ST accelerometers.

I will appreciate any help!!!

That is a problem with sensor communication, or the sensor library. Since you forgot to post the rest of the code, where the actual problem is, no one can help.

By the way, the six point calibration method you are using does not work well, or at all in some cases. See this forum post for a spectacular example.

from what I gather these two lines `
sensors_event_t Magnets;

  MagnetoMeter2->getEvent(&Magnets);`

inlcuded in my code, gets the new values from the magnometer. But in my case it does not update

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.