How to Find Heading Angle From MPU9250 With Raspberry Pico W

by mahmoodmustafashilleh in Circuits > Raspberry Pi

852 Views, 2 Favorites, 0 Comments

How to Find Heading Angle From MPU9250 With Raspberry Pico W

Untitled design (11).png

Youtube Link -> Link, comment, subscribe :)

The MPU9250 is a compact and versatile motion-tracking device that combines a 3-axis accelerometer, 3-axis gyroscope, and 3-axis magnetometer into a single package. Its onboard magnetometer can be used to estimate the "heading" angle. The heading angle, also known as the azimuth, refers to the direction in which an object or person is pointing or facing, relative to a reference direction, typically north. It is usually measured in degrees, with 0 degrees indicating a direction pointing towards true north, 90 degrees, 180 degrees, and 270 degrees indicating east, south, and west, respectively. The heading angle or azimuth can be determined using readings from a magnetometer with other calibration techniques to accurately estimate the north pole's direction. This can be useful for navigation purposes. We will be showing how to get such a value in this tutorial, which can be translated into a direction (North, South, East, West, etc).

Supplies

Understanding Hard-Iron and Soft-Iron Biases

Because we live in an age where we are surrounded by magnetic material and magnetic fields induced by electronics around us, such as our phones and laptop, we need to be able to remove the fluctuations these variables can cause on our experiment. From our surroundings, there are mainly two biases we need to consider in calibration: hard-iron and soft-iron biases.

Hard iron bias refers to a type of systematic error that is caused by the presence of a fixed magnetic field, such as the Earth's magnetic field or nearby ferromagnetic materials, that can distort the magnetometer readings. Hard iron bias can be corrected by subtracting a fixed offset value from the magnetometer readings, which can be determined by calibrating the sensor in a known magnetic field environment.

On the other hand, soft iron bias is caused by the presence of a non-uniform magnetic field, such as the distortion of the Earth's magnetic field by nearby objects or materials. Soft iron bias can result in the magnetometer readings being skewed towards a particular direction or axis. Soft iron bias can be corrected by using a calibration process that involves rotating the sensor in a 3D space and collecting magnetometer data, which can be used to calculate correction values that can be applied to the magnetometer readings to compensate for the non-uniform magnetic field.

In our MicroPython code, we will use an MPU9250 library that has a calibration function that accounts for both biases. For more details on the nature of the calibration please see https://www.appelsiini.net/2018/calibrate-magnetometer/

Understanding Low-Pass Filter

Despite calibration, we can still get sudden fluctuations, that is, random spikes in magnetic readings in our magnetometer! We do not want sudden fluctuations to deter us from the signal we are trying to look for, which is Earth's magnetic field. To deal with spikes of useless data we can implement a low-pass filter in a couple of lines of code shown here:

def low_pass_filter(prev_value, new_value):
return 0.85 * prev_value + 0.15 * new_value

You can see that the weights in the filter add up to 1 (0.85 + 0.15), this has to be the case. The premise of the filter is that we essentially trust the previous value more than we trust a new value. By taking this approach to sensor readings, we can eliminate or reduce this noise and improve the overall quality of our signal measuring.


The video shows an example of how this can be applied to an acceleration signal. You can see in red that the unfiltered raw value for acceleration is susceptible to sudden change while the filtered signal in blue is much more stable. While this does introduce a bias in our measurements it is okay because the signal always converges to the true signal over a period of time if the stimulus is consistent. This is the filter we will apply to our magnetometer readings to get a more accurate heading angle estimation

Physical Setup


Make connections as shown

Code and Library

You will need to add three libraries to your code to get readings, all found here

https://github.com/kevinmcaleer/mpu9250

  • MPU9250
  • ak8963
  • MPU6500

Once you have such libraries saved you can use my example code here to start getting readings

from machine import I2C, Pin
import math
import utime

from mpu9250 import MPU9250

i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
sensor = MPU9250(i2c)
filtered_magx, filtered_magy = 0, 0
DECLINATION = -1 * 3.19

# Want to thank Kevin McAleer

def low_pass_filter(prev_value, new_value):
return 0.85 * prev_value + 0.15 * new_value


def compass(angle):
if angle > 337 or angle <= 22:
direction = 'North'
elif angle > 22 and angle <= 67:
direction = 'North East'
elif angle > 67 and angle <= 112:
direction = "East"
elif angle > 112 and angle <= 157:
direction = "South East"
elif angle > 157 and angle <= 202:
direction = "South"
elif angle > 202 and angle <= 247:
direction = "South West"
elif angle > 247 and angle <= 292:
direction = "West"
elif angle > 292 and angle <= 337:
direction = "North West"
return direction


sensor.ak8963.calibrate()

while True:

# We do not need the z value
magx_new, magy_new, _ = sensor.magnetic

filtered_magx = low_pass_filter(filtered_magx, magx_new)
filtered_magy = low_pass_filter(filtered_magy, magy_new)

heading_angle_in_degrees = math.atan2(filtered_magx, filtered_magy) * (180 / math.pi)
heading_angle_in_degrees_plus_declination = heading_angle_in_degrees + DECLINATION

if heading_angle_in_degrees_plus_declination < 0:
heading_angle_in_degrees += 360
heading_angle_in_degrees_plus_declination += 360

print('###Without Declination###')
print(heading_angle_in_degrees)
print(compass(heading_angle_in_degrees))
print('###Plus Declination###')
print(heading_angle_in_degrees_plus_declination)
print(compass(heading_angle_in_degrees_plus_declination))

utime.sleep_ms(100)

The main thing in this code is the calibration, which you will need to ensure the accelerometer is on a flat horizontal surface. Once calibration begins be sure to move your accelerometer around in a figure 8 fashion (shown in my Youtube video).

Another important thing is the concept of declination. Which will be needed to calculate the direction to the true north pole rather than the magnetic north pole. You can find your declination angle by searching your location online on Google! Everyone's declination can be dramatically different depending on what area you are on the Earth, so be sure to change it in the code...

If you have done everything accurately you will get results on par with the compass app on the iPhone or other apps.

Conclusion

Hope you learned something awesome in this tutorial and you got great results. For any confusions please watch the Youtube Video as I go into more detail there. Do not forget to like, comment, and subscribe. As always, thanks for reading and stay tuned.