Step 3: Combining the Accelerometer and Gyro

Putting it all together - Combining accelerometer and gyroscope data.

If you're reading this article you probably acquired or are planning to acquire a IMU device, or probably you're planning to build one from separate accelerometer and gyroscope devices.

The first step in using a combination IMU device that combines an accelerometer and a gyroscope is to align their coordinate systems. The easiest way to do it is to choose the coordinate system of accelerometer as your reference coordinate system. Most accelerometer data sheets will display the direction of X,Y,Z axes relative to the image of the physical chip or device. For example here are the directions of X,Y,Z axes as shown in specifications for the Acc_Gyro board:

acc_gyro axes

Next steps are:

  • Identify the gyroscope outputs that correspond to RateAxz , RateAyz values discussed above.Determine if these outputs need to be inverted due to physical position of gyroscope relative to the accelerometer

Do not assume that if a gyroscope has an output marked X or Y, it will correspond to any axis in the accelerometer coordinate system, even if this output is part of an IMU unit. The best way is to test it. Assuming you have fixed the position of gyroscope relative to the accelerometer. It is assumed that the gyro and accelerometer borders are parallel to each other, i.e. you're placing the gyro at an angle multiple of 90deg relative to the accelerometer chip. If you acquired an IMU board chances are that they are already aligned this way. We're not going to discuss in this article models where gyroscope is placed at an irregular angle relative to accelerometer (let's say 45 or 30 degrees), although this might be useful in some applications.

Here is a sample sequence to determine which output of gyroscope corresponds to RateAxz value discussed above.

- start from placing the device in horizontal position. Both X and Y outputs of accelerometer would output the zero-g voltage (for example for Acc_Gyro board this is 1.65V)

- next start rotating the device around the Y axis, another way to say it is that you rotate the device in XZ plane, so that X and Z accelerometer outputs change and Y output remains constant.

- while rotating the device at a constant speed note which gyroscope output changes, the other gyroscope outputs should remain constant

- the gyroscope output that changed during the rotation around Y axis (rotation in XZ plane) will provide the input value for AdcGyroXZ, from which we calculate RateAxz

- the final step is to ensure the rotation direction corresponds to our model, in some cases you may have to invert the RateAxz value due to physical position of gyroscope relative to the accelerometer

- perform again the above test, rotating the device around the Y axis, this time monitor the X output of accelerometer (AdcRx in our model). If AdcRx grows (the first 90 degrees of rotation from horizontal position), then AdcGyroXZ should also grow. Otherwise you need to invert RateAxz , you can achieve this by introducing a sign factor in Eq.3, as follows:

RateAxz = InvertAxz * (AdcGyroXZ * Vref / 1023 - VzeroRate) / Sensitivity , where InvertAxz is 1 or -1

same test cane be done for RateAyz , by rotating the device around the X axis, and you can identify which gyroscope output corresponds to RateAyz, and if it needs to be inverted. Once you have the value for InvertAyz, you should use the following formula to calculate RateAyz:

RateAyz = InvertAyz * (AdcGyroYZ * Vref / 1023 - VzeroRate) / Sensitivity

If you would do these tests on Acc_Gyro board you would get following results:

- the output pin for RateAxz is GX4 and InvertAxz = -1.
- the output pin for RateAyz is GY4 and InvertAyz = -1

From this point on we'll consider that you have setup your IMU in such a way that you can calculate correct values for Axr, Ayr, Azr (as defined Part 1. Accelerometer) and RateAxz, RateAyz (as defined in Part 2. Gyroscope). Next we'll analyze the relations between these values that turn out useful in obtaining more accurate estimation of the inclination of the device relative to the ground plane.

You might be asking yourself by this point, if accelerometer model already gave us inclination angles of Axr,Ayr,Azr why would we want to bother with the gyroscope data ? The answer is simple: accelerometer data can't always be trusted 100%. There are several reason, remember that accelerometer measures inertial force, such a force can be caused by gravitation (and ideally only by gravitation), but it might also be caused by acceleration (movement) of the device. As a result even if accelerometer is in a relatively stable state, it is still very sensitive to vibration and mechanical noise in general. This is the main reason why most IMU systems use a gyroscope to smooth out any accelerometer errors. But how is this done ? And is the gyroscope free from noise ?

The gyroscope is not free from noise however because it measures rotation it is less sensitive to linear mechanical movements, the type of noise that accelerometer suffers from, however gyroscopes have other types of problems like for example drift (not coming back to zero-rate value when rotation stops). Nevertheless by averaging data that comes from accelerometer and gyroscope we can obtain a relatively better estimate of current device inclination than we would obtain by using the accelerometer data alone.

In the next steps I will introduce an algorithm that was inspired by some ideas used in Kalman filter, however it is by far more simple and easier to implement on embedded devices. Before that let's see first what we want our algorithm to calculate. Well , it is the direction of gravitation force vector R = [Rx,Ry,Rz] from which we can derive other values like Axr,Ayr,Azr or cosX,cosY,cosZ that will give us an idea about the inclination of our device relative to the ground plane, we discuss the relation between these values in Part 1. One might say - don't we already have these values Rx, Ry , Rz from Eq.2 in Part 1 ? Well yes, but remember that these values are derived from accelerometer data only, so if you would be to use them directly in your application you might get more noise than your application can tolerate. To avoid further confusion let's re-define the accelerometer measurements as follows:

Racc - is the inertial force vector as measured by accelerometer, that consists of following components (projections on X,Y,Z axes):

RxAcc = (AdcRx * Vref / 1023 - VzeroG) / Sensitivity
RyAcc = (AdcRy * Vref / 1023 - VzeroG) / Sensitivity
RzAcc = (AdcRz * Vref / 1023 - VzeroG) / Sensitivity

So far we have a set of measured values that we can obtain purely from accelerometer ADC values. We'll call this set of data a "vector" and we'll use the following notation.

Racc = [RxAcc,RyAcc,RzAcc]

Because these components of Racc can be obtained from accelerometer data , we can consider it an input to our algorithm.

Please note that because Racc measures the gravitation force you'll be correct if you assume that the length of this vector defined as follows is equal or close to 1g.

|Racc| = SQRT(RxAcc^2 +RyAcc^2 + RzAcc^2),

However to be sure it makes sense to update this vector as follows:

Racc(normalized) = [RxAcc/|Racc| , RyAcc/|Racc| , RzAcc/|Racc|].

This will ensure the length of your normalized Racc vector is always 1.

Next we'll introduce a new vector and we'll call it

Rest = [RxEst,RyEst,RzEst]

This will be the output of our algorithm , these are corrected values based on gyroscope data and based on past estimated data.

Here is what our algorithm will do:
- accelerometer tells us: "You are now at position Racc"
- we say "Thank you, but let me check",
- then correct this information with gyroscope data as well as with past Rest data and we output a new estimated vector Rest.
- we consider Rest to be our "best bet" as to the current position of the device.

Let's see how we can make it work.

We'll start our sequence by trusting our accelerometer and assigning:

Rest(0) = Racc(0)

By the way remember Rest and Racc are vectors , so the above equation is just a simple way to write 3 sets of equations, and avoid repetition:

RxEst(0) = RxAcc(0)
RyEst(0) = RyAcc(0)
RzEst(0) = RzAcc(0)

Next we'll do regular measurements at equal time intervals of T seconds, and we'll obtain new measurements that we'll define as Racc(1), Racc(2) , Racc(3) and so on. We'll also issue new estimates at each time intervals Rest(1), Rest(2), Rest(3) and so on.

Suppose we're at step n. We have two known sets of values that we'd like to use:

Rest(n-1) - our previous estimate, with Rest(0) = Racc(0)
Racc(n) - our current accelerometer measurement

Before we can calculate Rest(n) , let's introduce a new measured value, that we can obtain from our gyroscope and a previous estimate.

We'll call it Rgyro , and it is also a vector consisting of 3 components:

Rgyro = [RxGyro,RyGyro,RzGyro]

We'll calculate this vector one component at a time. We'll start with RxGyro.

gyro model

Let's start by observing the following relation in our gyroscope model, from the right-angle triangle formed by Rz and Rxz we can derive that:

tan(Axz) = Rx/Rz => Axz = atan2(Rx,Rz)

Atan2 might be a function you never used before, it is similar to atan, except it returns values in range of (-PI,PI) as opposed to (-PI/2,PI/2) as returned by atan, and it takes 2 arguments instead of one. It allows us to convert the two values of Rx,Rz to angles in the full range of 360 degrees (-PI to PI). You can read more about atan2 here.

So knowing RxEst(n-1) , and RzEst(n-1) we can find:

Axz(n-1) = atan2( RxEst(n-1) , RzEst(n-1) ).

Remember that gyroscope measures the rate of change of the Axz angle. So we can estimate the new angle Axz(n) as follows:

Axz(n) = Axz(n-1) + RateAxz(n) * T

Remember that RateAxz can be obtained from our gyroscope ADC readings. A more precise formula can use an average rotation rate calculated as follows:

RateAxzAvg = ( RateAxz(n) + RateAxz(n-1) ) / 2
Axz(n) = Axz(n-1) + RateAxzAvg * T

The same way we can find:

Ayz(n) = Ayz(n-1) + RateAyz(n) * T

Ok so now we have Axz(n) and Ayz(n). Where do we go from here to deduct RxGyro/RyGyro ? From Eq. 1 we can write the length of vector Rgyro as follows:

|Rgyro| = SQRT(RxGyro^2 + RyGyro^2 + RzGyro^2)

Also because we normalized our Racc vector, we may assume that it's length is 1 and it hasn't changed after the rotation, so it is relatively safe to write:

|Rgyro| = 1

Let's adopt a temporary shorter notation for the calculations below:

x =RxGyro , y=RyGyro, z=RzGyro

Using the relations above we can write:

x = x / 1 = x / SQRT(x^2+y^2+z^2)

Let's divide numerator and denominator of fraction by SQRT(x^2 + z^2)

x = ( x / SQRT(x^2 + z^2) ) / SQRT( (x^2 + y^2 + z^2) / (x^2 + z^2) )

Note that x / SQRT(x^2 + z^2) = sin(Axz), so:

x = sin(Axz) / SQRT (1 + y^2 / (x^2 + z^2) )

Now multiply numerator and denominator of fraction inside SQRT by z^2

x = sin(Axz) / SQRT (1 + y^2  * z ^2 / (z^2 * (x^2 + z^2)) )

Note that z / SQRT(x^2 + z^2) = cos(Axz) and y / z = tan(Ayz), so finally:

x = sin(Axz) / SQRT (1 + cos(Axz)^2 * tan(Ayz)^2 )

Going back to our notation we get:

RxGyro = sin(Axz(n)) / SQRT (1 + cos(Axz(n))^2 * tan(Ayz(n))^2 )

same way we find that

RyGyro = sin(Ayz(n)) / SQRT (1 + cos(Ayz(n))^2 * tan(Axz(n))^2 )

Now, finally we can find:

RzGyro  =  Sign(RzGyro)*SQRT(1 - RxGyro^2 - RyGyro^2).

Where Sign(RzGyro) = 1 when RzGyro>=0 , and Sign(RzGyro) = -1 when RzGyro<0.

One simple way to estimate this is to take:

Sign(RzGyro) = Sign(RzEst(n-1))

In practice be careful when RzEst(n-1) is close to 0. You may skip the gyro phase altogether in this case and assign:  Rgyro = Rest(n-1). Rz is used as a reference for calculating Axz and Ayz angles and when it's close to 0, values may oveflow and trigger bad results. You'll be in domain of large floating point numbers where tan() / atan() function implementations may lack precision.

So let's recap what we have so far, we are at step n of our algorithm and we have calculated the following values:

Racc - current readings from our accelerometer
Rgyro - obtained from Rest(n-1) and current gyroscope readings

Which values do we use to calculate the updated estimate Rest(n) ? You probably guessed that we'll use both. We'll use a weighted average, so that:

Rest(n) = (Racc * w1 + Rgyro * w2 ) / (w1 + w2)

We can simplify this formula by dividing both numerator and denominator of the fraction by w1.

Rest(n) = (Racc * w1/w1 + Rgyro * w2/w1 ) / (w1/w1 + w2/w1)

and after substituting w2/w1 = wGyro we get:

Rest(n) = (Racc + Rgyro * wGyro ) / (1 + wGyro)

In the above forumula wGyro tells us how much we trust our gyro compared to our accelerometer. This value can be chosen experimentally usually values between 5..20 will trigger good results.

The main difference of this algorithm from Kalman filter is that this weight is relatively fixed , whereas in Kalman filter the weights are permanently updated based on the measured noise of the accelerometer readings. Kalman filter is focused at giving you "the best" theoretical results, whereas this algorithm can give you results "good enough" for your practical application. You can implement an algorithm that adjusts wGyro depending on some noise factors that you measure, but fixed values will work well for most applications.

We are one step away from getting our updated estimated values:

RxEst(n) = (RxAcc + RxGyro * wGyro ) / (1 + wGyro)
RyEst(n) = (RyAcc + RyGyro * wGyro ) / (1 + wGyro)
RzEst(n) = (RzAcc + RzGyro * wGyro ) / (1 + wGyro)

Now let's  normalize this vector again:

R = SQRT(RxEst(n) ^2 + RyEst(n)^2 +  RzEst(n)^2 )

RxEst(n) = RxEst(n)/R
RyEst(n) = RyEst(n)/R
RzEst(n) = RzEst(n)/R

And we're ready to repeat our loop again.

This guide originally appeared on starlino.com, I've made a few light edits and re-posted it with permission. Thanks Starlino!

<p>Hi,<br><br>Can the sensor read low values of acceleration less than or a fraction of g? Say 0.2g? Thanks</p>
<p>Whata a great tutorial, I have one question though, what is the meaning of the &quot;T&quot; in the equation:</p><p>Axz(n) = Axz(n-1) + RateAxz(n) * T</p>
<p>thank you so much. You explain problem very clearly.</p>
<p>Very nice explanation.</p>
Great work
<p>Great tutorial.</p>
<p>Very nice. Thank you</p>
<p>Very nice and simple tutorial! Hope I will manage with it well :)</p><p>Thanks!</p>
<p>Hi ! Thanks for this very detailed instructable ! </p><p>But can you tell me how to convert Accelerometer data to Frequency to measure vibration ? is there a way ? </p><p>Regards. </p>
<p>Thank you very much! It helped a lot! :D</p>
<p>thanks for sharing good tutorial</p>
<p>Nice tutorial! i actually came here because i didn't understand why quadricopters use accelerator and why it is related to angle! but anyway, this page only helped me understand but i still wonder why don't they use a gyroscope ? isn't it easier?! whats the problem with that?!</p>
esta bien padre<br>
this info is priceless, great job...<br> 1 question: I am using the Razor 6DOF from sparkfun.com... it is an IMU with a 3 axis accel, an X/Y axis gyro, and a Z axis gyro all on one chip.<br><br>My question is that since all three chips are on the same board (flat), will the gyro work in this configuration or should I get separate accelerometer and gyro, placed at 90 degree angles to make this work?<br><br>here is a link to the board I have:<br>http://www.sparkfun.com/commerce/product_info.php?products_id=10010<br><br>Thanks in advance for any help
Check my guide:&nbsp;<a href="http://arduino.cc/forum/index.php/topic,58048.msg417140.html#msg417140">http://arduino.cc/forum/index.php/topic,58048.msg417140.html#msg417140</a><br> It is based on the Razor 6DOF chip from sparkfun.<br> <br>
<p>Is it possible to do some kind of 3d visualization with just an accelerometer? </p><p>This video shows a real-time model rotating using Qt with a LIS3DH Accelerometer and a Gyro : <iframe allowfullscreen="" frameborder="0" height="281" src="//www.youtube.com/embed/E2vSNgl-yv0" width="500"></iframe></p><p>What visualization can be done with just the LIS2DH alone?</p>
<p>You can properly use something Processing to do that as well.</p>
<p>Would this work with the Kionix accelerometers - the list is at http://www.kionix.com/accelerometers. They seem pretty cheap through DigiKey, and heard good things about them</p>
<p>Would this work with the Kionix accelerometers - the list is at http://www.kionix.com/accelerometers. They seem pretty cheap through DigiKey, and heard good things about them</p>
<p>If using a Digital Accelerometer are the first few steps necessary? Do you still need to incorperate a 0g voltage level? Is that the same as the zero g offset. I don't see a 0g voltage level in the data sheet. Thank you.</p>
<p>This is a so great tutorial and explanation! Thanks you! It makes me have a general picture of accelerator and gyroscope.</p>
<p>Great Job!! Thanks so much for your explanation</p>
<p>thanks for the beauty-full tutorial..it helps me a lot...God bless You</p>
Very nice explanation! Thank you very much. Right now I know how to use an accelerometer correctly.
i have a very basic doubt regarding the device placement of gyro and accelerometer+manganometer. Are they not required to be place on the exact center of PCB to get best performance. Do we compromise performance of devices by placing it offset to center. And is there particular measurement to place gyro and accelerometer apart?
Hello, <br>i am at the very first stage.i am just taking raw values from the accelerometer of GY-85IMU,it uses ADXL345. <br>But the problem is that it is giving me same value on Z-axis in every orientation. <br>This is the code: <br> <br>#include <br>#include <br>#include <br>#include <br>#include <br>#include <br>#include <br>#include <br> <br>//#define DEBUG <br>#include &quot;DebugUtils.h&quot; <br>#include &quot;CommunicationUtils.h&quot; <br>#include &quot;FreeIMU.h&quot; <br>#include <br>#include <br> <br>int raw_values[9]; <br>float conv_values[9]; <br>float ypr[3]; // yaw pitch roll <br>char str[256]; <br>float val[9]; <br>float values[9]; <br> <br>FreeIMU my3IMU = FreeIMU(); <br>//The command from the PC <br>char cmd; <br> <br>void setup() { <br> Serial.begin(115200); <br> Wire.begin(); <br> my3IMU.init(true); <br> <br> // LED <br> pinMode(13, OUTPUT); <br>} <br> <br> <br>void loop() { <br> <br> for(uint16_t i=0; i&lt;500; i++) <br> { <br> my3IMU.getRawValues(raw_values); <br> Serial.print('\n'); <br> Serial.print(&quot;RAccX=&quot;); Serial.print(raw_values[0]); Serial.print(&quot; &quot;); <br> Serial.print(&quot;RAccY=&quot;); Serial.print(raw_values[1]); Serial.print(&quot; &quot;); <br> Serial.print(&quot;RAccZ=&quot;); Serial.print(raw_values[2]); Serial.print(&quot; &quot;); <br> Serial.print('\n'); <br> Serial.print('\n'); <br> <br> } <br> <br> <br>while(1){}; <br>} <br> <br>can u tell me what is the problemm???
i am currently using mote modules MTM-CM5000 and MTM-CM3000 for data transmission and recieving along radio for a accelerometer.Output of my accelerometer can be see on oscilloscope which show me all data including voltage ,humidity,radioactivity etc all in graph form on my pc. MTS-EX1000 is also used for voltage amplification purpose.Except to all of these raw data output i only want to know about how to calculate the frequency that my accelerometer is sensing here. Thankx..
when I looked in the specifications of LIS302DL I found sensitivity = 18mg/digit, 72mg/digit and ZeroG level =? <br>here is the link please if anyone can help me determine the necessary specifications LIS purpose of applying the above formulas <br>&quot;&quot;http://www.digikey.com/product-search/en/sensors-transducers/accelerometers/1966355?k=m7&quot;&quot; <br>thinks <br>
Hello <br> I configured the accelerometer LIS302 DL card STM32F4 it shows me results between 0 and 255, and I just need to display the measurements in mm / s ^ 2 for the three axes. <br>I have read the above, I think it can help me a lot but on the voltage I do not know what value I should use. <br>if it can help me to convert the measured values ​​of the different axes, for example (0, 55.230, 245 ...) <br>((it attached a screen printed on running my application)) <br>thank you <br>
Where is the Code OF gyro ?? <br> <br>Plzz
Hi there! I have got one question: I am doing my project in android application which will give altitude, rotational movement to its users, so this information is applicable for me to using at java coding or matlab coding? or any other needed, can you please explain me! Thanks. <br>Moin.
I have a question: If we have a board with a 3-axis (x,y,z) gyroscope and a 2-axis (x,y) accelerometer is there any way to virtualize the z-axis of accelerometer with a mathematical algorithm through software since our board is missing the z-axis accelerometer? Even if it cannot be done precisely, can we estimate a range for z-accel? <br> <br>Thanks a bunch! <br> <br>
thanks for the info, i'm going to use a 5dof imu img500/adxl335, output frm them are analog for balancing my bot sould i have to build an another filter circuit like complementary filter?<br>if so how can we give the change in time rate values in our codes?(dt)<br>help me out with this <br>thank you
You can use a simple RC filter if the outputs are analog from the chip. <br> <br>To find da/dt, sample two value and subtract them. <br>Divide the result by the time passed between the two samples. <br> <br>da/dt = (Sample-1 - Sample-2) / (1 / Sampling-Frequency) <br> <br>You can get rid fo the division by using a factor k same as (1 / Sampling-Frequency). <br> <br>da/dt = (Sample-1 - Sample-2)
Hi guys,<br><br>I will make a project measurin tremor characteristics of parkinson diseased patients. To do this I need to use a sensor that can measure the movements accurately and sensitively. In the beginnin of my research I was ok with using only accelerometer but when I read more, I realized that using both accelerometer and gryo would give much better results. I will be working in arduino. Can anyone suggest me accelerometer and gryo boards to purchase? Shall I purchase acc_gyro imu board? or I shall buy them seperately?<br><br>Thanks in advance..
You can buy a board through Ebay based on &quot;MPU-6050&quot; or &quot;MPU-6000&quot; which is a gyroscope and accelerometer in the same chip. <br> <br>The cross talk is minimal and it is cheaper to buy them in the same package (my thought).
Thank you for the post,it is really interesting. I just have a question. Why should we have to divise each quantity Rx,Ry,Rz by R? What does it mean? <br>My second question is about the force Rx,Ry,Rz. I thought that only tangential forces from the accelerometer had to be add the the angle. Is Rx, Ry,Rz the tangentiel forces??
R is the resultant vector of the three component vectors, Rx, Ry and Rz. <br> <br>R^2 = Rx^2 + Ry^2 + Rz^2 <br>=&gt; R = SQRT(Rx^2 + Ry^2 + Rz^2) <br> <br>You need this division to measure the contribution of a component (Rx, Ry or Rz) to the resultant vector, R. R will incline towards the component having the higher value. If Rx, Ry and Rz have the same lengths (same acceleration in all axes), the resultant vector (R) will point precisely in their middle. <br> <br>Thus to find the angle between Rx, Ry or Rz and R, you need: <br>Axr = arccos(Rx/R) <br>Ayr = arccos(Ry/R) <br>Azr = arccos(Rz/R) <br> <br>Yes, Rx, Ry and Rz are tangential.
Hi, great instructable! <br> <br>I gave a question concerning the angles extracted from the accelerometer: It seems there is a hidden assumptions that the reading of the accelerations will always be done while stationary (or not moving). This is not true to most mobile/airborne applications. <br>In these cases there is also an additional external acceleration (like the acceleration of the car or an aircraft turning in a wide angle) and then the assumption about the total 1g vector size isn't right. <br>What am I missing? <br> <br>Thanks <br>Gabriel
You can always read the &quot;bias&quot; value by keeping the chip static. The datasheet must be providing this value as well. I think, it does not drift that much with time and thus you can always subtract a constant value from the readings. <br> <br>There is no hidden assumption here. If it is static, you will get 0 after the &quot;bias&quot; subtraction.
Guys, <br>can anybody tell me how can i get negative readings for x,y,z, axis from accelerometer ? i mean it show me just + value in x axes or other too. but not -(negative). so how i know if i made opposing motion
Read it above at, &quot;Let's say our 0g voltage level is VzeroG = 1.65V&quot;. <br> <br>If your reading is less than the zero-g value, you are accelerating in the negative direction.
Great Explanation . . .
Very helpful! I used this instructable to interpret data for a model airplane autopilot. I would like to add that if you are struggling to convert your accelerometer into degrees you should investigate the atan2() function. <br>somethings like: <br>pitch (in degrees) = atan2[x(in g's),y(in g's)] + pi
Thank you so much for posting this information! It would've had taken me days to figure this stuff out on my own.
Thank u very much !!! it was an awesome piece of informations!!
thanks a lot this really helped me
Fantastic Information. Thank you for dumbing it down to a hobbist level instead of an engineer tech babble.
This is a really good instructable! It really contains everything you need to know to start with those sensors. It answered a lot of my questions!<br><br>Thanks

About This Instructable



More by Gadget Gangster:Hack Your Car Talking Resistor Calculator Bananaphone: A Touch Capacitance Synth 
Add instructable to: