There are several types of cheap magnetometer now available, which you can use to sense a compass direction, but all of them (as far as I know) need calibration before you can get sensible results. In this Instructable, I'll demonstrate a simple manual method using both the XLoBorg from Piborg, and the MPU-9150, but the principles can easily be adapted to other devices.
In a companion Instructable I will show you an automatic method.
For reliable navigation there are around 4 corrections you'd need to make to the raw magnetometer output to get accurate results, but for many hobbyist purposes the so called "hard iron" correction is all you need to get a sensible output, this normally being the dominant error. Without the other corrections your magnetometer may show magnetic North a little East of the true direction when you're facing one way and a little West facing another. Also, if you try using it to make a 90 degrees turn you might find you've turned by something a little more or a little less. This may not matter even for a drone as the magnetometer would only be useful for determining a rough heading, given that the wind may be blowing you off course. Nevertheless, you could still use it to maintain a given heading. Note that it could be dangerous to rely on the calibration methods I describe for navigation at sea, or anywhere else where navigation errors could have serious consequences.
For each of the X, Y and Z magnetometer outputs the reading it gives will be the value of the earth's magnet field in that direction plus the magnetometer hard iron offset. The hard iron offset will be the same whichever way you turn it, but if you turn it through 180 degrees it will measure an equal and opposite value for the Earth's field. So all you have to do to get the offset is add the two readings and divide by 2.
Assuming the magnetometer defines X and Y as horizontal (in the plane of the magnetometer board) and Z as vertical (perpendicular to it), a single rotation will have reversed both X and Y, so we can get both the X and Y offsets. If we now turn it upside down we will reverse Z and can determine the Z offset. But we will have also reversed either X or Y once more (depending which way we flipped it) and can get a second estimate of that offset. Rotate it once more through 180 degrees and we will have 2 readings in each sense for X, Y and Z. Add all 4 X readings and divide by 4 and we'll have a slightly better estimate of the X offset, and the same for Y and Z.
You will need:
Plug the XLoBorg into the Raspberry Pi GPIO connector (as illustrated in the next step) and boot it into Raspbian.
You can run the Raspberry Pi with directly connected monitor, keyboard and mouse, or headless using VNC, or in terminal mode using PuTTy, whichever you are used to. Log in as usual.
Create a new folder called XLoBorg (or as you please) and copy the two Python programs XLoBorg.py and ReadCompass.py to it.
Launch a Terminal session, and in it type:
cd XLoBorg
chmod +x *.py ./ReadCompass.py -n 100 50
The last command will take 100 samples from the magnetometer with 50mS delay between each, and print the averages and standard deviations of the X, Y and Z readings. If you managed to hold it still, the standard deviation values should be relatively small, if not, maybe you jogged it and you can try again.
Before proceeding to the next step, if the file MAG3110offsets exists from a previous calibration, either delete it or insert a "#" at the start of any non-blank lines.
For the best accuracy, find a book, a thin box or a piece of wood somewhat thinner than the Raspberry Pi such that if you place the Pi upside down on the book, the XLoBorg will be about the same height off the desk as if you place it the right way up directly on the desk. By making sure the magnetometer is in the same position relative to the desk and any nearby iron or magnetic object their effects will be cancelled out along with the earth's magnetic field. However, ensuring that the side of the Pi is accurately a parallel with the front of the desk is probably more important.
Stick a piece of tape or a sticky label to the front of your desk or bench and make a mark on it.
Place the Pi along the front of the desk with the GPIO connector away from the edge and with the small black chip on the XLoBorg roughly lined up with the mark on the label. Take set of 100 readings by typing the following in a Terminal window:
./ReadCompass.py -n 100 50
Make a note of the average X, Y and Z values displayed.
Turn the Pi through 180 degrees. Keeping the edge of the Pi parallel with the desk edge and the small black chip on the XLoBorg roughly lined up with the mark on the label, move the Pi away from the desk edge until the XLoBorg is about the same distance from the desk edge as it was before.
Take another set of readings by typing the same command and note the averages in three columns underneath the previous readings.
Turn the Pi upside down and put it on the book, again with the edge of the Pi along or parallel with the desk edge and the black chip (in so far as you can estimate its position) lined up with the mark on the label. Take another set of readings and note the average. You can now calculate the offsets from the tabulated readings as in the example below (the numbers, of course, will be different). You will notice that each column has two pairs of readings in the same range, in this case, two positive and two negative. If not maybe you forgot to write down a minus sign.
X Y Z -105.4 158.0 263.9
118.2 -194.7 290.9
-83.2 -179.4 -662.4
114.0 113.8 -647.2
---- ---- ---- Totals: 43.6 -102.3 -754.8 Divide by 4: 10.9 -25.6 -188.7 OFFSETS
You can now write the offsets (without the decimal point or the fractional part) to a calibration file MAG3110offsets, and ReadCompass.py will automatically apply them, giving corrected readings. An easy way to do this is with a command such as:
echo "11 -26 -189" >MAG3110offsets
The MPU-9150 accelerometer/gyro/magnetometer works equally well with the Raspberry Pi and has the advantages over the XLoBorg that it includes the gyro function. It requires just 4 connections to the Pi's GPIO pins as below and as shown in the picture.
GPIO Pin MPU-9150 Pin
1 (3.3v) VCC
6 (Gnd) Gnd
5 (SCL) SCL
3 (SDA) SDA
The procedure is just the same except that you use the MPU9150.py program instead of XLoBorg.py, and ReadCompas9150.py instead of ReadCompass.py. The offsets file is MPU9150offsets instead of MAG3110offsets. Before starting the calibration, make sure this file doesn't exist, or that any non-blank lines in it start with a "#" character. You can create this file with the offsets in it if you like after calibration.
If you're needing to calibrate a MPU-9150 for use with an Arduino it's probably because you want to use it in some other project. In that case you can build it into that project and just use the sketch and the procedure described later with your own hardware. On the other hand, if you're just learning about the MPU-9150 you can connect it up as described here.
You will need:
Unfortunately the MPU-9150 inputs are not 5V tolerant, so if you run your Arduino at 5V you will need a 5V/3.3V level translator with 2 or more channels. These are very cheap from Far Eastern eBay sellers. Alternatively you can run both the Arduino and the MPU-9150 at 3.3V and dispense with the level translator.
If used, the level translator takes the SDA and SCL pins from the Arduino at 5V levels and presents them at 3.3V to the MPU-9150. To do so, it requires both a 5V supply on one side and a 3.3V supply on the other. Fortunately the common MPU-9150 boards contain a 3.3V regulator, but unfortunately its output is not presented at any of the pins. It is therefore necessary to solder a fine wire to the output pin on the regulator as shown in the photo.
Locate the regulator, which should be marked KB33 (at the top of the second picture). You will need a steady hand and a soldering iron with a fine pointed tip. Solder a piece of fine wire to the top right hand pin. Once you have made a good connection, cover it with a blob of superglue to stop it being easily pulled off.
The wiring will depend on whether you use stripboard or a solderless breadboard, which sort of Arduino, and whether you use the level translator, and so I'll leave you to work out the wiring or the stripboard layout. (If you don't feel confident to do that, go and try one or two simple Arduino projects, or projects using stripboard, and come back when you've got the idea.)
The level converter has two power inputs labelled HV and LV, in addition to Gnd. HV is connected to the 5V supply and LV to the 3.3V output of the MPU-9150 using the thin wire you soldered to it. The SDA and SCL pins from the Arduino use 5V logic levels and are connected to the HV1 and HV2 pins on the level converter. The LV1 and LV2 pins then present the same signals to the MPU-9150 at 3.3V logic levels. Your device may also have HV3, HV4, LV3 and LV4 connections, which are not used.
If you're not using the level converter, simply wire the SDA and SCL pins on the Arduino directly to the corresponding pins on the MPU-9150.
You may wish to wire the AD0 input on the MPU-9150 to the 3.3V output in order to change the I2C address from 0x68 to 0x69 so as not to clash with a DS1307 real time clock chip which also uses address 0x68, should you wish to add that later, for example to make a clock.
You can calibrate the MPU-9150 by taking 4 measurements with the device in 4 orientations exactly like for the XLoBorg. It's important that it's horizontal in all 4 tests - not hard for a Raspberry Pi in a case with a flat top and bottom, but it may be harder with the MPU-9150, depending on how it's mounted. As before, try to ensure the magnetometer chip is in the same position relative to the desk for all 4 readings.
You will need to download and install the MPU6050 library, which also contains code for the MPU-9150, which is a superset of the MPU6050. Compile and upload the attached sketch Calibrate_MPU9150. From the Arduino IDE, launch the Serial Monitor running at 38400 baud. This should continuously display accelerometer, gyro and magnetometer readings. At each of the 4 orientations, ensure that the accelerometer X and Y readings are as small as you can easily make them, indicating the device is horizontal, before taking a visual average of the magnetometer readings. Tabulate the readings as described for the XLoBorg and calculate the offsets in the same way.