# AHRS for Adafruit's 9-DOF, 10-DOF, LSM9DS0 Breakouts

## Introduction

Warning: 

https://www.youtube.com/watch?v=CoyU3W925io&feature=youtu.be

[AHRS](http://en.wikipedia.org/wiki/Attitude_and_heading_reference_system) is an acronym for _ **Attitude and Heading Reference System** _, a system generally used for aircraft of any sort to determine _heading, pitch, roll_, _altitude_ etc.  
  
A basic IMU (Intertial Measurement Unit) generally provides raw sensor data, whereas an AHRS takes this data one step further, converting it into heading or direction in degrees, converting the raw altitude data into standard units like feet or meters, etc.   
  
To help you get started designing your own AHRS system, or just tp help convert raw sensor data into useful numbers that you can relate to the real world, we've created a sample AHRS sketch for the [Adafruit 10-DOF IMU](https://www.adafruit.com/products/1604 "Link: https://www.adafruit.com/products/1604"), [Adafruit 9-DOF IMU](http://www.adafruit.com/products/1714 "Link: http://www.adafruit.com/products/1714"), and [Adafruit\_LSM9DS0](https://learn.adafruit.com/adafruit-lsm9ds0-accelerometer-gyro-magnetometer-9-dof-breakouts/overview "Link: https://learn.adafruit.com/adafruit-lsm9ds0-accelerometer-gyro-magnetometer-9-dof-breakouts/overview") breakouts. Danger: 

![](https://cdn-learn.adafruit.com/assets/assets/000/015/502/medium800thumb/sensors_Rabbit10DOF.jpg?1448311547)

# Related Links

- [Adafruit's 10-DOF Breakout Learning Guide](http://learn.adafruit.com/adafruit-10-dof-imu-breakout-lsm303-l3gd20-bmp180 "Link: http://learn.adafruit.com/adafruit-10-dof-imu-breakout-lsm303-l3gd20-bmp180")
- [Adafruit's 9-DOF Breakout Learning Guide](http://learn.adafruit.com/adafruit-9-dof-imu-breakout "Link: http://learn.adafruit.com/adafruit-9-dof-imu-breakout")
- [Adafruit's LSM9DS0 Breakout Learning Guide](https://learn.adafruit.com/adafruit-lsm9ds0-accelerometer-gyro-magnetometer-9-dof-breakouts/overview "Link: https://learn.adafruit.com/adafruit-lsm9ds0-accelerometer-gyro-magnetometer-9-dof-breakouts/overview")

# AHRS for Adafruit's 9-DOF, 10-DOF, LSM9DS0 Breakouts

## Installing the Software

Warning: 

The current example Arduino sketches are available on Github as part of the [Adafruit AHRS libray](https://github.com/adafruit/Adafruit_AHRS).

# Downloading the AHRS Sample Code

To install the drivers and AHRS sketch for your breakout, you simply need to install the **Adafruit\_AHRS** library and it's dependencies on your PC (the exact dependencies you choose will depend on which IMU board you are currently using).  
  
We've put together a tutorial showing you everything you need to do to install dependent libraries if you're just getting started with your breakout. Follow the guide below to install the right libraries depending on which board you are using:

- [Adafruit 10-DOF IMU Installation Guide](http://learn.adafruit.com/adafruit-10-dof-imu-breakout-lsm303-l3gd20-bmp180/software "Link: http://learn.adafruit.com/adafruit-10-dof-imu-breakout-lsm303-l3gd20-bmp180/software")
- [Adafruit 9-DOF IMU Installation Guide](http://learn.adafruit.com/adafruit-9-dof-imu-breakout/software "Link: http://learn.adafruit.com/adafruit-9-dof-imu-breakout/software")
- [Adafruit LSM9DS0 IMU Installation Guide](https://learn.adafruit.com/adafruit-lsm9ds0-accelerometer-gyro-magnetometer-9-dof-breakouts/wiring-and-test "Link: https://learn.adafruit.com/adafruit-lsm9ds0-accelerometer-gyro-magnetometer-9-dof-breakouts/wiring-and-test")

In addition to the dependencies above, make sure to install the **Adafruit\_AHRS** library. You can do that via the Arduino Library Manager.

Open up the Arduino Library manager:

![](https://cdn-learn.adafruit.com/assets/assets/000/085/877/medium800/sensors_1library_manager_menu.png?1576521852)

Search for the **Adafruit AHRS** library and install it

![](https://cdn-learn.adafruit.com/assets/assets/000/085/878/medium800/sensors_ahrs.png?1576521955)

If you aren't familiar with how to install an Arduino library, check out this [guide on installing libraries](https://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use/arduino-libraries).  
  

# Loading the Sample Sketch
Once the repository has been added to your libraries folder ("/libraries/Adafruit\_AHRS/", etc.) you should be able to access the AHRS examples from 'File \> Examples \> Adafruit\_AHRS' in the Arduino IDE. There should be an **ahrs\_9dof** , **ahrs\_10dof** , and **ahrs\_lsm9ds0** exampe.  
  
Pick the appropriate example for your board, for example the **ahrs\_10dof** example should be used with the **10-DOF** board: ![](https://cdn-learn.adafruit.com/assets/assets/000/015/472/medium800/sensors_00_Sketch.png?1395180447)

If you compile the sketch and then program your Uno with the code, you should be able to open up the **Serial Monitor** (Tools \> Serial Monitor), set the baud rate to 115200, and see the following output:

![](https://cdn-learn.adafruit.com/assets/assets/000/015/473/medium800/sensors_01_AHRSOutput.png?1395180516)

This raw data shows the main orientation data, consisting of ' **roll**', ' **pitch**' and ' **heading**' (or 'yaw) in degrees, followed by the current altitude and temperature if you are are using the 10-DOF breakout (the 9-DOF and LSM9DSO breakouts can't measure altitude).  
  
Now close the Serial Monitor and read on to the next page to do something useful with this data!

# AHRS for Adafruit's 9-DOF, 10-DOF, LSM9DS0 Breakouts

## Using AHRS Data

Warning: 

Info: 

The AHRS example sketchs reads raw data from the board's accelerometer/magnetometer and converts the raw data into easy to understand **Euler angles**.  
  
It does this with a bit of trigonometry (you remember high school math, right!?), but to save you from dusting off the textbooks or wading through endless application notes, we've wrapped up all of the calculation to convert raw accelerometer and magnetometer data to degrees in a convenient helper function:  

# 
```
bool getOrientation(sensors_vec_t *orientation)
```

The AHRS sketch creates an **Adafruit\_Simple\_AHRS** object which takes an accelerometer and magnetometer sensor as input to its constructor. You can actually pass any accelerometer or magnetometer object which supports the [Adafruit unified sensor library](https://learn.adafruit.com/using-the-adafruit-unified-sensor-driver/introduction "Link: https://learn.adafruit.com/using-the-adafruit-unified-sensor-driver/introduction") in to the AHRS algorithm, and the examples use the 9-DOF, 10-DOF, and LSM9DS0 sensors.  
  
Once the simple AHRS object is created the **getOrientation** function is called to retrieve the current orientation. Internally the function will read raw data from the accelerometer and magnetomber, converts the data to Euler angles, and spits the three-dimensional orientation data out. If you're interested in the math, you can have a look at the [source code on github](https://github.com/adafruit/Adafruit_AHRS/blob/master/Adafruit_Simple_AHRS.cpp "Link: https://github.com/adafruit/Adafruit\_AHRS/blob/master/Adafruit\_Simple\_AHRS.cpp"), but for now we'll just treat it as a mathemagical black box:

# Euler Angles
[Euler angles](http://en.wikipedia.org/wiki/Euler_angles "Link: http://en.wikipedia.org/wiki/Euler\_angles") describe orientation (in degrees) around a single reference point in three-dimensional space.  
  
Various names are employed for the three angles, but the most common terminology with aircraft is Roll (x), Pitch (y) and Yaw (z).  
  
The illustration below from the Wikipedia article on Euler angles should illustrate the concept clearly. You normally have both positive and negative angles (-180° to 180°) depending on the direction the airplane is tilted, with 0° in every direction corresponding to the airplane being perfectly aligned with each axis: ![](https://cdn-learn.adafruit.com/assets/assets/000/014/317/medium800/sensors_Yaw_Axis_Corrected.png?1392333680)

If you run the AHRS sketch, you should see something similar to the following in the Serial Monitor, where the three values after 'orientation' are the Euler angles:

![](https://cdn-learn.adafruit.com/assets/assets/000/015/474/medium800/sensors_01_AHRSOutput.png?1395180822)

In this case, we can see that the roll is about 18°, the pitch is about 78° and the heading or yaw is about 32°, and the sketch will keep updating itself with the latest values at whatever speed we've set in the example sketch.

# AHRS for Adafruit's 9-DOF, 10-DOF, LSM9DS0 Breakouts

## Visualizing Data

Warning: 

To help you visualize the data, we've put together a basic Processing sketch that loads a 3D model (in the .obj file format) and renders it using the data generated by the AHRS sketch on the Uno. The ahsr sketch on the uno published data over UART, which the Processing sketch reads in, rotating the 3D model based on the incoming orientation data.

# Requirements

- [Processing 2.x](https://processing.org/ "Link: https://processing.org/")
- [Saito's OBJ Loader](https://code.google.com/p/saitoobjloader/ "Link: https://code.google.com/p/saitoobjloader/") library for Processing ([installation tips here](https://code.google.com/p/saitoobjloader/#Download "Link: https://code.google.com/p/saitoobjloader/#Download"))
- [G4P GUI library](http://www.lagers.org.uk/g4p/ "Link: http://www.lagers.org.uk/g4p/") for Processing ([download the latest version here](http://sourceforge.net/projects/g4p/files/?source=navbar "Link: http://sourceforge.net/projects/g4p/files/?source=navbar") and copy the zip into the processing libraries folder like the tip for the OBJ loader library above mentions).

The OBJ library is required to load 3D models. It isn't strictly necessary and you could also render a boring cube in Processing, but why play with cubes when you have rabbits?!  
# Opening the Processing Sketch
The processing sketch to render the 3D model is contained in the sample folder as the ahrs sketch for the Uno.  
  
With Processing open, navigate to you Adafruit\_AHRS library folder (ex.: ' **libraries/Adafruit\_AHRS**'), and open ' **processing/bunnyrotate/bunnyrotate.pde'.** You should see something like this in Processing:  
Danger: 

![](https://cdn-learn.adafruit.com/assets/assets/000/018/614/medium800/sensors_processing.png?1407200969)

# Run the AHRS Sketch on the Uno
Make sure that the appropriate AHRS example sketch is running on the Uno (as described on the previous page), and that the Serial Monitor **is closed**.  
  
With the sample sketch running on the Uno, click the triangular 'play' icon in Processing to start the sketch. # Rabbit Disco!
You should see a rabbit similar to the following image: ![](https://cdn-learn.adafruit.com/assets/assets/000/018/613/medium800/sensors_bunny.png?1407200715)

Before the rabbit will rotate you will need to click the **:** to the right of the serial port name. This will open a list of available serial ports, and you will need to click the appropriate serial port that your Arduino uses (check the Arduino IDE to see the port name if you're unsure). The chosen serial port should be remembered if you later run the sketch again.  
  
As you rotate your breakout board, the rabbit should rotate to reflect the movement of the breakout in 3D-space, as seen in the video below ( **note that this video is using an older version of the cuberotate example and won't look exactly like what you see now** ):

https://www.youtube.com/watch?v=CoyU3W925io&feature=youtu.be

# A Note on Accuracy and Calibration
Note that the movement seen on the screen won't correlate exactly to the breakout since we are currently using **uncalibrated sensor data** , specifically uncalibrated magnetometer data which will throw the heading off. The magnetometer is required to generate 360° data, and if you want to improve the accuracy of your orientation data we have a [tutorial on calibrating the LSM303](http://learn.adafruit.com/lsm303-accelerometer-slash-compass-breakout/calibration "Link: http://learn.adafruit.com/lsm303-accelerometer-slash-compass-breakout/calibration"), but this particular example starts with raw data for simplicity sake. # AHRS for Adafruit's 9-DOF, 10-DOF, LSM9DS0 Breakouts

## Magnetometer Calibration

Warning: 

For more accurate orientation output, the magnetometer needs to be adjusted to compensate for offset errors (meaning a shift in either direction on the X/Y/Z axis), as well as something called 'soft iron error', which causes what should be spherical output of the magnetometer to actually be an elongated 'pill' shape or something similar.

In order to compensate for these two problems and generate accurate magnetometer data, which is critical to getting high quality orientation results, you will need to calibrate your magnetometer in the final enclosure and setup in which the device will be used.

Danger: 

# PJRC MotionCal

There are a variety of calibration tools out there, but [MotionCal](http://www.pjrc.com/store/prop_shield.html) from always awesome PJRC (Teensy, etc.) is probably the easiest to use, and they provide pre-compiled binaries for all major operating systems.

Download the Motion Sensor Calibration tool for your OS from the following link and open it up on your system:&nbsp;[http://www.pjrc.com/store/prop\_shield.html](http://www.pjrc.com/store/prop_shield.html)

By default, you should see something like this:

![](https://cdn-learn.adafruit.com/assets/assets/000/036/480/medium800/sensors_Screen_Shot_2016-10-13_at_11.47.36.png?1476352106)

Next open up the [ahrs\_calibration](https://github.com/adafruit/Adafruit_AHRS/blob/master/examples/ahrs_calibration/ahrs_calibration.ino)&nbsp;example from Adafruit\_AHRS:

Info: 

![](https://cdn-learn.adafruit.com/assets/assets/000/036/481/medium800/sensors_Screen_Shot_2016-10-13_at_11.49.13.png?1476352320)

Be default this is setup for the sensors found on the Adafruit 9DOF and 10DOF breakouts, but can be adjusted to work with any accelerometer, magnetometer and gyroscope that is based on the [Adafruit Unified Sensor system](../../../../using-the-adafruit-unified-sensor-driver/introduction).

![](https://cdn-learn.adafruit.com/assets/assets/000/036/482/medium800/sensors_Screen_Shot_2016-10-13_at_11.51.29.png?1476352424)

# Generating Calibration Data

Next run the sketch, and if it isn't already open, open the MotionCal app.

Select the appropriate serial port for your board, and once select start rotating the board around gently in figure eight type movements.

As you move the device, points should start to appear in a point cloud.

You need to keep moving the device in as many orientations as possible until the sphere is mostly complete and the&nbsp; **Gaps** percentage on the bottom of the app is reasonably low.

A good example of what you should aim for is shown below:

![](https://cdn-learn.adafruit.com/assets/assets/000/036/483/medium800/sensors_Screen_Shot_2016-10-10_at_11.33.42.png?1476352609)

# Note Offsets and Magnetic Mapping Values

Now that you have determined the values to compensate for magnetometer offset and soft-iron error, make a note of the values in the top-right hand corner of the app, which in this case is:

### Magnetic Offset

`-2.20, -5.53, -26.34`

### Magnetic Mapping

`0.934, 0.005, 0.013`  
`0.005, 0.948, 0.012`  
`0.013, 0.012, 1.129`

### Magnetic Field

`48.41`

Info: 

# That's It!

Congratulations, you have everything you need to generate reasonably accurate ouput on the magnetometer taking into account any local interference in your environment or caused by the board itself.

You'll need these values in the next step, which is feeding your compensated sensor output into a sensor fusion algorithm, but you can close the MotionCal app for now until you need to calibrate the device again, such as if you move it to a different setup or environment.

# AHRS for Adafruit's 9-DOF, 10-DOF, LSM9DS0 Breakouts

## Sensor Fusion Algorithms

Warning: 

There are a variety of sensor fusion algorithms out there, but the two most common in small embedded systems are the Mahony and Madgwick filters.

Mahony is more appropriate for very small processors, whereas Madgwick can be more accurate with 9DOF systems at the cost of requiring extra processing power (it isn't appropriate for 6DOF systems where no magnetometer is present, for example).

We will use the&nbsp;Mahony fusion algorithm in this example since it is the most relevant to a wide variety of devices, but it's easy to switch to Madgwick if you prefer to test another algorithm.

Danger: 

# MahonyAHRS and MadgwickAHRS Libraries

For best results, use the fork of MahonyAHRS and MadgwickAHRS from PJRC (based on the original Arduino libraries) available here:

- [https://github.com/PaulStoffregen/MahonyAHRS](https://github.com/PaulStoffregen/MahonyAHRS)
- [https://github.com/PaulStoffregen/MadgwickAHRS](https://github.com/PaulStoffregen/MadgwickAHRS)

You will need to download these as a zip file and then install them in your libraries folder, or git clone them in the Arduino libraries folder (ex. '`git clone https://github.com/PaulStoffregen/MahonyAHRS.git`').

For help installing libraries, see our [Arduino Libraries Learning Guide](../../../../adafruit-all-about-arduino-libraries-install-use/arduino-libraries).

# Enter Calibration Data into ahrs\_mahony

To get started, open the [**ahrs\_mahony** example](https://github.com/adafruit/Adafruit_AHRS/blob/master/examples/ahrs_mahony/ahrs_mahony.ino)&nbsp;from the Adafruit\_AHRS folder.

You will need to enter the magnetometer calibration values calculated earlier in this guide in the appropriate field, as shown in the screenshot below:

![](https://cdn-learn.adafruit.com/assets/assets/000/036/484/medium800/sensors_Screen_Shot_2016-10-13_at_12.12.14.png?1476353620)

These values are based on the following calibration data:

![](https://cdn-learn.adafruit.com/assets/assets/000/036/485/medium800/sensors_Screen_Shot_2016-10-10_at_11.33.42.png?1476353657)

# Run the Sketch

Next, compiled and run your sketch.

Open the Serial Monitor, and you should see a **millisecond timestamp** , followed by the output of the sensor fusion algorithm, which will give you Euler Angles for&nbsp; **Heading** ,&nbsp; **Pitch** and&nbsp; **Roll** in that order:

![](https://cdn-learn.adafruit.com/assets/assets/000/036/486/medium800/sensors_Screen_Shot_2016-10-10_at_16.35.04.png?1476353764)

# Tuning the Filter

One particularity of fusion algorithms (and most DSP algorithms) is that they are sensitive to timing. Make a note of the millisecond timestamp before the individual samples, can count approximately how many samples per second your device is outputting.

You need to tell the fusion algorithm how many samples per second we are generating to more accurately estimate positions in 3D space based on the accel, gyro and mag data.

In the filters&nbsp;**setup()** function, find the following lines and adjust this value to match the number of samples per second your system is outputting:

```
  // Filter expects 50 samples per second
  filter.begin(50);

```

Run the filter again and you should get slightly more accurate results.

# Switching to Madgwick

To switch to the Madgwick filter, simply comment the appropriate class instance at the top of the sketch and run the code again. The two filters have identical APIs and are easily interchangeable.

Change the code from this ...

```
// Mahony is lighter weight as a filter and should be used
// on slower systems
Mahony filter;
//Madgwick filter;
```

... to this:

```
//Mahony filter;
Madgwick filter;
```

# A Note on Orientation Values

Please note that at present all orientation values are&nbsp; **relative** and not&nbsp; **absolute**. What this means is that the orientation values will be relative to the starting position of the device, not absolute magnetic north or south, etc.

Before starting, put your device in a known, repeatable position if you require reasonably repeatable, consistent output.


## Featured Products

### Adafruit 9-DOF IMU Breakout - L3GD20H + LSM303

[Adafruit 9-DOF IMU Breakout - L3GD20H + LSM303](https://www.adafruit.com/product/1714)
This inertial-measurement-unit combines 2 of the best quality sensors available on the market to give you 9 axes of data: 3 axes of accelerometer data, 3 axes gyroscopic, and 3 axes magnetic (compass). We tested many different 'combination' sensors and found these were the best value,...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/1714)
[Related Guides to the Product](https://learn.adafruit.com/products/1714/guides)
### Adafruit 10-DOF IMU Breakout - L3GD20H + LSM303 + BMP180

[Adafruit 10-DOF IMU Breakout - L3GD20H + LSM303 + BMP180](https://www.adafruit.com/product/1604)
This inertial-measurement-unit combines 3 of the best quality sensors available on the market to give you 11 axes of data: 3 axes of accelerometer data, 3 axes gyroscopic, 3 axes magnetic (compass), barometric pressure/altitude and temperature. We tested many different 'combination'...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/1604)
[Related Guides to the Product](https://learn.adafruit.com/products/1604/guides)
### Adafruit 9-DOF Accel/Mag/Gyro+Temp Breakout Board - LSM9DS0

[Adafruit 9-DOF Accel/Mag/Gyro+Temp Breakout Board - LSM9DS0](https://www.adafruit.com/product/2021)
Add motion,&nbsp;direction and orientation&nbsp;sensing to your Arduino project with this all-in-one 9-DOF sensor. Inside the chip are three sensors, one is a classic 3-axis accelerometer, which can tell you which direction is down towards the Earth (by measuring gravity) or how fast the board...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/2021)
[Related Guides to the Product](https://learn.adafruit.com/products/2021/guides)
### FLORA 9-DOF Accelerometer/Gyroscope/Magnetometer - LSM9DS0

[FLORA 9-DOF Accelerometer/Gyroscope/Magnetometer - LSM9DS0](https://www.adafruit.com/product/2020)
Add motion,&nbsp;direction and orientation&nbsp;sensing to your wearable FLORA project with this high precision 9-DOF sensors. Inside are three sensors, one is a classic 3-axis accelerometer, which can tell you which direction is down towards the Earth (by measuring gravity) or how fast the...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/2020)
[Related Guides to the Product](https://learn.adafruit.com/products/2020/guides)

## Related Guides

- [Adafruit Trinkey QT2040](https://learn.adafruit.com/adafruit-trinkey-qt2040.md)
- [Adafruit's Raspberry Pi Lesson 12. Sensing Movement](https://learn.adafruit.com/adafruits-raspberry-pi-lesson-12-sensing-movement.md)
- [Sound Reactive Rapunzel Hair](https://learn.adafruit.com/sound-reactive-rapunzel-hair.md)
- [A Sillier Mousetrap: Logging Mouse Data to Adafruit IO with the Raspberry Pi](https://learn.adafruit.com/a-sillier-mousetrap-logging-mouse-data-to-adafruit-io-with-the-raspberry-pi.md)
- [PyPortal IoT Plant Monitor with Google Cloud IoT Core and CircuitPython](https://learn.adafruit.com/pyportal-iot-plant-monitor-with-google-cloud-iot-core-and-circuitpython.md)
- [Adafruit BNO055 Absolute Orientation Sensor](https://learn.adafruit.com/adafruit-bno055-absolute-orientation-sensor.md)
- [Adafruit SensorLab - Magnetometer Calibration](https://learn.adafruit.com/adafruit-sensorlab-magnetometer-calibration.md)
- [Sparkle Motion Dance Shoes](https://learn.adafruit.com/sparkle-motion-dance-shoes.md)
- [Mystery Box: Haunted Radio](https://learn.adafruit.com/mystery-box-haunted-radio.md)
- [Remote Controlled LED Tea Light Sconce](https://learn.adafruit.com/remote-controlled-led-candelabra.md)
- [Bubble Table with LED Animations and IR Remote Control](https://learn.adafruit.com/bubble-table-with-led-animations-and-ir-remote-control.md)
- [Adafruit STCC4 and SHT41 CO2, Temperature & Humidity Sensor](https://learn.adafruit.com/adafruit-stcc4-and-sht41-co2-temperature-humidity-sensor.md)
- [Alohamora Bottle](https://learn.adafruit.com/alohamora-bottle.md)
- [Exercise Buddy: Motion aware BLE media controller](https://learn.adafruit.com/exercise-buddy.md)
- [Circuit Playground's Motion Sensor](https://learn.adafruit.com/circuit-playgrounds-motion-sensor.md)
