61 #define SMALLQ0 1E-4F // limit of quaternion scalar component requiring special algorithm 62 #define CORRUPTQUAT 0.001F // threshold for deciding rotation quaternion is corrupt 63 #define SMALLMODULUS 0.01F // limit where rounding errors may appear 65 #if F_USING_ACCEL // Need tilt conversion routines 67 #if (THISCOORDSYSTEM == NED) || (THISCOORDSYSTEM == ANDROID) 81 fmodGxyz = fmodGyz + fGc[
CHX] * fGc[
CHX];
109 fmodGyz = sqrtf(fmodGyz);
110 fmodGxyz = sqrtf(fmodGxyz);
111 frecipmodGxyz = 1.0F / fmodGxyz;
112 ftmp = fmodGxyz / fmodGyz;
115 for (i =
CHX; i <=
CHZ; i++)
117 fR[i][
CHZ] = fGc[i] * frecipmodGxyz;
121 fR[
CHX][
CHX] = fmodGyz * frecipmodGxyz;
132 #endif // #if THISCOORDSYSTEM == NED 135 #if THISCOORDSYSTEM == ANDROID 143 #endif // #if THISCOORDSYSTEM == ANDROID 146 #if (THISCOORDSYSTEM == WIN8) || (THISCOORDSYSTEM == ANDROID) 160 fmodGxyz = fmodGxz + fGc[
CHY] * fGc[
CHY];
163 if (fmodGxyz == 0.0F)
174 if (fGc[
CHY] >= 0.0F)
188 fmodGxz = sqrtf(fmodGxz);
189 fmodGxyz = sqrtf(fmodGxyz);
190 frecipmodGxyz = 1.0F / fmodGxyz;
191 ftmp = fmodGxyz / fmodGxz;
198 for (i =
CHX; i <=
CHZ; i++)
200 fR[i][
CHZ] = -fGc[i] * frecipmodGxyz;
210 fR[
CHY][
CHY] = -fmodGxz * frecipmodGxyz;
219 #endif // #if (THISCOORDSYSTEM == WIN8) 220 #endif // #if F_USING_ACCEL // Need tilt conversion routines 222 #if F_USING_MAG // Need eCompass conversion routines 224 #if THISCOORDSYSTEM == NED 231 fmodBxy = sqrtf(fBc[
CHX] * fBc[
CHX] + fBc[
CHY] * fBc[
CHY]);
251 #endif // #if THISCOORDSYSTEM == NED 254 #if (THISCOORDSYSTEM == ANDROID) || (THISCOORDSYSTEM == WIN8) 261 fmodBxy = sqrtf(fBc[
CHX] * fBc[
CHX] + fBc[
CHY] * fBc[
CHY]);
281 #endif // #if THISCOORDSYSTEM == ANDROID 284 #if (THISCOORDSYSTEM == WIN8) 292 #endif // #if (THISCOORDSYSTEM == WIN8) 295 #if THISCOORDSYSTEM == NED 296 void feCompassNED(
float fR[][3],
float *pfDelta,
float *pfsinDelta,
float *pfcosDelta,
float fBc[],
float fGc[],
float *pfmodBc,
float *pfmodGc)
305 *pfDelta = *pfsinDelta = 0.0F;
309 for (i =
CHX; i <=
CHZ; i++)
331 if (!((fmod[CHX] == 0.0F) || (fmod[CHY] == 0.0F) || (fmod[CHZ] == 0.0F)))
334 for (j = CHX; j <=
CHZ; j++)
336 ftmp = 1.0F / fmod[j];
338 for (i = CHX; i <=
CHZ; i++)
353 *pfmodGc = fmod[
CHZ];
354 *pfmodBc = sqrtf(fBc[CHX] * fBc[CHX] + fBc[CHY] * fBc[CHY] + fBc[CHZ] * fBc[CHZ]);
356 if (!((*pfmodGc == 0.0F) || (*pfmodBc == 0.0F)))
358 *pfsinDelta = fGcdotBc / (*pfmodGc * *pfmodBc);
359 *pfcosDelta = sqrtf(1.0F - *pfsinDelta * *pfsinDelta);
365 #endif // #if THISCOORDSYSTEM == NED 368 #if THISCOORDSYSTEM == ANDROID 369 void feCompassAndroid(
float fR[][3],
float *pfDelta,
float *pfsinDelta,
float *pfcosDelta,
float fBc[],
float fGc[],
370 float *pfmodBc,
float *pfmodGc)
379 *pfDelta = *pfsinDelta = 0.0F;
383 for (i =
CHX; i <=
CHZ; i++)
405 if (!((fmod[CHX] == 0.0F) || (fmod[CHY] == 0.0F) || (fmod[CHZ] == 0.0F)))
408 for (j = CHX; j <=
CHZ; j++)
410 ftmp = 1.0F / fmod[j];
412 for (i = CHX; i <=
CHZ; i++)
427 *pfmodGc = fmod[
CHZ];
428 *pfmodBc = sqrtf(fBc[CHX] * fBc[CHX] + fBc[CHY] * fBc[CHY] + fBc[CHZ] * fBc[CHZ]);
430 if (!((*pfmodGc == 0.0F) || (*pfmodBc == 0.0F)))
432 *pfsinDelta = -fGcdotBc / (*pfmodGc * *pfmodBc);
433 *pfcosDelta = sqrtf(1.0F - *pfsinDelta * *pfsinDelta);
439 #endif // #if THISCOORDSYSTEM == ANDROID 442 #if (THISCOORDSYSTEM == WIN8) 443 void feCompassWin8(
float fR[][3],
float *pfDelta,
float *pfsinDelta,
float *pfcosDelta,
float fBc[],
float fGc[],
444 float *pfmodBc,
float *pfmodGc)
453 *pfDelta = *pfsinDelta = 0.0F;
457 for (i =
CHX; i <=
CHZ; i++)
459 fR[i][
CHZ] = -fGc[i];
479 if (!((fmod[CHX] == 0.0F) || (fmod[CHY] == 0.0F) || (fmod[CHZ] == 0.0F)))
482 for (j = CHX; j <=
CHZ; j++)
484 ftmp = 1.0F / fmod[j];
486 for (i = CHX; i <=
CHZ; i++)
501 *pfmodGc = fmod[
CHZ];
502 *pfmodBc = sqrtf(fBc[CHX] * fBc[CHX] + fBc[CHY] * fBc[CHY] + fBc[CHZ] * fBc[CHZ]);
504 if (!((*pfmodGc == 0.0F) || (*pfmodBc == 0.0F)))
506 *pfsinDelta = fGcdotBc / (*pfmodGc * *pfmodBc);
507 *pfcosDelta = sqrtf(1.0F - *pfsinDelta * *pfsinDelta);
513 #endif // #if (THISCOORDSYSTEM == WIN8) 514 #endif // #if F_USING_MAG // Need eCompass conversion routines 517 #if THISCOORDSYSTEM == NED 519 float *pfRhoDeg,
float *pfChiDeg)
528 if (*pfPhiDeg == 180.0F)
534 if (*pfTheDeg == 90.0F)
537 *pfPsiDeg =
fatan2_deg(R[CHZ][
CHY], R[CHY][CHY]) + *pfPhiDeg;
539 else if (*pfTheDeg == -90.0F)
542 *pfPsiDeg =
fatan2_deg(-R[CHZ][
CHY], R[CHY][CHY]) - *pfPhiDeg;
551 if (*pfPsiDeg < 0.0F)
557 if (*pfPsiDeg >= 360.0F)
563 *pfRhoDeg = *pfPsiDeg;
570 #endif // #if THISCOORDSYSTEM == NED 573 #if THISCOORDSYSTEM == ANDROID 575 float *pfRhoDeg,
float *pfChiDeg)
584 if (*pfTheDeg == 180.0F)
590 if (*pfPhiDeg == 90.0F)
595 else if (*pfPhiDeg == -90.0F)
607 if (*pfPsiDeg < 0.0F)
613 if (*pfPsiDeg >= 360.0F)
620 *pfRhoDeg = *pfPsiDeg;
627 #endif // #if THISCOORDSYSTEM == ANDROID 630 #if (THISCOORDSYSTEM == WIN8) 632 float *pfRhoDeg,
float *pfChiDeg)
659 if (R[CHZ][CHZ] < 0.0F)
662 *pfTheDeg = 180.0F - *pfTheDeg;
666 if (*pfTheDeg >= 180.0F)
672 if (*pfTheDeg == 90.0F)
677 else if (*pfTheDeg == -90.0F)
688 if (fabsf(*pfTheDeg) >= 90.0F)
695 if (*pfPsiDeg < 0.0F)
701 if (*pfPsiDeg >= 360.0F)
707 *pfRhoDeg = 360.0F - *pfPsiDeg;
710 if (*pfRhoDeg >= 360.0F)
720 #endif // #if (THISCOORDSYSTEM == WIN8) 734 fetadeg = fscaling * sqrtf(rvecdeg[
CHX] * rvecdeg[
CHX] + rvecdeg[
CHY] * rvecdeg[
CHY] + rvecdeg[
CHZ] * rvecdeg[
CHZ]);
736 fetarad2 = fetarad * fetarad;
740 if (fetarad2 <= 0.02F)
743 sinhalfeta = fetarad * (0.5F -
ONEOVER48 * fetarad2);
745 else if (fetarad2 <= 0.06F)
749 fetarad4 = fetarad2 * fetarad2;
755 sinhalfeta = (float)sinf(0.5F * fetarad);
762 ftmp = fscaling * sinhalfeta / fetadeg;
763 pq->
q1 = rvecdeg[
CHX] * ftmp;
764 pq->
q2 = rvecdeg[
CHY] * ftmp;
765 pq->
q3 = rvecdeg[
CHZ] * ftmp;
770 pq->
q1 = pq->
q2 = pq->
q3 = 0.0F;
775 fvecsq = pq->
q1 * pq->
q1 + pq->
q2 * pq->
q2 + pq->
q3 * pq->
q3;
779 pq->
q0 = sqrtf(1.0F - fvecsq);
798 pq->
q0 = sqrtf(fabsf(fq0sq));
804 recip4q0 = 0.25F / pq->
q0;
814 pq->
q1 = sqrtf(fabsf(0.5F + 0.5F * R[
CHX][
CHX] - fq0sq));
815 pq->
q2 = sqrtf(fabsf(0.5F + 0.5F * R[
CHY][
CHY] - fq0sq));
816 pq->
q3 = sqrtf(fabsf(0.5F + 0.5F * R[
CHZ][
CHZ] - fq0sq));
821 if ((R[
CHX][CHY] - R[CHY][
CHX]) < 0.0F) pq->
q3 = -pq->
q3;
835 float f2q0q0, f2q0q1, f2q0q2, f2q0q3;
836 float f2q1q1, f2q1q2, f2q1q3;
837 float f2q2q2, f2q2q3;
842 f2q0q0 = f2q * pq->
q0;
843 f2q0q1 = f2q * pq->
q1;
844 f2q0q2 = f2q * pq->
q2;
845 f2q0q3 = f2q * pq->
q3;
848 f2q1q1 = f2q * pq->
q1;
849 f2q1q2 = f2q * pq->
q2;
850 f2q1q3 = f2q * pq->
q3;
853 f2q2q2 = f2q * pq->
q2;
854 f2q2q3 = f2q * pq->
q3;
855 f2q3q3 = 2.0F * pq->
q3 * pq->
q3;
858 R[
CHX][
CHX] = f2q0q0 + f2q1q1 - 1.0F;
859 R[
CHX][
CHY] = f2q1q2 + f2q0q3;
860 R[
CHX][
CHZ] = f2q1q3 - f2q0q2;
861 R[
CHY][
CHX] = f2q1q2 - f2q0q3;
862 R[
CHY][
CHY] = f2q0q0 + f2q2q2 - 1.0F;
863 R[
CHY][
CHZ] = f2q2q3 + f2q0q1;
864 R[
CHZ][
CHX] = f2q1q3 + f2q0q2;
865 R[
CHZ][
CHY] = f2q2q3 - f2q0q1;
866 R[
CHZ][
CHZ] = f2q0q0 + f2q3q3 - 1.0F;
880 if ((pq->
q0 >= 1.0F) || (pq->
q0 <= -1.0F))
889 fetarad = 2.0F * acosf(pq->
q0);
894 if (fetadeg >= 180.0F)
901 sinhalfeta = (float)sinf(0.5F * fetarad);
904 if (sinhalfeta == 0.0F)
907 rvecdeg[
CHX] = rvecdeg[
CHY] = rvecdeg[
CHZ] = 0.0F;
912 ftmp = fetadeg / sinhalfeta;
913 rvecdeg[
CHX] = pq->
q1 * ftmp;
914 rvecdeg[
CHY] = pq->
q2 * ftmp;
915 rvecdeg[
CHZ] = pq->
q3 * ftmp;
931 if (fdeltaq.
q0 < 0.0F)
933 fdeltaq.
q0 = -fdeltaq.
q0;
934 fdeltaq.
q1 = -fdeltaq.
q1;
935 fdeltaq.
q2 = -fdeltaq.
q2;
936 fdeltaq.
q3 = -fdeltaq.
q3;
941 ftmp = flpf + (1.0F - flpf) * sqrtf(fabs(1.0F - fdeltaq.
q0 * fdeltaq.
q0));
948 fdeltaq.
q0 = sqrtf(fabsf(1.0F - fdeltaq.
q1 * fdeltaq.
q1 - fdeltaq.
q2 * fdeltaq.
q2 - fdeltaq.
q3 * fdeltaq.
q3));
952 ftmp = 1.0F / fdeltat;
953 fOmega[
CHX] = rvecdeg[
CHX] * ftmp;
954 fOmega[
CHY] = rvecdeg[
CHY] * ftmp;
955 fOmega[
CHZ] = rvecdeg[
CHZ] * ftmp;
970 pqA->
q0 = pqB->
q0 * pqC->
q0 - pqB->
q1 * pqC->
q1 - pqB->
q2 * pqC->
q2 - pqB->
q3 * pqC->
q3;
971 pqA->
q1 = pqB->
q0 * pqC->
q1 + pqB->
q1 * pqC->
q0 + pqB->
q2 * pqC->
q3 - pqB->
q3 * pqC->
q2;
972 pqA->
q2 = pqB->
q0 * pqC->
q2 - pqB->
q1 * pqC->
q3 + pqB->
q2 * pqC->
q0 + pqB->
q3 * pqC->
q1;
973 pqA->
q3 = pqB->
q0 * pqC->
q3 + pqB->
q1 * pqC->
q2 - pqB->
q2 * pqC->
q1 + pqB->
q3 * pqC->
q0;
984 qProd.
q0 = pqA->
q0 * pqB->
q0 - pqA->
q1 * pqB->
q1 - pqA->
q2 * pqB->
q2 - pqA->
q3 * pqB->
q3;
985 qProd.
q1 = pqA->
q0 * pqB->
q1 + pqA->
q1 * pqB->
q0 + pqA->
q2 * pqB->
q3 - pqA->
q3 * pqB->
q2;
986 qProd.
q2 = pqA->
q0 * pqB->
q2 - pqA->
q1 * pqB->
q3 + pqA->
q2 * pqB->
q0 + pqA->
q3 * pqB->
q1;
987 qProd.
q3 = pqA->
q0 * pqB->
q3 + pqA->
q1 * pqB->
q2 - pqA->
q2 * pqB->
q1 + pqA->
q3 * pqB->
q0;
1000 qProd.
q0 = pqA->
q0 * pqB->
q0 + pqA->
q1 * pqB->
q1 + pqA->
q2 * pqB->
q2 + pqA->
q3 * pqB->
q3;
1001 qProd.
q1 = pqA->
q0 * pqB->
q1 - pqA->
q1 * pqB->
q0 - pqA->
q2 * pqB->
q3 + pqA->
q3 * pqB->
q2;
1002 qProd.
q2 = pqA->
q0 * pqB->
q2 + pqA->
q1 * pqB->
q3 - pqA->
q2 * pqB->
q0 - pqA->
q3 * pqB->
q1;
1003 qProd.
q3 = pqA->
q0 * pqB->
q3 - pqA->
q1 * pqB->
q2 + pqA->
q2 * pqB->
q1 - pqA->
q3 * pqB->
q0;
1014 fNorm = sqrtf(pqA->
q0 * pqA->
q0 + pqA->
q1 * pqA->
q1 + pqA->
q2 * pqA->
q2 + pqA->
q3 * pqA->
q3);
1018 fNorm = 1.0F / fNorm;
1028 pqA->
q1 = pqA->
q2 = pqA->
q3 = 0.0F;
1047 pqA->
q1 = pqA->
q2 = pqA->
q3 = 0.0F;
1057 float fsqrt1plusudotv;
1061 fsqrt1plusudotv = sqrtf(fabsf(1.0F + fu[
CHX] * fv[
CHX] + fu[
CHY] * fv[
CHY] + fu[
CHZ] * fv[
CHZ]));
1070 if (fsqrt1plusudotv != 0.0F)
1074 pfq->
q1 = -fuxv[
CHX] * ftmp;
1075 pfq->
q2 = -fuxv[
CHY] * ftmp;
1076 pfq->
q3 = -fuxv[
CHZ] * ftmp;
1086 ftmp = sqrtf(fabsf(pfq->
q1 * pfq->
q1 + pfq->
q2 * pfq->
q2 + pfq->
q3 * pfq->
q3));
void f3DOFMagnetometerMatrixNED(float fR[][3], float fBc[])
Aerospace NED magnetometer 3DOF flat eCompass function, computing rotation matrix fR...
void fRotationMatrixFromQuaternion(float R[][3], const Quaternion *pq)
compute the rotation matrix from an orientation quaternion
#define CHY
Used to access Y-channel entries in various data data structures.
void f3DOFTiltNED(float fR[][3], float fGc[])
Aerospace NED accelerometer 3DOF tilt function, computing rotation matrix fR.
#define ONEOVERSQRT2
1/sqrt(2)
void fAndroidAnglesDegFromRotationMatrix(float R[][3], float *pfPhiDeg, float *pfTheDeg, float *pfPsiDeg, float *pfRhoDeg, float *pfChiDeg)
extract the Android angles in degrees from the Android rotation matrix
Lower level sensor fusion interface.
#define FPIOVER180
degrees to radians conversion = pi / 180
Functions to convert between various orientation representations.
void fNEDAnglesDegFromRotationMatrix(float R[][3], float *pfPhiDeg, float *pfTheDeg, float *pfPsiDeg, float *pfRhoDeg, float *pfChiDeg)
extract the NED angles in degrees from the NED rotation matrix
float q1
x vector component
void feCompassAndroid(float fR[][3], float *pfDelta, float *pfsinDelta, float *pfcosDelta, float fBc[], float fGc[], float *pfmodBc, float *pfmodGc)
Android: basic 6DOF e-Compass function, computing rotation matrix fR and magnetic inclination angle f...
void fQuaternionFromRotationMatrix(float R[][3], Quaternion *pq)
compute the orientation quaternion from a 3x3 rotation matrix
void fqAeq1(Quaternion *pqA)
set a quaternion to the unit quaternion
Quaternion qconjgAxB(const Quaternion *pqA, const Quaternion *pqB)
function compute the quaternion product conjg(qA) * qB
void fLPFOrientationQuaternion(Quaternion *pq, Quaternion *pLPq, float flpf, float fdeltat, float fOmega[])
function low pass filters an orientation quaternion and computes virtual gyro rotation rate ...
void f3DOFMagnetometerMatrixWin8(float fR[][3], float fBc[])
Windows 8 magnetometer 3DOF flat eCompass function, computing rotation matrix fR. ...
void fQuaternionFromRotationVectorDeg(Quaternion *pq, const float rvecdeg[], float fscaling)
computes normalized rotation quaternion from a rotation vector (deg)
void feCompassWin8(float fR[][3], float *pfDelta, float *pfsinDelta, float *pfcosDelta, float fBc[], float fGc[], float *pfmodBc, float *pfmodGc)
Win8: basic 6DOF e-Compass function, computing rotation matrix fR and magnetic inclination angle fDel...
void qAeqBxC(Quaternion *pqA, const Quaternion *pqB, const Quaternion *pqC)
function compute the quaternion product qB * qC
void fveqconjgquq(Quaternion *pfq, float fu[], float fv[])
Math approximations file.
The sensor_fusion.h file implements the top level programming interface.
#define CHZ
Used to access Z-channel entries in various data data structures.
#define F180OVERPI
radians to degrees conversion = 180 / pi
Matrix manipulation functions.
void f3DOFTiltAndroid(float fR[][3], float fGc[])
Android accelerometer 3DOF tilt function computing, rotation matrix fR.
#define CHX
Used to access X-channel entries in various data data structures.
void f3x3matrixAeqI(float A[][3])
function sets the 3x3 matrix A to the identity matrix
float q2
y vector component
void feCompassNED(float fR[][3], float *pfDelta, float *pfsinDelta, float *pfcosDelta, float fBc[], float fGc[], float *pfmodBc, float *pfmodGc)
NED: basic 6DOF e-Compass function, computing rotation matrix fR and magnetic inclination angle fDelt...
void fqAeqNormqA(Quaternion *pqA)
function normalizes a rotation quaternion and ensures q0 is non-negative
#define ONEOVER3840
1 / 3840
quaternion structure definition
void fRotationVectorDegFromQuaternion(Quaternion *pq, float rvecdeg[])
computes rotation vector (deg) from rotation quaternion
void f3x3matrixAeqScalar(float A[][3], float Scalar)
function sets every entry in the 3x3 matrix A to a constant scalar
float q3
z vector component
void f3DOFTiltWin8(float fR[][3], float fGc[])
Windows 8 accelerometer 3DOF tilt function computing, rotation matrix fR.
void qAeqAxB(Quaternion *pqA, const Quaternion *pqB)
function compute the quaternion product qA = qA * qB
float fatan2_deg(float y, float x)
void f3DOFMagnetometerMatrixAndroid(float fR[][3], float fBc[])
Android magnetometer 3DOF flat eCompass function, computing rotation matrix fR.
void fWin8AnglesDegFromRotationMatrix(float R[][3], float *pfPhiDeg, float *pfTheDeg, float *pfPsiDeg, float *pfRhoDeg, float *pfChiDeg)
extract the Windows 8 angles in degrees from the Windows 8 rotation matrix