Professional Documents
Culture Documents
Login Signup
A magnetometer allows you to detect the presence and strength of a magnetic field. A 3-axis magnetometer gives you
the strength of that magnetic field in 3 dimensions: along the X, Y, and Z axes. Combined, these give you a vector dictating
the strength and direction of the magnetic field.
Beyond just detecting nearby magnets, a magnetometer can also measure the Earth’s magnetic field. As a result, we can
use these tiny sensors as a method of constructing a digital compass. However, it’s not quite as easy as just reading the
strength of an ambient field.
This guide will walk you through the process of performing 3 types of calibration for a magnetometer: hard-iron
calibration, soft-iron calibration, and magnetic declination. With these, you should be able to build a functioning digital
compass out of your magnetometer readings!
Hardware Connections
I’ll be using an Adafruit Feather M0 and a LIS3MDL 3-axis magnetometer. The code we will use works for a number of
Adafruit magnetometer breakout boards, but the concepts should apply to all magnetometers.
Important! The Adafruit Sensor Lab code requires a good amount of flash memory. As a result, it will not fit on many older
Arduino boards (e.g. UNO). I recommend using a SAMD21 or better for this exercise. That being said, you are welcome to
write your own program that sends raw magnetometer (in uTesla) data to MotionCal.
Connect your magnetometer to your Arduino board. I’ll be using I2C to communicate with the sensor.
Hard-iron distortions are caused by nearby permanent magnets. These nearby magnetic fields result in a simple additive
offset to our readings and are relatively straightforward to correct. We take a bunch of X, Y, and Z raw readings while
moving the magnetometer about in all directions. We can plot the X/Y, Y/Z, and Z/X values, which would appear as 3
separate circles. With hard-iron distortion, these circles will appear in separate areas of the sample plot.
Next, we find the halfway point between the minimum and maximum values of each axis. These become our offsets.
When we subtract these offsets from future raw readings, we have successfully corrected for hard-iron distortions. If we
take a new series of readings and plot the results, the circles should overlap each other.
Soft-iron distortions result from the presence of iron, steel, and other ferrous materials near the sensor. Non-ferrous
materials can also cause some distortions, as different objects and materials can deflect and warp magnetic fields.
When plotted, the raw X, Y, and Z samples will look elliptical rather than spherical.
Note that MotionCal will automatically re-scale the display to make the collected points look more spherical, so I had to
manipulate the image some to demonstrate the concept.
The math to perform soft-iron calibration is a little more involved than we have time for in this article. You can read about
it here if you would like to dig into the math. Fortunately, we have software tools to help us out.
When complete, you end up with 2 sets of values: a vector for the hard-iron offsets and a matrix for the soft-iron scale
values. To compensate for the hard-iron effects, you simply need to subtract the hard-iron offset values from your raw
readings:
To compensate for soft-iron effects, you should perform a matrix multiplication using the soft-iron scale values. Note that
you can compensate for hard-iron distortion as well to create a set of completely calibrated values.
In the Arduino IDE, go to File > Preferences and add the following URL to the board manager list:
https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
Go to Tools > Board > Board Manager. Search for and install Adafruit SAMD Boards.
Go to Sketch > Include Library > Library Manager. Search for and install Adafruit Sensor Lab. This should install the
required library dependencies.
Open File > Examples > Adafruit Sensor Lab > calibration > imucal_nosave. Upload this program to your Arduino board.
Note that this program is intended to calibrate 9 DoF inertial measurement units (IMU), but we can use it on singular
sensors like our LIS3MDL magnetometer. It outputs raw accelerometer, gyroscope, and magnetometer data over the
serial port. If one or more sensor is not present, those values will be 0.
Download and install MotionCal from https://www.pjrc.com/store/prop_shield.html for your operating system. Run it, and
connect to the serial port of your Arduino (make sure that the serial port is not being used by another program). When the
connection is established, begin turning and twisting your magnetometer board in all directions.
The idea is to make a sphere with all of the captured x, y, and z magnetometer points. Aim to have gaps less than 1%.
When you’re done, you can select “none” under the serial port to have it stop collecting data.
Copy down the values from the “Magnetic Offset” (hard iron calibration) and “Magnetic Mapping” (soft iron calibration).
Magnetic Declination
If you are hoping to use the magnetometer as a compass, you should be aware of the differences between magnetic
heading and geographic heading. The north and south geographic poles are different from the earth’s magnetic poles.
Also, the magnetic poles shift continuously. You can find a fun animation of how the magnetic poles shift here:
https://geomag.colorado.edu/historical-main-field-change-and-declination.
To use your magnetometer like a regular compass (magnetic heading), you do not need to account for magnetic
declination (as a regular compass will point to magnetic north). However, if you’d like to find your heading based on the
geographic poles, you’ll need to convert from a magnetic heading to a geographic heading.
Copy Code
If your offset is east, the number should be positive. If the offset is west, the number should be negative.
Copy Code
Copy Code
/**
* Compass Demo
*
* Print heading (in degrees) to attached I2C OLED display. Demonstrate
* how to use magnetometer calibration data and convert magnetic heading
* to geographic heading.
*
* Author: Shawn Hymel
* Date: May 5, 14
*
* License: 0BSD (https://opensource.org/licenses/0BSD)
*/
#define DEBUG 1
#define OLED 0
#include <Wire.h>
#include <Adafruit_LIS3MDL.h>
#include <Adafruit_Sensor.h>
#if OLED
#include <SFE_MicroOLED.h>
#endif
// Pins
const int pin_reset = 8;
// Globals
Adafruit_LIS3MDL lis3mdl;
#if OLED
MicroOLED oled(pin_reset);
#endif
void setup() {
// Initialize magnetometer
if (!lis3mdl.begin_I2C()) {
#if DEBUG
Serial.println("ERROR: Could not find magnetometer");
#endif
while (1) {
delay(1000);
}
}
// Initialize OLED
#if OLED
delay(100);
Wire.begin();
oled.begin(0x3D, Wire);
// Clear display
oled.clear(ALL);
oled.display();
delay(1000);
oled.clear(PAGE);
#endif
}
void loop() {
delay(100);
}
Change the hard_iron array to match the “Magnetic Offset” values you obtained from MotionCal. Change the soft_iron
array to match the “Magnetic Mapping” values you copied from MotionCal. Finally, change the mag_decl value to the
magnetic declination value you obtained earlier.
Run the code, and open a Serial monitor. You should see the magnetic heading being printed to the console. Note that the
direction of heading is given by the Y axis, assuming Z is pointing to the sky.
If you attach an I2C OLED screen to your Arduino and enable the OLED code (#define OLED 1), you can see the heading
printed out to the OLED. The heading should match up with the readings from other digital compasses (note that you
might need to change their settings to report the geographic/true heading instead of a magnetic heading).
Because the hard iron and soft iron distortions will change depending on the environment of the magnetometer (due to
nearby speakers, motors, and ferrous items), you should ideally recalibrate the sensor any time it changes location.
Additionally, such distortions can be produced by nearby electronics. So, it’s a good idea to recalibrate if your
magnetometer is placed on a new PCB with or near other electronics.
I recommend checking out the following guides if you would like to learn more about calibrating magnetometers:
Code samples from this tutorial and the video can be found in this GitHub repository.
Mfr Part # 2772 Mfr Part # 4479 Mfr Part # 3955
FEATHER M0 BAS PROTO ATSAMD21G18 TRIPLE-AXIS MAGNETOMETER LIS3MDL JST PH 4-PIN TO MALE HEADER CA
Adafruit Industries LLC Adafruit Industries LLC Adafruit Industries LLC
TechForum
Have questions or comments? Continue the conversation on TechForum, Digi-Key's online community and technical
resource.
Visit TechForum
Arduino | 3D Printing | Raspberry Pi
Project Details
Platforms
Arduino
Development
C
C++
Tags
Arduino
Compass
Magnetic
Sensor
License
Attribution
Get Involved
Like
Save