OSVR-Core
IMUStateMeasurements.h
Go to the documentation of this file.
1 
11 // Copyright 2016 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 #ifndef INCLUDED_IMUStateMeasurements_h_GUID_85352E66_9988_42AD_816D_C745E3D24097
26 #define INCLUDED_IMUStateMeasurements_h_GUID_85352E66_9988_42AD_816D_C745E3D24097
27 
28 // Internal Includes
29 #include "AngVelTools.h"
30 #include "CrossProductMatrix.h"
31 #include "ModelTypes.h"
32 #include "SpaceTransformations.h"
33 
34 // Library/third-party includes
37 #include <osvr/Util/Angles.h>
38 #include <osvr/Util/EigenExtras.h>
40 
41 // Standard includes
42 // - none
43 
44 #undef OSVR_USE_OLD_MEASUREMENT_CLASS
45 #define OSVR_USE_CODEGEN
46 
47 namespace osvr {
48 
49 namespace kalman {
50  namespace {
51  struct QLast {
55  static Eigen::Matrix3d
56  getCommonSingleQJacobian(Eigen::Quaterniond const &innovationQuat) {
57  auto &q = innovationQuat;
58 #ifdef OSVR_USE_CODEGEN
59  Eigen::Vector3d q2(q.vec().cwiseProduct(q.vec()));
61  auto q_vecnorm = std::sqrt(q2.sum());
62  if (q_vecnorm < 1e-4) {
63  // effectively 0 - must avoid divide by zero.
64 
65  // When the jacobian is computed symbolically specifically
66  // for the case that q is the identity quaternion, a zero
67  // matrix is returned.
68  return Eigen::Matrix3d::Zero();
69  }
71  // Quat.QuatToRotVec(g(x) * q)
72  auto tmp0 = 1.0 / q_vecnorm;
73  auto tmp1 = -q.w() * tmp0;
74  auto tmp2 = std::pow(q_vecnorm, -3);
75  auto tmp3 = q.w() * tmp2;
76  auto tmp4 = q.z() * tmp0;
77  auto tmp5 = q.w() * q.x() * tmp2;
78  auto tmp6 = q.y() * tmp5;
79  auto tmp7 = q.y() * tmp0;
80  auto tmp8 = q.z() * tmp5;
81  auto tmp9 = q.x() * tmp0;
82  auto tmp10 = q.y() * q.z() * tmp3;
84  ret << q2.x() * tmp3 + tmp1, -tmp4 + tmp6, tmp7 + tmp8,
85  tmp4 + tmp6, q2.y() * tmp3 + tmp1, tmp10 - tmp9,
86  -tmp7 + tmp8, tmp10 + tmp9, q2.z() * tmp3 + tmp1;
87 #else
88  auto qvecnorm = q.vec().norm();
91 
92  if (qvecnorm < 1e-4) {
93  // effectively 0 - must avoid divide by zero.
94  // All numerators also go to 0 in this case, so we'll just
95  // eliminate them.
96  // The exception is the second term of the main diagonal:
97  // nominally -qw/2*vecnorm.
98  // qw would be 1, but in this form at least, the math goes
99  // to -infinity.
100 
101  // When the jacobian is computed symbolically specifically
102  // for the case that q is the identity quaternion, a zero
103  // matrix
104  // is returned.
105  return Eigen::Matrix3d::Zero();
106  }
107  Eigen::Matrix3d ret =
108  // first term: qw * (qvec outer product with itself), over 2
109  // * vecnorm^3
110  (q.w() * q.vec() * q.vec().transpose() /
111  (2 * qvecnorm * qvecnorm * qvecnorm)) +
112  // second term of each element: cross-product matrix of the
113  // negative vector part of quaternion over 2*vecnorm, minus
114  // the identity matrix * qw/2*vecnorm
115  ((vbtracker::skewSymmetricCrossProductMatrix3(-q.vec()) -
116  Eigen::Matrix3d::Identity() * q.w()) /
117  (2 * qvecnorm));
118 #endif
119  return ret;
120  }
121  static Eigen::Quaterniond
122  getInnovationQuat(Eigen::Quaterniond const &measInCamSpace,
123  Eigen::Quaterniond const &cRb) {
124  return cRb.inverse() * measInCamSpace;
125  }
126  static Eigen::Matrix3d
127  getJacobian(Eigen::Quaterniond const &measInCamSpace,
128  Eigen::Quaterniond const &cRb) {
129  Eigen::Quaterniond q = getInnovationQuat(measInCamSpace, cRb);
130  return getCommonSingleQJacobian(q);
131  }
132  };
133  struct QFirst {
134  static Eigen::Quaterniond
135  getInnovationQuat(Eigen::Quaterniond const &measInCamSpace,
136  Eigen::Quaterniond const &cRb) {
137  return measInCamSpace.conjugate() * cRb;
138  }
139  static Eigen::Matrix3d
140  getJacobian(Eigen::Quaterniond const &measInCamSpace,
141  Eigen::Quaterniond const &cRb) {
142  Eigen::Quaterniond q = getInnovationQuat(measInCamSpace, cRb);
143  return QLast::getCommonSingleQJacobian(q).transpose();
144  }
145  };
146 
147  struct SplitQ {
148  static Eigen::Quaterniond
149  getInnovationQuat(Eigen::Quaterniond const &measInCamSpace,
150  Eigen::Quaterniond const &cRb) {
151 
152  // this is the one that matches the original measurement class
153  // closest, despite the coordinate systems not making 100%
154  // sense.
155  return measInCamSpace * cRb.inverse();
156  }
157 
158  static Eigen::Matrix3d
159  getJacobian(Eigen::Quaterniond const &measInCamSpace,
160  Eigen::Quaterniond const &cRb) {
161 
162  Eigen::Quaterniond const &q = measInCamSpace;
163  Eigen::Quaterniond state_inv = cRb.inverse();
164  bool qIdentity = q.vec().isApproxToConstant(0.);
165  bool stateIdentity = state_inv.vec().isApproxToConstant(0.);
166  if (qIdentity && stateIdentity) {
167  // Avoid divide by zero - symbolic math for this case
168  // reports a zero matrix
169  return Eigen::Matrix3d::Zero();
170  } else if (qIdentity) {
171  auto tmp0 = std::pow(state_inv.x(), 2);
172  auto tmp1 = std::pow(state_inv.y(), 2);
173  auto tmp2 = std::pow(state_inv.z(), 2);
174  auto tmp3 = tmp0 + tmp1 + tmp2;
175  auto tmp4 = std::pow(tmp3, -1. / 2.);
176  auto tmp5 = -state_inv.w() * tmp4;
177  auto tmp6 = std::pow(tmp3, -3. / 2.);
178  auto tmp7 = state_inv.w() * tmp6;
179  auto tmp8 = state_inv.z() * tmp4;
180  auto tmp9 = state_inv.w() * state_inv.x() * tmp6;
181  auto tmp10 = state_inv.y() * tmp9;
182  auto tmp11 = state_inv.y() * tmp4;
183  auto tmp12 = state_inv.z() * tmp9;
184  auto tmp13 = state_inv.x() * tmp4;
185  auto tmp14 = state_inv.y() * state_inv.z() * tmp7;
187  ret << tmp0 * tmp7 + tmp5, tmp10 - tmp8, tmp11 + tmp12,
188  tmp10 + tmp8, tmp1 * tmp7 + tmp5, -tmp13 + tmp14,
189  -tmp11 + tmp12, tmp13 + tmp14, tmp2 * tmp7 + tmp5;
190  return ret;
191  }
192  Eigen::Quaterniond q2(q.coeffs().cwiseProduct(q.coeffs()));
193  if (stateIdentity) {
194  auto q_vecnorm = q.vec().norm();
195 
196  auto tmp0 = 1.0 / q_vecnorm;
197  auto tmp1 = -q.w() * tmp0;
198  auto tmp2 = std::pow(q_vecnorm, -3);
199  auto tmp3 = q.w() * tmp2;
200  auto tmp4 = q.z() * tmp0;
201  auto tmp5 = q.w() * q.x() * tmp2;
202  auto tmp6 = q.y() * tmp5;
203  auto tmp7 = q.y() * tmp0;
204  auto tmp8 = q.z() * tmp5;
205  auto tmp9 = q.x() * tmp0;
206  auto tmp10 = q.y() * q.z() * tmp3;
208  ret << q2.x() * tmp3 + tmp1, tmp4 + tmp6, -tmp7 + tmp8,
209  -tmp4 + tmp6, q2.y() * tmp3 + tmp1, tmp10 + tmp9,
210  tmp7 + tmp8, tmp10 - tmp9, q2.z() * tmp3 + tmp1;
211  return ret;
212  }
213  auto tmp0 = std::pow(state_inv.x(), 2);
214  auto tmp1 = std::pow(state_inv.y(), 2);
215  auto tmp2 = std::pow(state_inv.z(), 2);
216  auto tmp3 = std::pow(state_inv.w(), 2);
217  auto tmp4 = 2 * state_inv.x();
218  auto tmp5 = q.w() * q.x() * state_inv.w();
219  auto tmp6 = tmp4 * tmp5;
220  auto tmp7 = 2 * state_inv.y();
221  auto tmp8 = q.w() * q.y() * state_inv.w();
222  auto tmp9 = tmp7 * tmp8;
223  auto tmp10 = q.w() * q.z() * state_inv.w();
224  auto tmp11 = 2 * state_inv.z() * tmp10;
225  auto tmp12 = q.x() * q.y() * state_inv.y() * tmp4;
226  auto tmp13 = q.x() * q.z() * state_inv.z() * tmp4;
227  auto tmp14 = q.y() * q.z() * state_inv.z() * tmp7;
228  auto tmp15 = q2.w() * tmp0 + q2.w() * tmp1 + q2.w() * tmp2 +
229  q2.x() * tmp1 + q2.x() * tmp2 + q2.x() * tmp3 +
230  q2.y() * tmp0 + q2.y() * tmp2 + q2.y() * tmp3 +
231  q2.z() * tmp0 + q2.z() * tmp1 + q2.z() * tmp3 +
232  tmp11 - tmp12 - tmp13 - tmp14 + tmp6 + tmp9;
233  auto tmp16 = std::abs(tmp15);
234  auto tmp17 = std::pow(tmp16, -1. / 2.);
235  auto tmp18 =
236  std::sqrt(q2.w() * tmp3 + q2.x() * tmp0 + q2.y() * tmp1 +
237  q2.z() * tmp2 - tmp11 + tmp12 + tmp13 + tmp14 +
238  tmp16 - tmp6 - tmp9);
239  auto tmp19 = q.w() * tmp17 * tmp18;
240  auto tmp20 = -state_inv.w() * tmp19;
241  auto tmp21 = q.z() * tmp17 * tmp18;
242  auto tmp22 = state_inv.z() * tmp21;
243  auto tmp23 = tmp20 - tmp22;
244  auto tmp24 = q.x() * tmp17 * tmp18;
245  auto tmp25 = state_inv.x() * tmp24;
246  auto tmp26 = q.y() * tmp17 * tmp18;
247  auto tmp27 = state_inv.y() * tmp26;
248  auto tmp28 = -tmp27;
249  auto tmp29 = q2.x() * state_inv.x();
250  auto tmp30 = state_inv.w() * tmp29;
251  auto tmp31 = q2.z() * state_inv.z();
252  auto tmp32 = state_inv.y() * tmp31;
253  auto tmp33 = q2.w() * state_inv.w();
254  auto tmp34 = state_inv.x() * tmp33;
255  auto tmp35 = q2.y() * state_inv.y();
256  auto tmp36 = state_inv.z() * tmp35;
257  auto tmp37 = state_inv.z() * tmp8;
258  auto tmp38 = q.w() * q.y() * state_inv.y();
259  auto tmp39 = state_inv.x() * tmp38;
260  auto tmp40 = q.w() * q.z() * state_inv.z();
261  auto tmp41 = state_inv.x() * tmp40;
262  auto tmp42 = q.x() * q.y() * state_inv.w();
263  auto tmp43 = state_inv.y() * tmp42;
264  auto tmp44 = q.x() * q.z() * state_inv.w();
265  auto tmp45 = state_inv.z() * tmp44;
266  auto tmp46 = q.x() * q.z() * state_inv.y();
267  auto tmp47 = state_inv.x() * tmp46;
268  auto tmp48 = q.w() * q.x();
269  auto tmp49 = tmp0 * tmp48;
270  auto tmp50 = q.y() * q.z();
271  auto tmp51 = tmp1 * tmp50;
272  auto tmp52 = state_inv.y() * tmp10;
273  auto tmp53 = q.x() * q.y() * state_inv.z();
274  auto tmp54 = state_inv.x() * tmp53;
275  auto tmp55 = tmp3 * tmp48;
276  auto tmp56 = tmp2 * tmp50;
277  auto tmp57 = tmp30 + tmp32 - tmp34 - tmp36 + tmp37 + tmp39 +
278  tmp41 + tmp43 + tmp45 + tmp47 + tmp49 + tmp51 -
279  tmp52 - tmp54 - tmp55 - tmp56;
280  auto tmp58 = (((tmp15) > 0) - ((tmp15) < 0));
281  auto tmp59 = std::pow(tmp16, -3. / 2.);
282  auto tmp60 = q.z() * state_inv.y() * tmp18 * tmp58 * tmp59;
283  auto tmp61 = q.w() * state_inv.x() * tmp18 * tmp58 * tmp59;
284  auto tmp62 = q.x() * state_inv.w() * tmp18 * tmp58 * tmp59;
285  auto tmp63 = q.y() * state_inv.z() * tmp18 * tmp58 * tmp59;
286  auto tmp64 = 1.0 / tmp18;
287  auto tmp65 = 2 * q.w() * state_inv.x() * tmp17 * tmp64;
288  auto tmp66 = (1. / 2.) * tmp58;
289  auto tmp67 =
290  -1. / 2. * tmp30 - 1. / 2. * tmp32 + (1. / 2.) * tmp34 +
291  (1. / 2.) * tmp36 - 1. / 2. * tmp37 - 1. / 2. * tmp39 -
292  1. / 2. * tmp41 - 1. / 2. * tmp43 - 1. / 2. * tmp45 -
293  1. / 2. * tmp47 - 1. / 2. * tmp49 - 1. / 2. * tmp51 +
294  (1. / 2.) * tmp52 + (1. / 2.) * tmp54 + (1. / 2.) * tmp55 +
295  (1. / 2.) * tmp56 + tmp57 * tmp66;
296  auto tmp68 = 2 * q.x() * state_inv.w() * tmp17 * tmp64;
297  auto tmp69 = 2 * q.y() * state_inv.z() * tmp17 * tmp64;
298  auto tmp70 = 2 * q.z() * state_inv.y() * tmp17 * tmp64;
299  auto tmp71 = state_inv.x() * tmp26 + state_inv.y() * tmp24;
300  auto tmp72 = state_inv.w() * tmp21;
301  auto tmp73 = state_inv.z() * tmp19;
302  auto tmp74 = state_inv.z() * tmp29;
303  auto tmp75 = state_inv.w() * tmp35;
304  auto tmp76 = state_inv.y() * tmp33;
305  auto tmp77 = state_inv.x() * tmp31;
306  auto tmp78 = q.w() * q.x() * state_inv.x();
307  auto tmp79 = state_inv.y() * tmp78;
308  auto tmp80 = state_inv.x() * tmp10;
309  auto tmp81 = state_inv.y() * tmp40;
310  auto tmp82 = state_inv.x() * tmp42;
311  auto tmp83 = state_inv.y() * tmp53;
312  auto tmp84 = q.y() * q.z() * state_inv.w();
313  auto tmp85 = state_inv.z() * tmp84;
314  auto tmp86 = q.w() * q.y();
315  auto tmp87 = tmp1 * tmp86;
316  auto tmp88 = q.x() * q.z();
317  auto tmp89 = tmp2 * tmp88;
318  auto tmp90 = state_inv.z() * tmp5;
319  auto tmp91 = q.y() * q.z() * state_inv.x();
320  auto tmp92 = state_inv.y() * tmp91;
321  auto tmp93 = tmp3 * tmp86;
322  auto tmp94 = tmp0 * tmp88;
323  auto tmp95 = tmp74 + tmp75 - tmp76 - tmp77 + tmp79 + tmp80 +
324  tmp81 + tmp82 + tmp83 + tmp85 + tmp87 + tmp89 -
325  tmp90 - tmp92 - tmp93 - tmp94;
326  auto tmp96 =
327  tmp66 * tmp95 - 1. / 2. * tmp74 - 1. / 2. * tmp75 +
328  (1. / 2.) * tmp76 + (1. / 2.) * tmp77 - 1. / 2. * tmp79 -
329  1. / 2. * tmp80 - 1. / 2. * tmp81 - 1. / 2. * tmp82 -
330  1. / 2. * tmp83 - 1. / 2. * tmp85 - 1. / 2. * tmp87 -
331  1. / 2. * tmp89 + (1. / 2.) * tmp90 + (1. / 2.) * tmp92 +
332  (1. / 2.) * tmp93 + (1. / 2.) * tmp94;
333  auto tmp97 = state_inv.x() * tmp21 + state_inv.z() * tmp24;
334  auto tmp98 = state_inv.y() * tmp19;
335  auto tmp99 = state_inv.w() * tmp26;
336  auto tmp100 = state_inv.x() * tmp35;
337  auto tmp101 = state_inv.w() * tmp31;
338  auto tmp102 = state_inv.z() * tmp33;
339  auto tmp103 = state_inv.y() * tmp29;
340  auto tmp104 = state_inv.y() * tmp5;
341  auto tmp105 = state_inv.z() * tmp78;
342  auto tmp106 = state_inv.z() * tmp38;
343  auto tmp107 = state_inv.x() * tmp44;
344  auto tmp108 = state_inv.y() * tmp84;
345  auto tmp109 = state_inv.z() * tmp91;
346  auto tmp110 = q.w() * q.z();
347  auto tmp111 = tmp110 * tmp2;
348  auto tmp112 = q.x() * q.y();
349  auto tmp113 = tmp0 * tmp112;
350  auto tmp114 = state_inv.x() * tmp8;
351  auto tmp115 = state_inv.z() * tmp46;
352  auto tmp116 = tmp110 * tmp3;
353  auto tmp117 = tmp1 * tmp112;
354  auto tmp118 = tmp100 + tmp101 - tmp102 - tmp103 + tmp104 +
355  tmp105 + tmp106 + tmp107 + tmp108 + tmp109 +
356  tmp111 + tmp113 - tmp114 - tmp115 - tmp116 -
357  tmp117;
358  auto tmp119 =
359  -1. / 2. * tmp100 - 1. / 2. * tmp101 + (1. / 2.) * tmp102 +
360  (1. / 2.) * tmp103 - 1. / 2. * tmp104 - 1. / 2. * tmp105 -
361  1. / 2. * tmp106 - 1. / 2. * tmp107 - 1. / 2. * tmp108 -
362  1. / 2. * tmp109 - 1. / 2. * tmp111 - 1. / 2. * tmp113 +
363  (1. / 2.) * tmp114 + (1. / 2.) * tmp115 +
364  (1. / 2.) * tmp116 + (1. / 2.) * tmp117 + tmp118 * tmp66;
365  auto tmp120 = q.x() * state_inv.z() * tmp18 * tmp58 * tmp59;
366  auto tmp121 = q.w() * state_inv.y() * tmp18 * tmp58 * tmp59;
367  auto tmp122 = q.y() * state_inv.w() * tmp18 * tmp58 * tmp59;
368  auto tmp123 = q.z() * state_inv.x() * tmp18 * tmp58 * tmp59;
369  auto tmp124 = 2 * q.w() * state_inv.y() * tmp17 * tmp64;
370  auto tmp125 = 2 * q.x() * state_inv.z() * tmp17 * tmp64;
371  auto tmp126 = 2 * q.y() * state_inv.w() * tmp17 * tmp64;
372  auto tmp127 = 2 * q.z() * state_inv.x() * tmp17 * tmp64;
373  auto tmp128 = -tmp25;
374  auto tmp129 = state_inv.y() * tmp21 + state_inv.z() * tmp26;
375  auto tmp130 = state_inv.w() * tmp24;
376  auto tmp131 = state_inv.x() * tmp19;
377  auto tmp132 = q.y() * state_inv.x() * tmp18 * tmp58 * tmp59;
378  auto tmp133 = q.w() * state_inv.z() * tmp18 * tmp58 * tmp59;
379  auto tmp134 = q.x() * state_inv.y() * tmp18 * tmp58 * tmp59;
380  auto tmp135 = q.z() * state_inv.w() * tmp18 * tmp58 * tmp59;
381  auto tmp136 = 2 * q.w() * state_inv.z() * tmp17 * tmp64;
382  auto tmp137 = 2 * q.x() * state_inv.y() * tmp17 * tmp64;
383  auto tmp138 = 2 * q.y() * state_inv.x() * tmp17 * tmp64;
384  auto tmp139 = 2 * q.z() * state_inv.w() * tmp17 * tmp64;
386  ret << tmp23 + tmp25 + tmp28 + tmp57 * tmp60 - tmp57 * tmp61 -
387  tmp57 * tmp62 - tmp57 * tmp63 + tmp65 * tmp67 +
388  tmp67 * tmp68 + tmp67 * tmp69 - tmp67 * tmp70,
389  tmp60 * tmp95 - tmp61 * tmp95 - tmp62 * tmp95 -
390  tmp63 * tmp95 + tmp65 * tmp96 + tmp68 * tmp96 +
391  tmp69 * tmp96 - tmp70 * tmp96 + tmp71 + tmp72 - tmp73,
392  tmp118 * tmp60 - tmp118 * tmp61 - tmp118 * tmp62 -
393  tmp118 * tmp63 + tmp119 * tmp65 + tmp119 * tmp68 +
394  tmp119 * tmp69 - tmp119 * tmp70 + tmp97 + tmp98 - tmp99,
395  tmp120 * tmp57 - tmp121 * tmp57 - tmp122 * tmp57 -
396  tmp123 * tmp57 + tmp124 * tmp67 - tmp125 * tmp67 +
397  tmp126 * tmp67 + tmp127 * tmp67 + tmp71 - tmp72 + tmp73,
398  tmp120 * tmp95 - tmp121 * tmp95 - tmp122 * tmp95 -
399  tmp123 * tmp95 + tmp124 * tmp96 - tmp125 * tmp96 +
400  tmp126 * tmp96 + tmp127 * tmp96 + tmp128 + tmp23 +
401  tmp27,
402  tmp118 * tmp120 - tmp118 * tmp121 - tmp118 * tmp122 -
403  tmp118 * tmp123 + tmp119 * tmp124 - tmp119 * tmp125 +
404  tmp119 * tmp126 + tmp119 * tmp127 + tmp129 + tmp130 -
405  tmp131,
406  tmp132 * tmp57 - tmp133 * tmp57 - tmp134 * tmp57 -
407  tmp135 * tmp57 + tmp136 * tmp67 + tmp137 * tmp67 -
408  tmp138 * tmp67 + tmp139 * tmp67 + tmp97 - tmp98 + tmp99,
409  tmp129 - tmp130 + tmp131 + tmp132 * tmp95 - tmp133 * tmp95 -
410  tmp134 * tmp95 - tmp135 * tmp95 + tmp136 * tmp96 +
411  tmp137 * tmp96 - tmp138 * tmp96 + tmp139 * tmp96,
412  tmp118 * tmp132 - tmp118 * tmp133 - tmp118 * tmp134 -
413  tmp118 * tmp135 + tmp119 * tmp136 + tmp119 * tmp137 -
414  tmp119 * tmp138 + tmp119 * tmp139 + tmp128 + tmp20 +
415  tmp22 + tmp28;
416  return ret;
417  }
418  };
419 
420  struct QLastWithSplitInnovation {
421  static Eigen::Quaterniond
422  getInnovationQuat(Eigen::Quaterniond const &measInCamSpace,
423  Eigen::Quaterniond const &cRb) {
427  return SplitQ::getInnovationQuat(measInCamSpace, cRb);
428  }
429 
430  static Eigen::Matrix3d
431  getJacobian(Eigen::Quaterniond const &measInCamSpace,
432  Eigen::Quaterniond const &cRb) {
433  return QLast::getJacobian(measInCamSpace, cRb);
434  }
435  };
436  } // namespace
437 
441  template <typename PolicyT> class IMUOrientationMeasBase {
442  public:
443  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
444  static const types::DimensionType DIMENSION = 3;
449  types::Vector<3> const &emVariance)
450  : m_quat(quat), m_covariance(emVariance.asDiagonal()) {}
451 
452  template <typename State>
453  MeasurementSquareMatrix const &getCovariance(State const &) {
454  return m_covariance;
455  }
456 
458  using Policy = PolicyT;
459  // using Policy = SplitQ;
460  // using Policy = QLast;
461  // using Policy = QFirst;
462 
469  template <typename State>
471  const Eigen::Quaterniond residualq =
472  Policy::getInnovationQuat(m_quat, s.getCombinedQuaternion());
473 
474  // Two equivalent quaternions: but their logs are typically
475  // different: one is the "short way" and the other is the "long
476  // way". We'll compute both and pick the "short way".
477  // Multiplication of the log by 2 is the way to convert from a quat
478  // to a rotation vector.
479  MeasurementVector residual = 2 * util::quat_ln(residualq);
480 #if 0
481  MeasurementVector equivResidual =
482  2 * util::quat_ln(Eigen::Quaterniond(-(residualq.coeffs())));
483  return residual.squaredNorm() < equivResidual.squaredNorm()
484  ? residual
485  : equivResidual;
486 #else
487  return residual;
488 #endif
489  }
490 
491  template <typename State>
493  getResidual(MeasurementVector const &predictedMeasurement,
494  State const &s) const {
495  const Eigen::Quaterniond fullPredictedOrientation =
496  external_quat::vecToQuat(predictedMeasurement).normalized() *
497  s.getQuaternion();
498  const Eigen::Quaterniond residualq =
499  Policy::getInnovationQuat(m_quat, fullPredictedOrientation);
500 
501  // Two equivalent quaternions: but their logs are typically
502  // different: one is the "short way" and the other is the "long
503  // way". We'll compute both and pick the "short way".
504  // Multiplication of the log by 2 is the way to convert from a quat
505  // to a rotation vector.
506  MeasurementVector residual = 2 * util::quat_ln(residualq);
507 #if 1
508  MeasurementVector equivResidual =
509  2 * util::quat_ln(Eigen::Quaterniond(-(residualq.coeffs())));
510  return residual.squaredNorm() < equivResidual.squaredNorm()
511  ? residual
512  : equivResidual;
513 #else
514  return residual;
515 #endif
516  }
517 
519  void setMeasurement(Eigen::Quaterniond const &quat) { m_quat = quat; }
520 
523  template <typename State>
525  return Policy::getJacobian(m_quat, s.getCombinedQuaternion());
526  }
527 
528  private:
529  Eigen::Quaterniond m_iRc;
530  Eigen::Quaterniond m_cRi;
531  Eigen::Quaterniond m_quat;
532  MeasurementSquareMatrix m_covariance;
533  };
534 
537  template <typename StateType, typename PolicyT = SplitQ>
539 
541  template <typename PolicyT>
542  class IMUOrientationMeasurement<pose_externalized_rotation::State, PolicyT>
543  : public IMUOrientationMeasBase<PolicyT> {
544  public:
546  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
547  static const types::DimensionType STATE_DIMENSION =
550  using Base::DIMENSION;
552 
555  types::Vector<3> const &emVariance)
556  : Base(quat, emVariance) {}
557  JacobianType getJacobian(State const &s) const {
558  using namespace pose_externalized_rotation;
559  JacobianType ret = JacobianType::Zero();
560  ret.template block<DIMENSION, 3>(0, 3) = Base::getJacobianBlock(s);
561  return ret;
562  }
563 
564  types::Vector<3> predictMeasurement(State const &s) const {
565  return s.incrementalOrientation();
566  }
567  };
568 
570  public:
571  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
572  static const types::DimensionType DIMENSION = 3;
575 
576  IMUAngVelMeasurement(types::Vector<3> const &angVelVec,
577  types::Vector<3> const &variance)
578  : m_angVel(angVelVec), m_covariance(variance.asDiagonal()) {}
579 
580  template <typename State>
581  MeasurementSquareMatrix const &getCovariance(State const &) {
582  return m_covariance;
583  }
584 
585  template <typename State>
587  getResidual(MeasurementVector const &predictedMeasurement,
588  State const &s) const {
589  return m_angVel - predictedMeasurement;
590  }
591 
592  template <typename State>
593  types::Vector<3> predictMeasurement(State const &s) const {
594  return s.angularVelocity();
595  }
596 
598  void setMeasurement(types::Vector<3> const &angVelVec) {
599  m_angVel = angVelVec;
600  }
601 
602  private:
603  types::Vector<3> m_angVel;
604  MeasurementSquareMatrix m_covariance;
605  };
606 
607 } // namespace kalman
608 namespace vbtracker {
609  inline Eigen::Quaterniond
610  getTransformedOrientation(Eigen::Quaterniond const &imuQuat,
611  Eigen::Quaterniond const &roomToCameraRotation,
612  util::Angle /*yawCorrection*/) {
613  return roomToCameraRotation * imuQuat;
614  }
615 #ifdef OSVR_USE_OLD_MEASUREMENT_CLASS
616  using OrientationMeasurement =
618 #else
619  using OrientationMeasurement = kalman::IMUOrientationMeasurement<BodyState>;
620  template <typename PolicyT>
621  using OrientationMeasurementUsingPolicy =
623 #endif // OSVR_USE_OLD_MEASUREMENT_CLASS
624 } // namespace vbtracker
625 } // namespace osvr
626 
627 #endif // INCLUDED_IMUStateMeasurements_h_GUID_85352E66_9988_42AD_816D_C745E3D24097
AngleRadiansd Angle
Default angle type.
Definition: Angles.h:63
The measurement here has been split into a base and derived type, so that the derived type only conta...
Definition: IMUStateMeasurements.h:441
void setMeasurement(types::Vector< 3 > const &angVelVec)
Convenience method to be able to store and re-use measurements.
Definition: IMUStateMeasurements.h:598
typename detail::Dimension_impl< T >::type Dimension
Given a state or measurement, get the dimension as a std::integral_constant.
Definition: FlexibleKalmanBase.h:87
const Coefficients & coeffs() const
Definition: Quaternion.h:93
MeasurementVector getResidual(State const &s) const
Gets the measurement residual, also known as innovation: predicts the measurement from the predicted ...
Definition: IMUStateMeasurements.h:470
The main namespace for all C++ elements of the framework, internal and external.
Definition: namespace_osvr.dox:3
Scalar y() const
Definition: Quaternion.h:71
const Block< const Coefficients, 3, 1 > vec() const
Definition: Quaternion.h:87
Definition: IMUStateMeasurements.h:569
Scalar x() const
Definition: Quaternion.h:69
IMUOrientationMeasurement(Eigen::Quaterniond const &quat, types::Vector< 3 > const &emVariance)
Quat should already be rotated into camera space.
Definition: IMUStateMeasurements.h:554
Quaternion conjugate(void) const
Definition: Quaternion.h:395
Scalar w() const
Definition: Quaternion.h:75
This is the subclass of AbsoluteOrientationBase: only explicit specializations, and on state types...
Definition: AbsoluteOrientationMeasurement.h:98
Definition: Quaternion.h:47
Header.
This is the subclass of AbsoluteOrientationBase: only explicit specializations, and on state types...
Definition: IMUStateMeasurements.h:538
Scalar z() const
Definition: Quaternion.h:73
IMUOrientationMeasBase(Eigen::Quaterniond const &quat, types::Vector< 3 > const &emVariance)
Quat should already by in camera space!
Definition: IMUStateMeasurements.h:448
std::size_t DimensionType
Type for dimensions.
Definition: FlexibleKalmanBase.h:51
The matrix class, also used for vectors and row-vectors.
Definition: Matrix.h:127
Quaternion normalized() const
Definition: Quaternion.h:154
Eigen::Quaterniond getCombinedQuaternion() const
Definition: PoseState.h:238
Quaternion inverse(void) const
Definition: Quaternion.h:375
Header for measurements of absolute orientation.
Header.
PolicyT Policy
Specifies which innovation computation and jacobian to use.
Definition: IMUStateMeasurements.h:458
void setMeasurement(Eigen::Quaterniond const &quat)
Convenience method to be able to store and re-use measurements.
Definition: IMUStateMeasurements.h:519
types::Matrix< DIMENSION, 3 > getJacobianBlock(State const &s) const
Get the block of jacobian that is non-zero: your subclass will have to put it where it belongs for ea...
Definition: IMUStateMeasurements.h:524