altos: Add bit-bang i2c driver
[fw/altos] / src / kernel / ao_quaternion.h
1 /*
2  * Copyright © 2013 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #ifndef _AO_QUATERNION_H_
20 #define _AO_QUATERNION_H_
21
22 #include <math.h>
23
24 struct ao_quaternion {
25         float   r;              /* real bit */
26         float   x, y, z;        /* imaginary bits */
27 };
28
29 static inline void ao_quaternion_multiply(struct ao_quaternion *r,
30                                           const struct ao_quaternion *a,
31                                           const struct ao_quaternion *b)
32 {
33         struct ao_quaternion    t;
34 #define T(_a,_b)        (((a)->_a) * ((b)->_b))
35
36 /*
37  * Quaternions
38  *
39  *      ii = jj = kk = ijk = -1;
40  *
41  *      kji = 1;
42  *
43  *      ij = k;         ji = -k;
44  *      kj = -i;        jk = i;
45  *      ik = -j;        ki = j;
46  *
47  * Multiplication p * q:
48  *
49  *      (pr + ipx + jpy + kpz) (qr + iqx + jqy + kqz) =
50  *
51  *              ( pr * qr +  pr * iqx +  pr * jqy +  pr * kqz) +
52  *              (ipx * qr + ipx * iqx + ipx * jqy + ipx * kqz) +
53  *              (jpy * qr + jpy * iqx + jpy * jqy + jpy * kqz) +
54  *              (kpz * qr + kpz * iqx + kpz * jqy + kpz * kqz) =
55  *
56  *
57  *               (pr * qr) + i(pr * qx) + j(pr * qy) + k(pr * qz) +
58  *              i(px * qr) -  (px * qx) + k(px * qy) - j(px * qz) +
59  *              j(py * qr) - k(py * qx) -  (py * qy) + i(py * qz) +
60  *              k(pz * qr) + j(pz * qx) - i(pz * qy) -  (pz * qz) =
61  *
62  *              1 * ( (pr * qr) - (px * qx) - (py * qy) - (pz * qz) ) +
63  *              i * ( (pr * qx) + (px * qr) + (py * qz) - (pz * qy) ) +
64  *              j * ( (pr * qy) - (px * qz) + (py * qr) + (pz * qx) ) +
65  *              k * ( (pr * qz) + (px * qy) - (py * qx) + (pz * qr);
66  */
67
68         t.r = T(r,r) - T(x,x) - T(y,y) - T(z,z);
69         t.x = T(r,x) + T(x,r) + T(y,z) - T(z,y);
70         t.y = T(r,y) - T(x,z) + T(y,r) + T(z,x);
71         t.z = T(r,z) + T(x,y) - T(y,x) + T(z,r);
72 #undef T
73         *r = t;
74 }
75
76 static inline void ao_quaternion_conjugate(struct ao_quaternion *r,
77                                            const struct ao_quaternion *a)
78 {
79         r->r = a->r;
80         r->x = -a->x;
81         r->y = -a->y;
82         r->z = -a->z;
83 }
84
85 static inline float ao_quaternion_normal(const struct ao_quaternion *a)
86 {
87 #define S(_a)   (((a)->_a) * ((a)->_a))
88         return S(r) + S(x) + S(y) + S(z);
89 #undef S
90 }
91
92 static inline void ao_quaternion_scale(struct ao_quaternion *r,
93                                        const struct ao_quaternion *a,
94                                        float b)
95 {
96         r->r = a->r * b;
97         r->x = a->x * b;
98         r->y = a->y * b;
99         r->z = a->z * b;
100 }
101
102 static inline void ao_quaternion_normalize(struct ao_quaternion *r,
103                                            const struct ao_quaternion *a)
104 {
105         float   n = ao_quaternion_normal(a);
106
107         if (n > 0)
108                 ao_quaternion_scale(r, a, 1/sqrtf(n));
109         else
110                 *r = *a;
111 }
112
113 static inline float ao_quaternion_dot(const struct ao_quaternion *a,
114                                       const struct ao_quaternion *b)
115 {
116 #define T(_a)   (((a)->_a) * ((b)->_a))
117         return T(r) + T(x) + T(y) + T(z);
118 #undef T
119 }
120                                      
121
122 static inline void ao_quaternion_rotate(struct ao_quaternion *r,
123                                         const struct ao_quaternion *a,
124                                         const struct ao_quaternion *b)
125 {
126         struct ao_quaternion    c;
127         struct ao_quaternion    t;
128
129         ao_quaternion_multiply(&t, b, a);
130         ao_quaternion_conjugate(&c, b);
131         ao_quaternion_multiply(r, &t, &c);
132 }
133
134 /*
135  * Compute a rotation quaternion between two vectors
136  *
137  *      cos(θ) + u * sin(θ)
138  *
139  * where θ is the angle between the two vectors and u
140  * is a unit vector axis of rotation
141  */
142
143 static inline void ao_quaternion_vectors_to_rotation(struct ao_quaternion *r,
144                                                      const struct ao_quaternion *a,
145                                                      const struct ao_quaternion *b)
146 {
147         /*
148          * The cross product will point orthogonally to the two
149          * vectors, forming our rotation axis. The length will be
150          * sin(θ), so these values are already multiplied by that.
151          */
152
153         float x = a->y * b->z - a->z * b->y;
154         float y = a->z * b->x - a->x * b->z;
155         float z = a->x * b->y - a->y * b->x;
156
157         float s_2 = x*x + y*y + z*z;
158         float s = sqrtf(s_2);
159
160         /* cos(θ) = a · b / (|a| |b|).
161          *
162          * a and b are both unit vectors, so the divisor is one
163          */
164         float c = a->x*b->x + a->y*b->y + a->z*b->z;
165
166         float c_half = sqrtf ((1 + c) / 2);
167         float s_half = sqrtf ((1 - c) / 2);
168
169         /*
170          * Divide out the sine factor from the
171          * cross product, then multiply in the
172          * half sine factor needed for the quaternion
173          */
174         float s_scale = s_half / s;
175
176         r->x = x * s_scale;
177         r->y = y * s_scale;
178         r->z = z * s_scale;
179
180         r->r = c_half;
181
182         ao_quaternion_normalize(r, r);
183 }
184
185 static inline void ao_quaternion_init_vector(struct ao_quaternion *r,
186                                              float x, float y, float z)
187 {
188         r->r = 0;
189         r->x = x;
190         r->y = y;
191         r->z = z;
192 }
193
194 static inline void ao_quaternion_init_rotation(struct ao_quaternion *r,
195                                                float x, float y, float z,
196                                                float s, float c)
197 {
198         r->r = c;
199         r->x = s * x;
200         r->y = s * y;
201         r->z = s * z;
202 }
203
204 static inline void ao_quaternion_init_zero_rotation(struct ao_quaternion *r)
205 {
206         r->r = 1;
207         r->x = r->y = r->z = 0;
208 }
209
210 /*
211  * The sincosf from newlib just calls sinf and cosf. This is a bit
212  * faster, if slightly less precise
213  */
214
215 static inline void
216 ao_sincosf(float a, float *s, float *c) {
217         float   _s = sinf(a);
218         *s = _s;
219         *c = sqrtf(1 - _s*_s);
220 }
221
222 /*
223  * Initialize a quaternion from 1/2 euler rotation angles (in radians).
224  *
225  * Yes, it would be nicer if there were a faster way, but because we
226  * sample the gyros at only 100Hz, we end up getting angles too large
227  * to take advantage of sin(x) ≃ x.
228  *
229  * We might be able to use just a couple of elements of the sin taylor
230  * series though, instead of the whole sin function?
231  */
232
233 static inline void ao_quaternion_init_half_euler(struct ao_quaternion *r,
234                                                  float x, float y, float z)
235 {
236         float   s_x, c_x;
237         float   s_y, c_y;
238         float   s_z, c_z;
239
240         ao_sincosf(x, &s_x, &c_x);
241         ao_sincosf(y, &s_y, &c_y);
242         ao_sincosf(z, &s_z, &c_z);
243
244         r->r = c_x * c_y * c_z + s_x * s_y * s_z;
245         r->x = s_x * c_y * c_z - c_x * s_y * s_z;
246         r->y = c_x * s_y * c_z + s_x * c_y * s_z;
247         r->z = c_x * c_y * s_z - s_x * s_y * c_z;
248 }
249
250 #endif /* _AO_QUATERNION_H_ */