-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathquaternion.c
More file actions
286 lines (255 loc) · 8.98 KB
/
quaternion.c
File metadata and controls
286 lines (255 loc) · 8.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
//*****************************************************************************
//
// quaternion.c - Functions for performing quaternion operations.
//
// Copyright (c) 2013 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 2.0.1.11577 of the Tiva Firmware Development Package.
//
//*****************************************************************************
#include <math.h>
#include "quaternion.h"
//*****************************************************************************
//
//! \addtogroup quaternion_api
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// If M_PI has not been defined by the system headers, define it here.
//
//*****************************************************************************
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
//*****************************************************************************
//
//! Computes a quaternion from a set of eueler angles specified in degrees
//!
//! \param pfQOut is the inverted quaternion in W,X,Y,Z form
//! \param fRollDeg is roll in degrees
//! \param fPitchDeg is pitch in degrees
//! \param fYawDeg is yaw in degrees
//!
//! This function computes a quaternion from a set of euler angles specified
//! in degrees
//!
//! \return Returns a quaternion representing the provided eulers
//
//*****************************************************************************
void
QuaternionFromEuler(float pfQOut[4], float fRollDeg, float fPitchDeg,
float fYawDeg)
{
float fRoll, fPitch, fYaw;
float fCOSY, fCOSP, fCOSR;
float fSINY, fSINP, fSINR;
//
// Convert roll, pitch, and yaw from degrees into radians
//
fRoll = fRollDeg * M_PI / 180.0;
fPitch = fPitchDeg * M_PI / 180.0;
fYaw = fYawDeg * M_PI / 180.0;
//
// Pre-calculate the cosine of (yaw, pitch, roll divided by 2)
//
fCOSY = cosf(fYaw / 2.0);
fCOSP = cosf(fPitch / 2.0);
fCOSR = cosf(fRoll / 2.0);
//
// Pre-calculate the sine of (yaw, pitch, roll divided by 2)
//
fSINY = sinf(fYaw / 2.0);
fSINP = sinf(fPitch / 2.0);
fSINR = sinf(fRoll / 2.0);
//
// The W component
//
pfQOut[Q_W] = fCOSY * fCOSP * fCOSR - fSINY * fSINP * fSINR;
//
// The X component
//
pfQOut[Q_X] = fSINY * fSINP * fCOSR + fCOSY * fCOSP * fSINR;
//
// The Y component
//
pfQOut[Q_Y] = fCOSY * fSINP * fCOSR - fSINY * fCOSP * fSINR;
//
// The Z component
//
pfQOut[Q_Z] = fSINY * fCOSP * fCOSR + fCOSY * fSINP * fSINR;
}
//*****************************************************************************
//
//! Computes the magnitude of a quaternion.
//!
//! \param pfQIn is the source quaternion in W,X,Y,Z form
//!
//! This function computes the magnitude of a quaternion by summing the square
//! of each of the quatnerion components.
//!
//! \return Returns the scalar magnitude of the quaternion
//
//*****************************************************************************
float
QuaternionMagnitude(float pfQIn[4])
{
float fSumSq;
//
// Calculate the magnitude of the quaternion by finding the sum of the
// squares of each component.
//
fSumSq = ((pfQIn[Q_W] * pfQIn[Q_W]) + (pfQIn[Q_X] * pfQIn[Q_X]) +
(pfQIn[Q_Y] * pfQIn[Q_Y]) + (pfQIn[Q_Z] * pfQIn[Q_Z]));
return(fSumSq);
}
//*****************************************************************************
//
//! Computes the inverse of a quaternion.
//!
//! \param pfQOut is the inverted quaternion in W,X,Y,Z form
//! \param pfQIn is the source quaternion in W,X,Y,Z form
//!
//! This function computes the inverse of a quaternion. The inverse of a
//! quaternion produces a rotation opposite to the source quaternion. This
//! can be achieved by simply changing the signs of the imaginary components
//! of a quaternion when the quatnerion is a unit quaternion.
//!
//! \return Returns the inverse of a quaternion.
//
//*****************************************************************************
void
QuaternionInverse(float pfQOut[4], float pfQIn[4])
{
float fMag;
//
// Find magnitude of the quaternion. This will be used to normalize the
// source quaternion if it's not already. If it is a unit quaternion then
// the magnitude should be nearly equal to 1.0 and dividing by the
// magnitude has no mathemtical effect.
//
fMag = QuaternionMagnitude(pfQIn);
//
// Normalize the W component
//
pfQOut[Q_W] = pfQIn[Q_W] / fMag;
//
// Invert and normalize the X component
//
pfQOut[Q_X] = -pfQIn[Q_X] / fMag;
//
// Invert and normalize the Y component
//
pfQOut[Q_Y] = -pfQIn[Q_Y] / fMag;
//
// Invert and normalize the Z component
//
pfQOut[Q_Z] = -pfQIn[Q_Z] / fMag;
}
//*****************************************************************************
//
//! Computes the product of two quaternions.
//!
//! \param pfQOut is the product of In1 X In2
//! \param pfQIn1 is the source quaternion in W,X,Y,Z form
//! \param pfQIn2 is the source quaternion in W,X,Y,Z form
//!
//! This function computes the cross product of two quaternions.
//!
//! \return Returns the cross product of the two quaternions.
//
//*****************************************************************************
void
QuaternionMult(float pfQOut[4], float pfQIn1[4], float pfQIn2[4])
{
//
// Let Q1 and Q2 be two quaternions with components w,x,y,z
// Let Qp be the cross product Q1 x Q2. The components of Qp can be
// calculated as follows:
//
// Qp.w = (Q1w Q2w) - (Q1x Q2x) - (Q1y Q2y) - (Q1z Q2z)
// Qp.x = (Q1w Q2x) + (Q1x Q2w) - (Q1z Q2y) + (Q1y Q2z)
// Qp.y = (Q1y Q2w) + (Q1z Q2x) + (Q1w Q2y) - (Q1x Q2z)
// Qp.z = (Q1z Q2w) - (Q1y Q2x) + (Q1x Q2y) + (Q1w Q2z)
//
//
// Calculate the W term
//
pfQOut[Q_W] = ((pfQIn2[Q_W] * pfQIn1[Q_W]) - (pfQIn2[Q_X] * pfQIn1[Q_X]) -
(pfQIn2[Q_Y] * pfQIn1[Q_Y]) - (pfQIn2[Q_Z] * pfQIn1[Q_Z]));
//
// Calculate the X term
//
pfQOut[Q_X]= ((pfQIn2[Q_X] * pfQIn1[Q_W]) + (pfQIn2[Q_W] * pfQIn1[Q_X]) -
(pfQIn2[Q_Y] * pfQIn1[Q_Z]) + (pfQIn2[Q_Z] * pfQIn1[Q_Y]));
//
// Calculate the Y term
//
pfQOut[Q_Y]= ((pfQIn2[Q_W] * pfQIn1[Q_Y]) + (pfQIn2[Q_X] * pfQIn1[Q_Z]) -
(pfQIn2[Q_Y] * pfQIn1[Q_W]) - (pfQIn2[Q_Z] * pfQIn1[Q_X]));
//
// Calculate the Z term
//
pfQOut[Q_Z] = ((pfQIn2[Q_W] * pfQIn1[Q_Z]) - (pfQIn2[Q_X] * pfQIn1[Q_Y]) -
(pfQIn2[Q_Y] * pfQIn1[Q_X]) + (pfQIn2[Q_Z] * pfQIn1[Q_W]));
}
//*****************************************************************************
//
//! Computes the angle between two quaternions
//!
//! \param pfQIn1 is a source quaternion in W,X,Y,Z form
//! \param pfQIn2 is a source quaternion in W,X,Y,Z form
//!
//! This function computes the angle between two quaternions.
//!
//! \return Returns the angle, in radians, between the two quaternions.
//
//*****************************************************************************
float
QuaternionAngle(float pfQIn1[4], float pfQIn2[4])
{
float pfQInv[4];
float pfQProd[4];
//
// Let Q1 and Q2 be two quaternions having components w,x,y,z. The angle
// between the orientations represented by Q1 and Q2 can be calculated
// with:
//
// angle = arccos( (Q2 * Q1').w ) * 2.0;
//
// where Q1' is the inverse of Q1
//
//
// Calculate the inverse of Q1
//
QuaternionInverse(pfQInv, pfQIn1);
//
// Find the product of Q2 x Q1`
//
QuaternionMult(pfQProd, pfQIn2, pfQInv);
//
// calculate the arccos of the w component of the previous product.
//
return(acosf(pfQProd[Q_W]) * 2.0);
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************