ISPose.c
Go to the documentation of this file.
1 /*
2 MIT LICENSE
3 
4 Copyright (c) 2014-2021 Inertial Sense, Inc. - http://inertialsense.com
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
7 
8 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9 
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 */
12 
13 #define _MATH_DEFINES_DEFINED
14 #include <math.h>
15 
16 // #include "misc/debug.h"
17 #include "ISConstants.h"
18 #include "ISPose.h"
19 #include "ISEarth.h"
20 
21 //_____ M A C R O S ________________________________________________________
22 
23 //_____ D E F I N I T I O N S ______________________________________________
24 
25 //_____ G L O B A L S ______________________________________________________
26 
27 //_____ L O C A L P R O T O T Y P E S ____________________________________
28 
29 //_____ F U N C T I O N S __________________________________________________
30 
31 /*
32  * Initialize Quaternion q = [w, x, y, z]
33  */
35 {
36 #if 1
37  q[0] = 1.0;
38  q[1] = q[2] = q[3] = 0.0;
39 #else
40  ixEuler theta = { 0, 0, 0 };
41  euler2quat(theta, q);
42 #endif
43 }
44 
45 
46 /* Quaternion Conjugate: q* = [ w, -x, -y, -z ] of quaterion q = [ w, x, y, z ]
47  * Rotation in opposite direction.
48  */
49 void quatConj(ixQuat result, const ixQuat q)
50 {
51  result[0] = q[0];
52  result[1] = -q[1];
53  result[2] = -q[2];
54  result[3] = -q[3];
55 }
56 
57 
58 /*
59  * Product of two Quaternions. Order of q1 and q2 matters (same as applying two successive DCMs)!!!
60  * Combines two quaternion rotations into one rotation.
61  * result = q1 * q2
62  * Reference: http://www.mathworks.com/help/aeroblks/quaternionmultiplication.html
63  */
64 void mul_Quat_Quat(ixQuat result, const ixQuat q1, const ixQuat q2)
65 {
66  result[0] = q1[0]*q2[0] - q1[1]*q2[1] - q1[2]*q2[2] - q1[3]*q2[3];
67  result[1] = q1[0]*q2[1] + q1[1]*q2[0] - q1[2]*q2[3] + q1[3]*q2[2];
68  result[2] = q1[0]*q2[2] + q1[1]*q2[3] + q1[2]*q2[0] - q1[3]*q2[1];
69  result[3] = q1[0]*q2[3] - q1[1]*q2[2] + q1[2]*q2[1] + q1[3]*q2[0];
70 }
71 
72 /*
73 * Product of two Quaternions. Order of q1 and q2 matters (same as applying two successive DCMs)!!!
74 * Combines two quaternion rotations into one rotation.
75 * result = quatConj(q1) * q2
76 * Reference: http://www.mathworks.com/help/aeroblks/quaternionmultiplication.html
77 */
78 void mul_ConjQuat_Quat(ixQuat result, const ixQuat qc, const ixQuat q2)
79 {
80  result[0] = qc[0]*q2[0] + qc[1]*q2[1] + qc[2]*q2[2] + qc[3]*q2[3];
81  result[1] = qc[0]*q2[1] - qc[1]*q2[0] + qc[2]*q2[3] - qc[3]*q2[2];
82  result[2] = qc[0]*q2[2] - qc[1]*q2[3] - qc[2]*q2[0] + qc[3]*q2[1];
83  result[3] = qc[0]*q2[3] + qc[1]*q2[2] - qc[2]*q2[1] - qc[3]*q2[0];
84 }
85 
86 /*
87 * Product of two Quaternions. Order of q1 and q2 matters (same as applying two successive DCMs)!!!
88 * Combines two quaternion rotations into one rotation.
89 * result = q1 * quatConj(q2)
90 * Reference: http://www.mathworks.com/help/aeroblks/quaternionmultiplication.html
91 */
92 void mul_Quat_ConjQuat(ixQuat result, const ixQuat q1, const ixQuat qc)
93 {
94  result[0] = q1[0]*qc[0] + q1[1]*qc[1] + q1[2]*qc[2] + q1[3]*qc[3];
95  result[1] = -q1[0]*qc[1] + q1[1]*qc[0] + q1[2]*qc[3] - q1[3]*qc[2];
96  result[2] = -q1[0]*qc[2] - q1[1]*qc[3] + q1[2]*qc[0] + q1[3]*qc[1];
97  result[3] = -q1[0]*qc[3] + q1[1]*qc[2] - q1[2]*qc[1] + q1[3]*qc[0];
98 }
99 
100 /*
101  * Division of two Quaternions. Order matters!!!
102  * result = q1 / q2.
103  * Reference: http://www.mathworks.com/help/aeroblks/quaterniondivision.html
104  */
105 void div_Quat_Quat(ixQuat result, const ixQuat q1, const ixQuat q2)
106 {
107  f_t d = (f_t)1.0 / (q1[0] * q1[0] + q1[1] * q1[1] + q1[2] * q1[2] + q1[3] * q1[3]);
108 
109  result[0] = (q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2] + q1[3]*q2[3]) * d;
110  result[1] = (q1[0]*q2[1] - q1[1]*q2[0] - q1[2]*q2[3] + q1[3]*q2[2]) * d;
111  result[2] = (q1[0]*q2[2] + q1[1]*q2[3] - q1[2]*q2[0] - q1[3]*q2[1]) * d;
112  result[3] = (q1[0]*q2[3] - q1[1]*q2[2] + q1[2]*q2[1] - q1[3]*q2[0]) * d;
113 }
114 
115 
116 /* Quaternion rotation from vector v1 to vector v2.
117  */
118 void quat_Vec3_Vec3(ixQuat result, const ixVector3 v1, const ixVector3 v2)
119 {
120  ixVector3 w1, w2;
121 
122  // Normalize input vectors
123  mul_Vec3_X( w1, v1, recipNorm_Vec3(v1) );
124  mul_Vec3_X( w2, v2, recipNorm_Vec3(v2) );
125 
126  // q[1:3]
127  cross_Vec3( &result[1], w1, w2 );
128 
129  // q[0]
130  result[0] = (f_t)(_SQRT( dot_Vec3(w1) * dot_Vec3(w1) ) + dot_Vec3_Vec3(w1, w2));
131 
132  // Normalize quaternion
133  div_Vec4_X( result, result, mag_Vec4(result) );
134 }
135 
136 
137 /* Computationally simple means to apply quaternion rotation to a vector.
138  * Requires quaternion be normalized first.
139  * If quaternion describes current attitude, then rotation is body -> inertial frame.
140  * Equivalent to a DCM.T * vector multiply.
141  */
142 void quatRot(ixVector3 result, const ixQuat q, const ixVector3 v)
143 {
144  ixVector3 t;
145  cross_Vec3( t, &q[1], v );
146  mul_Vec3_X( t, t, (f_t)2.0 );
147 
148  cross_Vec3( result, &q[1], t );
149  mul_Vec3_X( t, t, q[0] );
150  add_Vec3_Vec3( result, result, t );
151  add_Vec3_Vec3( result, result, v );
152 }
153 
154 
155 /* Computationally simple means to apply quaternion conjugate (opposite) rotation to a vector
156  * (18 multiplies, 6 subtracts, 6 adds). Using a DCM uses (27 multiplies, 12 adds, 6 subtracts).
157  * Requires quaternion be normalized first.
158  * If quaternion describes current attitude, then rotation is inertial -> body frame.
159  * Equivalent to a DCM * vector multiply.
160  */
161 void quatConjRot(ixVector3 result, const ixQuat q, const ixVector3 v)
162 {
163  ixQuat qC;
164  ixVector3 t;
165 
166  // Rotation in opposite direction
167  quatConj( qC, q );
168 
169  cross_Vec3( t, &qC[1], v );
170  mul_Vec3_X( t, t, (f_t)2.0 );
171 
172  cross_Vec3( result, &qC[1], t );
173  mul_Vec3_X( t, t, qC[0] );
174  add_Vec3_Vec3( result, result, t );
175  add_Vec3_Vec3( result, result, v );
176 }
177 
178 
179 /*
180  * This will convert from quaternions to euler angles
181  * q(W,X,Y,Z) -> euler(phi,theta,psi) (rad)
182  *
183  * Reference: http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
184  */
185 void quat2euler(const ixQuat q, ixEuler theta)
186 {
187  float sinang = 2 * (q[0] * q[2] - q[3] * q[1]);
188  if (sinang > 1.0f) { sinang = 1.0f; }
189  if (sinang < -1.0f) { sinang = -1.0f; }
190 
191  theta[0] = _ATAN2(2 * (q[0]*q[1] + q[2]*q[3]), 1 - 2 * (q[1]*q[1] + q[2]*q[2]));
192  theta[1] = _ASIN (sinang);
193  theta[2] = _ATAN2(2 * (q[0]*q[3] + q[1]*q[2]), 1 - 2 * (q[2]*q[2] + q[3]*q[3]));
194 }
195 void quat2phiTheta(const ixQuat q, f_t *phi, f_t *theta)
196 {
197  float sinang = 2 * (q[0] * q[2] - q[3] * q[1]);
198  if (sinang > 1.0f) { sinang = 1.0f; }
199  if (sinang < -1.0f) { sinang = -1.0f; }
200 
201  *phi = _ATAN2( 2 * (q[0] * q[1] + q[2] * q[3]), 1 - 2 * (q[1] * q[1] + q[2] * q[2]) );
202  *theta = _ASIN (sinang);
203 }
204 void quat2psi(const ixQuat q, f_t *psi)
205 {
206  float sinang = 2 * (q[0] * q[2] - q[3] * q[1]);
207  if (sinang > 1.0f) { sinang = 1.0f; }
208  if (sinang < -1.0f) { sinang = -1.0f; }
209 
210  *psi = _ATAN2(2 * (q[0]*q[3] + q[1]*q[2]), 1 - 2 * (q[2]*q[2] + q[3]*q[3]));
211 }
212 
213 
214 /*
215  * This will convert from euler angles to quaternion vector
216  * euler(phi,theta,psi) (rad) -> q(W,X,Y,Z)
217  */
218 void euler2quat(const ixEuler euler, ixQuat q)
219 {
220  f_t hphi = euler[0] * (f_t)0.5;
221  f_t hthe = euler[1] * (f_t)0.5;
222  f_t hpsi = euler[2] * (f_t)0.5;
223 
224  f_t shphi = _SIN(hphi);
225  f_t chphi = _COS(hphi);
226 
227  f_t shthe = _SIN(hthe);
228  f_t chthe = _COS(hthe);
229 
230  f_t shpsi = _SIN(hpsi);
231  f_t chpsi = _COS(hpsi);
232 
233  q[0] = chphi * chthe * chpsi + shphi * shthe * shpsi;
234  q[1] = shphi * chthe * chpsi - chphi * shthe * shpsi;
235  q[2] = chphi * shthe * chpsi + shphi * chthe * shpsi;
236  q[3] = chphi * chthe * shpsi - shphi * shthe * chpsi;
237 }
238 
239 
240 /*
241 * Quaternion rotation to NED with respect to ECEF at specified LLA
242 */
243 // void quatEcef2Ned(ixVector4 Qe2n, const ixVector3d lla)
244 // {
245 // ixVector3 Ee2nLL;
246 // ixVector4 Qe2n0LL, Qe2nLL;
247 //
248 // //Qe2n0LL is reference attitude [NED w/r/t ECEF] at zero latitude and longitude (elsewhere qned0)
249 // Qe2n0LL[0] = cosf(-C_PIDIV4_F);
250 // Qe2n0LL[1] = 0.0f;
251 // Qe2n0LL[2] = sinf(-C_PIDIV4_F);
252 // Qe2n0LL[3] = 0.0f;
253 //
254 // //Qe2nLL is delta reference attitude [NED w/r/t ECEF] accounting for latitude and longitude (elsewhere qned)
255 // Ee2nLL[0] = 0.0f;
256 // Ee2nLL[1] = (float)(-lla[0]);
257 // Ee2nLL[2] = (float)(lla[1]);
258 //
259 // euler2quat(Ee2nLL, Qe2nLL);
260 //
261 // //Qe2b=Qe2n*Qn2b is vehicle attitude [BOD w/r/t ECEF]
262 // mul_Quat_Quat(Qe2n, Qe2n0LL, Qe2nLL);
263 // }
264 
265 
266 /* Attitude quaternion for NED frame in ECEF */
267 void quat_ecef2ned(float lat, float lon, float *qe2n)
268 {
269  float eul[3];
270 
271  eul[0] = 0.0f;
272  eul[1] = -lat - 0.5f * C_PI_F;
273  eul[2] = lon;
274  euler2quat(eul, qe2n);
275 }
276 
277 
278 /*
279 * Convert ECEF quaternion to NED euler at specified ECEF
280 */
281 void qe2b2EulerNedEcef(ixVector3 eul, const ixVector4 qe2b, const ixVector3d ecef)
282 {
283  ixVector3d lla;
284 
285 // ecef2lla_d(ecef, lla);
286  ecef2lla(ecef, lla, 5);
287  qe2b2EulerNedLLA(eul, qe2b, lla);
288 }
289 
290 
291 /*
292 * Convert ECEF quaternion to NED euler at specified LLA (rad)
293 */
294 void qe2b2EulerNedLLA(ixVector3 eul, const ixVector4 qe2b, const ixVector3d lla)
295 {
296  ixVector3 eulned;
297  ixVector4 qe2n;
298  ixVector4 qn2b;
299 
300  eulned[0] = 0.0f;
301  eulned[1] = ((float)-lla[0]) - 0.5f * C_PI_F;
302  eulned[2] = (float)lla[1];
303  euler2quat(eulned, qe2n);
304  mul_Quat_ConjQuat(qn2b, qe2b, qe2n);
305  quat2euler(qn2b, eul);
306 }
307 
308 
309 /*
310  * This will construct a direction cosine matrix from
311  * the psi angle - rotates from NE to body frame
312  *
313  * body = tBL(2,2)*NE
314  *
315  */
316 void psiDCM(const f_t psi, ixMatrix2 m)
317 {
318  f_t cpsi = _COS(psi); // cos(psi)
319  f_t spsi = _SIN(psi); // sin(psi)
320 
321  // Row 1
322  m[0] = cpsi;
323  m[1] = spsi;
324  // Row 2
325  m[2] = -spsi;
326  m[3] = cpsi;
327 }
328 
329 
330 /*
331 * This will extract the psi euler angle from a direction cosine matrix in the
332 * standard rotation sequence, for either a 2x2 or 3x3 DCM matrix.
333 * [phi][theta][psi] from NED to body frame
334 *
335 * body = tBL(2,2)*NE
336 * body = tBL(3,3)*NED
337 *
338 * reference: http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29
339 */
340 f_t DCMpsi(const f_t *m )
341 {
342  return _ATAN2( m[1], m[0] );
343 }
344 
345 
346 /*
347  * This will construct a direction cosine matrix from
348  * euler angles in the standard rotation sequence
349  * [phi][theta][psi] from NED to body frame
350  *
351  * body = tBL(3,3)*NED
352  *
353  * reference: http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29
354  */
355 void eulerDCM(const ixEuler euler, ixMatrix3 m)
356 {
357  f_t cphi = _COS(euler[0]); // cos(phi)
358  f_t cthe = _COS(euler[1]); // cos(theta)
359  f_t cpsi = _COS(euler[2]); // cos(psi)
360 
361  f_t sphi = _SIN(euler[0]); // sin(phi)
362  f_t sthe = _SIN(euler[1]); // sin(theta)
363  f_t spsi = _SIN(euler[2]); // sin(psi)
364 
365  // Row 1
366  m[0] = cpsi*cthe;
367  m[1] = spsi*cthe;
368  m[2] = -sthe;
369  // Row 2
370  m[3] = -spsi*cphi + cpsi*sthe*sphi;
371  m[4] = cpsi*cphi + spsi*sthe*sphi;
372  m[5] = cthe*sphi;
373  // Row 3
374  m[6] = spsi*sphi + cpsi*sthe*cphi;
375  m[7] = -cpsi*sphi + spsi*sthe*cphi;
376  m[8] = cthe*cphi;
377 }
378 
379 
380 void phiThetaDCM(const ixEuler euler, ixMatrix3 m )
381 {
382  f_t cphi = _COS( euler[0] ); // cos(phi)
383  f_t cthe = _COS( euler[1] ); // cos(theta)
384 
385  f_t sphi = _SIN( euler[0] ); // sin(phi)
386  f_t sthe = _SIN( euler[1] ); // sin(theta)
387 
388  // Row 1
389  m[0] = cthe;
390  m[1] = 0.0f;
391  m[2] = -sthe;
392  // Row 2
393  m[3] = sthe*sphi;
394  m[4] = cphi;
395  m[5] = cthe*sphi;
396  // Row 3
397  m[6] = sthe*cphi;
398  m[7] = -sphi;
399  m[8] = cthe*cphi;
400 }
401 
402 
403 /*
404 * This will construct the transpose matrix of
405 * the direction cosine matrix from
406 * euler angles in the standard rotation sequence
407 * [phi][theta][psi] from NED to body frame
408 *
409 * body = tBL(3,3)*NED
410 *
411 * reference: http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29
412 */
413 void eulerDCM_Trans(const ixEuler euler, ixMatrix3 m )
414 {
415  f_t cphi = _COS( euler[0] ); // cos(phi)
416  f_t cthe = _COS( euler[1] ); // cos(theta)
417  f_t cpsi = _COS( euler[2] ); // cos(psi)
418 
419  f_t sphi = _SIN( euler[0] ); // sin(phi)
420  f_t sthe = _SIN( euler[1] ); // sin(theta)
421  f_t spsi = _SIN( euler[2] ); // sin(psi)
422 
423  // Col 1
424  m[0] = cpsi*cthe;
425  m[3] = spsi*cthe;
426  m[6] = -sthe;
427  // Col 2
428  m[1] = -spsi*cphi + cpsi*sthe*sphi;
429  m[4] = cpsi*cphi + spsi*sthe*sphi;
430  m[7] = cthe*sphi;
431  // Col 3
432  m[2] = spsi*sphi + cpsi*sthe*cphi;
433  m[5] = -cpsi*sphi + spsi*sthe*cphi;
434  m[8] = cthe*cphi;
435 }
436 
437 
438 /*
439  * This will extract euler angles from a direction cosine matrix in the
440  * standard rotation sequence.
441  * [phi][theta][psi] from NED to body frame
442  *
443  * body = tBL(3,3)*NED
444  *
445  * reference: http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29
446  */
447 void DCMeuler(const ixMatrix3 m, ixEuler euler)
448 {
449  euler[0] = _ATAN2( m[5], m[8] ); // phi
450  euler[1] = _ASIN( -m[2] ); // theta
451  euler[2] = _ATAN2( m[1], m[0] ); // psi
452 }
453 
454 
455 /*
456  * This will construct a direction cosine matrix from
457  * quaternions in the standard rotation sequence
458  * [phi][theta][psi] from NED to body frame
459  * (18 multiplies, 6 adds, 6 subtracts)
460  *
461  * body = tBL(3,3)*NED
462  * q(4,1)
463  *
464  * Reference: http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29
465  */
466 void quatDCM(const ixQuat q, ixMatrix3 mat)
467 {
468  f_t q0q1 = q[0]*q[1];
469  f_t q0q2 = q[0]*q[2];
470  f_t q0q3 = q[0]*q[3];
471  f_t q1q1 = q[1]*q[1];
472  f_t q1q2 = q[1]*q[2];
473  f_t q1q3 = q[1]*q[3];
474  f_t q2q2 = q[2]*q[2];
475  f_t q2q3 = q[2]*q[3];
476  f_t q3q3 = q[3]*q[3];
477 
478  // Row 1
479  mat[0] = (f_t)1.0 - (f_t)2 * (q2q2 + q3q3);
480  mat[1] = (f_t)2 * (q1q2 + q0q3);
481  mat[2] = (f_t)2 * (q1q3 - q0q2);
482  // Row 2
483  mat[3] = (f_t)2 * (q1q2 - q0q3);
484  mat[4] = (f_t)1.0 - (f_t)2 * (q1q1 + q3q3);
485  mat[5] = (f_t)2 * (q2q3 + q0q1);
486  // Row 3
487  mat[6] = (f_t)2 * (q1q3 + q0q2);
488  mat[7] = (f_t)2 * (q2q3 - q0q1);
489  mat[8] = (f_t)1.0 - (f_t)2 * (q1q1 + q2q2);
490 }
491 void quatdDCM(const ixVector4d q, ixMatrix3 mat )
492 {
493  f_t q0q1 = (f_t)(q[0] * q[1]);
494  f_t q0q2 = (f_t)(q[0] * q[2]);
495  f_t q0q3 = (f_t)(q[0] * q[3]);
496  f_t q1q1 = (f_t)(q[1] * q[1]);
497  f_t q1q2 = (f_t)(q[1] * q[2]);
498  f_t q1q3 = (f_t)(q[1] * q[3]);
499  f_t q2q2 = (f_t)(q[2] * q[2]);
500  f_t q2q3 = (f_t)(q[2] * q[3]);
501  f_t q3q3 = (f_t)(q[3] * q[3]);
502 
503  // Row 1
504  mat[0] = (f_t)1.0 - (f_t)2.0 * (q2q2 + q3q3);
505  mat[1] = (f_t)2.0 * (q1q2 + q0q3);
506  mat[2] = (f_t)2.0 * (q1q3 - q0q2);
507  // Row 2
508  mat[3] = (f_t)2.0 * (q1q2 - q0q3);
509  mat[4] = (f_t)1.0 - (f_t)2.0 * (q1q1 + q3q3);
510  mat[5] = (f_t)2.0 * (q2q3 + q0q1);
511  // Row 3
512  mat[6] = (f_t)2.0 * (q1q3 + q0q2);
513  mat[7] = (f_t)2.0 * (q2q3 - q0q1);
514  mat[8] = (f_t)1.0 - (f_t)2.0 * (q1q1 + q2q2);
515 }
516 
517 /*
518  * This will construct quaternions from a direction cosine
519  * matrix in the standard rotation sequence.
520  * [phi][theta][psi] from NED to body frame
521  *
522  * body = tBL(3,3)*NED
523  * q(4,1)
524  *
525  * Reference: http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29
526  */
527 void DCMquat(const ixMatrix3 mat, ixQuat q)
528 {
529  f_t d;
530 
531  q[0] = (f_t)0.5 * _SQRT((f_t)1.0 + mat[0] + mat[4] + mat[8]);
532 
533  d = (f_t)1.0 / ((f_t)4.0 * q[0]);
534 
535  q[1] = d * (mat[5] - mat[7]);
536  q[2] = d * (mat[6] - mat[2]);
537  q[3] = d * (mat[1] - mat[3]);
538 }
539 
540 /*
541  * This will construct the euler omega-cross matrix
542  * wx(3,3)
543  * p, q, r (rad/sec)
544  */
545 void eulerWx(const ixEuler euler, ixMatrix3 mat)
546 {
547  f_t p = euler[0];
548  f_t q = euler[1];
549  f_t r = euler[2];
550 
551  // Row 1
552  mat[0] = 0;
553  mat[1] = -r;
554  mat[2] = q;
555  // Row 2
556  mat[3] = r;
557  mat[4] = 0;
558  mat[5] = -p;
559  // Row 3
560  mat[6] = -q;
561  mat[7] = p;
562  mat[8] = 0;
563 }
564 
565 /*
566  * This will construct the quaternion omega matrix
567  * W(4,4)
568  * p, q, r (rad/sec)
569  */
570 void quatW(const ixEuler euler, ixMatrix4 mat)
571 {
572  f_t p = euler[0] * (f_t)0.5;
573  f_t q = euler[1] * (f_t)0.5;
574  f_t r = euler[2] * (f_t)0.5;
575 
576  // Row 1
577  mat[0] = 0;
578  mat[1] = -p;
579  mat[2] = -q;
580  mat[3] = -r;
581  // Row 2
582  mat[4] = p;
583  mat[5] = 0;
584  mat[6] = r;
585  mat[7] = -q;
586  // Row 3
587  mat[8] = q;
588  mat[9] = -r;
589  mat[10] = 0;
590  mat[11] = p;
591  // Row 4
592  mat[12] = r;
593  mat[13] = q;
594  mat[14] = -p;
595  mat[15] = 0;
596 }
597 
598 
599 /*
600 * Convert quaternion to rotation axis (and angle). Quaternion must be normalized.
601 */
602 void quatRotAxis(const ixQuat q, ixVector3 pqr)
603 {
604  // Normalize quaternion
605 // mul_Vec4_X( q, q, 1/mag_Vec4(q) );
606 
607 // f_t theta = _ACOS( q[0] ) * (f_t)2.0;
608  f_t sin_a, d;
609 
610  sin_a = _SQRT( (f_t)1.0 - q[0] * q[0] );
611 
612  if ( _FABS( sin_a ) < (f_t)0.0005 )
613  sin_a = (f_t)1.0;
614 
615  d = (f_t)1.0 / sin_a;
616 
617  pqr[0] = q[1] * d;
618  pqr[1] = q[2] * d;
619  pqr[2] = q[3] * d;
620 }
621 
622 
623 /*
624  * Compute the derivative of the ixEuler angle psi with respect
625  * to the quaternion Q. The result is a row vector
626  *
627  * d(psi)/d(q0)
628  * d(psi)/d(q1)
629  * d(psi)/d(q2)
630  * d(psi)/d(q3)
631  */
632 void dpsi_dq(const ixQuat q, ixQuat dq)
633 {
634  f_t t1 = 1 - 2 * (q[2]*q[2] + q[3]*q[2]);
635  f_t t2 = 2 * (q[1]*q[2] + q[0]*q[3]);
636  f_t err = 2 / ( t1*t1 + t2*t2 );
637 
638  dq[0] = err * (q[3]*t1);
639  dq[1] = err * (q[2]*t1);
640  dq[2] = err * (q[1]*t1 + 2 * q[2]*t2);
641  dq[3] = err * (q[0]*t1 + 2 * q[3]*t2);
642 }
643 
644 
645 /*
646  * NED to ixEuler
647  */
648 void nedEuler(const ixVector3 ned, ixEuler e)
649 {
650  e[0] = 0;
651  e[1] = _ATAN2( -ned[2], _SQRT( ned[0] * ned[0] + ned[1] * ned[1] ) );
652  e[2] = _ATAN2( ned[1], ned[0] );
653 }
654 
655 
656 /*
657  * ixEuler to NED
658  */
659 void eulerNed(const ixEuler e, ixVector3 ned)
660 {
661  ixVector3 v = { 1, 0, 0};
662 
663  vectorBodyToReference( v, e, ned );
664 }
665 
666 
667 /*
668  * Rotate eulers from body to inertial frame by ins eulers, in order: phi, theta, psi
669  */
670 void eulerBodyToReference(const ixEuler e, const ixEuler rot, ixEuler result)
671 {
672  ixMatrix3 Ai, At, AiAt;
673  // Create DCMs (rotation matrices)
674  eulerDCM(rot, Ai);
675  eulerDCM(e, At);
676 
677  // Apply INS Rotation to Desired Target vector
678  mul_Mat3x3_Mat3x3(AiAt, At, Ai); // Apply rotation
679  DCMeuler(AiAt, result); // Pull out new eulers
680 }
681 
682 
683 /*
684  * Rotate eulers from inertial to body frame by ins eulers, in order: psi, theta, phi
685  */
686 void eulerReferenceToBody(const ixEuler e, const ixEuler rot, ixEuler result)
687 {
688  ixMatrix3 Ai, At, AiAt;
689  // Create DCMs (rotation matrices)
690  eulerDCM(rot, Ai);
691  eulerDCM(e, At);
692 
693  // Apply INS Rotation to Desired Target vector
694  mul_Mat3x3_Mat3x3_Trans(AiAt, At, Ai); // Apply rotation
695  DCMeuler(AiAt, result); // Pull out new eulers
696 }
697 
698 
699 /*
700  * Rotate vector from body to inertial frame by euler angles, in order: phi, theta, psi
701  */
702 void vectorBodyToReference(const ixVector3 v, const ixEuler rot, ixVector3 result)
703 {
704  ixMatrix3 DCM;
705 
706  // Create DCM (rotation matrix)
707  eulerDCM(rot, DCM);
708 
709  // Apply rotation to vector
710  mul_Mat3x3_Trans_Vec3x1( result, DCM, v );
711 }
712 
713 
714 /*
715  * Rotate vector from inertial to body frame by euler angles, in order: psi, theta, phi
716  */
717 void vectorReferenceToBody(const ixVector3 v, const ixEuler rot, ixVector3 result)
718 {
719  ixMatrix3 DCM;
720 
721  // Create DCM (rotation matrix)
722  eulerDCM(rot, DCM);
723 
724  // Apply rotation to vector
725  mul_Mat3x3_Vec3x1( result, DCM, v );
726 }
727 
728 
729 
void DCMquat(const ixMatrix3 mat, ixQuat q)
Definition: ISPose.c:527
d
ixVector4 ixQuat
Definition: ISConstants.h:796
f_t ixVector3[3]
Definition: ISConstants.h:791
void qe2b2EulerNedLLA(ixVector3 eul, const ixVector4 qe2b, const ixVector3d lla)
Definition: ISPose.c:294
void phiThetaDCM(const ixEuler euler, ixMatrix3 m)
Definition: ISPose.c:380
float f_t
Definition: ISConstants.h:786
void cross_Vec3(ixVector3 result, const ixVector3 v1, const ixVector3 v2)
Definition: ISMatrix.c:594
f_t dot_Vec3_Vec3(const ixVector3 v1, const ixVector3 v2)
Definition: ISMatrix.c:570
void quat_init(ixQuat q)
Definition: ISPose.c:34
void euler2quat(const ixEuler euler, ixQuat q)
Definition: ISPose.c:218
void eulerBodyToReference(const ixEuler e, const ixEuler rot, ixEuler result)
Definition: ISPose.c:670
#define _ATAN2
Definition: ISConstants.h:775
#define dot_Vec3(v)
Definition: ISMatrix.h:29
f_t ixMatrix4[16]
Definition: ISConstants.h:800
void psiDCM(const f_t psi, ixMatrix2 m)
Definition: ISPose.c:316
void quatdDCM(const ixVector4d q, ixMatrix3 mat)
Definition: ISPose.c:491
void mul_Mat3x3_Vec3x1(ixVector3 result, const ixMatrix3 m, const ixVector3 v)
Definition: ISMatrix.c:430
void quatRotAxis(const ixQuat q, ixVector3 pqr)
Definition: ISPose.c:602
void quat_ecef2ned(float lat, float lon, float *qe2n)
Definition: ISPose.c:267
void mul_Mat3x3_Mat3x3_Trans(ixMatrix3 result, const ixMatrix3 m1, const ixMatrix3 m2)
Definition: ISMatrix.c:386
void eulerWx(const ixEuler euler, ixMatrix3 mat)
Definition: ISPose.c:545
void eulerDCM_Trans(const ixEuler euler, ixMatrix3 m)
Definition: ISPose.c:413
void vectorReferenceToBody(const ixVector3 v, const ixEuler rot, ixVector3 result)
Definition: ISPose.c:717
void quatConjRot(ixVector3 result, const ixQuat q, const ixVector3 v)
Definition: ISPose.c:161
double ixVector3d[3]
Definition: ISConstants.h:790
f_t ixMatrix2[4]
Definition: ISConstants.h:798
void quatConj(ixQuat result, const ixQuat q)
Definition: ISPose.c:49
double ixVector4d[4]
Definition: ISConstants.h:792
void eulerDCM(const ixEuler euler, ixMatrix3 m)
Definition: ISPose.c:355
#define _ASIN
Definition: ISConstants.h:773
#define _SQRT
Definition: ISConstants.h:776
void quat2phiTheta(const ixQuat q, f_t *phi, f_t *theta)
Definition: ISPose.c:195
void mul_Mat3x3_Trans_Vec3x1(ixVector3 result, const ixMatrix3 m, const ixVector3 v)
Definition: ISMatrix.c:437
void mul_Quat_Quat(ixQuat result, const ixQuat q1, const ixQuat q2)
Definition: ISPose.c:64
#define _SIN
Definition: ISConstants.h:770
void div_Quat_Quat(ixQuat result, const ixQuat q1, const ixQuat q2)
Definition: ISPose.c:105
void vectorBodyToReference(const ixVector3 v, const ixEuler rot, ixVector3 result)
Definition: ISPose.c:702
#define C_PI_F
Definition: ISConstants.h:554
void mul_Mat3x3_Mat3x3(ixMatrix3 result, const ixMatrix3 m1, const ixMatrix3 m2)
Definition: ISMatrix.c:322
void mul_Vec3_X(ixVector3 result, const ixVector3 v, const f_t x)
Definition: ISMatrix.c:620
ixVector3 ixEuler
Definition: ISConstants.h:797
void DCMeuler(const ixMatrix3 m, ixEuler euler)
Definition: ISPose.c:447
void mul_Quat_ConjQuat(ixQuat result, const ixQuat q1, const ixQuat qc)
Definition: ISPose.c:92
void qe2b2EulerNedEcef(ixVector3 eul, const ixVector4 qe2b, const ixVector3d ecef)
Definition: ISPose.c:281
f_t ixMatrix3[9]
Definition: ISConstants.h:799
#define mag_Vec4(v)
Definition: ISMatrix.h:35
void quatRot(ixVector3 result, const ixQuat q, const ixVector3 v)
Definition: ISPose.c:142
void mul_ConjQuat_Quat(ixQuat result, const ixQuat qc, const ixQuat q2)
Definition: ISPose.c:78
void quat2euler(const ixQuat q, ixEuler theta)
Definition: ISPose.c:185
#define recipNorm_Vec3(v)
Definition: ISMatrix.h:42
void ecef2lla(const double *Pe, double *LLA, const int Niter)
Definition: ISEarth.c:54
void dpsi_dq(const ixQuat q, ixQuat dq)
Definition: ISPose.c:632
void quat_Vec3_Vec3(ixQuat result, const ixVector3 v1, const ixVector3 v2)
Definition: ISPose.c:118
void eulerReferenceToBody(const ixEuler e, const ixEuler rot, ixEuler result)
Definition: ISPose.c:686
void eulerNed(const ixEuler e, ixVector3 ned)
Definition: ISPose.c:659
void quatW(const ixEuler euler, ixMatrix4 mat)
Definition: ISPose.c:570
#define _COS
Definition: ISConstants.h:771
void add_Vec3_Vec3(ixVector3 result, const ixVector3 v1, const ixVector3 v2)
Definition: ISMatrix.c:675
f_t ixVector4[4]
Definition: ISConstants.h:793
f_t DCMpsi(const f_t *m)
Definition: ISPose.c:340
void div_Vec4_X(ixVector4 result, const ixVector4 v, const f_t x)
Definition: ISMatrix.c:658
#define _FABS
Definition: ISConstants.h:777
void nedEuler(const ixVector3 ned, ixEuler e)
Definition: ISPose.c:648
void quat2psi(const ixQuat q, f_t *psi)
Definition: ISPose.c:204
void quatDCM(const ixQuat q, ixMatrix3 mat)
Definition: ISPose.c:466


inertial_sense_ros
Author(s):
autogenerated on Sun Feb 28 2021 03:17:57