If you bought the cheap magnetomter module like HMC5883L you can not use it without calibration. Measurement of magnetic field will be subjected to distortion. There are two categories of these distortions: the hard iron distortions and the soft iron distortions. The hard iron errors refer to the presence of magnetic fields around the sensor (magnets, power supply wires) and are related to measurement offset errors, while the soft iron errors refer to the presence of ferromagnetic materials around the sensor, which skew the density of the Earth's magnetic field locally and are related to scaling offset errors. You can read more information about these distortions here.

In other words, to get the correct magnetometer data you should get the calibrated magnetometer data. One of the ways to resolve this problem: you should apply the bias to the vector of the non calibrated magnetometer data (X, Y, Z coordinates) and then multiply the transformation matrix by this resulting vector:

3689598033?profile=originalPicture 1

In this case the magnetometer calibration is the process of getting the transformation matrix and the bias. To get these data you can use the MagMaster program.

You can download MagMaster here.

Example of using the MagMaster



  • MagMaster (placed in MagMaster folder)
  • MagViewer (placed in MagMaster folder)


  • Arduino Sketch (placed in MagMaster folder)

3689598066?profile=originalPicture 2

3689598042?profile=originalPicture 3

3689598079?profile=originalPicture 4

Connect the magnetometer module to the arduino board via I2C bus (picture 4). Upload the arduino sketch to the arduino board (see "Arduino_Code" folder in the "MagMaster" folder). This arduino sketch requires the HMC5883L library, copy the folder "HMC5883L" (placed in "Arduino_Code" folder)  to the folder "C:\Program Files\Arduino\libraries".

Then run the MagViewer.exe, select the serial port of the arduino board (the boud rate of the seraial port should be 9600 bps) and click "Run MagViewer". Now you can see the coordinates of the magnetometer data vector in 3D space on a real time (picture 5, video 1, 2). These data are not calibrated yet.

3689597980?profile=originalPicture 5

Video 1

Video 2

If you see the points of the magnetometer vector coordinates in 3D space the arduino board and the PC connection works right.

Now close the MagViewer window and run the MagMaster.exe (picture 6). Select the serial port of the arduino board. The green strings X, Y, Z will indicates the coordinates of the magnetometer vector.

3689598100?profile=originalPicture 6

Place the magnetometer module as shown on the picture 8.1 and click "Point 0" button of the "Axis X+" groupbox. For the placement of the module you can use the wooden bar or the paper box (picture 7). If you can not connect your magnetometer device to PC then you can use any other way to get to know the magnetometer data. You can enter these data in the program manually.

3689598052?profile=originalPicture 7

Place the magnetometer as shown on the picture 8.2 and click "Point 180" button of the "Axis X+" groupbox and so on. You should do in the following way:

  • Picture 8.1: "Point 0", "Axis X+"
  • Picture 8.2: "Point 180", "Axis X+"
  • Picture 8.3: "Point 0", "Axis X-"
  • Picture 8.4: "Point 180", "Axis X-"
  • Picture 8.5: "Point 0", "Axis Y+"
  • Picture 8.6: "Point 180", "Axis Y+"
  • Picture 8.7: "Point 0", "Axis Y-"
  • Picture 8.8: "Point 180", "Axis Y-"
  • Picture 8.9: "Point 0", "Axis Z+"
  • Picture 8.10: "Point 180", "Axis Z+"
  • Picture 8.11: "Point 0", "Axis Z-"
  • Picture 8.12: "Point 180", "Axis Z-"

3689598213?profile=originalPicture 8

You should fill the table. After that click "Calculate Transformation Matrix and Bias" and get the required matrix and bias (picture 9).

3689598116?profile=originalPicture 9

The transformation matrix and the bias are got. Now you can calculate the calibrated magnetometer data in your device on a real time with using the matrix and the bias as shown on picture 1. The example of the arduino sketch of using this calculation you can find in the "Arduino_Test_Results" folder.

You can apply the sphere radius stabilization algorithm to your program (use for it the Arduino_Radius_Stabilization folder placed in MagMaster folder).

The calibrated magnetometer vector coordinates in 3D space with the radius stabilization shown on the picture 10 and video 3, 4.

3689598230?profile=originalPicture 10

Video 3

Video 4

Using of the arduino is only example, you can easy adopt the arduino code for any other system and use the MagMaster program with it.

E-mail me when people leave their comments –

You need to be a member of diydrones to add comments!

Join diydrones


  • It's work, Thank you.
  • Hello Yuri;

    Thanks for the work. I couldn't run MagViewer. The data is not processed.  MagMaster works fine. 


    My serial port data outputs are as follows. Baudrate 9600, message send 10Hz.


  • Hello, I would like to use the software that you have created but with the MPU9250, for that I would have to occupy any scketch for MPU9250 in such a way that it throws through the serial port MagX, MagY, MagZ ?, or I must calibrate before the gyroscope and accelerometer and then print on the serial MagX, MagY, MagZ?

  • Try my magnetometer calibration tool, based on an Matlab script written  by Alain Barraud.  For the whole saga start with  

    http://fpaynter.com/2016/04/magnetometer-calibration-part/ and then parts 2, 3, & 4.  If you want to skip to the end, all the required code (except Octave itself) is on my GitHub site at https://github.com/paynterf/MagCalTool 

    Hope this helps,


  • I have tried to get MagMaster and MagViewer to connect to a serial port without success. I can succesfully connect the device my Arduino(Mega) on my PC. and I can see all the data flowing. I have tried COM1, COM6 and COM72 but nothing works. I get no data points shown in Magviewer and MagMaster tells me that I have no port name or just port error. Has anyone come across the same issues. Help would be appreciated. Also any other options to get my HMC5883L calibrated??

  • Hi Yuri, you have done a great Job with this blog! Now I'm able to understand the challanges. I've downloaded the rar file immediately, but a few years later I have recived on the importand file some compiler Errors. I've used an arduino megaADK IDE 1.6.9. Later a BN 880 with a HMC5883L should be calibrated.
    Can you help me some how, to get the code running?
  • Ok some weird things going on here…


    I am using a Arduino Nano Clone with an onboard CH340 USB<->Serial bridge.

    At the beginning I had the same problems as Tim C (page 3-4) and could see the changing values in the SerialMonitor using your Arduino_Code.ino.

    The bad thing: MagViewer.exe did not show any dots and also MagMaster.exe didn’t work.


    I changed the port on my Windows 7 PC from COM14 to COM5, because I read that high COM-Port numbers causes issues.

    Then it started to work.

    I could use MagViewer and MagMaster with no problem for about 30min.


    I did a screenshot after calibration.


    I then wanted to play a little with MagViewer and also do it later again with my values from http://www.magnetic-declination.com/ to increase the accuracy but after some time, MagViewer stopped doing the dots!

    I started MagViewer again: only 1 dot... no more.

    Reconnecting the Arduino and try it again.



    I then changed the COM-Port on the PC again (this time to COM6). This didn’t solve it.

    I also used the Arduino_Code.ino and the values did not change when I move the HMC5883L.


    I didn’t check before (cause Arduio_Code.ino worked from the start), but I used an I2C scanner and saw that the address is 0x68. The weird thing is, that I see that the 0x1E address, that is set in the HMC5883L.h, was working before.

    Don’t know if the address could have changed or something.

    I am able (with another library and my own sketch) to test the compass and is still working. (so a hardware damage is not the case).


    In the library (the one given here) I used the HMC5883L_Example.ino.

    It gives me


    Starting the I2C interface.

    Constructing new HMC5883L

    Setting scale to +/- 1.3 Ga

    Entered scale was not valid, valid gauss values are: 0.88, 1.3, 1.9, 2.5, 4.0, 4.7, 5.6, 8.1

    Setting measurement mode to continous.

    Entered scale was not valid, valid gauss values are: 0.88, 1.3, 1.9, 2.5, 4.0, 4.7, 5.6, 8.1

    Raw:      929   1667   808                  Scaled: 852.84   1533.64   743.36               Heading:             1.11 Radians      63.54 Degrees                  

    Raw:      929   1667   808                  Scaled: 852.84   1533.64   743.36               Heading:             1.11 Radians      63.54 Degrees 



    The values doesn’t change when I move the HMC5883L.

    The same for the Arduino_Code.ino.

    It puts out:









    When I change the address in the HMC5883L.h from 0x1E to 0x68 it gives me:



    Starting the I2C interface.

    Constructing new HMC5883L

    Setting scale to +/- 1.3 Ga

    Setting measurement mode to continous.

    Raw:      -8208   -18698   -8702      Scaled: -7551.36   -17202.16   -8005.84                   Heading:             4.34 Radians      248.92 Degrees             

    Raw:      -8208   -18698   -8702      Scaled: -7551.36   -17202.16   -8005.84                   Heading:             4.34 Radians      248.92 Degrees 


    The values also doesn’t change here but the “Entered scale was not valid” error is gone…


    On the Arduino_Code.ino the values also doesn’t change:









    This was all confirmed at 3 different Arduino Nanos, that all never did any faults.

    I also did check this on an Arduino Uno and have the same problems here.


    Any ideas or hints are really appreciated.

    I have no ideas left.

  • I want to try that, but I'm still messing with my own app.  Here's a shot of 3DScatter which I modified to show the difference between Yuri's calibrated data and the raw data.3702267240?profile=original

  • Hi All,

    Well, I was able to produce a decent GUI for magnetometer calibration, based on a MATLAB script.  Since I wasn't smart enough to port all the MATLAB math to C#, I did the next best thing - I used calls into Octave to actually run the script, while the GUI does everything else.  You still need a recent copy of Octave (I'm using octave-cli-4.0.1.exe), but that is free and readily available for windoze.  

    I thought I had it made, until I discovered that my redistribution license for the EyeShot 3D visualization library I was using had expired, and it was WAY too expensive to re-subscribe!  So, I wound up re-doing the entire GUI in WPF in order to use the WPF 3D visualization capability.  Along with the use of the Helix Toolkit, I was able to (mostly) replace the EyeShot niceness with Helix Toolkit viewports and associated objects.

    In any case, I have attached a zip file to this post containing the first releasable version of my magnetometer calibration utility, and a screenshot that shows the layout.


    As can be seen from the above screenshot, the GUI is divided into three main sections.  The top section deals with acquiring, saving and importing raw magnetometer data.  Data is acquired by connecting your magnetometer's serial output to any PC USB port.  While the port is open and acquiring data, the magnetometer (or the device in which it is installed) is rotated in all three axes so as to form a nice filled spheroid of raw points.  There is no need to rotate in any particular order - just enough so that all areas in the sphere are covered with some data points.  Outlier points can be pruned by selecting and then removing all points outside a specified radius. The middle section shows the 'raw' and 'calibrated' 3D views, and is intended to facilitate preparation of a raw dataset for input into the MATLAB script, and display of the results of processing all 'raw' points through the calibration expression generated by the script.  The bottom section simply displays the compensation expression to be implemented in the end-user's program, along with the actual values generated by the MATLAB script.  If the values in the Compensation Matrix and the Center Offset are plugged into the Compensation Expression, then raw magnetometer values can be converted point-by-point to calibrated ones suitable for navigation.

    The utility should be reasonably self-explanatory, but I do plan to create a more detailed blog post on my personal blog 'Paynter's Palace'; please check there for additional details.  I also plan to set up a GitHub repository, as soon as I figure out how to do it ;-).

    This program is definitely a work in progress, so please feel free to tell me what problems you find or features you think should be included.

    Hmm, can't figure out how to attach a file, so instead I have put it on my Google Drive site.  It can be downloaded using this link



  • Hi Huri,

    As some people I can't open the COM port . I tried with low number like 1 or 2 with 9600 but it is the same thing.

    The arduino works well  and I can see the values in the serial monitor but nothing in MagViewer.

    When I open Magmaster and select too the good port com and I click on open a popup window says "empty port name"

    Do you have a solution?

    thank you very much

This reply was deleted.