move main.c (from fat driver) to sd_main.c
[protos/imu.git] / MadgwickAHRS.c
1 //=====================================================================================================\r
2 // MadgwickAHRS.c\r
3 //=====================================================================================================\r
4 //\r
5 // Implementation of Madgwick's IMU and AHRS algorithms.\r
6 // See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms\r
7 //\r
8 // Date                 Author          Notes\r
9 // 29/09/2011   SOH Madgwick    Initial release\r
10 // 02/10/2011   SOH Madgwick    Optimised for reduced CPU load\r
11 // 19/02/2012   SOH Madgwick    Magnetometer measurement is normalised\r
12 //\r
13 //=====================================================================================================\r
14 \r
15 //---------------------------------------------------------------------------------------------------\r
16 // Header files\r
17 \r
18 #include "MadgwickAHRS.h"\r
19 #include <math.h>\r
20 \r
21 \r
22 //---------------------------------------------------------------------------------------------------\r
23 // Definitions\r
24 \r
25 //#define sampleFreq    512.0f          // sample frequency in Hz\r
26 //#define sampleFreq    46.0f           // sample frequency in Hz\r
27 #define sampleFreq      85.0f           // sample frequency in Hz\r
28 #define betaDef         0.1f            // 2 * proportional gain\r
29 \r
30 //---------------------------------------------------------------------------------------------------\r
31 // Variable definitions\r
32 \r
33 volatile float beta = betaDef;                                                          // 2 * proportional gain (Kp)\r
34 volatile float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f;      // quaternion of sensor frame relative to auxiliary frame\r
35 \r
36 \r
37 //---------------------------------------------------------------------------------------------------\r
38 // Function declarations\r
39 \r
40 float invSqrt(float x);\r
41 \r
42 //====================================================================================================\r
43 // Functions\r
44 \r
45 //---------------------------------------------------------------------------------------------------\r
46 // AHRS algorithm update\r
47 \r
48 void MadgwickAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) {\r
49         float recipNorm;\r
50         float s0, s1, s2, s3;\r
51         float qDot1, qDot2, qDot3, qDot4;\r
52         float hx, hy;\r
53         float _2q0mx, _2q0my, _2q0mz, _2q1mx, _2bx, _2bz, _4bx, _4bz, _2q0, _2q1, _2q2, _2q3, _2q0q2, _2q2q3, q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3;\r
54 \r
55         // Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation)\r
56         if((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) {\r
57                 MadgwickAHRSupdateIMU(gx, gy, gz, ax, ay, az);\r
58                 return;\r
59         }\r
60 \r
61         // Rate of change of quaternion from gyroscope\r
62         qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz);\r
63         qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy);\r
64         qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx);\r
65         qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx);\r
66 \r
67         // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)\r
68         if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {\r
69 \r
70                 // Normalise accelerometer measurement\r
71                 recipNorm = invSqrt(ax * ax + ay * ay + az * az);\r
72                 ax *= recipNorm;\r
73                 ay *= recipNorm;\r
74                 az *= recipNorm;\r
75 \r
76                 // Normalise magnetometer measurement\r
77                 recipNorm = invSqrt(mx * mx + my * my + mz * mz);\r
78                 mx *= recipNorm;\r
79                 my *= recipNorm;\r
80                 mz *= recipNorm;\r
81 \r
82                 // Auxiliary variables to avoid repeated arithmetic\r
83                 _2q0mx = 2.0f * q0 * mx;\r
84                 _2q0my = 2.0f * q0 * my;\r
85                 _2q0mz = 2.0f * q0 * mz;\r
86                 _2q1mx = 2.0f * q1 * mx;\r
87                 _2q0 = 2.0f * q0;\r
88                 _2q1 = 2.0f * q1;\r
89                 _2q2 = 2.0f * q2;\r
90                 _2q3 = 2.0f * q3;\r
91                 _2q0q2 = 2.0f * q0 * q2;\r
92                 _2q2q3 = 2.0f * q2 * q3;\r
93                 q0q0 = q0 * q0;\r
94                 q0q1 = q0 * q1;\r
95                 q0q2 = q0 * q2;\r
96                 q0q3 = q0 * q3;\r
97                 q1q1 = q1 * q1;\r
98                 q1q2 = q1 * q2;\r
99                 q1q3 = q1 * q3;\r
100                 q2q2 = q2 * q2;\r
101                 q2q3 = q2 * q3;\r
102                 q3q3 = q3 * q3;\r
103 \r
104                 // Reference direction of Earth's magnetic field\r
105                 hx = mx * q0q0 - _2q0my * q3 + _2q0mz * q2 + mx * q1q1 + _2q1 * my * q2 + _2q1 * mz * q3 - mx * q2q2 - mx * q3q3;\r
106                 hy = _2q0mx * q3 + my * q0q0 - _2q0mz * q1 + _2q1mx * q2 - my * q1q1 + my * q2q2 + _2q2 * mz * q3 - my * q3q3;\r
107                 _2bx = sqrt(hx * hx + hy * hy);\r
108                 _2bz = -_2q0mx * q2 + _2q0my * q1 + mz * q0q0 + _2q1mx * q3 - mz * q1q1 + _2q2 * my * q3 - mz * q2q2 + mz * q3q3;\r
109                 _4bx = 2.0f * _2bx;\r
110                 _4bz = 2.0f * _2bz;\r
111 \r
112                 // Gradient decent algorithm corrective step\r
113                 s0 = -_2q2 * (2.0f * q1q3 - _2q0q2 - ax) + _2q1 * (2.0f * q0q1 + _2q2q3 - ay) - _2bz * q2 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q3 + _2bz * q1) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q2 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);\r
114                 s1 = _2q3 * (2.0f * q1q3 - _2q0q2 - ax) + _2q0 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q1 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + _2bz * q3 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q2 + _2bz * q0) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q3 - _4bz * q1) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);\r
115                 s2 = -_2q0 * (2.0f * q1q3 - _2q0q2 - ax) + _2q3 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q2 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + (-_4bx * q2 - _2bz * q0) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q1 + _2bz * q3) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q0 - _4bz * q2) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);\r
116                 s3 = _2q1 * (2.0f * q1q3 - _2q0q2 - ax) + _2q2 * (2.0f * q0q1 + _2q2q3 - ay) + (-_4bx * q3 + _2bz * q1) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q0 + _2bz * q2) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q1 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);\r
117                 recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude\r
118                 s0 *= recipNorm;\r
119                 s1 *= recipNorm;\r
120                 s2 *= recipNorm;\r
121                 s3 *= recipNorm;\r
122 \r
123                 // Apply feedback step\r
124                 qDot1 -= beta * s0;\r
125                 qDot2 -= beta * s1;\r
126                 qDot3 -= beta * s2;\r
127                 qDot4 -= beta * s3;\r
128         }\r
129 \r
130         // Integrate rate of change of quaternion to yield quaternion\r
131         q0 += qDot1 * (1.0f / sampleFreq);\r
132         q1 += qDot2 * (1.0f / sampleFreq);\r
133         q2 += qDot3 * (1.0f / sampleFreq);\r
134         q3 += qDot4 * (1.0f / sampleFreq);\r
135 \r
136         // Normalise quaternion\r
137         recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);\r
138         q0 *= recipNorm;\r
139         q1 *= recipNorm;\r
140         q2 *= recipNorm;\r
141         q3 *= recipNorm;\r
142 }\r
143 \r
144 //---------------------------------------------------------------------------------------------------\r
145 // IMU algorithm update\r
146 \r
147 void MadgwickAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az) {\r
148         float recipNorm;\r
149         float s0, s1, s2, s3;\r
150         float qDot1, qDot2, qDot3, qDot4;\r
151         float _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2 ,_8q1, _8q2, q0q0, q1q1, q2q2, q3q3;\r
152 \r
153         // Rate of change of quaternion from gyroscope\r
154         qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz);\r
155         qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy);\r
156         qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx);\r
157         qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx);\r
158 \r
159 \r
160         // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)\r
161         if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {\r
162 \r
163                 // Normalise accelerometer measurement\r
164                 recipNorm = invSqrt(ax * ax + ay * ay + az * az);\r
165                 ax *= recipNorm;\r
166                 ay *= recipNorm;\r
167                 az *= recipNorm;\r
168 \r
169                 // Auxiliary variables to avoid repeated arithmetic\r
170                 _2q0 = 2.0f * q0;\r
171                 _2q1 = 2.0f * q1;\r
172                 _2q2 = 2.0f * q2;\r
173                 _2q3 = 2.0f * q3;\r
174                 _4q0 = 4.0f * q0;\r
175                 _4q1 = 4.0f * q1;\r
176                 _4q2 = 4.0f * q2;\r
177                 _8q1 = 8.0f * q1;\r
178                 _8q2 = 8.0f * q2;\r
179                 q0q0 = q0 * q0;\r
180                 q1q1 = q1 * q1;\r
181                 q2q2 = q2 * q2;\r
182                 q3q3 = q3 * q3;\r
183 \r
184 \r
185                 // Gradient decent algorithm corrective step\r
186                 s0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1 - _2q1 * ay;\r
187                 s1 = _4q1 * q3q3 - _2q3 * ax + 4.0f * q0q0 * q1 - _2q0 * ay - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az;\r
188                 s2 = 4.0f * q0q0 * q2 + _2q0 * ax + _4q2 * q3q3 - _2q3 * ay - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az;\r
189                 s3 = 4.0f * q1q1 * q3 - _2q1 * ax + 4.0f * q2q2 * q3 - _2q2 * ay;\r
190                 recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude\r
191 \r
192 \r
193 \r
194                 s0 *= recipNorm;\r
195                 s1 *= recipNorm;\r
196                 s2 *= recipNorm;\r
197                 s3 *= recipNorm;\r
198 \r
199 \r
200                 // Apply feedback step\r
201                 qDot1 -= beta * s0;\r
202                 qDot2 -= beta * s1;\r
203                 qDot3 -= beta * s2;\r
204                 qDot4 -= beta * s3;\r
205         }\r
206 \r
207         // Integrate rate of change of quaternion to yield quaternion\r
208         q0 += qDot1 * (1.0f / sampleFreq);\r
209         q1 += qDot2 * (1.0f / sampleFreq);\r
210         q2 += qDot3 * (1.0f / sampleFreq);\r
211         q3 += qDot4 * (1.0f / sampleFreq);\r
212 \r
213 \r
214         // Normalise quaternion\r
215         recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);\r
216         q0 *= recipNorm;\r
217         q1 *= recipNorm;\r
218         q2 *= recipNorm;\r
219         q3 *= recipNorm;\r
220 \r
221         //printf("%+3.3f\t%+3.3f\t%+3.3f\r\n", q0, q1, q2);\r
222 \r
223 }\r
224 \r
225 \r
226 //---------------------------------------------------------------------------------------------------\r
227 // Fast inverse square-root\r
228 // See: http://en.wikipedia.org/wiki/Fast_inverse_square_root\r
229 /*\r
230 float invSqrt(float x) {\r
231         float halfx = 0.5f * x;\r
232         float y = x;\r
233         long i = *(long*)&y;\r
234         i = 0x5f3759df - (i>>1);\r
235         y = *(float*)&i;\r
236         y = y * (1.5f - (halfx * y * y));\r
237         return y;\r
238 }\r
239 */\r
240 float invSqrt(float x) {\r
241         return 1.0f / sqrtf(x);\r
242 }\r
243 //====================================================================================================\r
244 // END OF CODE\r
245 //====================================================================================================\r