Skyward boardcore
Loading...
Searching...
No Matches
SkyQuaternion.cpp
Go to the documentation of this file.
1/* Copyright (c) 2022 Skyward Experimental Rocketry
2 * Authors: Marco Cella, Alberto Nidasio
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#include "SkyQuaternion.h"
24
25#include <utils/Constants.h>
26
27#include <cmath>
28
29#include "iostream"
30
31using namespace std;
32using namespace Eigen;
33
34namespace Boardcore
35{
36
37namespace SkyQuaternion
38{
39
40Vector4f eul2quat(const Vector3f& euler)
41{
42 // Euler angles are ZYX
43 float yaw = euler(0) * Constants::DEGREES_TO_RADIANS;
44 float pitch = euler(1) * Constants::DEGREES_TO_RADIANS;
45 float roll = euler(2) * Constants::DEGREES_TO_RADIANS;
46
47 float cyaw = cosf(yaw * 0.5F);
48 float syaw = sinf(yaw * 0.5F);
49 float cpitch = cosf(pitch * 0.5F);
50 float spitch = sinf(pitch * 0.5F);
51 float croll = cosf(roll * 0.5F);
52 float sroll = sinf(roll * 0.5F);
53
54 float qx = cyaw * cpitch * sroll - syaw * spitch * croll;
55 float qy = cyaw * spitch * croll + syaw * cpitch * sroll;
56 float qz = syaw * cpitch * croll - cyaw * spitch * sroll;
57 float qw = cyaw * cpitch * croll + syaw * spitch * sroll;
58
59 return Vector4f(qx, qy, qz, qw);
60}
61
62Vector3f quat2eul(const Vector4f& quat)
63{
64 // Euler angles are ZYX
65 float qx = quat(0);
66 float qy = quat(1);
67 float qz = quat(2);
68 float qw = quat(3);
69
70 float yaw = atan2f(2.0F * (qx * qy + qw * qz),
71 powf(qw, 2) + powf(qx, 2) - powf(qy, 2) - powf(qz, 2));
72
73 float a = -2.0F * (qx * qz - qw * qy);
74 if (a > 1.0F)
75 a = 1.0F;
76 else if (a < -1.0F)
77 a = -1.0F;
78
79 float pitch = asinf(a);
80
81 float roll = atan2f(2.0F * (qy * qz + qw * qx),
82 powf(qw, 2) - powf(qx, 2) - powf(qy, 2) + powf(qz, 2));
83
84 return Vector3f(roll, pitch, yaw) * Constants::RADIANS_TO_DEGREES;
85}
86
87Vector3f quat2stepperAngles(const Vector4f& q)
88{
89 float qx = q[0];
90 float qy = q[1];
91 float qz = q[2];
92 float qw = q[3];
93
94 Vector3f angles;
95
96 // clang-format off
97 // DOWN EAST NORD
98 Matrix3f R{
99 {(2*(qw*qw + qx*qx)-1), -2*(qx*qy - qw*qz), -2*(qx*qz + qw*qy)},
100 {2*(qx*qy + qw*qz), -(2*(qw*qw + qy*qy)-1), -2*(qy*qz - qw*qx)},
101 {2*(qx*qz - qw*qy), -2*(qy*qz + qw*qx), -(2*(qw*qw + qz*qz)-1)}};
102 // clang-format on
103
104 // pitch: rotation of motor2 (how the Down-axis move on DN-fixed plane)
105 angles[1] = std::atan2(R(2, 0), R(0, 0)) * 180.0f / Constants::PI;
106
107 // yaw: rotation of motor1 (rotation angle of East-body-versor from
108 // East-fixed-versor seen from Down-body-versor )
109 Vector3f n = R.col(0); // observing vector: normal to
110 // East-body-vector and East-fixed-versor
111
112 Vector3f e = R.col(1);
113 Vector3f temp(0, 1, 0);
114
115 Vector3f x = temp.transpose().cross(e);
116
117 float sign = ((x.dot(n) > 0) ? 1.f : (x.dot(n) < 0) ? -1.f : 0.f);
118 float c = sign * x.norm();
119 angles[0] = -std::atan2(c, temp.dot(e)) * 180.0f / Constants::PI;
120
121 angles[2] = 0; // Roll assumed 0
122 return angles;
123}
124
125Vector4f rotationMatrix2quat(const Matrix3f& rtm)
126{
127 float r11 = rtm(0, 0);
128 float r12 = rtm(0, 1);
129 float r13 = rtm(0, 2);
130 float r21 = rtm(1, 0);
131 float r22 = rtm(1, 1);
132 float r23 = rtm(1, 2);
133 float r31 = rtm(2, 0);
134 float r32 = rtm(2, 1);
135 float r33 = rtm(2, 2);
136
137 float qx;
138 float qy;
139 float qz;
140 float qw;
141
142 float tr = r11 + r22 + r33;
143
144 if (tr > 0)
145 {
146 float sqtrp1 = sqrt(1 + tr);
147
148 qx = (r23 - r32) / (2.0 * sqtrp1);
149 qy = (r31 - r13) / (2.0 * sqtrp1);
150 qz = (r12 - r21) / (2.0 * sqtrp1);
151 qw = 0.5 * sqtrp1;
152 }
153 else if ((r22 > r11) && (r22 > r33))
154 {
155 float sqdip1 = sqrt(r22 - r11 - r33 + 1.0);
156
157 qy = 0.5 * sqdip1;
158
159 if (sqdip1 != 0)
160 sqdip1 = 0.5 / sqdip1;
161
162 qx = (r12 + r21) * sqdip1;
163 qz = (r23 + r32) * sqdip1;
164 qw = (r31 - r13) * sqdip1;
165 }
166 else if (r33 > r11)
167 {
168 float sqdip1 = sqrt(r33 - r11 - r22 + 1.0);
169
170 qz = 0.5 * sqdip1;
171
172 if (sqdip1 != 0)
173 sqdip1 = 0.5 / sqdip1;
174
175 qx = (r31 + r13) * sqdip1;
176 qy = (r23 + r32) * sqdip1;
177 qw = (r12 - r21) * sqdip1;
178 }
179 else
180 {
181 float sqdip1 = sqrt(r11 - r22 - r33 + 1.0);
182
183 qx = 0.5 * sqdip1;
184
185 if (sqdip1 != 0)
186 sqdip1 = 0.5 / sqdip1;
187
188 qy = (r12 + r21) * sqdip1;
189 qz = (r31 + r13) * sqdip1;
190 qw = (r23 - r32) * sqdip1;
191 }
192
193 return Vector4f(qx, qy, qz, qw);
194}
195
196Matrix3f quat2rotationMatrix(const Vector4f& q)
197{
198 // clang-format off
199 return Matrix3f{
200 {
201 q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3],
202 2.0f * (q[0] * q[1] - q[2] * q[3]),
203 2.0f * (q[0] * q[2] + q[1] * q[3]),
204 },
205 {
206 2.0f * (q[0] * q[1] + q[2] * q[3]),
207 - q[0] * q[0] + q[1] * q[1] - q[2] * q[2] + q[3] * q[3],
208 2.0f * (q[1] * q[2] - q[0] * q[3]),
209 },
210 {
211 2.0f * (q[0] * q[2] - q[1] * q[3]),
212 2.0f * (q[1] * q[2] + q[0] * q[3]),
213 - q[0] * q[0] - q[1] * q[1] + q[2] * q[2] + q[3] * q[3]
214 }
215 };
216 // clang-format on
217}
218
219bool quatNormalize(Vector4f& quat)
220{
221 float den = sqrt(powf(quat(0), 2) + powf(quat(1), 2) + powf(quat(2), 2) +
222 powf(quat(3), 2));
223 if (den < 1e-8)
224 return false;
225
226 quat = quat / den;
227
228 return true;
229}
230
231Vector4f quatProd(const Vector4f& q1, const Vector4f& q2)
232{
233 Vector3f qv1 = q1.head<3>();
234 float qs1 = q1(3);
235 Vector3f qv2 = q2.head<3>();
236 float qs2 = q2(3);
237
238 Vector4f quater;
239 // cppcheck-suppress constStatement
240 quater << qs1 * qv2 + qs2 * qv1 - qv1.cross(qv2), qs1 * qs2 - qv1.dot(qv2);
241 quater.normalize();
242
243 return quater;
244}
245
246} // namespace SkyQuaternion
247
248} // namespace Boardcore
Matrix3f quat2rotationMatrix(const Vector4f &q)
Vector4f quatProd(const Vector4f &q1, const Vector4f &q2)
Vector4f eul2quat(const Vector3f &euler)
Vector3f quat2eul(const Vector4f &quat)
Vector4f rotationMatrix2quat(const Matrix3f &rtm)
Vector3f quat2stepperAngles(const Vector4f &q)
bool quatNormalize(Vector4f &quat)
This file includes all the types the logdecoder script will decode.
Definition WIZ5500.h:318