M5Unit-IMU 0.0.2 git rev:e5b00aa
Loading...
Searching...
No Matches
quaternion.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UNIT_IMU_MATH_QUATERNION_HPP
11#define M5_UNIT_IMU_MATH_QUATERNION_HPP
12
13#include <cmath>
14
15#include "vector3.hpp"
16
17namespace m5 {
18namespace math {
19
21constexpr float QUATERNION_ZERO_EPSILON{1e-9f};
23constexpr float QUATERNION_PI{3.14159265358979323846f};
24
31struct Quaternion {
32 float w{1.0f};
33 float x{};
34 float y{};
35 float z{};
36
38 Quaternion() = default;
40 constexpr Quaternion(const float w_, const float x_, const float y_, const float z_) : w(w_), x(x_), y(y_), z(z_)
41 {
42 }
43
45 static inline Quaternion identity()
46 {
47 return Quaternion();
48 }
49
51 inline Quaternion operator*(const Quaternion& rhs) const
52 {
53 return Quaternion(w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z, w * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y,
54 w * rhs.y - x * rhs.z + y * rhs.w + z * rhs.x, w * rhs.z + x * rhs.y - y * rhs.x + z * rhs.w);
55 }
56
58 inline Quaternion conjugated() const
59 {
60 return Quaternion(w, -x, -y, -z);
61 }
62
64 inline float normSq() const
65 {
66 return w * w + x * x + y * y + z * z;
67 }
69 inline float norm() const
70 {
71 return std::sqrt(normSq());
72 }
77 bool normalize()
78 {
79 const float n = norm();
81 return false;
82 }
83 const float inv = 1.0f / n;
84 w *= inv;
85 x *= inv;
86 y *= inv;
87 z *= inv;
88 return true;
89 }
91 inline Quaternion normalized() const
92 {
93 Quaternion q(*this);
94 q.normalize();
95 return q;
96 }
97
103 inline Vector3 rotate(const Vector3& v) const
104 {
105 const Vector3 qv(x, y, z);
106 const Vector3 t = qv.cross(v) * 2.0f;
107 return v + t * w + qv.cross(t);
108 }
109
116 static inline Quaternion fromAxisAngle(const Vector3& axis, const float angle_rad)
117 {
118 if (axis.norm() < QUATERNION_ZERO_EPSILON) {
119 return identity();
120 }
121 const Vector3 a = axis.normalized();
122 const float half = angle_rad * 0.5f;
123 const float s = std::sin(half);
124 return Quaternion(std::cos(half), a.x * s, a.y * s, a.z * s);
125 }
126
134 static inline Quaternion fromEuler(const float roll_deg, const float pitch_deg, const float yaw_deg)
135 {
136 constexpr float deg2rad{QUATERNION_PI / 180.0f};
137 const float roll = roll_deg * deg2rad;
138 const float pitch = pitch_deg * deg2rad;
139 const float yaw = yaw_deg * deg2rad;
140
141 const float cr = std::cos(roll * 0.5f);
142 const float sr = std::sin(roll * 0.5f);
143 const float cp = std::cos(pitch * 0.5f);
144 const float sp = std::sin(pitch * 0.5f);
145 const float cy = std::cos(yaw * 0.5f);
146 const float sy = std::sin(yaw * 0.5f);
147
148 return Quaternion(cr * cp * cy + sr * sp * sy, sr * cp * cy - cr * sp * sy, cr * sp * cy + sr * cp * sy,
149 cr * cp * sy - sr * sp * cy);
150 }
151
160 inline void toEuler(float& roll_deg, float& pitch_deg, float& yaw_deg) const
161 {
162 constexpr float rad2deg{180.0f / QUATERNION_PI};
163
164 const float sinr_cosp = 2.0f * (w * x + y * z);
165 const float cosr_cosp = 1.0f - 2.0f * (x * x + y * y);
166 const float roll = std::atan2(sinr_cosp, cosr_cosp);
167
168 float sinp = 2.0f * (w * y - z * x);
169 if (sinp > 1.0f) {
170 sinp = 1.0f;
171 } else if (sinp < -1.0f) {
172 sinp = -1.0f;
173 }
174 const float pitch = std::asin(sinp);
175
176 const float siny_cosp = 2.0f * (w * z + x * y);
177 const float cosy_cosp = 1.0f - 2.0f * (y * y + z * z);
178 const float yaw = std::atan2(siny_cosp, cosy_cosp);
179
180 roll_deg = roll * rad2deg;
181 pitch_deg = pitch * rad2deg;
182 yaw_deg = yaw * rad2deg;
183 }
184
192 inline void integrate(const Vector3& gyro_rad_s, const float dt)
193 {
194 const Quaternion omega(0.0f, gyro_rad_s.x, gyro_rad_s.y, gyro_rad_s.z);
195 const Quaternion qdot = (*this) * omega;
196 const float half_dt = 0.5f * dt;
197 w += half_dt * qdot.w;
198 x += half_dt * qdot.x;
199 y += half_dt * qdot.y;
200 z += half_dt * qdot.z;
201 normalize();
202 }
203};
204
205} // namespace math
206} // namespace m5
207#endif
Top level namespace of M5Stack.
Definition ahrs_controller.cpp:26
constexpr float QUATERNION_ZERO_EPSILON
Quaternions with a norm below this are treated as zero (normalize safety)
Definition quaternion.hpp:21
constexpr float QUATERNION_PI
PI (float)
Definition quaternion.hpp:23
Plain Hamilton quaternion (float) used to represent attitude.
Definition quaternion.hpp:31
float norm() const
Norm (magnitude)
Definition quaternion.hpp:69
static Quaternion fromEuler(const float roll_deg, const float pitch_deg, const float yaw_deg)
Build a rotation quaternion from aerospace ZYX Euler angles.
Definition quaternion.hpp:134
static Quaternion identity()
Identity quaternion (no rotation)
Definition quaternion.hpp:45
constexpr Quaternion(const float w_, const float x_, const float y_, const float z_)
Construct from components.
Definition quaternion.hpp:40
float x
Vector part X.
Definition quaternion.hpp:33
Quaternion operator*(const Quaternion &rhs) const
Hamilton product (this rotation applied after rhs)
Definition quaternion.hpp:51
float normSq() const
Squared norm.
Definition quaternion.hpp:64
float w
Scalar part.
Definition quaternion.hpp:32
Quaternion conjugated() const
Conjugate (equals the inverse for a unit quaternion)
Definition quaternion.hpp:58
float z
Vector part Z.
Definition quaternion.hpp:35
static Quaternion fromAxisAngle(const Vector3 &axis, const float angle_rad)
Build a rotation quaternion from an axis and angle.
Definition quaternion.hpp:116
bool normalize()
Normalize this quaternion in place.
Definition quaternion.hpp:77
Quaternion()=default
Default-construct as identity (no rotation)
Quaternion normalized() const
Return a normalized copy.
Definition quaternion.hpp:91
void toEuler(float &roll_deg, float &pitch_deg, float &yaw_deg) const
Decompose this quaternion into aerospace ZYX Euler angles.
Definition quaternion.hpp:160
Vector3 rotate(const Vector3 &v) const
Rotate a vector by this quaternion (active rotation, right-handed)
Definition quaternion.hpp:103
void integrate(const Vector3 &gyro_rad_s, const float dt)
Integrate body-frame angular velocity over dt (gyro kinematics)
Definition quaternion.hpp:192
float y
Vector part Y.
Definition quaternion.hpp:34
Plain 3D vector (float)
Definition vector3.hpp:25
Vector3 normalized() const
Return a normalized copy (zero vector maps to zero vector)
Definition vector3.hpp:83
Vector3 cross(const Vector3 &rhs) const
Cross product (right-handed)
Definition vector3.hpp:57
float z
Z component.
Definition vector3.hpp:28
float norm() const
Euclidean norm (magnitude)
Definition vector3.hpp:62
float x
X component.
Definition vector3.hpp:26
float y
Y component.
Definition vector3.hpp:27
Minimal 3D vector arithmetic (framework independent)