2 * This file is part of INAV.
4 * INAV is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * INAV is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with INAV. If not, see <http://www.gnu.org/licenses/>.
17 * Original implementation by HaukeRa
18 * Refactored and adapted by DigitalEntity
26 #include "common/maths.h"
27 #include "common/vector.h"
33 static inline fpQuaternion_t
* quaternionInitUnit(fpQuaternion_t
* result
)
42 static inline fpQuaternion_t
* quaternionInitFromVector(fpQuaternion_t
* result
, const fpVector3_t
* v
)
51 static inline void quaternionToAxisAngle(fpAxisAngle_t
* result
, const fpQuaternion_t
* q
)
53 fpAxisAngle_t a
= {.axis
= {{1.0f
, 0.0f
, 0.0f
}}, .angle
= 0};
55 a
.angle
= 2.0f
* acos_approx(constrainf(q
->q0
, -1.0f
, 1.0f
));
57 if (a
.angle
> M_PIf
) {
58 a
.angle
-= 2.0f
* M_PIf
;
61 const float sinVal
= sqrtf(1.0f
- q
->q0
* q
->q0
);
63 // Axis is only valid when rotation is large enough sin(0.0057 deg) = 0.0001
65 a
.axis
.x
= q
->q1
/ sinVal
;
66 a
.axis
.y
= q
->q2
/ sinVal
;
67 a
.axis
.z
= q
->q3
/ sinVal
;
75 static inline fpQuaternion_t
* axisAngleToQuaternion(fpQuaternion_t
* result
, const fpAxisAngle_t
* a
)
78 const float s
= sin_approx(a
->angle
/ 2.0f
);
80 q
.q0
= cos_approx(a
->angle
/ 2.0f
);
81 q
.q1
= -a
->axis
.x
* s
;
82 q
.q2
= -a
->axis
.y
* s
;
83 q
.q3
= -a
->axis
.z
* s
;
89 static inline float quaternionNormSqared(const fpQuaternion_t
* q
)
91 return sq(q
->q0
) + sq(q
->q1
) + sq(q
->q2
) + sq(q
->q3
);
94 static inline fpQuaternion_t
* quaternionMultiply(fpQuaternion_t
* result
, const fpQuaternion_t
* a
, const fpQuaternion_t
* b
)
98 p
.q0
= a
->q0
* b
->q0
- a
->q1
* b
->q1
- a
->q2
* b
->q2
- a
->q3
* b
->q3
;
99 p
.q1
= a
->q0
* b
->q1
+ a
->q1
* b
->q0
+ a
->q2
* b
->q3
- a
->q3
* b
->q2
;
100 p
.q2
= a
->q0
* b
->q2
- a
->q1
* b
->q3
+ a
->q2
* b
->q0
+ a
->q3
* b
->q1
;
101 p
.q3
= a
->q0
* b
->q3
+ a
->q1
* b
->q2
- a
->q2
* b
->q1
+ a
->q3
* b
->q0
;
107 static inline fpQuaternion_t
* quaternionScale(fpQuaternion_t
* result
, const fpQuaternion_t
* a
, const float b
)
120 static inline fpQuaternion_t
* quaternionAdd(fpQuaternion_t
* result
, const fpQuaternion_t
* a
, const fpQuaternion_t
* b
)
124 p
.q0
= a
->q0
+ b
->q0
;
125 p
.q1
= a
->q1
+ b
->q1
;
126 p
.q2
= a
->q2
+ b
->q2
;
127 p
.q3
= a
->q3
+ b
->q3
;
133 static inline fpQuaternion_t
* quaternionConjugate(fpQuaternion_t
* result
, const fpQuaternion_t
* q
)
143 static inline fpQuaternion_t
* quaternionNormalize(fpQuaternion_t
* result
, const fpQuaternion_t
* q
)
145 float mod
= fast_fsqrtf(quaternionNormSqared(q
));
147 // Length is too small - re-initialize to zero rotation
154 result
->q0
= q
->q0
/ mod
;
155 result
->q1
= q
->q1
/ mod
;
156 result
->q2
= q
->q2
/ mod
;
157 result
->q3
= q
->q3
/ mod
;
163 static inline fpVector3_t
* quaternionRotateVector(fpVector3_t
* result
, const fpVector3_t
* vect
, const fpQuaternion_t
* ref
)
165 fpQuaternion_t vectQuat
, refConj
;
168 vectQuat
.q1
= vect
->x
;
169 vectQuat
.q2
= vect
->y
;
170 vectQuat
.q3
= vect
->z
;
172 quaternionConjugate(&refConj
, ref
);
173 quaternionMultiply(&vectQuat
, &refConj
, &vectQuat
);
174 quaternionMultiply(&vectQuat
, &vectQuat
, ref
);
176 result
->x
= vectQuat
.q1
;
177 result
->y
= vectQuat
.q2
;
178 result
->z
= vectQuat
.q3
;
182 static inline fpVector3_t
* quaternionRotateVectorInv(fpVector3_t
* result
, const fpVector3_t
* vect
, const fpQuaternion_t
* ref
)
184 fpQuaternion_t vectQuat
, refConj
;
187 vectQuat
.q1
= vect
->x
;
188 vectQuat
.q2
= vect
->y
;
189 vectQuat
.q3
= vect
->z
;
191 quaternionConjugate(&refConj
, ref
);
192 quaternionMultiply(&vectQuat
, ref
, &vectQuat
);
193 quaternionMultiply(&vectQuat
, &vectQuat
, &refConj
);
195 result
->x
= vectQuat
.q1
;
196 result
->y
= vectQuat
.q2
;
197 result
->z
= vectQuat
.q3
;