(Calibration GUI image by Fabio Varesano)


The LSM303 chips are factory calibrated to a level of accuracy sufficient for many purposes. But for ultra-critical applications such as an IMU, you may want to further calibrate the device.

Ultimate Calibration:

For super-precise accelerometer calibration, you will want to check out the FreeIMU Magnetometer and Accelerometer GUI by the late Fabio Varesano. The image above (from Fabio's site) shows a graphical representation of the sensor readings and the resulting calibration offsets calculated from the raw data.

This comprehensive calibration suite is designed to run on a PC. It is much too large to run on a microcontroller, like the Arduino, but the resulting calibration offsets it generates can be incorporated into your Arduino sketch for better accuracy.

Simplified Calibration:

A simpler method that still generates good results can be accomplished on the Arduino. This method uses a simple sketch to record the minimum and maximum readings on all 3 axis. While running the sketch, slowly rotate the LSM303 module multiple times in all three axis. The object is to record the absolute minimums and maximums for each axis, so the more you rotate it, the more likely you are to capture the absolute peak.

Be sure to rotate the sensor slowly about its center so that the accelerometer readings will represent just acceleration due to gravity and not linear acceleration of the sensor due to movement. After a while, the sketch output will stabilize. The values displayed will be the the min and max ranges for each axis and can be used to re-scale the output of the sensor.

The values obtained via the calibration sketch can be used to perform a 2-point calibration on each of the 3 axis:  Two Point Calibration

Calibration Sketch:
LSM303AGR

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LIS2MDL.h>


Adafruit_LIS2MDL mag = Adafruit_LIS2MDL(12345);

float MagMinX, MagMaxX;
float MagMinY, MagMaxY;
float MagMinZ, MagMaxZ;

long lastDisplayTime;

void setup(void)
{
  Serial.begin(115200);
  Serial.println("LIS2MDL Calibration"); Serial.println("");

  /* Initialise the magnetometer */
  if(!mag.begin())
  {
    /* There was a problem detecting the LIS2MDL ... check your connections */
    Serial.println("Ooops, no LIS2MDL detected ... Check your wiring!");
    while(1);
  }
  lastDisplayTime = millis();
}

void loop(void)
{
  /* Get a new sensor event */
  sensors_event_t magEvent;

  mag.getEvent(&magEvent);

  if (magEvent.magnetic.x < MagMinX) MagMinX = magEvent.magnetic.x;
  if (magEvent.magnetic.x > MagMaxX) MagMaxX = magEvent.magnetic.x;

  if (magEvent.magnetic.y < MagMinY) MagMinY = magEvent.magnetic.y;
  if (magEvent.magnetic.y > MagMaxY) MagMaxY = magEvent.magnetic.y;

  if (magEvent.magnetic.z < MagMinZ) MagMinZ = magEvent.magnetic.z;
  if (magEvent.magnetic.z > MagMaxZ) MagMaxZ = magEvent.magnetic.z;

  if ((millis() - lastDisplayTime) > 1000)  // display once/second
  {
    Serial.print("Mag Minimums: "); Serial.print(MagMinX); Serial.print("  ");Serial.print(MagMinY); Serial.print("  "); Serial.print(MagMinZ); Serial.println();
    Serial.print("Mag Maximums: "); Serial.print(MagMaxX); Serial.print("  ");Serial.print(MagMaxY); Serial.print("  "); Serial.print(MagMaxZ); Serial.println(); Serial.println();
    lastDisplayTime = millis();
  }
}

LSM303/LSM303DLH

#include <Adafruit_Sensor.h>
#include <Wire.h>
//#include <Adafruit_LSM303_U.h>
#include <Adafruit_LSM303DLH_Mag.h>

Adafruit_LSM303DLH_Mag_Unified mag = Adafruit_LSM303DLH_Mag_Unified(12345);

float MagMinX, MagMaxX;
float MagMinY, MagMaxY;
float MagMinZ, MagMaxZ;

long lastDisplayTime;

void setup(void) {
  Serial.begin(115200);
  Serial.println("LSM303 Calibration");
  Serial.println("");

  /* Initialise the magnetometer */
  if (!mag.begin()) {
    /* There was a problem detecting the LSM303 ... check your connections */
    Serial.println("Ooops, no LSM303 detected ... Check your wiring!");
    while (1)
      ;
  }
  lastDisplayTime = millis();
}

void loop(void) {
  /* Get a new sensor event */
  sensors_event_t magEvent;

  mag.getEvent(&magEvent);

  if (magEvent.magnetic.x < MagMinX)
    MagMinX = magEvent.magnetic.x;
  if (magEvent.magnetic.x > MagMaxX)
    MagMaxX = magEvent.magnetic.x;

  if (magEvent.magnetic.y < MagMinY)
    MagMinY = magEvent.magnetic.y;
  if (magEvent.magnetic.y > MagMaxY)
    MagMaxY = magEvent.magnetic.y;

  if (magEvent.magnetic.z < MagMinZ)
    MagMinZ = magEvent.magnetic.z;
  if (magEvent.magnetic.z > MagMaxZ)
    MagMaxZ = magEvent.magnetic.z;

  if ((millis() - lastDisplayTime) > 1000) // display once/second
  {
    Serial.print("Mag Minimums: ");
    Serial.print(MagMinX);
    Serial.print("  ");
    Serial.print(MagMinY);
    Serial.print("  ");
    Serial.print(MagMinZ);
    Serial.println();
    Serial.print("Mag Maximums: ");
    Serial.print(MagMaxX);
    Serial.print("  ");
    Serial.print(MagMaxY);
    Serial.print("  ");
    Serial.print(MagMaxZ);
    Serial.println();
    Serial.println();
    lastDisplayTime = millis();
  }
}

This guide was first published on Mar 10, 2013. It was last updated on Mar 10, 2013.

This page (Calibration) was last updated on Nov 27, 2020.