Quaternion Compass
Quaternion Compass
Quaternion Compass
by lingib
This instructable explains how to build, and calibrate, a tilt-stabilized compass using an Arduino UNO R3 and an
MPU-9250 accelerometer | gyro | magnetometer. [1]
The following options are available for displaying the compass heading | pitch | roll:
Serial Monitor
LCD display
A graphics “compass rose” on your PC screen
Videos
Images
Do not use this compass in situations involving safety to life, such as navigation at sea.
[1]
Strictly speaking the compass is not tilt-stabilized ... it uses “quaternions” ... but the effect is the same!
https://youtu.be/jZm6BQPh_vs
https://youtu.be/7-x7Xuu1HGQ
https://youtu.be/NquuVpm8eSc
Photo 1 shows how the Arduino UNO R3, The LCD display, and the MPU-9250 accelerometer/gyro/magnetometer
are wired together.
9 volt battery
9 volt battery clip/leads
Scrap plastic sheet for base
12 only threaded nylon spacers
20 only M3 x 5mm bolts
Step 3: Theory
"Quaternions" are a complex number system that enable us to calculate the attitude and heading of any object
relative to Earth in real time. [1]
If we feed all of this information into a “quaternion” we can calculate our pitch, roll and compass-heading.
Traditional compasses
The compass-heading from a stand-alone magnetometer is only valid if the compass is level ... if we tilt the
compass the compass-heading will vary.
Quaternion compass
This “quaternion” compass uses an entirely different technique ... it simply reports your “pitch” (nose-up), “roll”
For example:
Flip this compass upside down and the roll will change from 0 degrees to 180 degrees ... the other
readings won’t change.
Place the compass on a 45 degree sloping surface such that the pitch reads 45 degrees and the roll
reads zero. Now rotate the compass 90 degrees clockwise ... the roll changes to 45 degrees and
the pitch changes to zero because it is now horizontal.
Compass evolution
I found that the Sparkfun yaw angle varied whenever I tilted the MPU-9250.
The problem disappeared when I modified the Sparkfun MahonyQuaternionUpdate() function to read: [2][3]
If the gyro-yaw and the compass heading track then why not use the gyro-yaw as the compass-
heading?
If the yaw-angle doesn’t vary when the compass is tilted then traditional tilt-stabilization is not
required?
Notes
[1]
There is a lot of mystique about quaternions. From a simplistic viewpoint they are no more difficult to use than say
arcsin(Y/X).
Quaternion Compass: Page 5
Arcsin(Y/X) accepts two inputs (X,Y) and produces one output ... whereas a quaternion accepts multiple inputs
and produces four outputs. The reason it is called a quaternion is that the number of outputs is four !!
It starts by rotating a “point” around a 2D circle by continuously multiplying the current location of the “point” by “i”
(an imaginary number) ... after four multiplications we are back where we started. This concept is then extended to
3D.
We don’t need to understand the maths ... just how to apply the Madgwick/Mahony quaternion functions.
[2]
You can choose any MPU-9250 chip axis to be your North facing axis. I have chosen to use the
gyro X-axis.
Quaternions produce four outputs ... q0, q1, q2, q3
When the compass is level and pointing North q0, q1, q2, q3 should read 1,0,0,0
The three columns in photo 1 and photo 2 represent the directions that each of the MPU-9250 XYZ axes are
pointing when the gyro X-axis is pointing North.
N = North
S = South
W = West
E = East
U = Z-axis up
D = Z-axis down
A negative sign indicates that that particular MPU-9250 axis is pointing in the opposite direction.
The MahonyQuaternionUpdate( ... ) function has 10 parameters ... one for each of the accelerometer, gyro, and
magnetometer XYZ axes ... plus a “myIMU.deltat” parameter that controls the timing.
Only two of the possible combinations give a valid output. I chose the last option in photo1 ... these are the values
that I have plugged in to the MahonyQuaternionUpdate(...) function above.
[3]
“The Madgwick and Mahony filters (and quaternions in general I believe) work in a right-handed coordinate
system. So the data have to be "provided" to conform to this. Thus NED, ENU (the two most common orientation
So first step, the user decides which edge of the sensor board will be pointing to true North when the quaternions
read 1 0 0 0. This is one of two absolute references in the system (the other is gravity). Once the board edge
facing North is decided (yes, it is your choice!), then it is a simply matter to find out which accel axis point North,
no? Then West, then Up. Then the filter should get the data as AN, AW, AU...same for the other two sensors.”
The orientation that I have chosen for this “quaternion compass” is NEU.
Instructions:
The Instructables website no longer accepts *.zip files. A side-effect is that *.ino and *.pde files are
also blocked. PM (personal message) me with your email address and I will send you a zip file
containing ALL three software folders.
Notes
[1]
The quaternion compass folder contains eleven files. The main file is "quaternion_compass.ino" ... the other ten
files are "tabs" and "libraries"
[2]
It is essential that you edit your I2C Wire Library BEFORE uploading the compass code to your Arduino ...
instructions for doing this are given in Step 7: Software Installation
Instructions:
The Instructables website no longer accepts *.zip files. A side-effect is that *.ino and *.pde files are
also blocked. PM (personal message) me with your email address and I will send you a zip file
containing ALL three software folders.
Notes
[1]
A list of available COM ports appears on-screen whenever you start "compass_cal" .
If you get a COM port error try changing the number inside the square bracket below from [0] to one of the above.
Instructions:
The Instructables website no longer accepts *.zip files. A side-effect is that *.ino and *.pde files are
also blocked. PM (personal message) me with your email address and I will send you a zip file
containing ALL three software folders.
Notes
[1]
A list of available COM ports appears on-screen whenever you start "compass_rose" .
If you get a COM port error try changing the number inside the square bracket below from [0] to one of the above.
It is essential that you perform this step BEFORE uploading the compass code to your Arduino
According to the breakout board schematic (photo1) , the MPU-9250 chip has 10K ohm pull-up resistors
connected to 3.3 volts on each of the SDA (data) and SCL (clock) lines.
The Arduino, however, has internal pull-up resistors to 5 volts. These pull-up resistors are not required and should
be disabled to prevent the I2C lines from rising above 3.3 volts and damaging the MPU-9250.
These commands could be placed inside the Arduino setup() function following the Wire.begin() function but it is
still possible for the I2C lines to rise above their safe voltage level until the code lines are run.
Use a text editor such as Notepad++ when editing any files. Do NOT use a word processor.
Methods for calibrating the compass may be found in the next Step.
Note
[1]
The reason for disconnecting the I2C SDA (data), and SCL ( lines is that Arduino pins A4 & A5 may be in an
output “high” state from a previous project. Disconnecting these wires eliminates the possibility of 5 volts damaging
the MPU-9250.
Depending on their orientation with respect to the Earth’s magnetic field, the XYZ outputs from the magnetometer
change from +ve to -ve (positive to negative) as the magnetometer is rotated.
If you rotate the MPU-9250 about each axis, the XYZ outputs should each plot a perfect circle centered about the
3D XYZ coordinate (0,0,0) as shown in photo 1 (see calibrated).
Hard-iron distortion
In practice these circles are NOT centered over the 3D coordinate (0,0,0) but are displaced either up or down, or to
the left or right as shown in photo 1 (see uncalibrated).
These displacements are due to “Hard-iron” distortion from say a magnetized object such as a speaker. Such
distortions are always additive and the offsets can be calculated (then subtracted) using the following code: [1]
Soft-iron distortion
There is also another form of distortion called “Soft-iron” distortion” that arises from the proximity of ferrous, and
other materials, that disturb the earth’s magnetic field.
The effect of “soft-iron” distortion is to turn the ideal circles into ellipses which has the effect of altering the
compass heading.
The solution to this problem is to scale the X and Y readings in such a way as to form perfect circles. This is
achieved using the following code: [1]
This function MUST be run before you can use the compass. Theoretically this function is not required again
unless you change your location ... but to avoid going through this process each time you must record the offsets
and scale-factors using one of the following methods.
#define TASK 0
In this mode you are asked to “Tumble your compass for 30 seconds”. An accurate heading requires that you loop
the compass in a figure-eight pattern in each of the three XYZ axes.
#define TASK 1
You will be asked to “Tumble your compass for 30 seconds”. An accurate heading requires that you loop the
compass in a figure-eight pattern in each of the three XYZ axes.
This mode displays the compass offsets and scale factors on your Serial Monitor then stops.
Copy and paste the offsets and scale factors into your Arduino Header.
#define TASK 6
The offsets and scalefactors that you have recorded will be used each time you start the compass. You will no
longer be asked to “tumble” the compass.
#define TASK 2
Assign a red, green, or blue arrow to each of the three XYZ axes as shown in photo 3. In practice it doesn’t matter
which color you assign to which axis ... it just means that each circle color matches its axis color.
Start your Arduino with the above settings then run the Processing “compass_cal.pde” on your PC and follow the
on-screen instructions. Cut and paste the offsets shown in photo 3 to your Arduino header. [2]
#define TASK 6
The offsets and scale-factors that you have recorded will be used each time you start the compass. You will no
longer be asked to “tumble” the compass.
I find this method gives the most accurate results. Compass headings of +/- 2 degrees are possible.
This method is identical to method 3 except that you that you loop the compass in a figure-eight pattern in each of
the three XYZ axes whenever you are asked to rotate the compass. [2]
I find that this method is not quite as accurate as the circle method. I suspect the reason is that the dot-density is
higher for a circle than if we spread the same number of dots over the surface of a sphere.
Provision has been made in the header of “compass_cal.pde” to increase the number of samples but the graphics
slow to a crawl when you do this.
True North requires that you change these two lines in the “quaternion compass.ino header:
Upload these changes to your Arduino and all future compass headings will be relative to True North
The gyro is automatically calibrated each time you power-up the compass.
Notes
[2]
Moving your mouse over the graphics screen causes the 3D display to rotate.
Pressing the “O” key toggles the graphics between “uncalibrated” and “calibrated” mode (Photo 1)
Depending on the number of samples it may take a moment for the graphics screen to update.
Do not use this compass in situations involving safety to life, such as navigation at sea, as long term testing has
not been performed. The compass appears stable over several hours.
This software may also prove suitable as the inertial management unit (IMU) for a quadcopter.
Tried to download all files but all I got in ALL the files was:
# ImageMagick pixel enumeration: 612,792,65535,rgba
0,0: (65535,65535,65535,65535) #FFFFFFFFFFFF white
1,0: (65535,65535,65535,65535) #FFFFFFFFFFFF white
It would appear that text files containing code are also blocked ?
PM (personal message) me with your email address and I will send you a zip file containing ALL
three software folders.