Skip to content

Commit b75a201

Browse files
committed
added quaternions operations
1 parent 1610a09 commit b75a201

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed

geometry/quaternions.c

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/**
2+
* @file
3+
* @brief API Functions related to 3D vector operations.
4+
* @author Krishna Vedala
5+
*/
6+
7+
#include <stdio.h>
8+
#ifdef __arm__ // if compiling for ARM-Cortex processors
9+
#define LIBQUAT_ARM
10+
#include <arm_math.h>
11+
#else
12+
#include <math.h>
13+
#endif
14+
#include <assert.h>
15+
16+
#include "geometry_datatypes.h"
17+
18+
/**
19+
* @addtogroup quats 3D Quaternion operations
20+
* @{
21+
*/
22+
23+
/**
24+
* Function to convert given Euler angles to a quaternion.
25+
* \f{eqnarray*}{
26+
* q_{0} & =
27+
* &\cos\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right)
28+
* +
29+
* \sin\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right)\\
30+
* q_{1} & =
31+
* &\sin\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right)
32+
* -
33+
* \cos\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right)\\
34+
* q_{2} & =
35+
* &\cos\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right)
36+
* +
37+
* \sin\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right)\\
38+
* q_{3} & =
39+
* &\cos\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right)
40+
* -
41+
* \sin\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right)\\
42+
* \f}
43+
*
44+
* @param [in] in_euler input Euler angles instance
45+
* @returns converted quaternion
46+
*/
47+
quaternion quat_from_euler(const euler *in_euler)
48+
{
49+
quaternion out_quat;
50+
51+
if (!in_euler) // if null
52+
{
53+
fprintf(stderr, "%s: Invalid input.", __func__);
54+
return out_quat;
55+
}
56+
57+
quaternion temp;
58+
59+
float cy = cosf(in_euler->yaw * 0.5f);
60+
float sy = sinf(in_euler->yaw * 0.5f);
61+
float cp = cosf(in_euler->pitch * 0.5f);
62+
float sp = sinf(in_euler->pitch * 0.5f);
63+
float cr = cosf(in_euler->roll * 0.5f);
64+
float sr = sinf(in_euler->roll * 0.5f);
65+
66+
temp.w = cr * cp * cy + sr * sp * sy;
67+
temp.q1 = sr * cp * cy - cr * sp * sy;
68+
temp.q2 = cr * sp * cy + sr * cp * sy;
69+
temp.q3 = cr * cp * sy - sr * sp * cy;
70+
71+
return temp;
72+
}
73+
74+
/**
75+
* Function to convert given quaternion to Euler angles.
76+
* \f{eqnarray*}{
77+
* \phi & = &
78+
* \tan^{-1}\left[\frac{2\left(q_0q_1+q_2q_3\right)}{1-2\left(q_1^2+q_2^2\right)}\right]\\
79+
* \theta & =
80+
* &-\sin^{-1}\left[2\left(q_0q_2-q_3q_1\right)\right]\\
81+
* \psi & = &
82+
* \tan^{-1}\left[\frac{2\left(q_0q_3+q_1q_2\right)}{1-2\left(q_2^2+q_3^2\right)}\right]\\
83+
* \f}
84+
*
85+
* @param [in] in_quat input quaternion instance
86+
* @returns converted euler angles
87+
*/
88+
euler euler_from_quat(const quaternion *in_quat)
89+
{
90+
euler out_euler;
91+
if (!in_quat) // if null
92+
{
93+
fprintf(stderr, "%s: Invalid input.", __func__);
94+
return out_euler;
95+
}
96+
97+
out_euler.roll = atan2f(
98+
2.f * (in_quat->w * in_quat->q1 + in_quat->q2 * in_quat->q3),
99+
1.f - 2.f * (in_quat->q1 * in_quat->q1 + in_quat->q2 * in_quat->q2));
100+
out_euler.pitch =
101+
asinf(2.f * (in_quat->w * in_quat->q2 + in_quat->q1 * in_quat->q3));
102+
out_euler.yaw = atan2f(
103+
2.f * (in_quat->w * in_quat->q3 + in_quat->q1 * in_quat->q2),
104+
1.f - 2.f * (in_quat->q2 * in_quat->q2 + in_quat->q3 * in_quat->q3));
105+
106+
return out_euler;
107+
}
108+
109+
/**
110+
* Function to multiply two quaternions.
111+
* \f{eqnarray*}{
112+
* \mathbf{c} & = & \mathbf{a}\otimes\mathbf{b}\\
113+
* & = & \begin{bmatrix}a_{0} & a_{1} & a_{2} &
114+
* a_{3}\end{bmatrix}\otimes\begin{bmatrix}b_{0} & b_{1} & b_{2} &
115+
* b_{3}\end{bmatrix}\\
116+
* & = &
117+
* \begin{bmatrix}
118+
* a_{0}b_{0}-a_{1}b_{1}-a_{2}b_{2}-a_{3}b_{3}\\
119+
* a_{0}b_{1}+a_{1}b_{0}+a_{2}b_{3}-a_{3}b_{2}\\
120+
* a_{0}b_{2}-a_{1}b_{3}+a_{2}b_{0}+a_{3}b_{1}\\
121+
* a_{0}b_{3}+a_{1}b_{2}-a_{2}b_{1}+a_{3}b_{0}
122+
* \end{bmatrix}^{T}
123+
* \f}
124+
*
125+
* @param [in] in_quat1 first input quaternion instance
126+
* @param [in] in_quat2 second input quaternion instance
127+
* @returns resultant quaternion
128+
*/
129+
quaternion quaternion_multiply(const quaternion *in_quat1,
130+
const quaternion *in_quat2)
131+
{
132+
quaternion out_quat;
133+
if (!in_quat1 || !in_quat2) // if null
134+
{
135+
fprintf(stderr, "%s: Invalid input.", __func__);
136+
return out_quat;
137+
}
138+
139+
out_quat.w = in_quat1->w * in_quat2->w - in_quat1->q1 * in_quat2->q1 -
140+
in_quat1->q2 * in_quat2->q2 - in_quat1->q3 * in_quat2->q3;
141+
out_quat.q1 = in_quat1->w * in_quat2->q1 + in_quat1->q1 * in_quat2->w +
142+
in_quat1->q2 * in_quat2->q3 - in_quat1->q3 * in_quat2->q2;
143+
out_quat.q2 = in_quat1->w * in_quat2->q2 - in_quat1->q1 * in_quat2->q3 +
144+
in_quat1->q2 * in_quat2->w + in_quat1->q3 * in_quat2->q1;
145+
out_quat.q3 = in_quat1->w * in_quat2->q3 + in_quat1->q1 * in_quat2->q2 -
146+
in_quat1->q2 * in_quat2->q1 + in_quat1->q3 * in_quat2->w;
147+
148+
return out_quat;
149+
}
150+
151+
/** @} */
152+
153+
static void test()
154+
{
155+
quaternion quat = {0.7071f, 0.7071f, 0.f, 0.f};
156+
euler eul = euler_from_quat(&quat);
157+
printf("Euler: %.4g, %.4g, %.4g\n", eul.pitch, eul.roll, eul.yaw);
158+
159+
quaternion test_quat = quat_from_euler(&eul);
160+
printf("Quaternion: %.4g %+.4g %+.4g %+.4g\n", test_quat.w,
161+
test_quat.dual.x, test_quat.dual.y, test_quat.dual.z);
162+
163+
assert(fabs(test_quat.w - quat.w) < .01);
164+
assert(fabs(test_quat.q1 - quat.q1) < .01);
165+
assert(fabs(test_quat.q2 - quat.q2) < .01);
166+
assert(fabs(test_quat.q3 - quat.q3) < .01);
167+
}
168+
169+
int main()
170+
{
171+
test();
172+
return 0;
173+
}

0 commit comments

Comments
 (0)