I have been trying to calculate the compass heading using the magnetometer in an MPU9250 sensor. But the result is not making sense to me. I am completely new in this and do not have much understanding in how magnetometers work and just trying to find resources in the internet to make it work. I am calculating the atan2 of the y and x axis readings of the sensor to find out the angle:

float mx = imu.mag_x_ut();
float my = imu.mag_y_ut();
float mz = imu.mag_z_ut();

float heading = atan2(my, mx) * 180 / PI;


My understanding is that when the x axis of my magnetometer faces the north direction the value of heading should be 0, for east 90, south 180 and then for west 270. But my calculations are nowhere near the expected results. I am not even getting a zero reading in any directon. I am attaching the screenshots of the direction reading :

This is when x axis points to north. x pointed to north

Rotated x axis towards east. x pointed to east

x towards south. x pointed to south

x towards west. x pointed to west

I have also added the raw readings from the magnetometer represnted by mx, my and mz. Is something wrong with my sensor or there is some misunderstanding from my part.

EDIT: Readings after hard iron offset compensation.

after hard iron offset

  • The displayed heading seems consistent with the measured mx and my. These values, however, seem wrong: The modulus of the magnetic field changes as you turn the device. It should not. Either you are doing something wrong while getting the readings, or there is something magnetic next to (or on) your device that affects the local field. Sep 10, 2023 at 12:54
  • @EdgarBonet, hi can you elaborate a bit on your statement " the modulus of the magnetic field changes as you turn the device", sorry if that's a newb question. I used this library for mpu9250 github.com/bolderflight/invensense-imu and just calling the methods for getting the data. Sep 10, 2023 at 14:35
  • 1. I mean the norm of the vector. You can plot it: it should not depend on the orientation of the sensor. 2. Re “just calling the methods”: can you post the complete code? Sep 10, 2023 at 15:27

1 Answer 1


Consider calibrating your magnetometer. Off the shelf, almost all magnetometers require calibration before making use of their data. The offset (commonly referred to as Hard Iron) and the magnitude (commonly referred to as Soft Iron) need to be found for each of the 3 sensors (X, Y & Z) for individual magnetometers.

As there is no accelerometer in this design let us simplify the problem and assume the magnetometer will always be used on a flat surface with its Z axis normal to the surface of the Earth. Let us also assume the X and Y sensors in the magnetometer are perfectly orthogonal to one another.

To calibrate the magnetometer remove metal objects from the local vicinity and avoid large metal object such as cars by 10s of meters. Sample the X and Y sensors many times as these sensors point toward and away from north. Find the maximum and minimum X and Y values.

Find the offset calibration value by adding the minimum and maximum values then divining by 2. Find the magnitude calibration value by arbitrarily picking one axis and adjusting the magnitude of the other to match. Picking X, we subtract the X minimum from the X maximum to find the X range. We do the same for Y to find the Y range. Then we assume the X magnitude calibration value to be 1 and the Y magnitude calibration value to be x-range divided by y-range.

Once calibration is done, to get calibrated X and Y values we subtract the X and Y offset respectively. Then we multiply the offset adjusted Y value by the Y magnitude calibration value.

Note, this type of calibrated compass is difficult to carry around by hand because it may not be held level with the surface of the earth. Also, because the inclination of the magnetic field points deeper into the earth the more one travels away from the equator, it will require re-calibration when traveling to a different latitude.

Calibration calculations based on data in question:

X max to min is 42 to -22 so offset is 10 and range is 64
Y max to min is 120 to 48 so offset is 84 and range is 72
So Y magnitude calibration is 64/72 or 0.889

Data when sensors are pointed East:

Y ~48 & X ~11 
bearing = atan2(((48 - Y_offset) * Y_magnitude), ((11 - X_offset) * X_magnitude)) 
bearing = atan2(((48 - 84) * 0.889), ((11 - 10) * 1))
bearing = atan2(((-36) * 0.889), (1 * 1))
bearing = atan2(-32.004, 1)
bearing = -1.540 rad = -88.236 degrees

If instead of -88.236 degrees the value of approximately 90 degrees is desired, change the sign of the Y sensor as part of the calibration process.

The C programming function atan2 is an enhanced form of the math arc tan operation. The C programming function atan2 will calculate to a full 2-Pi circle. To verify how this works use this online atan2 calculator.

  • You could almost derive offset and magnitude calibration values from the data posted. But it would be better if you rotated the sensor all the way around and observe the maximum and minimum values. Because they may not be where you expect them. Magnetic declination changes (in what appears like a random pattern) all around the world.
    – st2000
    Sep 10, 2023 at 14:24
  • Hi thanks for your response, I will try with the calibration. However is there a way to tell if the readings by the sensor are accurate? For example in case of an accelerometer I can use gravity vector as reference. @st2000 Sep 10, 2023 at 14:40
  • You don't need to change the X and Y values to any of the dozens of different magnetic measurement standards! You are only interested in the relationship between the X and Y sensors. Since the C programming atan2 function essentially divides one by the other, you will cancel out any effort you make at calculating a given magnetic dimension standard. BTW, I think your X and Y sensor data looks good. I think you just need to calibrate and apply that calibration before using the atan2 function.
    – st2000
    Sep 10, 2023 at 14:56
  • Okay thanks, I will work on the calibration and get back here. @st2000 Sep 10, 2023 at 15:35
  • 1
    @SayantanDas: Smooth your readings using a digital low-pass filter, e.g. an exponentially weighted moving average. Beware, though, that you will have to handle the angles wrapping around at 0°/360°. I suggest you try the runningAngle library, which takes care of correctly handling the wrapping for you. Sep 13, 2023 at 8:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.