<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Starlino Electronics &#187; gyroscope</title>
	<atom:link href="http://www.starlino.com/tag/gyroscope/feed" rel="self" type="application/rss+xml" />
	<link>http://www.starlino.com</link>
	<description>Electronics and Robotics Projects, Tutorials, Reviews, Experiments</description>
	<lastBuildDate>Sat, 28 Jan 2012 01:38:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>DCM Tutorial &#8211; An Introduction to Orientation Kinematics</title>
		<link>http://www.starlino.com/dcm_tutorial.html</link>
		<comments>http://www.starlino.com/dcm_tutorial.html#comments</comments>
		<pubDate>Fri, 27 May 2011 02:15:31 +0000</pubDate>
		<dc:creator>starlino</dc:creator>
				<category><![CDATA[IMU Theory and Experiments]]></category>
		<category><![CDATA[accelerometer]]></category>
		<category><![CDATA[Acc_Gyro]]></category>
		<category><![CDATA[dcm]]></category>
		<category><![CDATA[gyro]]></category>
		<category><![CDATA[gyroscope]]></category>
		<category><![CDATA[imu]]></category>
		<category><![CDATA[inclination]]></category>
		<category><![CDATA[kinematics]]></category>
		<category><![CDATA[mems]]></category>
		<category><![CDATA[orientation]]></category>
		<category><![CDATA[sensor]]></category>

		<guid isPermaLink="false">http://www.starlino.com/?p=226</guid>
		<description><![CDATA[Introduction This article is a continuation of my IMU Guide, covering additional orientation kinematics topics. I will go through some theory first and then I will present a practical example with code build around an Arduino and a 6DOF IMU sensor (acc_gyro_6dof). The scope of this experiment is to create an algorithm for fusing gyroscope [...]]]></description>
			<content:encoded><![CDATA[<h2>Introduction</h2>
<p>This article is a continuation of my <a href="http://www.starlino.com/imu_guide.html">IMU Guide</a>, covering additional orientation kinematics topics. I will go through some theory first and then I will present a practical example with code build around an Arduino and a 6DOF IMU sensor (acc_gyro_6dof). The scope of this experiment is to create an algorithm for fusing gyroscope and accelerometer data in order to create an estimation of the device orientation in space. Such an algorithm was already presented in part 3 of my “IMU Guide” and a practical Arduino experiment with code was presented in the “<a href="http://www.starlino.com/imu_kalman_arduino.html">Using a 5DOF IMU</a>” article and was nicknamed “Simplified Kalman Filter”, providing a simple alternative to the well known Kalman Filter algorithm. In this article we’ll use another approach utilizing the DCM (Direction Cosine Matrix). For the reader that is unfamiliar with MEMS sensors it is recommended to read Part 1 and 2 of the IMU Guide article. Also for following the experiments presented in this text it is recommended to acquire an Arduino board and an <a href="http://www.gadgetgangster.com/367">acc_gyro_6dof</a> sensor. </p>
<h2>Prerequisites</h2>
<p>No really advanced math is necessary. Find a good book on matrix operations, that’s all you might need above school math course. If you would like to refresh your knowledge below are some quick articles:   <br />Cartesian Coordinate System &#8211; <a href="http://en.wikipedia.org/wiki/Cartesian_coordinate_system">http://en.wikipedia.org/wiki/Cartesian_coordinate_system</a>    <br />Rotation &#8211; <a href="http://en.wikipedia.org/wiki/Rotation_%28mathematics%29">http://en.wikipedia.org/wiki/Rotation_%28mathematics%29</a>    <br />Vector scalar product &#8211; <a href="http://en.wikipedia.org/wiki/Dot_product">http://en.wikipedia.org/wiki/Dot_product</a>    <br />Vector cross product &#8211; <a href="http://en.wikipedia.org/wiki/Cross_product">http://en.wikipedia.org/wiki/Cross_product</a>    <br />Matrix Multiplication &#8211; <a href="http://en.wikipedia.org/wiki/Matrix_multiplication">http://en.wikipedia.org/wiki/Matrix_multiplication</a>    <br />Block Matrix &#8211; <a href="http://en.wikipedia.org/wiki/Block_matrix">http://en.wikipedia.org/wiki/Block_matrix</a>    <br />Transpose Matrix &#8211; <a href="http://en.wikipedia.org/wiki/Transpose">http://en.wikipedia.org/wiki/Transpose</a>    <br />Triple Product &#8211; <a href="http://en.wikipedia.org/wiki/Triple_product">http://en.wikipedia.org/wiki/Triple_product</a></p>
<h2>Notations</h2>
<p>Vectors are marked in <b>bold text </b>-<b> </b>so for example “<b>v</b>”<b> </b>is a vector and “v” is a scalar (if you can’t distinguish the two there’s problem with the text formatting wherever you’re reading this).</p>
<h2>Part 1. The DCM Matrix</h2>
<p>Generally speaking orientation kinematics deals with calculating the relative orientation of a body relative to a global coordinate system. It is useful to attach a coordinate system to our body frame and call it Oxyz, and another one to our global frame and call it OXYZ. Both the global and the body frames have the same fixed origin O (see <i>Fig. 1</i>). Let’s also define <b>i, j, k</b> to be unity vectors co-directional with the body frame’s x, y, and z axes &#8211; in other words they are versors of Oxyz and let <b>I, J, K </b>be the versors of global frame OXYZ. </p>
<p><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0024.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image002[4]" border="0" alt="clip_image002[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0024_thumb.jpg" width="279" height="249" /></a></p>
<p><i>Figure 1</i></p>
<p>Thus, by definition, expressed <b>in terms of global coordinates</b> vectors <b>I, J, K</b> can be written as:</p>
<p><b>I</b><sup>G</sup> = {1,0,0}<b><sup> T</sup></b>, <b>J</b><sup>G</sup>={0,1,0}<b><sup> T</sup></b> , <b>K</b><sup>G</sup> = {0,0,1}<b><sup> T </sup></b></p>
<p><i>Note: we use {…}<sup> T </sup>notation to denote a column vector, in other words a column vector is a translated row vector. The orientation of vectors (row/column) will become relevant once we start multiplying them by a matrix later on in this text.</i></p>
<p>And similarly, <b>in terms of body coordinates </b>vectors<b> i, j, k </b>can be written as:</p>
<p><b>i</b><sup>B</sup> = {1,0,0}<b><sup> T</sup></b>, <b>j</b><sup>B</sup>={0,1,0}<b><sup> T</sup></b> , <b>k</b><sup>B</sup> = {0,0,1}<b><sup> T</sup></b></p>
<p>Now let’s see if we can write vectors <b>i, j, k </b>in terms of global coordinates. Let’s take vector <b>i </b>as an example and write its global coordinates:</p>
<p><b>i</b><sup>G</sup> = {i<sub>x</sub><sup>G</sup> , i<sub>y</sub><sup>G </sup>, i<sub>z</sub><sup>G</sup>}<b><sup> T</sup></b></p>
<p>Again, by example let’s analyze the X coordinate i<sub>x</sub><sup>G</sup>, it’s calculated as the length of projection of the <b>i </b>vector onto the global X axis. </p>
<p>i<sub>x</sub><sup>G </sup>= |<b>i</b>| cos(X,<b>i</b>) = cos(<b>I</b>,<b>i</b>)</p>
<p>Where |<b>i</b>| is the norm (length) of the <b>i</b> unity vector and cos(<b>I</b>,<b>i</b>) is the cosine of the angle formed by the vectors <b>I</b> and <b>i</b>. Using the fact that |<b>I</b>| = 1 and |<b>i</b>| = 1 (they are unit vectors by definition). We can write:</p>
<p>i<sub>x</sub><sup>G </sup>= cos(<b>I</b>,<b>i</b>) = |<b>I</b>||<b>i</b>| cos(<b>I</b>,<b>i</b>) = <b>I.i </b></p>
<p>Where <b>I.i</b>. is the scalar (dot) product of vectors <b>I</b> and <b>i</b>. For the purpose of calculating scalar product <b>I.i </b>it doesn’t matter in which coordinate system these vectors are measured as long as they are both expressed in the same system, since a rotation does not modify the angle between vectors so: <b>I.i = I</b><sup>B</sup><b>.i</b><sup>B</sup> = <b>I</b><sup>G</sup><b>.i</b><sup>G </sup>= cos(<b>I</b><sup>B</sup><b>.i</b><sup>B</sup>) = cos(<b>I</b><sup>G</sup><b>.i</b><sup>G</sup>) , so for simplicity we’ll skip the superscript in scalar products <b>I.i , J.j , K.k </b>and in cosines<b> </b>cos(<b>I</b>,<b>i</b>), cos(<b>J</b>,<b>j</b>), cos(<b>K</b>,<b>k</b>).</p>
<p>Similarly we can show that:</p>
<p>i<sub>y</sub><sup>G</sup> = <b>J.i</b><sup> </sup>, i<sub>z</sub><sup>G</sup>=<b>K.i </b>, so now we can write vector <b>i</b> in terms of global coordinate system as:</p>
<p><b>i</b><sup>G</sup>= {<b> I.i, J.i, K.i</b>}<sup>T</sup><b> </b></p>
<p>Furthermore, similarly it can be shown that <b>j</b><sup>G</sup>= {<b> I.j, J.j, K.j</b>}<sup> T</sup><b> , k</b><sup>G</sup>= {<b> I.k, J.k, K.k</b>}<sup> T</sup>.</p>
<p>We now have a complete set of global coordinates for our body’s versors <b>i, j, k </b>and we can organize these values in a convenient matrix form:</p>
<p><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0044.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image004[4]" border="0" alt="clip_image004[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0044_thumb.gif" width="620" height="74" /></a><i> (Eq. 1.1)</i><i>     <br /></i></p>
<p>This matrix is called Direction Cosine Matrix for now obvious reasons &#8211; it consists of cosines of angles of all possible combinations of body and global versors. </p>
<p>The task of expressing the global frame versors <b>I</b><sup>G</sup>, <b>J</b><sup>G</sup>, <b>K</b><sup>G</sup> in body frame coordinates is symmetrical in nature and can be achieved by simply swapping the notations <b>I, J, K </b>with <b>i, j, k, </b>the results being:</p>
<p><b>I</b><sup>B</sup>= {<b> I.i, I.j, I.k</b>}<sup>T</sup><b> </b>,<b> J</b><sup>B</sup>= {<b> J.i, J.j, J.k</b>}<sup>T</sup><b> , K</b><sup>B</sup>= {<b> K.i, K.j, K.k</b>}<sup>T</sup><b> </b></p>
<p>and organized in a matrix form: </p>
<p><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0064.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image006[4]" border="0" alt="clip_image006[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0064_thumb.gif" width="620" height="74" /></a><i> (Eq. 1.2)</i></p>
<p>It is now easy to notice that DCM<sup>B</sup> = (DCM<sup>G</sup>)<sup>T </sup>or <sup></sup>DCM<sup>G</sup> = (DCM<sup>B</sup>)<sup>T </sup>, in other words the two matrices are translates of each other, we’ll use this important property later on. </p>
<p>Also notice that DCM<sup>B</sup>. DCM<sup>G</sup> = (DCM<sup>G</sup>)<sup>T</sup> .DCM<sup>G</sup> = DCM<sup>B</sup>. (DCM<sup>B</sup>)<sup>T</sup> = I<sub>3</sub> , where I<sub>3</sub> is the 3&#215;3 identity matrix. In other words the DCM matrices are orthogonal.</p>
<p>This can be proven by simply expanding the matrix multiplication in block matrix form:</p>
<p><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0084.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image008[4]" border="0" alt="clip_image008[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0084_thumb.gif" width="624" height="145" /></a><i> (Eq. 1.3)</i></p>
<p>To prove this we use such properties as for example: <b>i</b><sup>GT</sup>.<b> i</b><sup>G</sup> = |<b> i</b><sup>G</sup>||<b> i</b><sup>G</sup>|cos(0) = 1 and <b>i</b><sup>GT</sup>.<b> j</b><sup>G</sup> = 0 because (<b>i </b>and<b> j</b> are orthogonal) and so forth.</p>
<p>The DCM matrix (also often called the rotation matrix) has a great importance in orientation kinematics since it defines the rotation of one frame relative to another. It can also be used to determine the global coordinates of an arbitrary vector if we know its coordinates in the body frame (and vice versa). </p>
<p>Let’s consider such a vector with body coordinates:</p>
<p><b>r</b><sup>B</sup>= {<b> </b>r<sub>x</sub><sup>B</sup>, r<sub>y</sub><sup>B</sup>, r<sub>z</sub><sup>B</sup>}<sup> T</sup> and let’s try to determine its coordinates in the global frame, by using a known rotation matrix DCM<sup>G</sup>. </p>
<p>We start by doing following notation:</p>
<p><b>r</b><sup>G</sup> = { r<sub>x</sub><sup>G</sup> , r<sub>y</sub><sup>G</sup> , r<sub>z</sub><sup>G</sup> } <sup>T</sup>.</p>
<p>Now let’s tackle the first coordinate r<sub>x</sub><sup>G</sup>:</p>
<p>r<sub>x</sub><sup>G</sup> = |<b> r</b><sup>G</sup>| cos(<b>I</b><sup>G</sup>,<b>r</b><sup>G</sup>) , because r<sub>x</sub><sup>G</sup> is the projection of <b>r</b><sup>G</sup> onto X axis that is co-directional with <b>I</b><sup>G</sup>.</p>
<p>Next let’s note that by definition a rotation is such a transformation that does not change the scale of a vector and does not change the angle between two vectors that are subject to the same rotation, so if we express some vectors in a different rotated coordinate system the norm and angle between vectors will not change:</p>
<p>|<b> r</b><sup>G</sup>| = |<b> r</b><sup>B</sup>| , |<b> I</b><sup>G</sup>| = |<b> I</b><sup>B</sup>| = 1 and cos(<b>I</b><sup>G</sup>,<b>r</b><sup>G</sup>) = cos(<b>I</b><sup>B</sup>,<b>r</b><sup>B</sup>), so we can use this property to write</p>
<p>r<sub>x</sub><sup>G</sup> = |<b> r</b><sup>G</sup>| cos(<b>I</b><sup>G</sup>,<b>r</b><sup>G</sup>) = |<b> I</b><sup>B</sup> ||<b> r</b><sup>B</sup>| cos(<b>I</b><sup>B</sup>,<b>r</b><sup>B</sup>) = <b>I</b><sup>B</sup>.<b> r</b><sup>B</sup> = <b>I</b><sup>B</sup>. {<b> </b>r<sub>x</sub><sup>B</sup>, r<sub>y</sub><sup>B</sup>, r<sub>z</sub><sup>B</sup>}<sup> T</sup> , by using one the two definition of the scalar product.</p>
<p>Now recall that <b>I</b><sup>B</sup>= {<b> I.i, I.j, I.k</b>}<sup>T</sup><b> </b>and by using the other definition of scalar product:</p>
<p>r<sub>x</sub><sup>G</sup> = <b>I</b><sup>B</sup>.<b> r</b><sup>B</sup> = {<b> I.i, I.j, I.k</b>}<sup>T</sup><b> . </b>{<b> </b>r<sub>x</sub><sup>B</sup>, r<sub>y</sub><sup>B</sup>, r<sub>z</sub><sup>B</sup>}<sup> T</sup> = r<sub>x</sub><sup>B</sup><b> I.i </b>+<b> </b>r<sub>y</sub><sup>B</sup><b> I.j </b>+ r<sub>z</sub><sup>B</sup><b> I.k</b></p>
<p>In same fashion it can be shown that:</p>
<p>r<sub>y</sub><sup>G</sup> = r<sub>x</sub><sup>B</sup><b> J.i </b>+<b> </b>r<sub>y</sub><sup>B</sup><b> J.j </b>+ r<sub>z</sub><sup>B</sup><b> J.k     <br /></b>r<sub>z</sub><sup>G</sup> = r<sub>x</sub><sup>B</sup><b> K.i </b>+<b> </b>r<sub>y</sub><sup>B</sup><b> K.j </b>+ r<sub>z</sub><sup>B</sup><b> K.k</b></p>
<p>Finally let’s write this in a more compact matrix form:</p>
<p><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0104.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image010[4]" border="0" alt="clip_image010[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0104_thumb.gif" width="386" height="80" /></a><i> (Eq. 1.4)</i><b></b></p>
<p><b></b></p>
<p>Thus the DCM matrix can be used to covert an arbitrary vector <b>r<sup>B</sup></b> expressed in one coordinate system B, to a rotated coordinate system G. <b></b></p>
<p>We can use similar logic to prove the reverse process:</p>
<p><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0124.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image012[4]" border="0" alt="clip_image012[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0124_thumb.gif" width="125" height="26" /></a><i> (Eq. 1.5)</i></p>
<p>Or we can arrive at the same conclusion by multiplying both parts in <i>(Eq. 1.4) </i>by DCM<sup>B</sup> which equals to DCM<sup>GT</sup>, and using the property that DCM<sup>GT</sup>.DCM<sup>G</sup> = I<sub>3</sub> , see (<i>Eq. 1.3)</i>:<sup></sup></p>
<p>DCM<sup>B</sup><b> r</b><sup>G</sup> = DCM<sup>B</sup> DCM<sup>G</sup><b> r</b><sup>B</sup> = DCM<sup>GT</sup> DCM<sup>G</sup><b> r</b><sup>B</sup> = I<sub>3</sub><b> r</b><sup>B </sup>= <b>r</b><sup>B</sup><b></b></p>
<h4></h4>
<h2>Part 2. Angular Velocity</h2>
<p>So far we have a way to characterize the orientation of one frame relative to another rotated frame, it is the DCM matrix and it allows us to easily convert the global and body coordinates back and forth using <i>(Eq. 1.4) </i>and <i>(Eq. 1.5). </i>In this section we’ll analyze the rotation as a function of time that will help us establish the rules of updating the DCM matrix based on a characteristic called angular velocity. Let’s consider an arbitrary rotating vector <b>r </b>and define it’s coordinates at time t to be <b>r</b>(t). Now let’s consider a small time interval dt and make the following notations: <b>r</b> = <b>r</b> (t) , <b>r’</b>= <b>r</b> (t+dt) and d<b>r = r</b>’ – <b>r</b>:<sub></sub></p>
<p><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0144.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image014[4]" border="0" alt="clip_image014[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0144_thumb.jpg" width="199" height="205" /></a></p>
<p><i>Figure 2</i></p>
<p>Let’s say that during a very small time interval dt → 0 the vector <b>r </b>has<b> </b>rotated about an axis co-directional with a unity vector <b>u</b><sub> </sub>by an angle dθ and ended up in the position <b>r’</b>. Since <b>u </b>is our axis of rotation it is perpendicular to the plane in which the rotation took place (the plane formed by<b> r</b> and <b>r</b>’) so <b>u </b>is orthogonal to both <b>r</b> and <b>r</b>’. There are two unity vectors that are orthogonal to the plane formed by <b>r</b> and <b>r’</b>, they are shown on the picture as <b>u </b>and <b>u’</b> since we’re still defining things we’ll choose the one that is co-directional with the cross product <b>r</b> x <b>r’</b>, following the rule of <a href="http://en.wikipedia.org/wiki/Right-hand_rule">right-handed coordinate system</a>. Thus because <b>u </b>is a unity vector |<b>u</b>| = 1 and is co-directional with <b>r</b> x <b>r’ </b>we can deduct it as follows:<b></b></p>
<p><b>u</b> =<b> </b>(<b>r</b> x <b>r</b>’) / |<b>r</b> x <b>r</b>’| =<b> </b>(<b>r</b> x <b>r</b>’) / (|<b>r</b>||<b> r</b>’|sin(dθ)) = <b></b>(<b>r</b> x<b> r</b>’) / (|<b>r</b>|<sup>2</sup> sin(dθ)) <i>(Eq. 2.1)</i><b></b></p>
<p>Since a rotation does not alter the length of a vector we used the property that|<b> r</b>’| = |<b>r</b>|. </p>
<p>The linear velocity of the vector <b>r </b>can<b> </b>be defined as the vector:</p>
<p><b>v = </b>d<b>r </b>/ dt = (<b> r</b>’ &#8211; <b>r</b>) / dt <i>(Eq. 2.2)</i></p>
<p>Please note that since our dt approaches 0 so does dθ → 0, hence the angle between vectors <b>r</b> and d<b>r </b>(let’s call it α)<b> </b>can be found from the isosceles triangle contoured by <b>r </b>, <b>r’ </b>and<b> </b>d<b>r: </b></p>
<p>α = (π – dθ) / 2 and because dθ → 0 , then α → π/2 </p>
<p>What this tells us is that <b>r </b>is perpendicular to<b> </b>d<b>r</b> when dt → 0 and hence <b>r</b> is perpendicular to <b>v</b> since <b>v</b> and d<b>r</b> are co-directional from<b> </b><i>(Eq. 2.2): </i></p>
<p><b><i>v</i></b> ⊥ r <i>(Eq. 2.21)</i> <b></b></p>
<p>We are now ready to define the angular velocity vector. Ideally such a vector should define the rate of change of the angle θ and the axis of the rotation, so we define it as follows:</p>
<p><b>w </b>= (dθ/dt ) <b>u </b><i>(Eq. 2.3)</i><b></b></p>
<p>Indeed the norm of the <b>w</b> is |<b>w</b>| = dθ/dt and the direction of <b>w </b>coincides with the axis of rotation <b>u</b>. Let’s expand <i>(Eq. 2.3) </i>and try to establish a relationship with the linear velocity <b>v:</b></p>
<p>Using <i>(Eq. 2.3) </i>and<i> (Eq. 2.1)</i>:</p>
<p><b>w </b>= (dθ/dt ) <b>u </b>= (dθ/dt ) (<b>r</b> x<b> r</b>’) / (|<b>r</b>|<sup>2</sup> sin(dθ)) </p>
<p>Now note that when dt → 0, so does dθ → 0 and hence for small dθ, sin(dθ) ≈ dθ , we end up with:</p>
<p><b>w </b>= (<b>r</b> x<b> r</b>’) / (|<b>r</b>|<sup>2</sup> dt) <i>(Eq. 2.4)</i></p>
<p>Now because <b>r</b>’ = <b>r</b> + d<b>r</b> , d<b>r</b>/dt = <b>v , r </b>x <b>r = 0 </b>and using the distributive property of cross product over addition:</p>
<p><b>w </b>= (<b>r</b> x (<b>r</b> + d<b>r)</b>) / (|<b>r</b>|<sup>2</sup> dt) = (<b>r</b> x <b>r</b> + <b>r </b>x d<b>r)</b>) / (|<b>r</b>|<sup>2</sup> dt) = <b>r </b>x (d<b>r</b>/dt) / |<b>r</b>|<sup>2</sup></p>
<p>And finally:</p>
<p><b>w </b>= <b>r</b> x <b>v </b>/ |<b>r</b>|<sup>2</sup>­ <i>(Eq. 2.5)</i></p>
<p>This equation establishes a way to calculate angular velocity from a known linear velocity <b>v</b>. </p>
<p>We can easily prove the reverse equation that lets us deduct linear velocity from angular velocity:</p>
<p><b>v </b>=<b> w </b>x<b> r </b>­ <i>(Eq. 2.6)</i></p>
<p>This can be proven simply by expanding <b>w</b> from <i>(Eq. 2.5) </i>and using vector <a href="http://en.wikipedia.org/wiki/Triple_product">triple product</a> rule (<b>a </b>x <b>b</b>) x <b>c</b> = (<b>a</b>.<b>c</b>)<b>b</b> &#8211; (<b>b</b>.<b>c</b>)<b>a</b>. Also we’ll use the fact that <b>v </b>and<b> r </b>are perpendicular <i>(Eq. 2.21)</i> and thus <b>v</b>.<b>r </b>= 0</p>
<p><b>w </b>x<b> r </b>=<b> </b>(<b>r</b> x <b>v </b>/ |<b>r</b>|<sup>2</sup>­) x <b>r </b>= (<b>r</b> x <b>v) </b>x <b>r</b> / |<b>r</b>|<sup>2</sup>­ = ((<b>r</b>.<b>r</b>) <b>v</b> + (<b>v</b>.<b>r</b>)<b>r</b>) / |<b>r</b>|<sup>2</sup>­ = ( |<b>r</b>|<sup>2</sup>­ <b>v</b> + 0) |<b>r</b>|<sup>2 </sup>= <b>v</b></p>
<p>So we just proved that <i>(Eq. 2.6)</i> is true. Just to check <i>(Eq. 2.6) </i>intuitively &#8211; from <i>Figure 2 </i>indeed <b>v </b>has the direction of <b>w </b>x<b> r </b>using the right hand rule and indeed <b><i>v</i></b> ⊥ <b>r </b>and <b><i>v</i></b> ⊥ <b>w </b>because it is in the same plane with<b> r </b>and <b>r’</b>.</p>
<h4></h4>
<h2>Part 3. Gyroscopes and angular velocity vector </h2>
<p>A 3-axis MEMS gyroscope is a device that senses rotation about 3 axes attached to the device itself (body frame). If we adopt the device’s coordinate system (body’s frame), and analyze some vectors attached to the earth (global frame), for example vector <b>K </b>pointing to the zenith or vector <b>I </b>pointing North &#8211; then it would appear to an observer inside the device that these vector rotate about the device center. Let w<sub>x </sub>, w<sub>y </sub>, w<sub>z </sub>be the outputs of a gyroscope expressed in rad/s &#8211; the measured rotation about axes x, y , z respectively. Converting from the raw output of the gyroscope to physical values is discussed for example here: <a href="http://www.starlino.com/imu_guide.html">http://www.starlino.com/imu_guide.html</a> . If we query the gyroscope at regular, small time intervals <b>dt, </b>then what gyroscope output tells us is that during this time interval the earth rotated about gyroscope’s <i>x</i> axis by an angle of dθ<sub>x</sub> = w<sub>x</sub>dt, about <i>y</i> axis by an angle of dθ<sub>y</sub> = w<sub>y</sub>dt and about <i>z</i> axis by an angle of dθ<sub>z</sub> = w<sub>z</sub>dt. These rotations can be characterized by the angular velocity vectors: <b>w</b><sub>x<b> </b></sub>= w<sub>x</sub><b> i </b>= {w<sub>x </sub>, 0<sub> </sub>, 0<sub> </sub>}<sup>T </sup>, <b>w</b><sub>y<b> </b></sub>= w<sub>y</sub><b> j </b>= { 0<sub> </sub>, w<sub>y </sub>, 0<sub> </sub>}<sup>T</sup> , <b>w</b><sub>z<b> </b></sub>= w<sub>z</sub><b> k </b>= { 0<sub> </sub>, 0, w<sub>z </sub>}<sup>T</sup> , where <b>i,j,k </b>are versors of the local coordinate frame (they are co-directional with body’s axes x,y,z respectively). Each of these three rotations will cause a linear displacement which can be expressed by using <i>(Eq. 2.6)</i>: </p>
<p>d<b>r</b><sub>1</sub> = dt <b>v</b><sub>1</sub><b> </b>= dt (<b>w</b><sub>x</sub><b> </b>x<b> r</b>) ; d<b>r</b><sub>2</sub> = dt <b>v</b><sub>2</sub><b> </b>= dt (<b>w</b><sub>y</sub><b> </b>x<b> r</b>) ; d<b>r</b><sub>3</sub> = dt <b>v</b><sub>3</sub><b> </b>= dt (<b>w</b><sub>z</sub><b> </b>x<b> r</b>) <i>. </i></p>
<p>The combined effect of these three displacements will be:</p>
<p>d<b>r </b>= d<b>r</b><sub>1 </sub>+ d<b>r</b><sub>2 </sub>+ d<b>r</b><sub>3 </sub>= dt (<b>w</b><sub>x</sub><b> </b>x<b> r </b>+ <b>w</b><sub>y</sub><b> </b>x<b> r </b>+<b> w</b><sub>z</sub><b> </b>x<b> r</b>) = dt (<b>w</b><sub>x</sub><b> </b>+ <b>w</b><sub>y</sub><b> </b>+<b> w</b><sub>z</sub>) x<b> r </b>(cross product is distributive over addition)<b></b></p>
<p>Thus the equivalent linear velocity resulting from these 3 transformations can be expressed as:</p>
<p><b>v</b> = d<b>r/</b>dt = (<b>w</b><sub>x</sub><b> </b>+ <b>w</b><sub>y</sub><b> </b>+<b> w</b><sub>z</sub>) x<b> r </b>= <b>w </b>x<b> r </b>, where we introduce <b>w</b> = <b>w</b><sub>x</sub><b> </b>+ <b>w</b><sub>y</sub><b> </b>+<b> w</b><sub>z</sub> = {w<sub>x </sub>, w<sub>y </sub>, w<sub>z </sub>}</p>
<p>Which looks exactly like <i>(Eq. 2.6) </i>and suggests that<i> </i>the combination of three <b>small</b> rotations about axes x,y,z characterized by angular rotation vectors <b>w</b><sub>x</sub><b> </b>, <b>w</b><sub>y</sub><b> </b>,<b> w</b><sub>z</sub> is equivalent to one <b>small</b> rotation characterized by angular rotation vector <b>w</b> = <b>w</b><sub>x</sub><b> </b>+ <b>w</b><sub>y</sub><b> </b>+<b> w</b><sub>z</sub> = {w<sub>x </sub>, w<sub>y </sub>, w<sub>z </sub>}. Please note that we’re stressing out that these are <b>small</b> rotations, since in general when you combine large rotations the order in which rotations are performed become important and you cannot simply sum them up. Our main assumption that let us go from a linear displacement to a rotation by using <i>(Eq. 2.6) </i>was that dt is really small, and thus the rotations dθ<i><sub> </sub></i>and linear displacement dr are small as well. In practice this means that the larger the dt interval between gyro queries the larger will be our accumulated error, we’ll deal with this error later on. Now, since w<sub>x </sub>, w<sub>y </sub>, w<sub>z </sub>are the output of the gyroscope, then we arrive at the conclusion that in fact a 3 axis gyroscope measures the instantaneous angular velocity of the world rotating about the device’s center.</p>
<h2>Part 4. DCM complimentary filter algorithm using 6DOF or 9DOF IMU sensors</h2>
<p>In the context of this text a 6DOF device is an IMU device consisting of a 3 axis gyroscope and a 3 axis accelerometer. A 9DOF device is an IMU device of a 3 axis gyroscope, a 3 axis accelerometer and a 3 axis magnetometer. Let’s attach a global right-handed coordinate system to the Earth’s frame such that the <b>I </b>versor points North, <b>K </b>versor points to the Zenith and thus, with these two versors fixed, the <b>J </b>versor<b> </b>will be constrained to point<b> </b>West.</p>
<p><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0164.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image016[4]" border="0" alt="clip_image016[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0164_thumb.jpg" width="359" height="331" /></a></p>
<p><i>Figure 3 </i></p>
<p>Also let’s consider the body coordinate system to be attached to our IMU device (acc_gyro used as an example), </p>
<p><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0184.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image018[4]" border="0" alt="clip_image018[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0184_thumb.jpg" width="257" height="175" /></a></p>
<p><i>Figure 4 </i></p>
<p>We already established the fact that gyroscopes can measure the angular velocity vector. Let’s see how accelerometer and magnetometer measurements will fall into our model.</p>
<p>Accelerometers are devices that can sense gravitation. Gravitation vector is pointing towards the center of the earth and is opposite to the vector pointing to Zenith <b>K</b><sup>B</sup>. If the 3 axis accelerometer output is <b>A </b>= {A<sub>x </sub>, Ay , A<sub>z</sub> } and we assume that there are no external accelerations or we have corrected them then we can estimate that <b>K</b><sup>B</sup> = -<b>A</b>. (See this IMU Guide for more clarifications <a href="http://www.starlino.com/imu_guide.html">http://www.starlino.com/imu_guide.html</a>).</p>
<p>Magnetometers are devices that are really similar to accelerometers, except that instead of gravitation they can sense the Earth’s magnetic North. Just like accelerometers they are not perfect and often need corrections and initial calibration. If the corrected 3-axis magnetometer output is <b>M </b>= {M<sub>x </sub>, My , M<sub>z</sub> }, then according to our model <b>I</b><sup>B</sup> is pointing North , thus <b>I</b><sup>B</sup> = <b>M</b>.</p>
<p>Knowing <b>I</b><sup>B</sup> and <b>K</b><sup>B</sup> allows us calculate <b>J</b><sup>B</sup> = <b>K</b><sup>B</sup> x <b>I</b><sup>B</sup>.</p>
<p>Thus an accelerometer and a magnetometer alone can give us the DCM matrix , expressed either as DCM<sup>B</sup> or DCM<sup>G </sup></p>
<p>DCM<sup>G</sup> = DCM<sup>BT</sup> = [<b>I</b><sup>B</sup>,<b> J</b><sup>B</sup>,<b> K</b><sup>B</sup>]<sup>T</sup></p>
<p>The DCM matrix can be used to convert any vector from body’s(devices) coordinate system to the global coordinate system. Thus for example if we know that the nose of the plane has some fixed coordinates expressed in body’s coordinate system as <b>r<sup>B</sup></b> = {1,0,0}, the we can find where the device is heading in other words the coordinates of the nose in global coordinate systems using <i>(Eq. 1.4)</i>:</p>
<p><b>r</b><sup>G</sup><b> </b>= DCM<sup>G</sup> <b>r</b><sup>B</sup></p>
<p>So far you’re asking yourself if an accelerometer and a magnetometer gives us the DCM matrix at any point in time, why do we need the gyroscope ? The gyroscope is actually a more precise device than the accelerometer and magnetomer are , it is used to “fine-tune” the DCM matrix returned by the accelerometer and magnetometer.</p>
<p>Gyroscopes have no sense of absolute orientation of the device , i.e. they don’t know where north is and where zenith is (things that we can find out using the accelerometer and magnetometer), instead if we know the orientation of the device at time t, expressed as a DCM matrix DCM(t) , we can find a more precise orientation DCM(t+dt) using the gyroscope , then the one estimated directly from the accelerometer and magnetometer direct readings which are subject to a lot of noise in form of external (non-gravitational) inertial forces (i.e. acceleration) or magnetically forces that are not caused by the earth’s magnetic field.</p>
<p>These facts call for an algorithm that would combine the readings from all three devices (accelerometer, magnetometer and gyroscope) in order to create our best guess or estimate regarding the device orientation in space (or space’s orientation in device’s coordinate systems), the two orientations are related since they are simply expressed using two DCM matrices that are transpose of one another (DCM<sup>G</sup> = DCM<sup>BT </sup>).</p>
<p>We’ll now go ahead and introduce such an algorithm.</p>
<p>We’ll work with the DCM matrix that consists of the versors of the global (earth’s) coordinate system aligned on each row:</p>
<p><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0204.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image020[4]" border="0" alt="clip_image020[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0204_thumb.gif" width="624" height="149" /></a></p>
<p>If we read the rows of DCM<sup>G</sup> we get the vectors <b>I</b><sup>B</sup>,<b> J</b><sup>B</sup>,<b> K</b><sup>B</sup>. We’ll work mostly with vectors <b>K</b><sup>B</sup> (that can be directly estimated by accelerometer) and vector <b>I</b><sup>B </sup>(that can be directly estimated by the magnetometer). The vector <b>J</b><sup>B </sup>is simply calculated as <b>J</b><sup>B</sup> = <b>K</b><sup>B</sup> x <b>I</b><sup>B</sup> , since it’s orthogonal to the other two vectors (remember versors are unity vectors with same direction as coordinate axes).</p>
<p>Let’s say we know the zenith vector expressed in body frame coordinates at time t<sub>0</sub> and we note it as <b>K</b><sup>B</sup><sub>0. <i></i></sub>Also let’s say we measured our gyro output and we have determined that our angular velocity is <b>w = </b>{w<sub>x </sub>, w<sub>y </sub>, w<sub>z </sub>}. Using our gyro we want to know the position of our zenith vector after a small period of time dt has passed we’ll note it as <b>K</b><sup>B</sup><sub>1G </sub>. And we find it using <i>(Eq. 2.6)</i>:<i></i></p>
<p><b>K</b><sup>B</sup><sub>1G</sub> ≈ <b>K</b><sup>B</sup><sub>0</sub> + dt<b> v </b>= <b>K</b><sup>B</sup><sub>0</sub> + dt (<b>w<sub>g</sub> </b>x<b> K</b><sup>B</sup><sub>0</sub>) = <b>K</b><sup>B</sup><sub>0</sub> + ( d<b>θ<sub>g</sub> </b>x<b> K</b><sup>B</sup><sub>0</sub>) </p>
<p>Where we noted d<b>θ<sub>g</sub> </b>= dt <b>w<sub>g</sub></b>. Because <b>w<sub>g</sub> </b>is angular velocity as measured by the gyroscope. We’ll call d<b>θ<sub>g</sub> </b>angular displacement. In other words it tells us by what <b>small</b> angle (given for all 3 axis in form of a vector) has the orientation of a vector <b>K</b><sup>B</sup> changed during this <b>small</b> period of time dt.</p>
<p>Obviously, another way to estimate <b>K</b><sup>B</sup> is by making another reading from accelerometer so we can get a reading that we note as <b>K</b><sup>B</sup><sub>1A </sub>.</p>
<p>In practice the values <b>K</b><sup>B</sup><sub>1G</sub> will be different from from <b>K</b><sup>B</sup><sub>1A. </sub>One was estimated using our gyroscope and the other was estimated using our accelerometer.</p>
<p>Now it turns out we can go the reverse way and estimate the angular velocity <b>w</b><sub>a</sub> or angular displacement d<b>θ<sub>a ­</sub></b>=<b> </b>dt <b>w<sub>a</sub></b> , from the new accelerometer reading <b>K</b><sup>B</sup><sub>1A­ </sub>, we’ll use <i>(Eq. 2.5):</i></p>
<p><b>w</b>­<sub>a</sub><b> </b>= <b>K</b><sup>B</sup><sub>0</sub> x <b>v<sub>a</sub> </b>/ |<b> K</b><sup>B</sup><sub>0</sub>|<sup>2</sup>­</p>
<p>Now <b>v</b><sub>a </sub>= (<b>K</b><sup>B</sup><sub>1A­ </sub>- <b>K</b><sup>B</sup><sub>0</sub>) / dt , and is basically the linear velocity of the vector <b>K</b><sup>B</sup><sub>0</sub>. And |<b> K</b><sup>B</sup><sub>0</sub>|<sup>2</sup>­­ = 1 , since <b>K</b><sup>B</sup><sub>0</sub> is a unity vector. So we can calculate: </p>
<p>d<b>θ<sub>a ­</sub></b>=<b> </b>dt <b>w<sub>a </sub></b>= <b>K</b><sup>B</sup><sub>0</sub> x (<b>K</b><sup>B</sup><sub>1A­ </sub>- <b>K</b><sup>B</sup><sub>0</sub>)</p>
<p>The idea of calculating a new estimate <b>K</b><sup>B</sup><sub>1 ­</sub> that combines both <b>K</b><sup>B</sup><sub>1A</sub> and <b>K</b><sup>B</sup><sub>1G</sub> is to first estimate d<b>θ </b>as a weighted average of<b> </b>d<b>θ<sub>a</sub> </b>and d<b>θ<sub>g</sub></b> :    <br /><b><sub>       <br /></sub></b>d<b>θ </b>= <b></b>(s<sub>a</sub> d<b>θ<sub>a</sub> </b>+<b> </b>s<sub>g</sub> d<b>θ<sub>g</sub></b>) / (s<sub>a</sub> + s<sub>g­</sub>), we’ll discuss about the weights later on , but shortly they are determined and tuned experimentally in order to achieve a desired response rate and noise rejection.</p>
<p>And then <b>K</b><sup>B</sup><sub>1 ­ </sub>is calculated similar to how we calculated <b>K</b><sup>B</sup><sub>1G</sub>:</p>
<p><b>K</b><sup>B</sup><sub>1</sub> ≈ <b>K</b><sup>B</sup><sub>0</sub> + ( d<b>θ </b>x<b> K</b><sup>B</sup><sub>0</sub>) </p>
<p>Why we went all the way to calculate d<b>θ </b>and did not apply the weighted average formula directly to <b>K</b><sup>B</sup><sub>1A</sub> and <b>K</b><sup>B</sup><sub>1G </sub>? Because d<b>θ </b>can be used to calculate the other elements of our DCM matrix in the same way:</p>
<p><b>I</b><sup>B</sup><sub>1</sub> ≈ <b>I</b><sup>B</sup><sub>0</sub> + ( d<b>θ </b>x<b> I</b><sup>B</sup><sub>0</sub>) </p>
<p><b>J</b><sup>B</sup><sub>1</sub> ≈ <b>J</b><sup>B</sup><sub>0</sub> + ( d<b>θ </b>x<b> J</b><sup>B</sup><sub>0</sub>) </p>
<p>The idea is that all three versors <b>I</b><sup>B</sup>,<b> J</b><sup>B</sup>,<b> K</b><sup>B</sup> are attached to each other and will follow the same angular displacement d<b>θ </b>during our small interval dt. So in a nutshell this is the algorithm that allows us to calculate the DCM<sub>1</sub> matrix at time t<sub>1 </sub>from our previous estimated DCM<sub>0 </sub>matrix at time t­­<sub>0</sub>. It is applied recursively at regular small time intervals dt and gives us an updated DCM matrix at any point in time. The matrix will not drift too much because it is fixed to the absolute position dictated by the accelerometer and will not be too noisy from external accelerations because we also use the gyroscope data to update it.</p>
<p>So far we didn’t mention a word about our magnetometer. One reasons being that it is not available on all IMU units (6DOF) and we can go away without using it, but our resulting orientation will then have a drifting heading (i.e. it will not show if we’re heading north, south, west or east), or we can introduce a virtual magnetometer that is always pointing North, to introduce stability in our model. This situation is demonstrated in the accompanying source code that used a 6DOF IMU.</p>
<p>Now we’ll show how to integrate magnetometer readings into our algorithm. As it turns out it is really simple since magnetometer is really similar to accelerometer (they even use similar calibration algorithms), the only difference being that instead of estimating the Zenith vector <b>K</b><sup>B</sup><sub> </sub>vector it estimates the vector pointing North <b>I</b><sup>B</sup>. Following the same logic as we did for our accelerometer we can determine the angular displacement according to the updated magnetometer reading as being:</p>
<p>d<b>θ<sub>m ­</sub></b>=<b> </b>dt <b>w<sub>m </sub></b>= <b>I</b><sup>B</sup><sub>0</sub> x (<b>I</b><sup>B</sup><sub>1M­ </sub>- <b>I</b><sup>B</sup><sub>0</sub>)</p>
<p>Now let’s incorporate it into our weighted average:</p>
<p>d<b>θ </b>= <b></b>(s<sub>a</sub> d<b>θ<sub>a</sub> </b>+<b> </b>s<sub>g</sub> d<b>θ<sub>g </sub></b>+<b> </b>s<sub>m</sub> d<b>θ<sub>m</sub></b>) / (s<sub>a</sub> + s<sub>g</sub> +<sub>­ </sub>s<sub>m</sub>)</p>
<p>From here we go the same path to calculate the updated DCM<sub>1­</sub></p>
<p><b>I</b><sup>B</sup><sub>1</sub> ≈ <b>I</b><sup>B</sup><sub>0</sub> + ( d<b>θ </b>x<b> I</b><sup>B</sup><sub>0</sub>) , <b>K</b><sup>B</sup><sub>1</sub> ≈ <b>K</b><sup>B</sup><sub>0</sub> + ( d<b>θ </b>x<b> K</b><sup>B</sup><sub>0</sub>) and <b>J</b><sup>B</sup><sub>1 </sub>≈ <b>J</b><sup>B</sup><sub>0</sub> + ( d<b>θ </b>x<b> J</b><sup>B</sup><sub>0</sub>), </p>
<p>In practice we’ll calculate <b>J</b><sup>B</sup><sub>1 </sub>= <b>K</b><sup>B</sup><sub>1 </sub>x <b>I</b><sup>B</sup><sub>1,</sub> after correcting <b>K</b><sup>B</sup><sub>1 </sub>and <b>I</b><sup>B</sup><sub>1 </sub>to be perpendicular unity vectors again , note that all our logic is approximated and dependent on dt being small, the larger the dt the larger the error we’ll accumulate.</p>
<p>So if vectors <b>I</b><sup>B</sup><sub>0</sub>,<b> J</b><sup>B</sup><sub>0</sub>,<b> K</b><sup>B</sup><sub>0 </sub>form a valid DCM matrix , in other words they are orthogonal to each other and are unity vectors, then we can’t say the same about <b>I</b><sup>B</sup><sub>1</sub>,<b> J</b><sup>B</sup><sub>1</sub>,<b> K</b><sup>B</sup><sub>1 </sub>, the formulas used for calculating them does not guarantee the orthogonality or length of the vector to be preserved , however we will not get a big error if dt is small, all we need to do is to correct them after each iteration. </p>
<p>First let’s see how we can ensure that two vectors are orthogonal again. Let’s consider two unity vectors <b>a </b>and <b>b</b> that are “almost orthogonal” in other words the angle between these two vectors is close to 90°, but not exactly 90°. We’re looking to find a vector <b>b’</b> that is orthogonal to <b>a</b> and that is in the same plane formed by the vectors <b>a </b>and <b>b. </b>Such a vector is easy to find as shown in Figure 5. First we find vector <b>c = a x b </b>that by the rules of cross product is orthogonal to both <b>a</b> and <b>b </b>and thus is perpendicular to the plane formed by <b>a</b> and <b>b</b>. Next the vector <b>b’ = c x a </b>is calculated as the cross product of <b>c</b> and <b>a. </b>From the definition of cross product <b>b’ </b>is orthogonal to <b>a </b>and because it is also orthogonal to <b>c</b> &#8211; it end up in the plane orthogonal to <b>c</b> , which is the plane formed by <b>a </b>and <b>b. </b>Thus <b>b’</b> is the corrected vector we’re seeking that is orthogonal to <b>a</b> and belongs to the plane formed by <b>a</b> and <b>b</b>.     <br /><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0224.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image022[4]" border="0" alt="clip_image022[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0224_thumb.jpg" width="307" height="272" /></a></p>
<p><i>Figure 5</i></p>
<p>We can extend the equation using <a href="http://en.wikipedia.org/wiki/Triple_product">the triple product rule</a> and the fact that <b>a.a</b> = |<b>a</b>| = 1:</p>
<p><b>b’</b> = <b>c</b> x <b>a</b> = (<b>a</b> x <b>b</b>) x <b>a</b> = -<b>a</b> (<b>a</b>.<b>b</b>) + b(<b>a</b>.<b>a</b>) = <b>b</b> – <b>a</b> (<b>a.b</b>) = <b>b </b>+<b> d , </b>where <b>d </b>=<b> &#8211; a (a.b) </b>(Scenario 1, <b>a</b> is fixed <b>b</b> is corrected)</p>
<p>You can reflect a little bit on the results … So we obtain corrected vector <b>b’ </b>from vector <b>b </b>by adding a “correction” vector<b> d </b>=<b> &#8211; a (a.b). </b>Notice that <b>d</b> is parallel to <b>a</b>. Its direction is dependent upon the angle between <b>a</b> and <b>b</b>, for example in Figure 5 <b>a</b>.<b>b</b> = cos (<b>a</b>,<b>b</b>) &gt; 0 , because angle between <b>a</b> and <b>b</b> is less than<b> </b>90°thus <b>d </b>has opposite direction from <b>a</b> and a magnitutde of cos(<b>a</b>,<b>b</b>)<b> </b>=<b> </b>sin(<b>b,b’</b>).</p>
<p>In the scenario above we considered that vector <b>a </b>is fixed and we found a corrected vector <b>b’</b> that is orthogonal to <b>a</b>. We can consider the symmetric problem – we fix <b>b</b> and find the corrected vector <b>a’:</b></p>
<p><b>a’ </b>= <b>a</b> – <b>b</b> (<b>b</b>.<b>a</b>) = <b>a</b> – <b>b</b> (<b>a</b>.<b>b</b>) = <b>a</b> + <b>e</b>, where <b>e </b>=<b> </b>-<b> b </b>(<b>a.b</b>) (Scenario 2, <b>b</b> is fixed <b>a</b> is corrected)</p>
<p>Finally in the third scenario we want both vectors to move towards their corrected state, we consider them both “equally wrong”, so intuitively we apply half correction to both vectors from scenario 1 and 2:</p>
<p><b>a’ </b>= <b>a</b> – <b>b</b> (<b>a</b>.<b>b</b>) / 2 (Scenario 3, both <b>a</b> and <b>b</b> are corrected)    <br /><b>b’ </b>= <b>b</b> – <b>a</b> (<b>a</b>.<b>b</b>) / 2</p>
<p><a href="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0244.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image024[4]" border="0" alt="clip_image024[4]" src="http://www.starlino.com/wp-content/uploads/2011/11/clip_image0244_thumb.jpg" width="307" height="272" /></a></p>
<p><i>Figure 6</i></p>
<p>This is an relatively easy formula to calculate on a microprocessor since we can pre-compute Err = (<b>a</b>.<b>b</b>)/2 and then use it to correct both vectors:</p>
<p><b>a’ </b>= <b>a</b> &#8211; Err * <b>b</b>    <br /><b>b’ </b>= <b>b</b> &#8211; Err * <b>a</b></p>
<p>Please note that we’re not proving that <b>a’</b> and <b>b’ </b>are orthogonal in Scenario 3, but we presented the intuitive reasoning why the angle between <b>a’</b> and <b>b’</b> will get closer to 90°if we apply the above corrective transformations. </p>
<p>Now going back to our updated DCM matrix that consists of three vectors <b>I</b><sup>B</sup><sub>1</sub>,<b> J</b><sup>B</sup><sub>1</sub>,<b> </b>we apply the following corrective actions before reintroducing the DCM matrix into the next loop:</p>
<p>Err = ( <b>I</b><sup>B</sup><sub>1</sub> . <b>J</b><sup>B</sup><sub>1 </sub>) / 2</p>
<p><b>I</b><sup>B</sup><sub>1</sub><sup>’ </sup>= <b>I</b><sup>B</sup><sub>1</sub> – Err * <b>J</b><sup>B</sup><sub>1     <br /></sub><b>J</b><sup>B</sup><sub>1</sub><sup>’ </sup>= <b>J</b><sup>B</sup><sub>1</sub> – Err * <b>I</b><sup>B</sup><sub>1     <br /></sub><b>I</b><sup>B</sup><sub>1</sub><sup>’’ </sup>= Normalize[<b>I</b><sup>B</sup><sub>1</sub><sup>’</sup>]    <br /><b>J</b><sup>B</sup><sub>1</sub><sup>’’ </sup>= Normalize[<b>J</b><sup>B</sup><sub>1</sub><sup>’</sup>]    <br /><b>K</b><sup>B</sup><sub>1</sub><sup>’’ </sup>= <b>I</b><sup>B</sup><sub>1</sub><sup>’’</sup> x <b>J</b><sup>B</sup><sub>1</sub><sup>’’</sup></p>
<p>Where Normalize[<b>a</b>] = <b>a </b>/ |<b>a</b>| , is the formula calculating the unit vector co-directional with <b>a</b>. </p>
<p>So finally our corrected DCM<sub>1</sub> matrix can be recomposed from vectors <b>I</b><sup>B</sup><sub>1</sub><sup>’’</sup>, <b>J</b><sup>B</sup><sub>1</sub><sup>’’</sup>, <b>K</b><sup>B</sup><sub>1</sub><sup>’’ </sup>that have been ortho-normalized (each vector constitutes a row of the updated and corrected DCM matrix).</p>
<p>We repeat the loop to find DCM<sub>2 ,</sub> DCM<sub>3 ,</sub> or in general DCM<sub> n </sub>, at any time interval n.</p>
<h2>References </h2>
<p>1. <a href="http://www.amazon.com/gp/product/1441917497/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;tag=librarian06-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399353&amp;creativeASIN=1441917497">Theory of Applied Robotics: Kinematics, Dynamics, and Control (Reza N. Jazar)</a></p>
<p>2. <a href="http://www.amazon.com/gp/product/0321287134/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;tag=librarian06-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399349&amp;creativeASIN=0321287134">Linear Algebra and Its Applications (David C. Lay)</a></p>
<p>3. <a href="http://www.amazon.com/gp/product/0470528338/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;tag=librarian06-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399353&amp;creativeASIN=0470528338">Fundamentals of Matrix Computations (David S. Watkins)</a></p>
<p>4. <a href="http://gentlenav.googlecode.com/files/DCMDraft2.pdf">Direction Cosine Matrix IMU: Theory (W Premerlani)</a></p>
<h2>Additional Notes</h2>
<p>For the implementation of the algorithm for now see my quadcopter project in particular releases 6/7 have a nice <a href="http://processing.org/" target="_blank">Processing </a>program for visual display of the DCM matrix and a model plane. The entire code is on SVN repository:</p>
<p><a href="http://code.google.com/p/picquadcontroller/source/browse/?r=7#svn%2Ftrunk" target="_blank">http://code.google.com/p/picquadcontroller/source/browse/?r=7#svn%2Ftrunk</a>     </p>
<p>The code is in imu.h file:</p>
<p><a href="http://code.google.com/p/picquadcontroller/source/browse/trunk/imu.h?r=7" target="_blank">http://code.google.com/p/picquadcontroller/source/browse/trunk/imu.h?r=7</a>     </p>
<p>A PDF Version of this article is available here</p>
<p><span style="background-color: #ffff00"><strong><a href="http://www.starlino.com/wp-content/uploads/data/dcm_tutorial/Starlino_DCM_Tutorial_01.pdf" target="_blank">DCM Tutorial &#8211; An Introduction to Orientation Kinematics by Starlino (PDF, Rev 0.1 Draft)</a>             </strong></span></p>
<p>Please mention and link to the source when using information in this article: </p>
<p><a href="http://www.starlino.com/dcm_tutorial.html">http://www.starlino.com/dcm_tutorial.html</a> </p>
<p>Starlino Electronics&#160; // Spring , 2011</p>
]]></content:encoded>
			<wfw:commentRss>http://www.starlino.com/dcm_tutorial.html/feed</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>IMU breakout boards from ST</title>
		<link>http://www.starlino.com/new-cheap-imu-breakout-boards-from-st-dont-miss-out.html</link>
		<comments>http://www.starlino.com/new-cheap-imu-breakout-boards-from-st-dont-miss-out.html#comments</comments>
		<pubDate>Thu, 11 Nov 2010 02:20:27 +0000</pubDate>
		<dc:creator>starlino</dc:creator>
				<category><![CDATA[News and Discussions]]></category>
		<category><![CDATA[accelerometer]]></category>
		<category><![CDATA[breakout]]></category>
		<category><![CDATA[gyroscope]]></category>
		<category><![CDATA[imu]]></category>
		<category><![CDATA[magenteometer]]></category>

		<guid isPermaLink="false">http://www.starlino.com/?p=163</guid>
		<description><![CDATA[Sign that someone from ST is reading the blogs &#8211; a series of breakout boards directly from ST , just couple of good ones: $26.95&#160; STEVAL-MKI093V1 ( breakout for LYPR540AH&#160; &#8211; 3 axis analog gyro ) http://www.mouser.com/ProductDetail/STMicroelectronics/STEVAL-MKI093V1/?qs=Mmr5WwCtLzNTGieQUi715w%3d%3d Looks like , Mouser has all datasheet , pictures and descriptions wrong at the time of this post. [...]]]></description>
			<content:encoded><![CDATA[<p>Sign that someone from ST is reading the blogs &#8211; a series of breakout boards directly from ST , just couple of good ones:</p>
<p><img alt="" height="361" src="http://www.starlino.com/wp-content/uploads/11-10-2010 9-13-59 PM.png" width="460" /></p>
<p><strong>$26.95&nbsp; </strong><span id="ctl00_ContentMain_lblManufacturerPartNum">STEVAL-MKI093V1 ( breakout for </span><span id="ctl00_ContentMain_lblDescription">LYPR540AH&nbsp; &#8211; </span><span id="ctl00_ContentMain_lblManufacturerPartNum">3 axis analog gyro )<br />
	</span></p>
<p><a href="http://www.mouser.com/ProductDetail/STMicroelectronics/STEVAL-MKI093V1/?qs=Mmr5WwCtLzNTGieQUi715w%3d%3d">http://www.mouser.com/ProductDetail/STMicroelectronics/STEVAL-MKI093V1/?qs=Mmr5WwCtLzNTGieQUi715w%3d%3d<br />
	</a></p>
<p>Looks like , Mouser has all datasheet , pictures and descriptions wrong at the time of this post.</p>
<p><span id="ctl00_ContentMain_lblManufacturerPartNum">correct datasheet&nbsp;&nbsp; <a href="http://www.st.com/stonline/products/literature/bd/17906/steval-mki093v1.pdf ">http://www.st.com/stonline/products/literature/bd/17906/steval-mki093v1.pdf </a></span></p>
<p>&nbsp;</p>
<p><img alt="" height="374" src="http://www.starlino.com/wp-content/uploads/11-10-2010 9-14-26 PM.png" width="490" /></p>
<p>&nbsp;</p>
<p><span id="ctl00_ContentMain_lblMouserPartNum"><strong>$26.95</strong> STEVAL-MKI064V1 (breakout for </span><span id="ctl00_ContentMain_lblDescription">LSM303DLH&nbsp; 3-axis magnetometer + 3-axis accelerometer)<br />
	</span></p>
<p><a href="http://www.mouser.com/ProductDetail/STMicroelectronics/STEVAL-MKI064V1/?qs=Mmr5WwCtLzNMjRxMWs1ArA%3d%3d"><span>http://www.mouser.com/ProductDetail/STMicroelectronics/STEVAL-MKI064V1/?qs=Mmr5WwCtLzNMjRxMWs1ArA%3d%3d</span><br />
	</a></p>
<p>correct datasheet <a href="http://www.st.com/stonline/products/literature/bd/17844/steval-mki064v1.pdf">http://www.st.com/stonline/products/literature/bd/17844/steval-mki064v1.pdf<br />
	</a></p>
<p>&nbsp;</p>
<p>Order while they are in stock :-)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.starlino.com/new-cheap-imu-breakout-boards-from-st-dont-miss-out.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quadcopter Prototype using Acc_Gyro and a PIC</title>
		<link>http://www.starlino.com/quadcopter_acc_gyro.html</link>
		<comments>http://www.starlino.com/quadcopter_acc_gyro.html#comments</comments>
		<pubDate>Wed, 09 Jun 2010 23:27:15 +0000</pubDate>
		<dc:creator>starlino</dc:creator>
				<category><![CDATA[Quadcopter]]></category>
		<category><![CDATA[accelerometer]]></category>
		<category><![CDATA[gyroscope]]></category>
		<category><![CDATA[imu]]></category>
		<category><![CDATA[pic]]></category>
		<category><![CDATA[quadcopter]]></category>

		<guid isPermaLink="false">http://quadcopter_acc_gyro</guid>
		<description><![CDATA[<p>This article introduces a new project I am working on - a&#160; Quadcopter using Acc_Gyro and a PIC. I share some things I learned along the way so far.</p>]]></description>
			<content:encoded><![CDATA[<p>For anyone following this site, here is what I&#39;ve been up to lately &#8211; building a quadcopter based on the <a href="http://gadgetgangster.com/213">Acc_Gyro 5DOF IMU</a> sensor and a 16bit PIC. Although it&#39;s still a work in progress I decided to start putting together an article placeholder and build it up as project evolves. It&#39;s going to be a long one !</p>
<p>The source code will be Open-Source and will be hosted on Google Code, you can get code for quad copter here:</p>
<p><a href="http://code.google.com/p/picquadcontroller/source/browse/#svn/trunk">http://code.google.com/p/picquadcontroller/source/browse/#svn/trunk</a></p>
<p>As usual I like to start with a video demo, it&#39;s basically me controlling the tilt of the quad using a RC controller:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" height="505" width="640"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/q_BZfG2xYdI&amp;hl=en_US&amp;fs=1&amp;" /><embed allowfullscreen="true" allowscriptaccess="always" height="505" src="http://www.youtube.com/v/q_BZfG2xYdI&amp;hl=en_US&amp;fs=1&amp;" type="application/x-shockwave-flash" width="640"></embed></object></p>
<p><span id="more-22"></span>This is a PID feedback algorithm and a &quot;Simplified Kalman Filter&quot; as&nbsp; described in my other articles.</p>
<p>First of all there&#39;s a a RCGroups thread where I first introduced the project</p>
<p>http://www.rcgroups.com/forums/showthread.php?t=1235360</p>
<p>You&#39;ll find some specs there and I will put some material here&nbsp; as well.</p>
<p>Here is Revision 0.1 of schematic (what I started with):</p>
<p><a href="data/PicQuadController/PicQuadControllerRev01.pdf">PicQuadControllerRev01.pdf</a></p>
<p>The major parts list is as follows:</p>
<p><strong>MCU:</strong>&nbsp; DSPIC33FJ128MC802&nbsp; (<a href="http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en532302">http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en532302</a>)</p>
<p><strong>Sensors</strong>: 5DOF Acc_Gyro ( <a href="http://gadgetgangster.com/213">http://gadgetgangster.com/213</a> )&nbsp; + 1Dof Pololu LIST300AL-BREAKOUT (<a href="http://www.pololu.com/catalog/product/765">http://www.pololu.com/catalog/product/765</a>).</p>
<p><strong>Motor Drivers:</strong>&nbsp; Power N-Channel Mosfets (Many choices -Low Rds(on) and rated for the current , I used&nbsp; IRLR8743 ). Schottky diodes to protect against back-EMF ( I used SS2H10-E3/52T )</p>
<p><strong>Frame , motors propellers</strong>: I picked a ready platform that was on sale <a href="http://www.rctoys.com/rc-toys-and-parts/DF-COMPLETE-AIRFRAME/RC-PARTS-DRAGANFLYER-FRAME.html" target="_blank">Dragandfly IV Frame</a> these are actually brushed motors same ones as used in Esky helicopters.</p>
<p>I did some tests on the lift force potential of this frame+motors+props, and was surprise to find out it performed better than some entry-level brushless motors. The lift force of this platform is up to 2.25 lbs.&nbsp; The results of lift-force experiments are compiled in this spreadheet: <a href="data/PicQuadController/MotorLiftPower.pdf" target="_blank">MotorLiftPower.pdf</a>.</p>
<p>How I measured the lift force ?&nbsp; I didn&#39;t have any fancy equipment so I simply fixed the quad in a vise and weighted&nbsp; it it at different throttle levels &#8211; the difference in weight gave me the lift power.</p>
<p><a href="/wp-content/uploads/data/PicQuadController/IMG_1463.JPG" target="_blank"><img alt="IMG_1463.JPG"  src="/wp-content/uploads/data/PicQuadController/IMG_1463.JPG" width="740" /></p>
</a><p>For testing just one motor, I used a string attached to the weight:</p>
<p><a href="/wp-content/uploads/data/PicQuadController/IMG_1460.JPG" target="_blank"><img alt="IMG_1460.JPG"  src="/wp-content/uploads/data/PicQuadController/IMG_1460.JPG" width="740" /></p>
</a><p>I built a test rig out of wood for testing the tilt balancing algorithm as you see in the video.</p>
<p>Here are some close-ups of the motor drivers. You&#39;ll&nbsp; see the Mosfets and the Schottky diodes, also note the extra solder added to support the high currents that will flow through those traces ( up to 5A per motor !).</p>
<p><a href="/wp-content/uploads/data/PicQuadController/IMG_1465.JPG" target="_blank"><img alt="IMG_1465.JPG"  src="/wp-content/uploads/data/PicQuadController/IMG_1465.JPG" width="740" /></p>
</a><p>Finally here is a view on the top of the board ( notice the PIC , the switching regulator&nbsp; ,&nbsp; Acc_Gyro 5DOF IMU and single axes Gyro breakout , from top-left to bottom right).</p>
<p><a href="/wp-content/uploads/data/PicQuadController/IMG_1466.JPG" target="_blank"><img alt="IMG_1466.JPG"  src="/wp-content/uploads/data/PicQuadController/IMG_1466.JPG" width="740" /></p>
</a><p>This is it for now hope to bring you more interesting stuff on this and other projects if time allows&nbsp; !</p>
<p>//starlino//</p>
]]></content:encoded>
			<wfw:commentRss>http://www.starlino.com/quadcopter_acc_gyro.html/feed</wfw:commentRss>
		<slash:comments>41</slash:comments>
		</item>
		<item>
		<title>Arduino code for IMU Guide algorithm. Using a 5DOF IMU (accelerometer and gyroscope combo)</title>
		<link>http://www.starlino.com/imu_kalman_arduino.html</link>
		<comments>http://www.starlino.com/imu_kalman_arduino.html#comments</comments>
		<pubDate>Fri, 22 Jan 2010 14:03:44 +0000</pubDate>
		<dc:creator>starlino</dc:creator>
				<category><![CDATA[IMU Theory and Experiments]]></category>
		<category><![CDATA[accelerometer]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[filter]]></category>
		<category><![CDATA[gyroscope]]></category>
		<category><![CDATA[imu]]></category>

		<guid isPermaLink="false">http://imu_kalman_arduino</guid>
		<description><![CDATA[<p>This article introduces an&#160; implementation of a simplified filtering algorithm that was inspired by Kalman filter. The Arduino code is tested using a 5DOF IMU unit from GadgetGangster - <a href="http://www.gadgetgangster.com/213">Acc_Gyro</a> . The theory behind this algorithm was first introduced in my <a href="imu_guide.html">Imu Guide article</a>.</p>]]></description>
			<content:encoded><![CDATA[<p>This article introduces an&nbsp; implementation of a simplified filtering algorithm that was inspired by Kalman filter. The Arduino code is tested using a 5DOF IMU unit from GadgetGangster &#8211; <a href="http://www.gadgetgangster.com/367">Acc_Gyro</a> . The theory behind this algorithm was first introduced in my <a href="imu_guide.html">Imu Guide article</a>.</p>
<p>The <a href="http://www.gadgetgangster.com/213">Acc_Gyro</a> is mounted on a regular proto-shield on top of an Arduino Duemilanove board.</p>
<p><img alt="IMG_1359.JPG" src="/wp-content/uploads/data/imu_kalman_arduino/IMG_1359.JPG" /></p>
<p><span id="more-16"></span></p>
<p><strong>Parts needed to complete the project:</strong></p>
<p>- Arduino Duemilanove (or similar Arduino platform)<br />
	- <a href="http://www.gadgetgangster.com/213">Acc_Gyro 5DOF IMU board<br />
	</a>- Protoshield (optional)<br />
	- Breadboard<br />
	- Hook-up wire 22AWG</p>
<p>The hook-up diagram is as follows:</p>
<p><strong>Acc_Gyro</strong> &lt;&#8212;&gt;&nbsp; <strong>Arduino</strong><br />
	5V&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&#8212;&gt;&nbsp; 5V&nbsp; <br />
	GND&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&#8212;&gt;&nbsp; GND<br />
	AX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&#8212;&gt;&nbsp; AN0<br />
	AY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&#8212;&gt;&nbsp; AN1<br />
	AZ&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&#8212;&gt;&nbsp; AN2<br />
	GX4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&#8212;&gt;&nbsp; AN3&nbsp; <br />
	GY4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&#8212;&gt;&nbsp; AN4&nbsp;&nbsp;</p>
<p>Once you have completed the hardware part, load the following sketch to your Arduino.</p>
<p><a href="data/imu_kalman_arduino/Imu_Arduino.zip">imu_arduino.zip</a></p>
<p>Run the project and make sure you are receiving an output on your serial terminal (you can start the terminal from your Arduino IDE).</p>
<p>To analyze the data I have developed a small utility called SerialChart. It is open-source so feel free to customize it for your own needs.</p>
<p>Here is the output from SerialChart software:</p>
<p><img alt="imu_arduino_serial_chart.png" src="/wp-content/uploads/data/imu_kalman_arduino/imu_arduino_serial_chart.png" /></p>
<p>&nbsp;</p>
<p>The test was performed as follows:</p>
<p>- first I was tilting the board slowly (marked &quot;smooth tilting&quot; on the screenshot)</p>
<p>- next I continued tilting the board, but I also started applying some vibration &#8211; by tapping the board quickly with my finger (marked &quot;Titlting with vibration noise&quot;)</p>
<p>As you can see from the chart the filtered&nbsp; signal (red line)&nbsp; is indeed more immune to noise than the accelerometer readings alone (blue line). The filtered signal was obtained by combining the Accelerometer and Gyroscope data. Gyroscope data is important, because if you would simply average the Accelerometer data you would get a delayed signal. Given the simplicity of the code and of the algorithm I am satisfied with the results. One feature that I would like to add is compensation for the drift effect that you might encounter with some gyroscopes. However the Acc_Gyro board proved to be very stable in this respect, since it has built-in high pass filters.</p>
<p>If you&#39;d like to experiment on your own, I recommended first reproducing this testing setup ,&nbsp; then shift slowly towards your application needs. For example you may take the C code and port it to PIC&#39;s C18/C30 or AVR-GCC (it shouldn&#39;t be too dificult).</p>
<p>Below are some useful resources and their descriptions.</p>
<p>SerialChart executables can be downloaded from here:</p>
<p><a href="data/imu_kalman_arduino/SerialChart_01.zip">SerialChart_01.zip</a></p>
<p>Once you start SerialChart application you will need to load the <strong>imu_arduino.scc</strong> configuration file for this project(included in the <a href="data/imu_kalman_arduino/Imu_Arduino.zip">imu_arduino.zip</a>) archive.</p>
<p>In this configuration file make sure to update the &#39;port&#39; settings to Arduino&#39;s COM port. On my computer Arduino was detected on COM3, on yours it might be different.</p>
<p>For more information on configuration file syntax see:</p>
<p><a href="http://code.google.com/p/serialchart/wiki/ConfigurationFileSyntax" target="_blank">http://code.google.com/p/serialchart/wiki/ConfigurationFileSyntax</a></p>
<p>You can also download and compile SerialChart from Google Code:</p>
<p><a href="http://code.google.com/p/serialchart/source/browse/#svn/trunk">http://code.google.com/p/serialchart/source/browse/#svn/trunk</a></p>
<p>You will need a SVN client to checkout the code (I use RapidSVN for Windows).</p>
<p>SerialChart was developed using&nbsp; Qt SDK from Nokia: <a href="http://qt.nokia.com/downloads">http://qt.nokia.com/downloads</a></p>
<p>&nbsp;</p>
<p><strong>UPDATE 2010-03-18</strong></p>
<p>Many people ask me what about the other 2 axis, here is the code that outputs 3 axis, including the SerialChart configuration script.</p>
<p><a href="data/imu_kalman_arduino/Imu_Arduino_3axis_output_2010-03-18.zip">Imu_Arduino_3axis_output_2010-03-18.zip</a></p>
<p>I also removed some overhead code that Alex pointed out in the comments, this reduced the interval between samples.</p>
<p>In the example below I rotate the board around the X axis(blue) which is parallel to the ground.I do it by hand so X is not exactly 0, but close. The axes that change are Y(red) and Z(green).&nbsp; Please note the relationship X^2+Y^2+Z^2 = 1. The dashed&nbsp; cyan, magenta and lime lines are unfiltered signals coming from accelerometer alone (RwAcc).</p>
<p><img alt="imu_kalman_arduino_3_axis_captured.png" src="/wp-content/uploads/data/imu_kalman_arduino/imu_kalman_arduino_3_axis_captured.png" /></p>
<p>&nbsp;</p>
<p>//starlino//</p>
]]></content:encoded>
			<wfw:commentRss>http://www.starlino.com/imu_kalman_arduino.html/feed</wfw:commentRss>
		<slash:comments>70</slash:comments>
		</item>
		<item>
		<title>A Guide To using  IMU (Accelerometer and Gyroscope Devices)  in Embedded Applications.</title>
		<link>http://www.starlino.com/imu_guide.html</link>
		<comments>http://www.starlino.com/imu_guide.html#comments</comments>
		<pubDate>Tue, 29 Dec 2009 17:39:13 +0000</pubDate>
		<dc:creator>starlino</dc:creator>
				<category><![CDATA[IMU Theory and Experiments]]></category>
		<category><![CDATA[accelerometer]]></category>
		<category><![CDATA[Acc_Gyro]]></category>
		<category><![CDATA[gyroscope]]></category>
		<category><![CDATA[imu]]></category>
		<category><![CDATA[motion]]></category>

		<guid isPermaLink="false">http://imu_guide</guid>
		<description><![CDATA[<p>This article discussed the theory behind accelerometer and gyroscope devices. It shows a simple&#160; Kalman filter alternative, that allows you to combine accelerometer and gyroscope data in order to obtain more accurate estimates about the inclination of the device relative to the ground plane.</p>]]></description>
			<content:encoded><![CDATA[<h2>Introduction</h2>
<p>This guide is intended to everyone interested in inertial MEMS (Micro-Electro-Mechanical Systems) sensors, in particular Accelerometers and Gyroscopes as well as combination IMU devices (<a href="http://en.wikipedia.org/wiki/Inertial_measurement_unit" title="Inertial Measurment Unit">Inertial Measurement Unit</a>).</p>
<p><a href="http://www.starlino.com/store/acc-gyro" target="_blank"><img alt="Acc_Gyro_6DOF  and UsbThumb MCU unit" height="332" src="http://www.starlino.com/wp-content/uploads/data/imu_guide/acc_gyro_6dof_usbthumb.jpg" width="720" /></a></p>
<p><em><strong>Example IMU unit:</strong>&nbsp; <a href="http://www.starlino.com/store/acc-gyro" target="_blank">Acc_Gyro_6DOF</a> on top of MCU processing unit <a href="http://www.gadgetgangster.com/240" target="_blank">UsbThumb</a> providing USB/Serial connectivity<br />
	</em></p>
<p>I&#39;ll try try to cover few basic but important topics in this article:</p>
<p>- what does an accelerometer measure<br />
	- what does a gyroscope (aka gyro) measure <br />
	- how to convert analog-to-digital (ADC) readings that you get from these sensor to physical units (those would be g for accelerometer, deg/s for gyroscope)<br />
	- how to combine accelerometer and gyroscope readings in order to obtain accurate information about the inclination of your device relative to the ground plane</p>
<p><span id="more-15"></span>Throughout the article I will try to keep the math to the minimum. If you know what Sine/Cosine/Tangent are then you should be able to understand and use these ideas in your project no matter what platform you&#39;re using Arduino, Propeller, Basic Stamp, Atmel chips, Microchip PIC, etc. There are people out there who believe that you need complex math in order to make use of an IMU unit (complex FIR or IIR filters such as Kalman filters, Parks-McClellan filters, etc). You can research all those and achieve wonderful but complex results. My way of explaining things require just basic math. I am a great believer in simplicity. I think a system that is simple is easier to control and monitor, besides many embedded devices do not have the power and resources to implement complex algorithms requiring matrix calculations.</p>
<p>I&#39;ll use as an example a new IMU unit that I designed &#8211; the <a href="http://www.starlino.com/store/acc-gyro" target="_blank" title="Acc_Gyro Accelerometer + Gyro IMU">Acc_Gyro Accelerometer + Gyro IMU.</a> We&#39;ll use parameters of this device in our examples below. This unit is a good device to start with because it consists of 3 devices:</p>
<p>- LIS331AL (<a href="http://www.starlino.com/wp-content/uploads/data/acc_gyro/LIS331AL.pdf" target="_blank">datasheet</a>) &#8211; analog 3-axis 2G accelerometer <br />
	- LPR550AL (<a href="http://www.starlino.com/wp-content/uploads/data/acc_gyro/LPR550AL.pdf" target="_blank">datasheet</a>) &#8211; a dual-axis (Pitch and Roll), 500deg/second gyroscope <br />
	- LY550ALH (<a href="http://www.starlino.com/wp-content/uploads/data/acc_gyro/LY550ALH.pdf" rel="nofollow" target="_blank">datasheet</a>) &#8211; a single axis (Yaw) gyroscope (this last device is not used in this tutorial but it becomes relevant when you move on to <a href="http://starlino.com/dcm_tutorial.html" target="_blank">DCM Matrix implementation</a>)</p>
<p>Together they represent a 6-Degrees of Freedom Inertial Measurement Unit. Now that&#39;s a fancy name! Nevertheless, behind the fancy name is a very useful combination device that we&#39;ll cover and explain in detail below.</p>
<h2>Part 1. Accelerometer</h2>
<p>To understand this unit we&#39;ll start with the accelerometer. When thinking about accelerometers it is often useful to image a box in shape of a cube with a ball inside it. You may imagine something else like a cookie or a donut , but I&#39;ll imagine a ball:</p>
<p><img alt="accelerometer model" height="310" src="/wp-content/uploads/data/imu_guide/04.png" width="450" /></p>
<p>If we take this box in a place with no gravitation fields or for that matter with no other fields that might affect the ball&#39;s position &#8211; the ball will simply float in the middle of the box. You can imagine the box is in outer-space far-far away from any cosmic bodies, or if such a place is hard to find imagine at least a space craft orbiting around the planet where everything is in weightless state . From the picture above you can see that we assign to each axis a pair of walls (we removed the wall Y+ so we can look inside the box). Imagine that each wall is pressure sensitive. If we move suddenly the box to the left (we accelerate it with acceleration 1g = 9.8m/s^2), the ball will hit the wall X-. We then measure the pressure force that the ball applies to the wall and output a value of -1g on the X axis.</p>
<p><img alt="accelerometer model" height="280" src="/wp-content/uploads/data/imu_guide/05.png" width="450" /></p>
<p>Please note that the accelerometer will actually detect a force that is directed in the opposite direction from the acceleration vector. This force is often called <a href="http://en.wikipedia.org/wiki/Fictitious_force">Inertial Force or Fictitious Force </a>. One thing you should learn from this is that an accelerometer measures acceleration indirectly through a force that is applied to one of it&#39;s walls (according to our model, it might be a spring or something else in real life accelerometers). This force can be caused by the acceleration , but as we&#39;ll see in the next example it is not always caused by acceleration.</p>
<p>If we take our model and put it on Earth the ball will fall on the Z- wall and will apply a force of 1g on the bottom wall, as shown in the picture below:</p>
<p><img alt="accelerometer model" height="300" src="/wp-content/uploads/data/imu_guide/06.png" width="450" /></p>
<p>In this case the box isn&#39;t moving but we still get a reading of -1g on the Z axis. The pressure that the ball has applied on the wall was caused by a gravitation force. In theory it could be a different type of force &#8211; for example, if you imagine that our ball is metallic, placing a magnet next to the box could move the ball so it hits another wall. This was said just to prove that in essence accelerometer measures force not acceleration. It just happens that acceleration causes an inertial force that is captured by the force detection mechanism of the accelerometer.</p>
<p>While this model is not exactly how a MEMS sensor is constructed it is often useful in solving accelerometer related problems. There are actually similar sensors that have metallic balls inside, they are called tilt switches, however they are more primitive and usually they can only tell if the device is inclined within some range or not, not the extent of inclination.</p>
<p>So far we have analyzed the accelerometer output on a single axis and this is all you&#39;ll get with a single axis accelerometers. The real value of triaxial accelerometers comes from the fact that they can detect inertial forces on all three axes. Let&#39;s go back to our box model, and let&#39;s rotate the box 45 degrees to the right. The ball will touch 2 walls now: Z- and X- as shown in the picture below:</p>
<p><img alt="accelerometer model" height="390" src="/wp-content/uploads/data/imu_guide/07.png" width="450" /></p>
<p>The values of 0.71 are not arbitrary, they are actually an approximation for SQRT(1/2). This will become more clear as we introduce our next model for the accelerometer.</p>
<p>In the previous model we have fixed the gravitation force and rotated our imaginary box. In last 2 examples we have analyzed the output in 2 different box positions, while the force vector remained constant. While this was useful in understanding how the accelerometer interacts with outside forces, it is more practical to perform calculations if we fix the coordinate system to the axes of the accelerometer and imagine that the force vector rotates around us.</p>
<p><img alt="accelerometer model" height="370" src="/wp-content/uploads/data/imu_guide/01.png" width="450" /></p>
<p>Please have a look at the model above, I preserved the colors of the axes so you can make a mental transition from the previous model to the new one. Just imagine that each axis in the new model is perpendicular to the respective faces of the box in the previous model. The vector R is the force vector that the accelerometer is measuring (it could be either the gravitation force or the inertial force from the examples above or a combination of both). Rx, Ry, Rz are projection of the R vector on the X,Y,Z axes. Please notice the following relation:</p>
<p>R^2 = Rx^2 + Ry^2 + Rz^2 <strong>&nbsp;&nbsp;&nbsp;&nbsp;(Eq. 1)</strong></p>
<p>which is basically the equivalent of the <a href="http://demonstrations.wolfram.com/PythagoreanTheorem3D/">Pythagorean theorem in 3D</a>.</p>
<p>Remember that a little bit earlier I told you that the values of SQRT(1/2) ~ 0.71 are not random. If you plug them in the formula above, after recalling that our gravitation force was 1 g we can verify that:</p>
<p>1^2 = (-SQRT(1/2) )^2 + 0 ^2 + (-SQRT(1/2))^2</p>
<p>simply by substituting R=1, Rx = -SQRT(1/2), Ry = 0 , Rz = -SQRT(1/2) in <strong>Eq.1</strong></p>
<p>After a long preamble of theory we&#39;re getting closer to real life accelerometers. The values Rx, Ry, Rz are actually linearly related to the values that your real-life accelerometer will output and that you can use for performing various calculations.</p>
<p>Before we get there let&#39;s talk a little about the way accelerometers will deliver this information to us. Most accelerometers will fall in two categories: digital and analog. Digital accelerometers will give you information using a serial protocol like I2C , SPI or USART, while analog accelerometers will output a voltage level within a predefined range that you have to convert to a digital value using an ADC (analog to digital converter) module. I will not go into much detail about how ADC works, partly because it is such an extensive topic and partly because it is different from one platform to another. Some microcontroller will have a built-in ADC modules some of them will need external components in order to perform the ADC conversions. No matter what type of ADC module you use you&#39;ll end up with a value in a certain range. For example a 10-bit ADC module will output a value in the range of 0..1023, note that 1023 = 2^10 -1. A 12-bit ADC module will output a value in the range of 0..4095, note that 4095 = 2^12-1.</p>
<p>Let&#39;s move on by considering a simple example, suppose our 10bit ADC module gave us the following values for the three accelerometer channels (axes):</p>
<p>AdcRx = 586<br />
	AdcRy = 630<br />
	AdcRz = 561</p>
<p>Each ADC module will have a reference voltage, let&#39;s assume in our example it is 3.3V. To convert a 10bit adc value to voltage we use the following formula:</p>
<p>VoltsRx = AdcRx * Vref / 1023</p>
<p>A quick note here: that for 8bit ADC the last divider would be 255 = 2 ^ 8 -1 , and for 12bit ADC last divider would be 4095 = 2^12 -1.</p>
<p>Applying this formula to all 3 channels we get:</p>
<p>VoltsRx = 586 * 3.3V / 1023 =~ 1.89V (we round all results to 2 decimal points)<br />
	VoltsRy = 630 * 3.3V / 1023 =~ 2.03V<br />
	VoltsRz = 561 * 3.3V / 1023 =~ 1.81V</p>
<p>Each accelerometer has a zero-g voltage level, you can find it in specs, this is the voltage that corresponds to 0g. To get a signed voltage value we need to calculate the shift from this level. Let&#39;s say our 0g voltage level is VzeroG = 1.65V. We calculate the voltage shifts from zero-g voltage as follows::</p>
<p>DeltaVoltsRx = 1.89V &#8211; 1.65V = 0.24V<br />
	DeltaVoltsRy = 2.03V &#8211; 1.65V = 0.38V<br />
	DeltaVoltsRz = 1.81V &#8211; 1.65V = 0.16V</p>
<p>We now have our accelerometer readings in Volts , it&#39;s still not in g (9.8 m/s^2), to do the final conversion we apply the accelerometer sensitivity, usually expressed in mV/g. Lets say our Sensitivity = 478.5mV/g = 0.4785V/g. Sensitivity values can be found in accelerometer specifications. To get the final force values expressed in g we use the following formula:</p>
<p>Rx = DeltaVoltsRx / Sensitivity</p>
<p>Rx = 0.24V / 0.4785V/g =~ 0.5g<br />
	Ry = 0.38V / 0.4785V/g =~ 0.79g<br />
	Rz = 0.16V / 0.4785V/g =~ 0.33g</p>
<p>We could of course combine all steps in one formula, but I went through all the steps to make it clear how you go from ADC readings to a force vector component expressed in g.</p>
<p>Rx = (AdcRx * Vref / 1023 &#8211; VzeroG) / Sensitivity <strong>(Eq.2</strong>)<br />
	Ry = (AdcRy * Vref / 1023 &#8211; VzeroG) / Sensitivity<br />
	Rz = (AdcRz * Vref / 1023 &#8211; VzeroG) / Sensitivity</p>
<p>We now have all 3 components that define our inertial force vector, if the device is not subject to other forces other than gravitation, we can assume this is the direction of our gravitation force vector. If you want to calculate inclination of device relative to the ground you can calculate the angle between this vector and Z axis. If you are also interested in per-axis direction of inclination you can split this result into 2 components: inclination on the X and Y axis that can be calculated as the angle between gravitation vector and X / Y axes. Calculating these angles is more simple than you might think, now that we have calculated the values for Rx,Ry and Rz. Let&#39;s go back to our last accelerometer model and do some additional notations:</p>
<p><img alt="" height="370" src="/wp-content/uploads/data/imu_guide/02.png" width="450" /></p>
<p>The angles that we are interested in are the angles between X,Y,Z axes and the force vector R. We&#39;ll define these angles as Axr, Ayr, Azr. You can notice from the right-angle triangle formed by R and Rx that:</p>
<p>cos(Axr) = Rx / R , and similarly :<br />
	cos(Ayr) = Ry / R<br />
	cos(Azr) = Rz / R</p>
<p>We can deduct from <strong>Eq.1</strong> that R = SQRT( Rx^2 + Ry^2 + Rz^2).</p>
<p>We can find now our angles by using arccos() function (the inverse cos() function ):</p>
<p>Axr = arccos(Rx/R)<br />
	Ayr = arccos(Ry/R)<br />
	Azr = arccos(Rz/R)</p>
<p>We&#39;ve gone a long way to explain the accelerometer model, just to come up to these formulas. Depending on your applications you might want to use any intermediate formulas that we have derived. We&#39;ll also introduce the gyroscope model soon, and we&#39;ll see how accelerometer and gyroscope data can be combined to provide even more accurate inclination estimations.</p>
<p>But before we do that let&#39;s do some more useful notations:</p>
<p>cosX = cos(Axr) = Rx / R<br />
	cosY = cos(Ayr) = Ry / R<br />
	cosZ = cos(Azr) = Rz / R</p>
<p>This triplet is often called <a href="http://en.wikipedia.org/wiki/Direction_cosine" target="_blank">Direction Cosine</a> , and it basically represents the unit vector (vector with length 1) that has same direction as our R vector. You can easily verify that:</p>
<p>SQRT(cosX^2 + cosY^2 + cosZ^2) = 1</p>
<p>This is a nice property since it absolve us from monitoring the modulus(length) of R vector. Often times if we&#39;re just interested in direction of our inertial vector, it makes sense to normalize it&#39;s modulus in order to simplify other calculations.</p>
<h2>Part 2. Gyroscope</h2>
<p>We&#39;re not going to introduce any equivalent box model for the gyroscope like we did for accelerometer, instead we&#39;re going to jump straight to the second accelerometer model and we&#39;ll show what does the gyroscope measure according to this model.</p>
<p><img alt="" height="380" src="/wp-content/uploads/data/imu_guide/03.png" width="450" /></p>
<p>Each gyroscope channel measures the rotation around one of the axes. For instance a 2-axes gyroscope will measure the rotation around (or some may say &quot;about&quot;) the X and Y axes. To express this rotation in numbers let&#39;s do some notations. First let&#39;s define:</p>
<p>Rxz &#8211; is the projection of the inertial force vector R on the XZ plane<br />
	Ryz &#8211; is the projection of the inertial force vector R on the YZ plane</p>
<p>From the right-angle triangle formed by Rxz and Rz, using Pythagorean theorem we get:</p>
<p>Rxz^2 = Rx^2 + Rz^2 , and similarly:<br />
	Ryz^2 = Ry^2 + Rz^2</p>
<p>also note that:</p>
<p>R^2 = Rxz^2 + Ry^2 , this can be derived from<strong> Eq.1</strong> and above equations, or it can be derived from right-angle triangle formed by R and Ryz<br />
	R^2 = Ryz^2 + Rx^2</p>
<p>We&#39;re not going to use these formulas in this article but it is useful to note the relation between all the values in our model.</p>
<p>Instead we&#39;re going to define the angle between the Z axis and Rxz, Ryz vectors as follows:</p>
<p>Axz &#8211; is the angle between the Rxz (projection of R on XZ plane) and Z axis<br />
	Ayz &#8211; is the angle between the Ryz (projection of R on YZ plane) and Z axis</p>
<p>Now we&#39;re getting closer to what the gyroscope measures. Gyroscope measures the rate of changes of the angles defined above. In other words it will output a value that is linearly related to the rate of change of these angles. To explain this let&#39;s assume that we have measured the rotation angle around axis Y (that would be Axz angle) at time t0, and we define it as Axz0, next we measured this angle at a later time t1 and it was Axz1. The rate of change will be calculated as follows:</p>
<p>RateAxz = (Axz1 &#8211; Axz0) / (t1 &#8211; t0).</p>
<p>If we express Axz in degrees, and time in seconds , then this value will be expressed in deg/s . This is what a gyroscope measures.</p>
<p>In practice a gyroscope(unless it is a special digital gyroscope) will rarely give you a value expressed in deg/s. Same as for accelerometer you&#39;ll get an ADC value that you&#39;ll need to convert to deg/s using a formula similar to <strong>Eq. 2</strong> that we have defined for accelerometer. Let&#39;s introduce the ADC to deg/s conversion formula for gyroscope (we assume we&#39;re using a 10bit ADC module , for 8bit ADC replace 1023 with 255, for 12bit ADC replace 1023 with 4095).</p>
<p>RateAxz = (AdcGyroXZ * Vref / 1023 &#8211; VzeroRate) / Sensitivity <strong>Eq.3</strong><br />
	RateAyz = (AdcGyroYZ * Vref / 1023 &#8211; VzeroRate) / Sensitivity</p>
<p>AdcGyroXZ, AdcGyroYZ &#8211; are obtained from our adc module and they represent the channels that measure the rotation of projection of R vector in XZ respectively in YZ planes, which is the equivalent to saying rotation was done around Y and X axes respectively.</p>
<p>	Vref &#8211; is the ADC reference voltage we&#39;ll use 3.3V in the example below</p>
<p>	VzeroRate &#8211; is the zero-rate voltage, in other words the voltage that the gyroscope outputs when it is not subject to any rotation, for the <a href="http://gadgetgangster.com/213" target="_blank">Acc_Gyro</a> board it is for example 1.23V (you can find this values in the specs &#8211; but don&#39;t trust the specs most gyros will suffer slight offset after being soldered so measure VzeroRate for each axis output using a voltmeter, usually this value will not change over time once the gyro was soldered, if it variates &#8211; write a calibration routine to measure it before device start-up, user must be instructed to keep device in still position&nbsp; upon start-up for gyros to calibrate).</p>
<p>	Sensitivity &#8211; is the sensitivity of your gyroscope it is expressed in mV / (deg / s) often written as mV/deg/s , it basically tells you how many mV will the gyroscope output increase , if you increase the rotation speed by one deg/s. The sensitivity of <a href="http://gadgetgangster.com/213" target="_blank">Acc_Gyro</a> board is for example 2mV/deg/s or 0.002V/deg/s</p>
<p>Let&#39;s take an example, suppose our ADC module returned following values:</p>
<p>AdcGyroXZ = 571<br />
	AdcGyroXZ = 323</p>
<p>Using the above formula, and using the specs parameters of <a href="http://gadgetgangster.com/213" target="_blank">Acc_Gyro</a> board we&#39;ll get:</p>
<p>RateAxz = (571 * 3.3V / 1023 &#8211; 1.23V) / ( 0.002V/deg/s) =~ 306 deg/s<br />
	RateAyz = (323 * 3.3V / 1023 &#8211; 1.23V) / ( 0.002V/deg/s) =~ -94 deg/s</p>
<p>In other words the device rotates around the Y axis (or we can say it rotates in XZ plane) with a speed of 306 deg/s and around the X axis (or we can say it rotates in YZ plane) with a speed of -94 deg/s. Please note that the negative sign means that the device rotates in the opposite direction from the conventional positive direction. By convention one direction of rotation is positive. A good gyroscope specification sheet will show you which direction is positive, otherwise you&#39;ll have to find it by experimenting with the device and noting which direction of rotation results in increasing voltage on the output pin. This is best done using an oscilloscope since as soon as you stop the rotation the voltage will drop back to the zero-rate level. If you&#39;re using a multimeter you&#39;d have to maintain a constant rotation rate for at least few seconds and note the voltage during this rotation, then compare it with the zero-rate voltage. If it is greater than the zero-rate voltage it means that direction of rotation is positive.</p>
<h2>Part 3. Putting it all together. Combining accelerometer and gyroscope data.</h2>
<p>If you&#39;re reading this article you probably acquired or are planning to acquire a IMU device, or probably you&#39;re planning to build one from separate accelerometer and gyroscope devices.</p>
<p><strong>NOTE: </strong>FOR PRACTICAL IMPLEMENTATION AND TESTING&nbsp; OF THIS ALGORITHM PLEASE READ THIS ARTICLE:</p>
<p><a href="imu_kalman_arduino.html">http://starlino.com/imu_kalman_arduino.html</a><strong><br />
	</strong></p>
<p>&nbsp;</p>
<p>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 <a href="http://gadgetgangster.com/213" target="_blank">Acc_Gyro</a> board:</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><img alt="acc_gyro axes" height="164" src="/wp-content/uploads/data/imu_guide/acc_gyro_axes.png" width="272" /></p>
<p>Next steps are:</p>
<p>- identify the gyroscope outputs that correspond to RateAxz , RateAyz values discussed above. <br />
	- determine if these outputs need to be inverted due to physical position of gyroscope relative to the accelerometer</p>
<p>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.</p>
<p>Here is a sample sequence to determine which output of gyroscope corresponds to RateAxz value discussed above.</p>
<p>- start from placing the device in horizontal position. Both X and Y outputs of accelerometer would output the zero-g voltage (for example for <a href="http://gadgetgangster.com/213" target="_blank">Acc_Gyro</a> board this is 1.65V)<br />
	- 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. <br />
	- while rotating the device at a constant speed note which gyroscope output changes, the other gyroscope outputs should remain constant<br />
	- 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<br />
	- 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<br />
	- 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 decrease. This is due to the fact that we are monitoring the gravitation vector and when device rotates in one direction the vector will rotate in oposite direction (relative to the device coordonate system, which we are using). So, otherwise you need to invert RateAxz , you can achieve this by introducing a sign factor in <strong>Eq.3</strong>, as follows:</p>
<p>RateAxz = InvertAxz * (AdcGyroXZ * Vref / 1023 &#8211; VzeroRate) / Sensitivity , where InvertAxz is 1 or -1</p>
<p>same test can 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:</p>
<p>RateAyz = InvertAyz * (AdcGyroYZ * Vref / 1023 &#8211; VzeroRate) / Sensitivity</p>
<p>If you would do these tests on <a href="http://gadgetgangster.com/213">Acc_Gyro</a> board you would get following results:</p>
<p>- the output pin for RateAxz is GX4 and InvertAxz = 1<br />
	- the output pin for RateAyz is GY4 and InvertAyz = 1</p>
<p>From this point on we&#39;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&#39;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.</p>
<p>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&#39;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 ?</p>
<p>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.</p>
<p>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&#39;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 &#8211; don&#39;t we already have these values Rx, Ry , Rz from <strong>Eq.2</strong> 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&#39;s re-define the accelerometer measurements as follows:</p>
<p>Racc &#8211; is the inertial force vector as measured by accelerometer, that consists of following components (projections on X,Y,Z axes):</p>
<p>RxAcc = (AdcRx * Vref / 1023 &#8211; VzeroG) / Sensitivity<br />
	RyAcc = (AdcRy * Vref / 1023 &#8211; VzeroG) / Sensitivity<br />
	RzAcc = (AdcRz * Vref / 1023 &#8211; VzeroG) / Sensitivity</p>
<p>So far we have a set of measured values that we can obtain purely from accelerometer ADC values. We&#39;ll call this set of data a &quot;vector&quot; and we&#39;ll use the following notation.</p>
<p>Racc = [RxAcc,RyAcc,RzAcc]</p>
<p>Because these components of Racc can be obtained from accelerometer data , we can consider it an input to our algorithm.</p>
<p>Please note that because Racc measures the gravitation force you&#39;ll be correct if you assume that the length of this vector defined as follows is equal or close to 1g.</p>
<p>|Racc| = SQRT(RxAcc^2 +RyAcc^2 + RzAcc^2),</p>
<p>However to be sure it makes sense to update this vector as follows:</p>
<p>Racc(normalized) = [RxAcc/|Racc| , RyAcc/|Racc| , RzAcc/|Racc|].</p>
<p>This will ensure the length of your normalized Racc vector is always 1.</p>
<p>Next we&#39;ll introduce a new vector and we&#39;ll call it</p>
<p>Rest = [RxEst,RyEst,RzEst]</p>
<p>This will be the output of our algorithm , these are corrected values based on gyroscope data and based on past estimated data.</p>
<p>Here is what our algorithm will do:<br />
	- accelerometer tells us: &quot;You are now at position Racc&quot;<br />
	- we say &quot;Thank you, but let me check&quot;,<br />
	- then correct this information with gyroscope data as well as with past Rest data and we output a new estimated vector Rest. <br />
	- we consider Rest to be our &quot;best bet&quot; as to the current position of the device.</p>
<p>Let&#39;s see how we can make it work.</p>
<p>We&#39;ll start our sequence by trusting our accelerometer and assigning:</p>
<p>Rest(0) = Racc(0)</p>
<p>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:</p>
<p>RxEst(0) = RxAcc(0)<br />
	RyEst(0) = RyAcc(0)<br />
	RzEst(0) = RzAcc(0)</p>
<p>Next we&#39;ll do regular measurements at equal time intervals of T seconds, and we&#39;ll obtain new measurements that we&#39;ll define as Racc(1), Racc(2) , Racc(3) and so on. We&#39;ll also issue new estimates at each time intervals Rest(1), Rest(2), Rest(3) and so on.</p>
<p>Suppose we&#39;re at step n. We have two known sets of values that we&#39;d like to use:</p>
<p>Rest(n-1) &#8211; our previous estimate, with Rest(0) = Racc(0)<br />
	Racc(n) &#8211; our current accelerometer measurement</p>
<p>Before we can calculate Rest(n) , let&#39;s introduce a new measured value, that we can obtain from our gyroscope and a previous estimate.</p>
<p>We&#39;ll call it Rgyro , and it is also a vector consisting of 3 components:</p>
<p>Rgyro = [RxGyro,RyGyro,RzGyro]</p>
<p>We&#39;ll calculate this vector one component at a time. We&#39;ll start with RxGyro.</p>
<p><img alt="gyro model" height="380" src="/wp-content/uploads/data/imu_guide/03.png" width="450" /></p>
<p>Let&#39;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:</p>
<p>tan(Axz) = Rx/Rz =&gt; Axz = atan2(Rx,Rz)</p>
<p>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 <a href="http://en.wikipedia.org/wiki/Atan2" target="_blank">atan2 here</a>.</p>
<p>So knowing RxEst(n-1) , and RzEst(n-1) we can find:</p>
<p>Axz(n-1) = atan2( RxEst(n-1) , RzEst(n-1) ).</p>
<p>Remember that gyroscope measures the rate of change of the Axz angle. So we can estimate the new angle Axz(n) as follows:</p>
<p>Axz(n) = Axz(n-1) + RateAxz(n) * T</p>
<p>Remember that RateAxz can be obtained from our gyroscope ADC readings. A more precise formula can use an average rotation rate calculated as follows:</p>
<p>RateAxzAvg = ( RateAxz(n) + RateAxz(n-1) ) / 2 <br />
	Axz(n) = Axz(n-1) + RateAxzAvg * T</p>
<p>The same way we can find:</p>
<p>Ayz(n) = Ayz(n-1) + RateAyz(n) * T</p>
<p>Ok so now we have Axz(n) and Ayz(n). Where do we go from here to deduct RxGyro/RyGyro ? From <strong>Eq. 1</strong> we can write the length of vector Rgyro as follows:</p>
<p>|Rgyro| = SQRT(RxGyro^2 + RyGyro^2 + RzGyro^2)</p>
<p>Also because we normalized our Racc vector, we may assume that it&#39;s length is 1 and it hasn&#39;t changed after the rotation, so it is relatively safe to write:</p>
<p>|Rgyro| = 1</p>
<p>Let&#39;s adopt a temporary shorter notation for the calculations below:</p>
<p>x =RxGyro , y=RyGyro, z=RzGyro</p>
<p>Using the relations above we can write:</p>
<p>x = x / 1 = x / SQRT(x^2+y^2+z^2)</p>
<p>Let&#39;s divide numerator and denominator of fraction by SQRT(x^2 + z^2)</p>
<p>x = ( x / SQRT(x^2 + z^2) ) / SQRT( (x^2 + y^2 + z^2) / (x^2 + z^2) )</p>
<p>Note that x / SQRT(x^2 + z^2) = sin(Axz), so:</p>
<p>x = sin(Axz) / SQRT (1 + y^2 / (x^2 + z^2) )</p>
<p>Now multiply numerator and denominator of fraction inside SQRT by z^2</p>
<p>x = sin(Axz) / SQRT (1 + y^2&nbsp; * z ^2 / (z^2 * (x^2 + z^2)) )</p>
<p>Note that z / SQRT(x^2 + z^2) = cos(Axz) and y / z = tan(Ayz), so finally:</p>
<p>x = sin(Axz) / SQRT (1 + cos(Axz)^2 * tan(Ayz)^2 )</p>
<p>Going back to our notation we get:</p>
<p>RxGyro = sin(Axz(n)) / SQRT (1 + cos(Axz(n))^2 * tan(Ayz(n))^2 )</p>
<p>same way we find that</p>
<p>RyGyro = sin(Ayz(n)) / SQRT (1 + cos(Ayz(n))^2 * tan(Axz(n))^2 )</p>
<p><em><strong>Side Note: it is possible to further simplify this formula. By dividing both parts of the fraction by sin(Axz(n)) you get:</strong><br />
	RxGyro =&nbsp; 1&nbsp; / SQRT (1/ <strong>sin(Axz(n))^2</strong>&nbsp; + cos(Axz(n))^2 / <strong>sin(Axz(n))^2</strong>&nbsp; * tan(Ayz(n))^2 )<br />
	RxGyro =&nbsp; 1&nbsp; / SQRT (1/ sin(Axz(n))^2&nbsp; + cot(Axz(n))^2&nbsp; * <strong>sin(Ayz(n))^2&nbsp; / cos(Ayz(n))^2</strong> )&nbsp; <br />
	now add and substract &nbsp;&nbsp;&nbsp; cos(Axz(n))^2/sin(Axz(n))^2&nbsp;&nbsp; = cot(Axz(n))^2 <br />
	RxGyro =&nbsp; 1&nbsp; / SQRT (1/ sin(Axz(n))^2&nbsp; <strong>-&nbsp; cos(Axz(n))^2/sin(Axz(n))^2</strong> &nbsp; + cot(Axz(n))^2&nbsp; * sin(Ayz(n))^2&nbsp; / cos(Ayz(n))^2&nbsp; <strong>+ cot(Axz(n))^2 </strong>)<br />
	and by grouping&nbsp; terms 1&amp;2 and then 3&amp;4&nbsp; we get&nbsp; <br />
	<strong>RxGyro =&nbsp; 1&nbsp; / SQRT (1&nbsp; + &nbsp; cot(Axz(n))^2 * sec(Ayz(n))^2 ), &nbsp; &nbsp;&nbsp; where&nbsp; cot(x) = 1 / tan(x)&nbsp; and&nbsp; sec(x) = 1 / cos(x)</strong><br />
	This formula uses only 2 trigonometric functions and can be computationally less expensive. If you have Mathematica program you can verify it<br />
	</em><em>by evaluating &nbsp;&nbsp; FullSimplify [Sin[A]^2/ ( 1 + Cos[A]^2&nbsp; * Tan[B]^2)]<br />
	</em></p>
<p>Now, finally we can find:</p>
<p>RzGyro&nbsp; =&nbsp; Sign(RzGyro)*SQRT(1 &#8211; RxGyro^2 &#8211; RyGyro^2).</p>
<p>Where Sign(RzGyro) = 1 when RzGyro&gt;=0 , and Sign(RzGyro) = -1 when RzGyro&lt;0.</p>
<p>One simple way to estimate this is to take:</p>
<p>Sign(RzGyro) = Sign(RzEst(n-1))</p>
<p><em>In practice be careful when RzEst(n-1) is close to 0. You may skip the gyro phase altogether in this case and assign:&nbsp; Rgyro = Rest(n-1). Rz is used as a reference for calculating Axz and Ayz angles and when it&#39;s close to 0, values may overflow and trigger bad results. You&#39;ll be in domain of large floating point numbers where tan() / atan() function implementations may lack precision.<br />
	</em></p>
<p>So let&#39;s recap what we have so far, we are at step <strong>n</strong> of our algorithm and we have calculated the following values:</p>
<p>Racc &#8211; current readings from our accelerometer<br />
	Rgyro &#8211; obtained from Rest(n-1) and current gyroscope readings</p>
<p>Which values do we use to calculate the updated estimate Rest(n) ? You probably guessed that we&#39;ll use both. We&#39;ll use a weighted average, so that:</p>
<p>Rest(n) = (Racc * w1 + Rgyro * w2 ) / (w1 + w2)</p>
<p>We can simplify this formula by dividing both numerator and denominator of the fraction by w1.</p>
<p>Rest(n) = (Racc * w1/w1 + Rgyro * w2/w1 ) / (w1/w1 + w2/w1)</p>
<p>and after substituting w2/w1 = wGyro we get:</p>
<p>Rest(n) = (Racc + Rgyro * wGyro ) / (1 + wGyro)</p>
<p>In the above formula 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.</p>
<p>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 &quot;the best&quot; theoretical results, whereas this algorithm can give you results &quot;good enough&quot; 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.</p>
<p>We are one step away from getting our updated estimated values:</p>
<p>RxEst(n) = (RxAcc + RxGyro * wGyro ) / (1 + wGyro)<br />
	RyEst(n) = (RyAcc + RyGyro * wGyro ) / (1 + wGyro)<br />
	RzEst(n) = (RzAcc + RzGyro * wGyro ) / (1 + wGyro)</p>
<p>Now let&#39;s&nbsp; normalize this vector again:</p>
<p>R = SQRT(RxEst(n) ^2 + RyEst(n)^2 +&nbsp; RzEst(n)^2 )</p>
<p>RxEst(n) = RxEst(n)/R<br />
	RyEst(n) = RyEst(n)/R<br />
	RzEst(n) = RzEst(n)/R</p>
<p>And we&#39;re ready to repeat our loop again.</p>
<p><strong>NOTE: </strong>FOR PRACTICAL IMPLEMENTATION AND TESTING&nbsp; OF THIS ALGORITHM PLEASE READ THIS ARTICLE:</p>
<p><a href="imu_kalman_arduino.html">http://starlino.com/imu_kalman_arduino.html</a><strong><br />
	</strong></p>
<p>&nbsp;</p>
<p><strong>Other Resources on Accelerometer and Gyroscope IMU Fusion:</strong></p>
<p><a href="http://www.mikroquad.com/pub/Research/ComplementaryFilter/filter.pdf">http://www.mikroquad.com/pub/Research/ComplementaryFilter/filter.pdf</a><strong><br />
	</strong></p>
<p><a href="http://stackoverflow.com/questions/1586658/combine-gyroscope-and-accelerometer-data">http://stackoverflow.com/questions/1586658/combine-gyroscope-and-accelerometer-data</a></p>
<p><a href="http://www.dimensionengineering.com/accelerometers.htm">http://www.dimensionengineering.com/accelerometers.htm</a></p>
<p><img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=librarian06-20&amp;l=as2&amp;o=1&amp;a=1580532551" style="border: medium none ! important; margin: 0px ! important;" width="1" /></p>
<p><iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=librarian06-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=1580532551&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="width: 120px; height: 240px;"></iframe></p>
<p>//starlino//</p>
]]></content:encoded>
			<wfw:commentRss>http://www.starlino.com/imu_guide.html/feed</wfw:commentRss>
		<slash:comments>146</slash:comments>
		</item>
		<item>
		<title>USB Motion Gamepad Update: wide accelerometer and gyroscope support, configuration utility software</title>
		<link>http://www.starlino.com/usb_gamepad_gyro.html</link>
		<comments>http://www.starlino.com/usb_gamepad_gyro.html#comments</comments>
		<pubDate>Sat, 26 Sep 2009 09:44:54 +0000</pubDate>
		<dc:creator>starlino</dc:creator>
				<category><![CDATA[Motion Sensing USB Devices]]></category>
		<category><![CDATA[accelerometer]]></category>
		<category><![CDATA[gyroscope]]></category>
		<category><![CDATA[imu]]></category>
		<category><![CDATA[Motion Gamepad]]></category>
		<category><![CDATA[pic]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[usb]]></category>

		<guid isPermaLink="false">http://usb_gamepad_gyro</guid>
		<description><![CDATA[<p>I have received some feedback from my readers regarding my first usb gamepad project , so for the past few weeks I was working on a new imrpoved design.&#160;&#160;&#160; There are plenty of new improvements that I hope will address many of your requests. The new device supports a wide range of gyroscopes and accelerometers that can be configured using&#160; Configuration Utility for Windows. Have a look at this article as it features new suggested schematics as well as a full feature log. Firmware and configuration utility are free to download for private use.</p>]]></description>
			<content:encoded><![CDATA[<p>I have received some feedback from my readers regarding my first <a href="usb_gamepad.html">usb gamepad project</a> , so for the past few weeks I was working on a new imrpoved design. There are plenty of new improvements that I hope will address many of your requests.</p>
<p><span id="more-11"></span><strong>Release Notes / Change Log</strong>:</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
	2009-09-25<br />
	Config Utility Version 1.0.0<br />
	Device Firmware Version 1.5<br />
	&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>- device supports a wide range of accelerometers and gyroscopes<br />
	- implements smoothing filtering algorithm <br />
	- implements algorithm for combining gyroscope and accelerometer data<br />
	- HID USB interface makes the device compatible virtually with all modern operating systems (Mac,Windows,Linux)<br />
	- configuration utility (for Windows only for now)<br />
	- adjustable smoothing and scale factor for outputs<br />
	- configurable sensibility for accelerometer and gyroscope (can be set per axis)<br />
	- configurable midpoint (0g voltage) for accelerometer (can be set per axis)<br />
	- auto-find gyroscope midpoint (0 deg/s voltage)<br />
	- you can use separate accelerometer/gyroscopes for different axis<br />
	- Z axis not implemented in this release<br />
	- configurable analog input ports AN0-AN5 for each axis (please note 18F2550 does not have AN5 input , but 18F4550 does)<br />
	- ability to invert axis<br />
	- capture output and raw adc data into a comma separated values file (.csv)<br />
	- charting feature of all inputs/outputs <br />
	- graphical display of output and buttons<br />
	- supports up to 8 buttons<br />
	- configuration is stored in device EEPROM<br />
	- it is possible to use accelerometer alone on any axis (1, 2 or 3-axis) in this case set Smoothing to 0-10 value<br />
	- it is possible to gyro alone on any axis (1,2 or 3 axis) in this case set Smoothing to 100-255 , please note that the output will snap to middle after a while since gyro only provides rate information<br />
	- it is possible to use to use gyro and accelerometer on any axis (RECOMMENDED) in this case set smoothing to 20-100 value<br />
	- you can use multiple accelerometers or gyroscopes<br />
	- you can orient gyro or accelerometer as you like (but aligned to 90 degrees increments)<br />
	- you can connect your gyro and accelerometer outputs to any of the AN0-AN4 ports (for PIC18F2550).</p>
<p><strong>Suggested Circuit Schematic</strong></p>
<p>Below is a new suggested schematic , using a 2-axis Gyroscope and an a 2-axis Accelerometer. As mentioned above the new firmware and configuration utility is very flexible regarding the way the gyro and accelerometer are connected (this is one of the features requested , to be able to use device with various MEMS sensors).</p>
<p><img alt="Schematic  for USB Gamepad with Accelerometer and Gyroscope" height="748" src="data/usb_gamepad_gyro/usb_gamepad_gyro_schematic.gif" width="698" /></p>
<p><strong>Configuration Utility</strong></p>
<p>Here is a screen shot of the configuration utility, please note that I am using the gyro just for one output axis (X), thus I set smoothing to 50 as recommended in release notes above. The other axis (Y) uses just accelerometer data so Smoothing is set to 5. Device automatically detected the Gyro midpoint to be 1.35V , you must hold device still for at least 1s to let it calibrate when you plug it in. The Gyro axis is also inverted due to the way it is mounted in the case.</p>
<p><a href="data/usb_gamepad_gyro/usb_gamepad_config_utility_1.gif" target="_blank"><img alt="usb motion gamepad configuration utility"  src="data/usb_gamepad_gyro/usb_gamepad_config_utility_1.gif" width="740" /></p>
</a><p><strong>Hardware Setup</strong></p>
<p>My old accelerometer-only device , got modified to make space for a gyro. Here is how it all fit inside the case:</p>
<p><img alt="usb tilt / pan gamepad in Wii steering wheel, uses accelerometer, gyro and pic18f2550" height="480" src="data/usb_gamepad_gyro/IMG_1116.JPG" width="640" /></p>
<p><strong>Demo</strong></p>
<p>Finally here is a new demo with another game I found to work well with this device PURE. In this game you can actually use the FORWARD/BACK tilt (Y axis of the device), besides the usual LEFT/RIGHT (X axis) I demonstrated in the TMNations demos (see my <a href="usb_gamepad.html">first usb gamepad article)</a>.</p>
<p><object height="385" width="480"><param name="movie" value="http://www.youtube.com/v/_FQgmpv_Wc4&amp;hl=en&amp;fs=1&amp;rel=0" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed allowfullscreen="true" allowscriptaccess="always" height="385" src="http://www.youtube.com/v/_FQgmpv_Wc4&amp;hl=en&amp;fs=1&amp;rel=0" type="application/x-shockwave-flash" width="480"></embed></object></p>
<p><strong>Downloads</strong></p>
<p>Configuration Utility Setup (Windows XP/Vista) <a href="data/usb_gamepad_gyro/StarlinoGamepadConfigSetup_100.exe">StarlinoGamepadConfigSetup_100.exe</a></p>
<p>PIC18F2550 Firmware <a href="data/usb_gamepad_gyro/18Fx550_USB_GAMEPAD_GYRO_15.hex">18Fx550_USB_GAMEPAD_GYRO_15.hex</a> (right click on the link and choose Save Link/Target As if HEX file opens in browser).</p>
<p><em>I will continue to edit this article , please let me know what questions/suggestions you have in the comments area below. I will try to update this page and design based on your feedback.</em></p>
<p>//starlino//</p>
]]></content:encoded>
			<wfw:commentRss>http://www.starlino.com/usb_gamepad_gyro.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>

