Understanding MinIMU-9-Arduino-AHRS code


I am playing my MinIMU-9 for a while. Currently, I want to write my own code to track the heading of the board. So I referenced the MinIMU-9-Arduino-AHRS code. I understood the code well until I got to the Normalize() function in DCM.ino. I find there are comments at the end of each line in this function, such as “eq. 19”. I think the code must be written based on some equations in some article. Do you know where I can get this article? Reading code is too abstract and painful to me. Thanks!

I think I found the source. code.google.com/p/ardu-imu/wiki/Theory
This site includes two links, one is for the tutorial of DCM, which I believe is used by the MinIMU-9-Arduino-AHRS code. The other is a series of related papers. Hope it helps!


I think Equation 19 is found in this paper:

PDF: http://gentlenav.googlecode.com/files/DCMDraft2.pdf
Page linking to it: http://diydrones.ning.com/profiles/blogs/dcm-imu-theory-first-draft

The code I wrote for the Raspberry Pi + MinIMU-9 might make more sense to you. I spent a lot of time cleaning up the code and making it readable. It is different from the MinIMU-9 AHRS Arduino program in that it uses a quaternion to store its state instead of a matrix. Normalizing a quaternion is much more straightforward than normalizing a matrix. I still haven’t found a way of normalizing a matrix that I am totally happy with. The method of normalizing a matrix presented in that paper treats the Z axis specially. I think that an ideal, general-purpose algorithm would not treat any axis specially.



Currently I am using MinIMU-9-Arduino-AHRS code, and it works pretty nice. To run this code, we need the calibration values (min and max values) about the magnetometer through running the calibration code in Arduino. I just want to know after I getting the max and min values, can I use these values in any environment or I need to re-calibrate it if I change to another environment? My purpose is to get the accurate heading using MinIMU-9-Arduino-AHRS code. Thanks!

I am not sure what you mean by “environment”. If you mean a different software development environment or IDE, the answer would be no. If you make any change that affects the magnetometer readings, you will have to recalibrate it. The magnetometer readings are affects by lots of things, such as nearby objects.


The environment here means physical places. For example, I do the calibration in side the building, and then want to use the code to track the heading outside of the building. I need to recalibrate it, right?

It is hard for me to say. I suggest that you do some experiments to see. If you calibrate the magnetometer while the device sits on a desk inside the building, and then you want to use it outside without a desk, then you would probably need to recalibrate it. If you make an effort to ensure that the objects near the mangetometer when it is inside the building are the same as the objects that are near the magnetometer when it is outside the building, you might not need to recalibrate it.


Hi, David,

I am studying your minimu9-ahrs code (minimu9-ahrs.cpp ). In this file, I found there is a class matrix. I just want to know where it is defined (I am not an expert of c++)? I want to take a look at it in the detail implementation. Thanks!

Hello. The matrix type is defined in vector.h:

typedef Eigen::Matrix3f matrix;

It’s really just an alias for the 3x3 matrix of floats that is defined in Eigen. The appropriate documentation is here:



Do you find that your readings oscillate?

I’m working on a balancing bot so I’m focusing on just the pitch angle and with the board flat on the table and not moving the pitch angle fluctuates from .5 to -.5. I believe this is being caused by the PID. My novice understanding of PID is that the D is used to prevent this “overshooting” but it looks like the code only implements the P I. How could the dampening be implemented in the code?

Here’s the PID section in the Normalize function

  Accel_magnitude = sqrt(Accel_Vector[0]*Accel_Vector[0] + Accel_Vector[1]*Accel_Vector[1] + Accel_Vector[2]*Accel_Vector[2]);
  Accel_magnitude = Accel_magnitude / GRAVITY; // Scale to gravity.
  // Dynamic weighting of accelerometer info (reliability filter)
  // Weight for accelerometer info (<0.5G = 0.0, 1G = 1.0 , >1.5G = 0.0)
  Accel_weight = constrain(1 - 2*abs(1 - Accel_magnitude),0,1);  //  

  Vector_Cross_Product(&errorRollPitch[0],&Accel_Vector[0],&DCM_Matrix[2][0]); //adjust the ground of reference

I did not notice any particular oscillation. To implement a D term, you would need to take some variable you are measuring and get an estimate of its derivative. An easy way to do that is to compute how much it changed between the last run of the loop and the current run. Then multiply that derivative by some constant and add it to your formula. We have some PID examples in the Pololu AVR C/C++ Library for a different application.


Hello David
I’m working with the sensor, acquired two sensors I want to communicate to work together. I’m programming in CCS and in the first instance using the PIC18F4550 and then change it to an AMP.

It succeeds in obtaining the information from the sensors:
The accelerometer having an output of from 0 to 4095.
The magnetometer output 0-4095.
The output gyroscope with 65535.

According to information, the accelerometer has an output of 16 bits but takes only 12 bits left justified. What I do like other programs in arduino is the right move. But I do not complement, and do not know if that’s my first mistake, since I did not add it again to get the actual decimal number.

The magnetometer does this not only because it is shifted left justified. And neither complement.

The gyroscope is 16 bit output. Here I have a question also of how it should be the actual output. Since the axis “y” sometimes this values of 20 or 59, etc. While other outlets are almost always on their highest value.

Already read the datasheet of each sensor, but still do not understand how to change the sensor data in real units, ie gravity, angular velocity and magnetic field.

Just need to know how to interpret this in their units outputs real or actual output vectors.
I have reviewed some programs on arduino with this sensor (previous version of minimu) but do not quite understand the language. Eg. That means the instructions for a-> y * b->. As:

L3G :: vector_cross void (const vector * a, const vector * b, vector * out)
out-> x = a-> y * b-> z - a-> z * b-> y;
out-> y = a-> z * b-> x - a-> x * b-> z;
out-> z = a-> x * b-> y - a-> y * b-> x;

And also
a-> x / = mag;

I hope you can guide me that I can do.
Greetings and thanks. I await your response.

Hello, Hector. I am not sure which version of the MinIMU-9 you have. Could you provide the full name of the Pololu product you are using or a link to its product page?

It seems like you are confused about the C++ syntax used in some of our example code. This is standard C++ syntax and the best way to learn it would be to read an introductory book about C++. The expression “a->x” means that “a” is a pointer to some structure and we will dereference the pointer and get the member of the structure named “x”. The variable “a” represents a vector which has an X, Y, and Z component. When we write “a->x” we are referring to the X component of vector a. When we write “a->x /= mag;”, that is equivalent to:

a->x = a->x / mag;

This means to take the x component of the a vector and divide it by the value of the “mag” variable.


Hi David.

The sensor is the minimu 9 v2(pololu.com/catalog/product/1268), using a PIC and CCS. And not how to interpret the code example. I knew it was a pointer but did not know how to pass, so far I explain.
I have i2c signals, but do not understand yet how to translate those numbers to acceleration or gravity can understand, the same thing happens with the other sensors.


For the accelerometer, the MinIMU-9 v2 uses the LSM303DLHC. The LSM303DLHC datasheet is available under the resources tab for the MinIMU-9 v2. The property that will let you convert the raw readings into real units is called the linear acceleration sensitivity (LA_So) and it is specified in Table 3. The conversion depends on what setting you chose for the FS bits. For example, if you have set the FS bits to 10, then the sensitivity will be 4 mg/LSB. The “mg” means one thousandth of a g, where g is the acceleration of objects due to gravity on the Earth’s surface. The “LSB” probably stands for LSB stands for “least significant bit”. So if your FS bits are 10, you can convert the raw acceleration reading into mg by multiplying the raw reading by 4. A good way to test this is to just orient your accelerometer so that one axis is pointing down. On that axis, if your FS bits are 10, you should expect to see a reading of approximately 250 or -250. For the best results, you might need to do some calibration of the accelerometer to account for offsets in the raw readings.

The MinIMU-9 v2’s magnetometer is also part of the LSM303DLHC. On Table 3 of the datasheet there is a parameter you could use to convert the raw readings into gauss, but we generally do not use that. The magnetometer readings differ from unit to unit and are also affected greatly by your setup. You will need to do some kind of calibration of the magnetometer, and there are many different techniques for this with different levels of complexity. Also, usually the exact magnitude of the magnetic field is not important and we just want to know which direction the field is pointing.

The MinIMU-9 v2’s gyro is the L3GD20. The property that will let you convert the raw readings into real units is called the sensitivity (So) and it is specified in Table 4 of the datasheet. Just like with the accelerometer, it depends on what measurement range (FS) setting you chose. If you chose an FS = 17.50 dps, then the sensitivity is 17.50 mdps/digit. That means you can take the raw reading and multiply by 17.50 to get a value in units of thousandths of a degree per second (mdps).

For the best results, you might need to do some calibration of the gyro to account for offsets in the raw readings.


Thanks David.
I’m reading the datasheet.