MinIMU-9 AHRS code

I think the yaw movement at the beginning is normal as the AHRS adjusts to the north heading measured by the magnetometer (if I remember right, it happens when the IMU is used with the board parallel to the ground too). It might be possible to rewrite the program to eliminate that movement, but I have not looked into it.

It’s certainly worth trying to recalibrate the magnetometer a few more times to see if you get better (or different) results. For the best results, you should try to keep the IMU away from anything that could influence the magnetometer (large metal objects, high currents, etc).

- Kevin

I re-calibrated the magnetometer and I noticed a distinct improvement. I have yet to do a rigorous test, but it is certainly improved.

I will look into eliminating the initial yaw movement out of curiosity, but it is not detrimental to my application. I imagine it would be as simple as introducing an additional offset.

I noticed that after changing the axes in the I2C script to accomodate my orientation the yaw reading would eventually arrive upon the right value, but when rotated it would swing wildly in the opposite direction. I quickly realized that this was because the gyro and magnetometer were “disagreeing” about the direction of increasing yaw. I think this was because my orientation swapped the parity of the existing coordinate system. For anyone interested, I was able to easily solve this problem by modifying the axis definitions:

// X axis pointing forward
// Y axis pointing to the right
// Z axis pointing up
int SENSOR_SIGN[9] = {1,1,-1,-1,-1,1,1,1,-1}; //Correct directions x,y,z - gyro, accelerometer, magnetometer

Someone mentioned dynamic calibration in an earlier post. Have you known anyone to do this? It would be very nice to implement, but from what I understand of the calibration process this is not practical/ possible in most applications. I think that if someone were to run the calibration continuously the settings would be tainted as soon as an adverse magnetic field (or just ferrous material) was introduced, which defeats the purpose. If the calibration was performed on intervals, the readings would also be unreliable unless the system somehow allowed the IMU to swing around wildly for a few seconds. The only other solution I can imagine is some kind of fixed external reference for the mag to compare its readings to, but this would require a different calibration routine and a project of its own.

Today I updated my Arduino IDE to version 1.0. The AHRS libraries have dependencies on WProgram.h which has been renamed to Arduino.h. Additionally, the commands send() and receive() in the Wire library have been replaced with write() and read(). After making these changes everything worked as before.

Another point of interest…
I implemented a mode filter from the arduino playground to weed out some of the outliers produced by electronic noise. It adds readings to a 20 element array, deleting the last entry and shifting everything to make room for a new one. A function sorts the elements and returns the mode. I was filling the arrays with values from the roll pitch and yaw variables, and then reassigning the variables with the filtered output for printing. This made the program very unhappy, at least as far as the yaw reading was concerned. The yaw estimation jumped around wildly, unless the unit was pointed towards “zero yaw.”

I found out that this was because the heading updated slower than I was reassigning the values, so the program performed calculations based on the filtered values. This didn’t seem so bad at first, but it turned out to be very problematic.

In the first few moments the program thought the yaw was zero and continued to use zero in the calculations until the heading was updated. After a new value was added to the matrix, it would re-calculate the mode, and again return zero because the matrix was mostly populated with zeros. Sometimes after the array filled with enough “real” data the yaw would jump to the right value, but the artificial values would quickly take over and pull the estimation back down. In a sort of tug-of-war beween the near-zero artificial values and the real heading estimation, the output would swing between zero and the heading.

I was able to solve this problem by returning the filtered result to a new variable rather than reassigning the old variables.

Hopefully this story will help someone else who’s experimenting with filtering!

I was fiddling around with the sensor some more to get a better feel for its capabilities and I noticed that the roll reading misbehaves when the sensor is pitched to the neighborhood of 90 degrees. When the pitch is zero the roll is consistent and seems accurate, but when I pitch it past 70 degrees or so, the roll begins to increase by tens of degrees. Under these conditions the reading for roll still changes in a consistent manner, but it is way off and very sensitive.

My first thought was that the modifications I made to the code was to blame, so I uploaded the original code and I still noticed the problem.

I have a mac, so I haven’t been able to get the python program running, but I assume it works without the 3D model rolling around like crazy when it’s pitched on end. Is this a known limitation, a problem on my end, or not a problem at all and just me failing to interpret the data correctly?

My application requires accurate sensing of pitch and roll over a range of just a few degrees (tens at the most), so this question doesn’t come with any real urgency.


I tried doing what you described with a MinIMU-9 AHRS and saw the same thing (roll angle changing quickly); I think it is normal. I think what you are seeing is something called gimbal lock, which will happen with any representation of an heading that uses 3 angles (Euler angles), although I am not completely sure. The accuracy overall heading does not seem to really be affected; it is just that the angles used to represent that heading can swing wildly when you do certain rotations.

It is a lot easier to see what is happening by watching the visualization program, so that would probably be the best way for you to understand it. We do not have much experience working with Macs, but we do have a Mac here, so we might be able to offer you some (limited) help trying to get the Python program to work. What have you tried so far, and where are you running into trouble?

- Kevin

help me. I try calibrate minIMU9 with folder example library LSM303.

this is result form example calibate.

M min X: -513 Y: -4096 Z: -384 M max X: 293 Y: 85 Z: 372
M min X: -513 Y: -4096 Z: -384 M max X: 293 Y: 85 Z: 372
M min X: -513 Y: -4096 Z: -384 M max X: 293 Y: 85 Z: 372
M min X: -513 Y: -4096 Z: -384 M max X: 293 Y: 85 Z: 372
M min X: -513 Y: -4096 Z: -384 M max X: 293 Y: 85 Z: 372

the value min Y is -4096 to big and fix. min Y: Not change when roll pitch yaw 360 with board (begin value -4096 and not to change). pleas help me

thank you

(I’m not good at English langauge.)

I can not speak english langauge. I will present with vdo. compass axis Y is not a correct.

Hello, ponggoa.

The reading of -4096 means that the magnetometer reading is overflowing, as discussed in the FAQ on the product page. If you reduce the gain of the magnetometer, it should solve the problem, and the FAQ gives a line of code that demonstrates how to do this.

- Kevin

thank you. my problem is solve. I have a question about axis Pitch. An axis Pitch not a turn 360 degree. I use AHRS axis roll (red line) can turn 360 degree but axis pitch (green line) can turn 180 degree. Is this a valid.


Yes, that is normal; the AHRS program represents roll as an angle in the range of -180 to +180 degrees, while pitch is represented in the range of -90 to +90 degrees. If you increase the pitch of the IMU past 90 degrees (vertical), it flips the yaw angle 180 degrees and starts decreasing the pitch angle.

- Kevin

Hi Everyone, just joined the forums!

my question not directly concern the ahrs code, but only the LSM303 library.

In the code, after have read the accel value, the code make a right shift over 4 bits because these bits are meaningless. And if i don’t suppress these 4 bits the IMU does’nt work correctly.

But in the datasheet i’ve not find anything about these 4 bits. the datasheet says the 16 bits (for each axis) are significant.

has anyone an explanation about that ?



Hello, Yves.

Could you tell me what page of the datasheet says that all 16 bits are significant? It might help to also provide a quote of the sentence you are looking at.


Hi David,

the datasheet says that the datas are given with 16 significant bits at the first page in “features”, where it’s only said “16 bit data output”, without other precision over mag or accel datas.

In the section concerning the accel output, the datasheet only says (§7.1.9) : “X-axis acceleration data. The value is expressed in 2’s complement”, same thing with Y and Z axis without any precision about resolution.

In an other way , if you look at the description of the temperature of the magnetometer (§7.2.9), where the temperature is only given on 12bit, it’s clearly expressed in tablea 86 : “Temperature data (8LSB/deg - 12-bit resolution). The value is expressed as 2’s complement.” And in the datasheet the 4 LSB of register TEMP_OUT_L_M have no name.

After these things i don’t understand the 4 bits right shift (>> 4) that we find in this part of code of the LSM303 library

byte xla =;
byte xha =;
byte yla =;
byte yha =;
byte zla =;
byte zha =;

// combine high and low bytes, then shift right to discard lowest 4 bits (which are meaningless)
// GCC performs an arithmetic right shift for signed negative numbers, but this code will not work
// if you port it to a compiler that does a logical right shift instead.
a.x = ((int16_t)(xha << 8 | xla)) >> 4;
a.y = ((int16_t)(yha << 8 | yla)) >> 4;
a.z = ((int16_t)(zha << 8 | zla)) >> 4;

Am i clear about this question ? (please sorry my bad writing !)

thanks you for your help

Thank you for the information. I looked in the LSM303DLHC datasheet and I cannot find any indication that the accelerometer data only has 12 bits. However, if you look in the datasheet for the older version of that chip (LSM303DLH), in Table 3, third row, it says “12 bit representation” in reference to the acceleration data. We probably tested the LSM303DLHC at some point and verified that it behaves like the LSM303DLH and those lower 4 bits don’t have any data in them. You can, of course, test it yourself.

If you look at the LSM303DLHC datasheet, Table 3, third row, it says that when the FS bits are set to 00, you get 1 mg/LSB of sensitivity. That means that if you hold the accelerometer still with the Z axis pointing up, you should see a value of 1000 on the Z axis accelerometer reading. If you try running our code without doing the right shift, you would actually see a value of 16000 or -16000, so that is a pretty convincing way that we can know that shifting right is the correct thing to do.

In general, ignoring some lower bits of a sensor reading will not cause any inherent problems: it just means that we might be doing our calculations with less precision than is possible.



thank for your informations and explainations.

I’ve tried to run the “serial” example given in the lsm303 librarie, whitout the 4 lsb right shift. And the result is on the z axis the value of +/-4096. So the right shift is necessary of course.

I’m just supprised that it’s not said clearly in the datasheet.

So, every things is good and work well…

thank you for your help


I have been working with this code for a little while, but I have a few questions. Is the Yaw outputting data relative to its heading? If it is, is there a way to make it reference its starting position like the pitch and roll? the project I’m working on does not depend on a compass heading, but rather a relative position. Also, when I turn it 90 degrees (yaw) it only seems to account for about 60-70 degrees. I’ve done the calibration. Another question, what would it take to make the output of all 3 directions to be 0-360?

Thanks in advance


I am not sure I understand what you mean when you ask “Is the Yaw outputting data relative to its heading?” Could you please clarify?

Also, something seems to be wrong if you are getting only 60-70 degrees when you expect 90. Could you please tell us more about your setup? Could you post a photo of your entire setup, including all the connections?

- Jeremy

When it first starts, the roll and pitch start at zero and adjust as you move, with reference to the staring position (and always seem to be really accurate). The yaw however, in my setup, starts at -16. I believe that is based on the compass reading correct? Since my project does not depend on the direction it’s pointing, but rather the relative position, I would like the yaw to behave like the roll or pitch. Does this make more sense?
Currently I am just working with the MinIMU-9 and a bread board connected to the Uno. My yaw angle seems to be more accurate today. When I start the silk screen is pointed up, even though I would like to start with my IMU vertical. I have experimented a little with burkleypatterson’s solution for a vertical IMU, but then my yaw seems to be off more. For now, I have reverted back to the original code.

5V -> VIN
Analog Pin 5 -> SCL
Analog Pin 4 -> SDA

It looks like you might have a calibration issue. I recommend reading the documentation on that are in Arduino libraries for the LSM303 and L3GD20. You might have to adjust the values in heading() with the readings obtained during calibration.

Although I do not completely understand you when you say " I would like the yaw to behave like the roll or pitch.", you will most likely have to compute some sort of change in coordinate system to get yaw to behave like roll.

I think the results you get with the silk screen pointed up is expected, since the library was designed around that orientation.

- Jeremy

Hi, all,
first, thank you for this nice and great little thing called MiniIMU9 v2! :wink:
And thanks for the libraries and the fine pice of clearly readible code coming with lots of comments a well as the AHRS-code basing on the Julio/Munoz/Weibel (and others) work. :wink:
I set it up and got it running from scratch within two hours including header soldering connected to a Wattuino pro Mini (Arduino pro mini with ATMEL 328/3,3V 8MHz clone) and download of the latest Arduino environment together with the libraries and Python demo.

But this Kalman filter code to my opinion has some severe pitfalls:
A) I notice a noise level of up to one degree in all three coordinate axes.
B) If I shake the sensor board quickly in a circle while keeping its relative orientation straight north and level, the device (code) starts drifting heavily - turning its yaw axis within seconds by 80, 90 degrees off north.
compare with:

where the claim is 0.08 Degrees noise level (standard deviation) on the resting sensor in all three angles
and accelleration independancy within the time scale of jumps and bumps…

Ok, guess this is no issue for slow and steady moving objects like a quadcopter or such,
I’ll have to see if I can get better AHRS specs out of the bare chips by coding, I’ll keep you updated in case of success