Quaternion Compass




Introduction: Quaternion Compass

About: 55+ years in electronics, computers, and teaching ... now retired.

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.


  • “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.


  • 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”


Do not use this compass in situations involving safety to life, such as navigation at sea.


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,

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 !!!



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.


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.


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"


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]



WinRAR is available fromhttps://www.win-rar.com/download.html?&L=0


7-Zip is available from https://www.7-zip.org/


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


  • 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"


    "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]



    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
      myPort = new Serial(this, Serial.list()[0], 115200);
      myPort.bufferUntil('\n');  // serialEvent() won't trigger until buffer has "\n"

    Step 6: Software 3 ... Compass_rose.pde


    "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]



    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
      myPort = new Serial(this, Serial.list()[0], 115200);
      myPort.bufferUntil('\n');	// serialEvent() won't trigger until buffer has "\n"

    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.



    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.


    "Simple and Effective Magnetometer Calibration", Kris Winer, https://github.com/kriswiner/MPU6050/wiki/Simple-and-Effective-Magnetometer-Calibration


    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.

    Be the First to Share


      • Clocks Speed Challenge

        Clocks Speed Challenge
      • Toys & Games Contest

        Toys & Games Contest
      • Big vs Small Challenge

        Big vs Small Challenge



      Question 5 weeks ago on Introduction

      Super tutorial with beautiful documentation!
      I would like to test with an Arduino NANO, is this possible please?


      Answer 4 weeks ago

      Thank you for your interest in my project :)
      I don't have an Arduino NANO to try but I can't see why not.


      Question 2 months ago

      Heya! Great tutorial, thank you. I have got everything working with the Arduino side and I have installed Processing 3, buit when I run the code for calibration, nothing happens. Its just a screen frozen on the Bisected Cube sitting at an angle. Ive not used Processing before, am I missing something obvious? I have the correct com [port selected by way of changing the code, but nothing is happening compared to your video. The arduino is happily streaming the data when I monitor it over serail.


      Answer 2 months ago

      Mate, ignore my question. Im an absolute roaster. The data is displayed in the main program, not to the left of the cube. Had the bloody cube fullscreen and hadn't spotted it until I watch your video for the 38th time hahahahaha! All working. Thank you so much!


      Reply 2 months ago

      Thank you for your interest in my project :)
      You had me worried for a moment ... glad you got it working :)


      4 months ago

      Hi Im trying to build an remotly controllable car and Im using a modified version of your code to track the orientation of the vehicle. However first of all everything seemed to work just fine but suddenly, without any changes in the code or hardware, the microcontroller wasn`t able to read the Who am I register of the magnetometer correctly, the answer was always 0xFF instead of 0x48. I wasnt able to spot any mistake so I thought I somehow killed another chip and replaced the sensor with a new one. After that everything worked again for a few hours but now Im facing exactly the same problem again. Only thing I could Imagine to be the problem is that the mpu9250 is not in pass throu mode but thats done in your code or am I wrong? Do you have any suggestions what could be the problem?


      Reply 4 months ago

      The interrupts and bypass enable (that connects the magnetometer to the I2C bus) are performed in code lines 907..913. The fact that "everything worked for a few hours" indicates that the software is working.

      Am alarmed at your comment "so I thought I somehow killed another chip" ... 0xFF is not a good look. The MPU-9250 I2C lines are not 5 volt tolerant. I assume that you have no external I2C pull-up resistors and have edited your I2C Wire Library as explained in Step 7.

      Also assuming that your remotely controlled car is battery operated. Is there a possibility that you are getting a voltage spike from your motors? The motor wiring needs to be well away from the I2C lines to prevent transformer action and preferably have their own supply.

      Try running Compass_cal.pde using the software in Step 4 ... this should confirm whether your MPU-9250 module is still working.

      Apart from that I can't think of anything else. You mention that you have modified my code. Not certain what you have done but the fact that every thing works for a few hours indicates that it isn't the cause.


      Reply 4 months ago

      Hi thanks for your reply.
      I´m pretty sure the code isn´t the problem here basically its your code in Task 4 without all of the unnecessary parts. Also tested the imu´s with an arduino nano with my old setup for testing and got similar results. mpu 9250 is working flawlessly but its not possible to read the status bit from the magnetometer.

      Tryed running compass_cal.pde but only got zeros on all axis...

      I´m forced to use Softwarewire instead of the wire libary because it wasn´t planed to use an IMU on the car and there are only regular digital pins available. However with this libary it´s possible to disable the pull ups in the code. Even if that is the problem would it it be possible that only the magnetometer gets damaged by this on two different chips?

      Im using 2s Lipo with a voltage regulator chip for the microcontroller and IMU. I´ve never had problems with these and the voltage always seemed to be 5V when I measured. I don´t think there are voltage spikes in the system Motors are controlled by H-bridge drivers with internal diodes to prevent this.

      is it possible that the communication with the Magnetometer is somehow just interrupted or is this chip also fried?


      Reply 4 months ago

      According to the data sheet the "MPU-9250 is a multi-chip module (MCM) consisting of two dies integrated into a single QFN package. One die
      houses the (Invensense) 3-Axis gyroscope and the 3-Axis accelerometer. The other die houses the AK8963 3-Axis magnetometer from Asahi Kasei Microdevices Corporation"

      If you look at the block diagram of the MPU-9250 the Invensense die is more isolated from the I2C bus than the AK8963 magnetometer. I suspect that the I2C voltage is (briefly) exceeding 3.3 volts absolute maximum at boot up and taking out your AK8963's.

      This would explain why you can talk to the gyro/accelerometer but not the magnetometer. Exceeding 3.3 volts may not kill a CMOS chip immediately but in time it is likely to fail.

      This would also explain your first post: "However first of all everything seemed to work just fine but suddenly, without any changes in the code or hardware, the microcontroller wasn`t able to read the Who am I register of the magnetometer correctly, the answer was always 0xFF instead of 0x48. I wasnt able to spot any mistake so I thought I somehow killed another chip and replaced the sensor with a new one. After that everything worked again for a few hours but now Im facing exactly the same problem again."

      It would have helped if you had described your hardware and software changes ... until now I assumed that you were using an Arduino UNO R3 and the Arduino Wire library ... instead you are using an Arduino Nano and the Softwarewire library which, it appears, can use any Arduino Nano pins for I2C

      Am not certain which pins you are using for I2C but the following two links suggest that only pins A4 and A5 should be used for I2C

      They also suggest that pins A5 and A6 don't have pull-up resistors.

      To avoid any more disasters you may need to consider a bidirectional I2C level shifter

      Another remote possiblity is the I2C speed which is 400Kbps.

      As I see it:
      Your project has, on two occasion, worked for a few hours then failed. This suggsets that the hardware and software are correct. So what's causing the failure?

      On both occasions your AK8963 magnetometers have stopped working. I suspect the I2C lines are exceeding 3.3 volts at some stage!!

      This is likely if you are using the Softwarewire library as:
      - editing the Wire library will not disable the I2C pullup resistors as you are not using an Arduino UNO R3
      - the arduino nano is powering up before the Softwarewire library can disable the pull-up resistors
      - you say you are using regular digital (5V) pins?
      - you may not be using the pins better suited to I2C

      In answer to your question " is this chip also fried?" ... I suspect that it is :(

      I know my circuit, as published, works as others are using it successfully.

      Feel free to ask questions but at this point I have run out of ideas.


      Reply 4 months ago

      Thank you for your detailed reply! happy new year everybody!

      I should have made this clear before:
      As stated, I´m building an remotly controlled car. The car is controlled by an Atmega328p in combination with H-bridge drivers on a previously desinged PCB. The commands come frome an HC-06 bluetooth module wich is connected to an smartphone. The car already works perfectly.

      Now I´m trying to make the steering easier by tracking the orientation and controlling the motors with PID (you don´t need to think about the orientation of the car instead you give the absolute angle you want the car to be in and the car controlls itselve). Thats why I implemented your project.

      I used the arduino nano for testing of your and my version of your code. Thats what I mean with prievious setup.

      sadly I´m not able to redo the PCB thats why I have to use digital pin 0, 1, 4 or 7 for the I2C.

      I also thought about using an bidirectional level shifter but want to keep the number of additional components on the car and the total price as low as possible.

      your explanation with the somehow too high bus voltage and slight differences in the isolation sounds reasonable is there any way to measure the Voltage during runtime (not neccesarily while there´s communication)? That would show that the softI2C libary does not disable the pullups and could get fixed. However if the problem really comes frome voltage spikes at startup I need to figure something else out.

      what do you mean with: "Another remote possiblity is the I2C speed which is 400Kbps." Do you think a lower bus speed could help?


      Reply 4 months ago

      Connect a voltmeter between your I2C pins and ground ... the voltage readings should never exceed 3 volts. ( Depending on the I2C state one of the pins may read zero. )

      A storage oscilloscope is needed to detect transient spikes.

      Regarding my I2C comment ... the default speed for I2C is 100Kbps ... my code uses 400Kbps. Try commenting out line 435 "Wire.setClock(400000); // 400 kbit/sec I2C speed" in my setup. It crossed my mind that the AK8963 may be having a problem ... highly unlikely but ?


      Question 6 months ago

      HI - Would it be Possible to replace the LCD with a Small OLED - I want to try and Set this up as a HUD. I am trying to get the MPU-9250 to display similar info but on an OLED and your tutorial has got me the closest to the end product i am busy with

      WhatsApp Image 2020-11-10 at 14.54.19.jpeg

      Answer 5 months ago

      Thank you for your interest in my project :)
      An OLED display should work well but you will need to replace the LCD library in code lines 75..81 with an OLED library that matches your display.
      You will also have to modify the lcd.print(...) code in the view_heading() function commencing code line 1810.


      6 months ago

      Hi, first of all, thank you for this really nice tutorial. Im running your sketch on an arduino nano with partially exeptional results by using the on board calibration method. However as soon as I try to use the compass_cal method im getting really strange readings. Pitch stays at around -30 while roll jumps around somewhere between 180 and -180, as soon as I angle the IMU a little bit in ether direction. The Heading is also far from accurate in a level position. The strange thing is that the heading gets accurate to within a few degrees as soon as I angle the IMU on the pitch axis around 30 degrees, but the pitch reading still stays at -30..
      Do you have any idea what im doing wrong?


      Reply 6 months ago

      Sorry I don't ... but these suggestions may help.

      Something in your compass may be affecting the sensor if you are calibrating your sensor with compass_cal, then putting it back into your compass. This would explain why the tumbling method seems to work for you.

      My sensor is separate to my compass. If yours is attached to your compass then the entire compass should be rotated around each axis when using compass_cal.

      In theory you should get perfect results if you tumble your compass for long enough. In practice not all points on an imaginary ball point towards magnetic North ... any gaps means the theoretical maximum and minimum readings may have not been obtained. You can see these gaps in the "sphere" shown in photo 2 of the introduction.

      Compass_cal attempts to overcome the shortcomings of tumbling by taking a series of slices through the imaginary ball. If all axes are measured at this fixed angle then their ratios are the same and the calibration will be valid. Not only is this faster ... I found that I got more consistent results.

      When using compass_cal it is important that you avoid rocking the compass as the rings will develop kinks ... something to try

      Also, repeat the compass_cal readings if you see any extraneous dots outside of the rings ... any stray dots (readings) will affect the calibration.

      A final thought ... do several compass_cal runs and record the numbers. Discard any where there is a large variation then average the results.


      Reply 6 months ago

      Figured it out, one axis of the accelerometer reads the same no matter what ..
      I think this must have happened somehow after i tried the tumbling method. Thanks for your tips, will get a new sensor and try it again


      Reply 6 months ago

      Great that you have found the problem ... thanks for the update :)


      7 months ago

      hi, tutorial very well done, I appreciate the good work done by LINGIB, I tried the quaternion software indicated but I have a compass stabilization problem .... moving the pitch the compass is OK keeping the indication stable, but moving the roll the compass varies by many degrees ....
      furthermore, when switched on, with the module perfectly level, the display indicates a pith of about 15 degrees while the roll of about 5 degrees and I cannot reset this value .... the compass has an oscillation of about 5 degrees .. .. do you have any information about it ....
      I specify that the calibration has been regularly carried out as indicated in the tutorial ..... thanks for your kind reply ....
      WhatsApp Image 2020-10-13 at 21.34.17 (1).jpegWhatsApp Image 2020-10-13 at 21.34.17.jpegWhatsApp Image 2020-10-13 at 21.34.19.jpeg

      Reply 7 months ago

      Thank you for your interest in my project :)

      Sorry to learn that you are having a problem :(

      The project definitely works, as many have made it, which points to something in your environment. Common problems include nearby TV's and proximity to metal. For instance there may be reinforcing steel in the concrete below your tiles. Your sensor is also close to the LCD display.

      Not certain about the oscillation ... possibly related to the calibration issue. If you check my videos you will see a slight movement but not 5 degrees.

      Some things to try:
      - position the sensor further away from the LCD
      - try recalibrating the sensor in another location
      - unlikely ... try another sensor if you have one
      - probably has no effect but I notice that you are using an Arduino MEGA ... the gyro is sensitive to timing. Does rotating the the compass 360 degrees bring you back to zero?

      Each time you run compass_cal.pde you should get
      - similar values and
      - there should not be any extraneous dots amongst the 3D rings.
      - the axes must all be vertical when using compass cal. If the 3D circles have a kink then you've wobbled.


      Question 9 months ago

      I have to look very intensive to Your Video to figure out witch axis is the right color. ;-) I hope that is correct now .