Introduction: Quaternion Compass
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
Calibration is simple ... three methods are provided:
- Tumble the compass every time at switch-on
- Tumble the compass once and save the results
- Use my “compass_cal” software and save the results
A compass-heading of +/- 2 degrees is possible using my “compass_cal” software.
The estimated cost for this project is $20 USD.
Videos
- “compass_cal” demonstrates my magnetometer calibration software. The user is asked to rotate the compass in 6 different orientations. The results are shown in a rotatable 3D display. The required magnetometer offsets and scale-factors are calculated and presented in a manner suitable for use with cut-&-paste. Compass heading accuracy is within +/- 2 degrees.
- “compass_rose” demonstrates my graphics “compass rose”. The scale rotates beneath the compass needle which is fixed.
- “heading_pitch_roll” demonstrates the compass accuracy at 90 degree intervals. The affect of pitch and roll on the compass heading is also demonstrated.
Images
- Photo 1 shows the compass resting on a 30 degree protractor
- Photo 2 shows the output from my “compass_cal” calibration routine
- Photo 3 shows my graphics “compass_rose”
Warning
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!
Step 1: Circuit Diagram
Photo 1 shows how the Arduino UNO R3, The LCD display, and the MPU-9250 accelerometer/gyro/magnetometer are wired together.
The MPU-9250 must:
- be level when the compass is switched on.
- be clear of any ferrous metals
Step 2: Parts List
The following parts where obtained from https://www.aliexpress.com/
- 1 only Arduino UNO R3 and USB cable
- 1 only serial LCD display
- 1 only MPU-9250 accelerometer/gyro/magnetometer
- 2 only Arduino female-to-female jumper cables
- 6 only Arduino male-to-female jumper cables
The following parts were obtained locally:
- 9 volt battery
- 9 volt battery clip/leads
- Scrap plastic sheet for base
- 12 only threaded nylon spacers
- 20 only M3 x 5mm bolts
The estimated cost for this project is $20 USD.
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]
The MPU-9250 chip contains:
- an accelerometer which knows which way is down
- a gyro which knows how much each axis has rotated
- and a magnetometer that knows which direction is North
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.
These variations may be minimized using standard tilt-compensation formulas. My instructable https://www.instructables.com/id/Tilt-Compensated... demonstrates this technique.
Quaternion compass
This “quaternion” compass uses an entirely different technique ... it simply reports your “pitch” (nose-up), “roll” (right-wing down), and compass-headings in real time. Tilt-stabilization formulas are not required as the compass knows its exact orientation and heading at all times.
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
This compass uses the "Sparkfun MPU-9250 Breakout Arduino Library", https://github.com/sparkfun/SparkFun_MPU-9250_Brea...which was forked from https://github.com/kriswiner/MPU9250
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]
MahonyQuaternionUpdate( myIMU.ax, -myIMU.ay, myIMU.az, myIMU.gx * DEG_TO_RAD, -myIMU.gy * DEG_TO_RAD, myIMU.gz * DEG_TO_RAD, myIMU.my, -myIMU.mx, -myIMU.mz, myIMU.deltat);
Following this change:
- The pitch and roll work as normal.
- The yaw angle no longer varies when the compass is tilted
- The “compass-heading” and “gyro-yaw” track each other 100%.
Some lateral thinking:
- 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?
We now have a tilt-stabilized quaternion compass !!!
Notes
[1]
Quaternions are used in applied mathematics to rotate objects in 3D space
There is a lot of mystique about quaternions. From a simplistic viewpoint they are no more difficult to use than say arcsin(Y/X).
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 !!
The following article, “3D Game Programming, Understanding Quaternions”, https://www.3dgep.com/understanding-quaternions/#m... , explains the concept behind quaternions really well.
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]
Some arbitary rules: [3]
- 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.
The columns are labelled as follows:
- 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 author of the MPU-9250 library has this to say https://github.com/kriswiner/MPU9250/issues/345
“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 conventions) or even NWU will all work. As long as the sensor data is provided in a manner consistent with the chosen convention.
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.
Step 4: Software 1 ... "quaternion_compass.ino"
Instructions:
The attached file "QC_files.rar" contains all of the code for this project ... use WinRAR [1] or 7-Zip [2] to extract.
The folder "quaternion_compass" contains all eleven Arduino files and is "ready-to-go". Copy this folder to your Arduino directory and open "quaternion_compass.ino" [3]
Notes:
[1]
WinRAR is available fromhttps://www.win-rar.com/download.html?&L=0
[2]
7-Zip is available from https://www.7-zip.org/
[3]
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
Code update
6 March 2020 :
The attached file, "quaternion_compass_new_v8.ino", is essentially the same as "QC_files.rar" but with these differences:
- The code is now contained in a single *ino file.
- Mode selection is easier ... just change one number.
- Sections of the quaternion code have been rearranged for easier reading.
- Soft-iron distortion code has been added.
- The code compiles for both the Arduino Uno R3 and the Adafruit ATSAMD51 Feather M4 Express https://www.adafruit.com/product/3857
Notes:
- The code is 100% compatible with "compass_cal.pde" and "compass_rose.pde.
- The references to "M4" are for the Adafruit ATSAMD51 Feather M4 Express
- The code uses "short" rather than "int" otherwise the M4 doesn't compile.
- The response time is affected by the Kp free variable but at the expense of settling time.
- Kp values above zero appear stable.
- Kp values below zero produce interesting (and possible useful) effects.
Step 5: Software 2 ... "compass_cal.pde"
Instructions:
"QC_files.rar" in Step 4 contains all of the code for this project ... use WinRAR or 7-Zip to extract.
The folder "compass_cal" contains the Processing "calibration" software. Copy this folder to your Processing directory and open "compass_cal.pde" [1]
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.
The following code is found in setup().
// ----- configure the serial port printArray(Serial.list()); myPort = new Serial(this, Serial.list()[0], 115200); myPort.bufferUntil('\n'); // serialEvent() won't trigger until buffer has "\n" myPort.clear();
Step 6: Software 3 ... Compass_rose.pde
Instructions:
"QC_files.rar" in Step 4 contains all of the code for this project ... use WinRAR or 7-Zip to extract.
The folder "compass_rose" contains the Processing "compass rose" software. Copy this folder to your Processing directory and open "compass_rose.pde" [1]
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.
The following code is found in setup().
// ----- configure the serial port printArray(Serial.list()); myPort = new Serial(this, Serial.list()[0], 115200); myPort.bufferUntil('\n'); // serialEvent() won't trigger until buffer has "\n" myPort.clear();
Step 7: Software Installation
It is essential that you perform this step BEFORE uploading the compass code to your Arduino
Editing your I2C Wire Library
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.
I recommend editing lines 75 ,76, & 77 in file “C:Users\...\Documents\Arduino\libraries\Wire\utility\twi.c” to read:
// deactivate internal pullups for twi. digitalWrite(SDA, 0); digitalWrite(SCL, 0);
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.
Installing the software
Before plugging in your Arduino:
- Disconnect the I2C lines from your Arduino [1]
- Edit your I2C Wire library as described above.
- Download and install the software in Steps 4,5,6
- Upload the “quaternion_compass.ino” sketch to your Arduino.
- Unplug the Arduino.
- Reconnect the Arduino I2C lines.
- Your compass is now ready for calibration
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.
Step 8: Calibrating the Compass
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]
Mag_x_offset = (mag_x_max + mag_x_min) / 2; Mag_y_offset = (mag_y_max + mag_y_min) / 2; Mag_z_offset = (mag_z_max + mag_z_min) / 2;
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]
chord_x = ((float)(mag_x_max - mag_x_min)) / 2; chord_y = ((float)(mag_y_max - mag_y_min)) / 2; chord_z = ((float)(mag_z_max - mag_z_min)) / 2; chord_average = (chord_x + chord_y + chord_z) / 3; Mag_x_scale = chord_average / chord_x; Mag_y_scale = chord_average / chord_y; Mag_z_scale = chord_average / chord_z;
The above calculations are performed by the myIMU.calibrateMPU9250(...) function in setup().
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.
Method 1 ... (calibrate every time)
Change the header setting in “quaternion_compass.ino” to read
#define TASK 0
and upload this change to your Arduino.
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.
The heading is then displayed on your LCD screen.
Method 2 ... (calibrate once)
Change the header setting in “quaternion_compass.ino” to read:
#define TASK 1
and upload this change to your Arduino
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.
Now change the header setting to:
#define TASK 6
upload this change to your Arduino
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.
Method 3 ... (circle method)
Change the header setting in “quaternion_compass.ino” to read:
#define TASK 2
and upload this change to your Arduino.
Tape your Arduino compass to the inside of a cardboard box as shown in photo 2. Ensure that your compass is parallel to the inside wall of the box.
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]
Now change the header settings to:
#define TASK 6
and upload this change to your Arduino
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.
Method 4 ... (sphere method)
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 (Geographic) North
By default the compass indicates Magnetic North.
True North requires that you change these two lines in the “quaternion compass.ino header:
#define True_North false // change this to "true"for True North float Declination = +22.5833; // replace this with the declination for your location
Upload these changes to your Arduino and all future compass headings will be relative to True North
You can obtain your magnetic declination from http://www.magnetic-declination.com/
Calibrating the gyro
The gyro is automatically calibrated each time you power-up the compass.
Notes
[1]
"Simple and Effective Magnetometer Calibration", Kris Winer, https://github.com/kriswiner/MPU6050/wiki/Simple-and-Effective-Magnetometer-Calibration
[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.
Step 9: Summary
This “quaternion” compass:
- Comprises an Arduino UNO R3 microcontroller and an MPU-9250 chip that contains an accelerometer, gyro and magnetometer in the same package.
- The XYZ outputs from the accelerometer, gyro and magnetometer are fed into a “quaternion” function that calculates the compass pitch, roll, and yaw.
- The values chosen for the “quaternion” are such that the compass heading tracks the gyro yaw ... instead of calculating the compass heading we use the compass yaw.
- Pitch and roll does not affect the compass heading.
- An accurate method for calibrating the compass is included.
- Once calibrated, the resulting compass headings are accurate to within +/- 2 degrees.
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.
The estimated cost to build this project is $20.00 USD.
This software may also prove suitable as the inertial management unit (IMU) for a quadcopter.
Click here to view my other instructables.
93 Comments
Question 3 months ago
Do you think would it be possible to achieve similar results using an MPU9255 module instead of an MPU9250 module? If it's possible can you guide me which parts are going to be different so I can tinker with it to find out.
Edit: I figured it out, it was very easy actually. If anyone wonders how I did it I shared my results in the "I Made It!"
Answer 3 months ago
Thank you for sharing your results :)
Question 5 months ago on Step 9
Hello, Your isntructable was very interesting. I was wondering how hard it would be for the unit to control a servo to maintain a compass heading. THe application is for a boat with a high gain directional LTE antenna. THe intent is to keep teh antenna pointed WEST at all tmes. Currently there is no serive once over 5 miles offshore. The small LTE antenna (Microtik SXT LTE) will be mounted on a pole that is mounted to a bearing pack to allow for rotation. The base of the bearing is a DOCYKE SERVO-350B 2in1 Robot Servo High Power High Torque
Servo. The inent would be have a knob to set the compass heading and the unit should hold the heading regardless fo the boats orientation. How hard would that be to achieve? Essentially the compass would control the servo to keep the selected compass heading.
Answer 5 months ago
Thank you for your interest in my project :)
Regarding your question "how hard it would be for the unit to control a servo to maintain a compass heading." ... probably not too hard. If you know your current heading then you can calculate the offset to West. After that it's a matter of coding.
Not certain that a servo is your best option as their angle of rotation is usually limited.
Good luck with your project.
Question 1 year ago on Step 9
Hi. I am trying to duplicate the results that you have shown in this excellent instructable, and to some extent have been successful. This is my first attempt to use 'Processing' code so am not sure where the problem lies.
I have loaded the sketch (v8) into an arduino pro mini, 8MHz 3v3, no LCD attached. This compiles and loads without error and if I set it in TASK 4 mode I get continuous data output to the serial monitor. When I set the mode to TASK 2 and run compass-cal on the PC, it connects, builds the 3D model and starts to collect data for the 'Red Arrow' down. I get a small Red blob on the 3D model.
The data collection stops after a series of static values, this is then followed by an error in the Processing console indicating a problem with the 'serial.event' routine. The *.csv files a created but are not populated with any readings.
I have reached the limit of my knowledge, what have I not done, or done incorrectly?
Answer 1 year ago
Ignore my question, I have just read all the other questions and responses and found your posting of 2 years ago!
Sorry I should have researched a bit further first.
Great project and thorough answers to all the questions.
Thank you.
Reply 1 year ago
Thank you for your interest in my project :)
Glad you have solved the problem.
Happy New Year :)
Reply 1 year ago
I tried putting a delay into compass-cal, in the line prior where 'S' is sent to the Arduino at the end of the loop. I think this is the right place to put it?
I tried a delay of 500mS to start but it still freezes I then increased to 1000mS but it still freezes without ending the red arrow down pass.
Did the other person report getting the code to work with a Pro-Mini or not?
I altered the TASK to 5 and left it running over night and although the readings were meaningless they were stable and continued to be output all night. This gives me confidence that if I can successfully calibrate the compass then I will be able to complete my project. (I want to output the heading using the SeaTalk protocol to incorporate in a navigation system for my yacht!)
Thanks for you reply and help thus far.
Reply 1 year ago
My circuit and code using a 16MHz Arduino UNO R3 with an ATMEG328P chip definitely works. I would be inclined to try and get things working with an Arduino UNO R3 first to get a feel for what happens. It is important that you complete the calibration ... the readings will all be meaningless until this has been done.
FYI one user has advised that the magnetometer in some of the current MPU9250 breakout modules is missing/defective ... it may well be that you have a faulty module ?
I have never tried an 8MHz Pro-Mini but I have successully ported the existing code to a 120MHz Feather M4 Express featuring the ATSAMD51.
The 'S' handshaking shouldn't need an extra delay but adding one shouldn't prevent the code from working.
Am not famililiar with the SeaTalk protocol but draw your attention to my warning at the start of the instructable "Warning - Do not use this compass in situations involving safety to life, such as navigation at sea." My reasoning is that magnetic fields vary with location; the cost of a proven satnav system relative to the cost of a yaght is cheap.
Reply 1 year ago
Thanks again lingib for the reply.
I have absolutely no doubt your code works. The Pro-Mini is also based on the 328 chip and is available as a 16Mhz/5V or 8Mhz/3v3 module. Mine is the latter. I am fairly confident that I do get gyro, accelerometer and magnetometer readings from the 9250, at least the code indicates all devices respond to the "Who am I's" and TASK 4 gives all the results.
WRT to the navigation issue, my reason to build this project is less about relying on it for navigation and more about the mental stimulus of being able to take data from the various instruments and integrate it with a 'moving chart' display!
I take your point about replicating your test conditions as a way of proving and understanding the project. The SeaTalk integration part is already working just lacking the compass input - I don't have an electronic compass instrument.
Thanks again for a great project, well documented and presented and for the continued follow up you have provided.
Best regards.
Reply 1 year ago
Just a thought ...
The MPU9250 calibration values for https://www.instructables.com/Tilt-Compensated-Com... can be used in your https://www.instructables.com/Quaternion-Compass/ and vice versa ... same hardware connections ... different software.
This would verify the MPU9250 and Pro Mini compatibility
With regards to the software the https://www.instructables.com/Quaternion-Compass/ has the greatest long term stability.
Reply 7 months ago
You report that the calibration values are the same, but in the first case you are using ASA correction factors, in this case you are not.
tilt_comp_compass_v1.01:
void calibrate_magnetometer()
{
...
mag_x = (Wire.read() | Wire.read() << 8) * ASAX;
...
quaternion_compass_new_v8:
void magCalMPU9250(float * bias_dest, float * scale_dest)
{
...
readMagData(mag_temp); // Read the raw mag data
...
void readMagData(short * destination)
{
...
destination[0] = ((short)rawData[1] << 8) | rawData[0] ;
...
Added:
compass_cal function uses ASA and mRes (=1.5)
Thus, we have three different values of the coefficients, which will differ on ASA and mRes, i.e. 1.18(1.14)*1.5 = 1.77(1.71) times.
So what is the correct coefficient?
Reply 7 months ago
The manufacturers ASA values are applied in both compasses.
In https://www.instructables.com/Tilt-Compensated-Co... the ASA vaues are applied in code lines 470,471,472:
mag_x = (Wire.read() | Wire.read() << 8) * ASAX; // Combine LSB,MSB X-axis, apply ASA corrections
mag_y = (Wire.read() | Wire.read() << 8) * ASAY; // Combine LSB,MSB Y-axis, apply ASA corrections
mag_z = (Wire.read() | Wire.read() << 8) * ASAZ; // Combine LSB,MSB Z-axis, apply ASA corrections
In https://www.instructables.com/Quaternion-Compass/... the ASA values are applied in code lines 1139,1140,1141:
bias_dest[0] = (float)mag_bias[0] * magCalibration[0] * mRes; // rawMagX * ASAX * 0.6
bias_dest[1] = (float)mag_bias[1] * magCalibration[1] * mRes; // rawMagY * ASAY * 0.6
bias_dest[2] = (float)mag_bias[2] * magCalibration[2] * mRes; // rawMagZ * ASAZ * 0.6
Reply 7 months ago
Yes, you are right, ASA is taken into account in Mag_n_offset calculation in both programs.
But tilt_comp_compass_v1.01 does not take m_res into account.
For example, when calibrating my magnetometer in both programs, I got the following values:
1.tilt_comp_compass_v1.01
int Mag_x_offset = -54, Mag_y_offset = 186, Mag_z_offset = -307;
2. quaternion_compass_new_v8
TASK2
float
Mag_x_offset = -81.36502,
Mag_y_offset = 283.01,
Mag_z_offset = -478.87,
The corresponding values differ just about m_res (~1.5) times. So I would not directly use the values from the first program in the second one and vice versa.
Thank you very much for your excellent work and accessible presentation of the material!
Reply 7 months ago
Thank you for sharing your test results :)
Another way of expressing your ratios is 1/1.5 = ~0.6 = mRes LSB resolution
In pratice the mRes scaling factors cancel out when calculating the magnetic angle
Example: tan((Xreading*ASI*mRes)/(Yreading*ASI*mRes)) = tan((Xreading*ASI)/(Yreading*ASI)) = tan(tan((Xreading)/(Yreading))
This explains why the quarternion values can be used in the tilt compass.
Both compasses work but my preference is for the quaternion as that has better long term stability.
Reply 7 months ago
Thanks, you are right again!
Quaternion compass is more stable, but choosing Mahony/Madgwick free parameters for convenient use is a rather difficult task :)
Reply 1 year ago
I have continued working with compass-cal and have got a result. Sounds odd but I reduced the size of the sample array 1200 and with a delay prior to sending 'S' of 100mS. Not ideal but it proves to me that the Pro-mini will work out ok.
With the above calibration the heading jitters around a fairly accurate reading (when eyeball compared with a small handheld compass) of +/- 2 degrees over a 24 hour period.
Thanks again.
Reply 1 year ago
That's great ... thanks for your update :)
The comparison table at the end of this link
https://core-electronics.com.au/tutorials/compare-...
indicates that some Arduino variants have less SRAM which may account for having to reduce the array size ?
Question 1 year ago on Step 9
Hi. I've been struggling with an issue with this project. I would love to get it running so hope you are able to help. I seem to have a communication issue with the magnetometer. I get pitch and roll values but the heading gives only one value which doesn't change in any orientation. The serial monitor gives "MPU9250 WHO_AM_I = 0x70, I should be 0x71 or 0x73". What does this indicate, and what would you suggest? I have sent an image of the sensor board I used. Perhaps a more recent version uses different addresses? Many thanks for any help.
Answer 1 year ago
Thank you for your interest in my project :)
The MPU9250 comprises three chips within a single package ... two from one company and one from another.
Code line 510 checks whether the gyro & accelerometer chips are present. Code line 547 checks whether the third-party magnetometer chip is present. The code won't progress unless all chips are present.
The response "MPU9250 WHO_AM_I = 0x70, I should be 0x71 or 0x73" is telling you that it doesn't recognise the validation number 0x70 from the gyro/accelerometer.
It could well be that the board is a valid variant but with a different validation number as Kris Winer suggests. I had a similar problem when I first tried Kris's code and added the number I got to code line 510
Try modifying code line 510 to read
if ((c == 0x70) || (c == 0x71) || (c == 0x73)) // MPU925?=0x70; MPU9250=0x71; MPU9255=0x73;
This will get you past this "codeblock" and hopefully work.