|
1 |
| -/* |
2 |
| - This sketch shows to perform operations on quaternions and how to convert arrays to quaternions. |
3 |
| - */ |
4 |
| - |
5 |
| -#include <quaternion_type.h> |
6 |
| - |
7 |
| -//======= Display functions ======= |
8 |
| - |
9 |
| -void printQuat( vec3_t vec ) { |
10 |
| - Serial.print( vec.x ); |
11 |
| - Serial.print( ", " ); |
12 |
| - Serial.print( vec.y ); |
13 |
| - Serial.print( ", " ); |
14 |
| - Serial.print( vec.z ); |
15 |
| -} |
16 |
| - |
17 |
| -void printQuat( quat_t quat ) { |
18 |
| - Serial.print( quat.w ); |
19 |
| - Serial.print( ", " ); |
20 |
| - printQuat( quat.v ); |
21 |
| -} |
22 |
| - |
23 |
| -template<typename T=quat_t> |
24 |
| -void printOperation(String label, T input) { |
25 |
| - Serial.println(label); |
26 |
| - Serial.print( "\t\t(" ); |
27 |
| - printQuat(input); |
28 |
| - Serial.print( ")\n\n" ); |
29 |
| -} |
30 |
| - |
31 |
| -//========== Main program ========= |
32 |
| - |
33 |
| -void setup() { |
34 |
| - Serial.begin(9600); |
35 |
| - Serial.flush(); |
36 |
| - |
37 |
| - //-------- Quaternions -------- |
38 |
| - quat_t q1 = { 1, 0, 0, 0 }; |
39 |
| - quat_t q2 = { 0, 1, 0, 0 }; |
40 |
| - quat_t q3 = { 0, 0, 1, 0 }; |
41 |
| - quat_t q4 = { 0, 0, 0, 1 }; |
42 |
| - quat_t q5; |
43 |
| - |
44 |
| - // 1. Basic operations: |
45 |
| - // Quaternions can be manipulated in the same way as scalar values |
46 |
| - |
47 |
| - // Addition |
48 |
| - q5 = q1 + q2; |
49 |
| - printOperation( "1. Addition: ", q5 ); |
50 |
| - |
51 |
| - // Subtraction |
52 |
| - q5 = q2 - q3; |
53 |
| - printOperation( "2. Subtraction: ", q5 ); |
54 |
| - |
55 |
| - // Negation: |
56 |
| - q5 = -q5; |
57 |
| - printOperation( "3. Negation: ", q5 ); |
58 |
| - |
59 |
| - // Increment: |
60 |
| - q5 += q4; |
61 |
| - printOperation( "4. Increment: ", q5 ); |
62 |
| - |
63 |
| - // Decrement: |
64 |
| - q5 -= q1; |
65 |
| - printOperation( "5. Decrement: ", q5 ); |
66 |
| - |
67 |
| - // Scalar product: |
68 |
| - q5 = q5*5; |
69 |
| - printOperation( "6A. Scalar product: ", q5 ); |
70 |
| - // Reverse order |
71 |
| - q5 = -3*q5; |
72 |
| - printOperation( "6B. Scalar product (reverse order): ", q5 ); |
73 |
| - |
74 |
| - // Scalar divide: |
75 |
| - q5 = q5/8; |
76 |
| - printOperation( "7. Scalar divide: ", q5 ); |
77 |
| - |
78 |
| - // Scalar self multiply: |
79 |
| - q5 *= 10; |
80 |
| - printOperation( "8. Scalar self multiply: ", q5 ); |
81 |
| - |
82 |
| - // Scalar self divide: |
83 |
| - q5 /= 2; |
84 |
| - printOperation( "9. Scalar self divide: ", q5 ); |
85 |
| - |
86 |
| - // 2. Quaternion multiplication and division: |
87 |
| - /* Quats can be multiplied together to generate a new quaternion. This can encode multiple rotations */ |
88 |
| - |
89 |
| - // Multiply |
90 |
| - q5 = q5*q1; |
91 |
| - printOperation( "10. Quaternion multiply: ", q5 ); |
92 |
| - |
93 |
| - // Divide |
94 |
| - q5 = q5/q2; |
95 |
| - printOperation( "11. Quaternion division: ", q5 ); |
96 |
| - |
97 |
| - // Self multiply |
98 |
| - q5 *= q3; |
99 |
| - printOperation( "12. Quaternion self multiply: ", q5 ); |
100 |
| - |
101 |
| - // Self divide |
102 |
| - q5 /= q4; |
103 |
| - printOperation( "13. Quaternion self divide: ", q5 ); |
104 |
| - |
105 |
| - // 3. Important operations: |
106 |
| - |
107 |
| - // Conjugate |
108 |
| - printOperation( "14. Conjugate: ", q5.conj() ); |
109 |
| - |
110 |
| - // Normalize |
111 |
| - printOperation( "15. Normalize: ", q5.norm() ); |
112 |
| - |
113 |
| - // Inner product |
114 |
| - Serial.print( "16. Inner product: " ); |
115 |
| - Serial.println( q5.inner() ); |
116 |
| - |
117 |
| - // Magnitude |
118 |
| - Serial.print( "17. Magnitude: " ); |
119 |
| - Serial.print( q5.mag() ); |
120 |
| - Serial.print("\n\n"); |
121 |
| - |
122 |
| - // 4. Compatibility with arrays: |
123 |
| - /* In operations between a quaternion and an array, the array will be interpreted as a quaternion */ |
124 |
| - float arr[] = {1, 2, 3, 4}; |
125 |
| - |
126 |
| - printOperation( "18. Quaternion and array addition: " , q5 + arr ); |
127 |
| - printOperation( "19. Quaternion and array subtraction: ", q5 - arr ); |
128 |
| - printOperation( "20. Quaternion and array multiply: " , q5 * arr ); |
129 |
| - |
130 |
| - // Operations with arrays are not converted to a quaternion type. These need to be explicitly converted. |
131 |
| - printOperation( "21. Array conversion (multiply): ", quat_t(arr)*3 ); |
132 |
| - printOperation( "22. Array conversion (divide): " , quat_t(arr)/10 ); |
133 |
| - |
134 |
| - //-- Compatibility with vectors |
135 |
| - /* Vectors will be interpreted as quaternions without a scalar value (w = 0) */ |
136 |
| - vec3_t vec = {1, 2, 3}; |
137 |
| - |
138 |
| - printOperation( "23. Quaternion and vector addition: " , q5 + vec ); |
139 |
| - printOperation( "24. Quaternion and vector subtraction: ", q5 - vec ); |
140 |
| - printOperation( "25. Quaternion and vector multiply; " , q5 * vec ); |
141 |
| - |
142 |
| - // 5. Vector rotation: a quaternion can rotate and stretch a 3D vector |
143 |
| - |
144 |
| - // A) Rotate by angle about axis |
145 |
| - constexpr float angle = (PI/180.0) * 30; |
146 |
| - vec3_t axis = { 0, 1, 0 }; |
147 |
| - |
148 |
| - /* Can choose between LARGE_ANGLE and SMALL_ANGLE. |
149 |
| - * Use SMALL_ANGLE for a small angle approximation (less than 30 deg) and faster excecution */ |
150 |
| - quat_t qrot; qrot.setRotation( axis, angle, SMALL_ANGLE ); |
151 |
| - vec3_t vec_rot; // rotated vector |
152 |
| - vec = { 1,0,0 }; // initial vector |
153 |
| - |
154 |
| - // Rotate into angle |
155 |
| - vec_rot = qrot.rotate(vec, GLOBAL_FRAME); |
156 |
| - |
157 |
| - printOperation<vec3_t>( "26. Rotate by axis and angle (Global): ", vec_rot ); |
158 |
| - |
159 |
| - // Rotate away from angle |
160 |
| - vec_rot = qrot.rotate(vec, LOCAL_FRAME); |
161 |
| - |
162 |
| - printOperation<vec3_t>( "27. Rotate by axis and angle (local): ", vec_rot ); |
163 |
| - |
164 |
| - // B) Rotate by unit vector of magnitude sin(angle) |
165 |
| - qrot.setRotation( axis, LARGE_ANGLE ); |
166 |
| - vec_rot = qrot.rotate(vec, GLOBAL_FRAME); |
167 |
| - |
168 |
| - printOperation<vec3_t>( "28. Rotate by unit vector: ", vec_rot ); |
169 |
| - |
170 |
| - // 6. Axes projections: can choose between GLOBAL_FRAME and LOCAL_FRAME |
171 |
| - /* GLOBAL_FRAME projects local axis-vectors to global coordinates |
172 |
| - * LOCAL_FRAME projects global axis-vectors to local coordinates */ |
173 |
| - qrot.setRotation( axis, angle, LARGE_ANGLE ); |
174 |
| - |
175 |
| - vec3_t x = qrot.axisX(GLOBAL_FRAME); |
176 |
| - vec3_t y = qrot.axisY(GLOBAL_FRAME); |
177 |
| - vec3_t z = qrot.axisZ(GLOBAL_FRAME); |
178 |
| - |
179 |
| - printOperation<vec3_t>( "29. X-axis vector: ", x ); |
180 |
| - printOperation<vec3_t>( "30. Y-axis vector: ", y ); |
181 |
| - printOperation<vec3_t>( "31. Z-axis vector: ", z ); |
182 |
| -} |
183 |
| - |
184 |
| -void loop() {} |
| 1 | +/* |
| 2 | + This sketch shows to perform operations on quaternions and how to convert arrays to quaternions. |
| 3 | + */ |
| 4 | + |
| 5 | +#include <quaternion_type.h> |
| 6 | + |
| 7 | +// Display functions |
| 8 | + |
| 9 | +void printVector( vec3_t vec ) { |
| 10 | + Serial.print( vec.x ); |
| 11 | + Serial.print( ", " ); |
| 12 | + Serial.print( vec.y ); |
| 13 | + Serial.print( ", " ); |
| 14 | + Serial.print( vec.z ); |
| 15 | + Serial.println(); |
| 16 | +} |
| 17 | + |
| 18 | +void printQuat( quat_t quat ) { |
| 19 | + Serial.print( quat.w ); |
| 20 | + Serial.print( ", " ); |
| 21 | + printVector( quat.v ); |
| 22 | +} |
| 23 | + |
| 24 | +void setup() { |
| 25 | + Serial.begin(9600); |
| 26 | + Serial.flush(); |
| 27 | + |
| 28 | + //-------- Quaternions -------- |
| 29 | + quat_t q1 = { 1, 0, 0, 0 }; |
| 30 | + quat_t q2 = { 0, 1, 0, 0 }; |
| 31 | + quat_t q3 = { 0, 0, 1, 0 }; |
| 32 | + quat_t q4 = { 0, 0, 0, 1 }; |
| 33 | + quat_t q5; |
| 34 | + |
| 35 | + //-- Operations: |
| 36 | + // Quaternions can be manipulated in the same way as scalar values |
| 37 | + |
| 38 | + // Addition |
| 39 | + q5 = q1 + q2; |
| 40 | + printQuat( q5 ); |
| 41 | + |
| 42 | + // Subtraction |
| 43 | + q5 = q5 - q3; |
| 44 | + printQuat( q5 ); |
| 45 | + |
| 46 | + // Negation: |
| 47 | + q5 = -q5; |
| 48 | + printQuat( q5 ); |
| 49 | + |
| 50 | + // Increment: |
| 51 | + q5 += q4; |
| 52 | + printQuat( q5 ); |
| 53 | + |
| 54 | + // Decrement: |
| 55 | + q5 -= q1; |
| 56 | + printQuat( q5 ); |
| 57 | + |
| 58 | + // Scalar product: |
| 59 | + q5 = q5*5; |
| 60 | + printQuat( q5 ); |
| 61 | + // Reverse order |
| 62 | + q5 = -3*q5; |
| 63 | + printQuat( q5 ); |
| 64 | + |
| 65 | + // Scalar divide: |
| 66 | + q5 = q5/8; |
| 67 | + printQuat( q5 ); |
| 68 | + |
| 69 | + // Scalar self multiply: |
| 70 | + q5 *= 10; |
| 71 | + printQuat( q5 ); |
| 72 | + |
| 73 | + // Scalar self divide: |
| 74 | + q5 /= 20; |
| 75 | + printQuat( q5 ); |
| 76 | + |
| 77 | + //- Important operations: |
| 78 | + // These are useful operations that are commonly encountered. They are explicitly named for clarity. |
| 79 | + |
| 80 | + // Conjugate |
| 81 | + printQuat( q5.conj() ); |
| 82 | + |
| 83 | + // Inner product |
| 84 | + Serial.println( q5.inner() ); |
| 85 | + |
| 86 | + // Magnitude |
| 87 | + Serial.println( q5.mag() ); |
| 88 | + |
| 89 | + // Normalize |
| 90 | + printQuat( q5.norm() ); |
| 91 | + |
| 92 | + //- Quaternion multiplication and division: |
| 93 | + // Quats can be multiplied together to generate a new quaternion. This can encode simultaneous rotations. |
| 94 | + |
| 95 | + // Multiply |
| 96 | + q5 = q5*q2; |
| 97 | + printQuat( q5 ); |
| 98 | + |
| 99 | + // Divide |
| 100 | + q5 = q5/q2; |
| 101 | + printQuat( q5 ); |
| 102 | + |
| 103 | + // Self multiply |
| 104 | + q5 *= q4; |
| 105 | + printQuat( q5 ); |
| 106 | + |
| 107 | + // Self divide |
| 108 | + q5 /= q3; |
| 109 | + printQuat( q5 ); |
| 110 | + |
| 111 | + //- Vector rotation: |
| 112 | + // A quaternion can rotate and stretch a 3D vector |
| 113 | + |
| 114 | + // A) Rotate by angle about axis |
| 115 | + constexpr float angle = (PI/180.0) * 30; |
| 116 | + vec3_t axis = { 0, 1, 0 }; |
| 117 | + |
| 118 | + quat_t qrot; |
| 119 | + qrot.setRotation( false, axis, angle ); // Unit quaternion: true = small angle approximation ; false = exact rotation |
| 120 | + vec3_t vec = { 1,0,0 }; // Vector to rotate |
| 121 | + |
| 122 | + // Rotate into angle |
| 123 | + printQuat( qrot.rotate(true, vec) ); |
| 124 | + // Rotate away from angle |
| 125 | + printQuat( qrot.rotate(false, vec) ); |
| 126 | + |
| 127 | + // Axes projections |
| 128 | + printVector( qrot.axisX(true) ); |
| 129 | + printVector( qrot.axisY(true) ); |
| 130 | + printVector( qrot.axisZ(true) ); |
| 131 | + |
| 132 | + // B) Rotate by unit vector |
| 133 | + qrot.setRotation( false, axis ); // Unit vector has magniude sin(angle) |
| 134 | + |
| 135 | + printQuat( qrot.rotate(true, vec) ); |
| 136 | + |
| 137 | + //-- Compatibility with arrays: |
| 138 | + // In operations between a quaternion and an array, the array will be interpreted as a quaternion. |
| 139 | + |
| 140 | + float arr[] = {1, 2, 3, 4}; |
| 141 | + |
| 142 | + printQuat( qrot + arr ); |
| 143 | + printQuat( qrot - arr ); |
| 144 | + printQuat( qrot*arr ); |
| 145 | + |
| 146 | + // Operations with arrays are not converted to a quaternion type. These need to be explicitly converted. |
| 147 | + printQuat( quat_t(arr)*3 ); |
| 148 | + printQuat( quat_t(arr)/10 ); |
| 149 | + |
| 150 | + printQuat( qrot.rotate(true, vec) ); |
| 151 | + |
| 152 | + //-- Compatibility with vectors |
| 153 | + // Vectors will be interpreted as quaternions without a scalar value (w = 0) |
| 154 | + |
| 155 | + vec3_t v = {1, 2, 3}; |
| 156 | + quat_t q6 = {1, 3, 3, 3}; |
| 157 | + |
| 158 | + printQuat( q6 + v ); |
| 159 | + printQuat( q6 - v ); |
| 160 | + printQuat( q6*v ); |
| 161 | +} |
| 162 | + |
| 163 | +void loop() {} |
0 commit comments