ctrl-utils
euclidian.h
1 
10 #ifndef CTRL_UTILS_EUCLIDIAN_H_
11 #define CTRL_UTILS_EUCLIDIAN_H_
12 
13 #include <ctrl_utils/eigen.h>
14 
15 namespace ctrl_utils {
16 
40 inline Eigen::Vector3d OrientationError(const Eigen::Quaterniond& quat,
41  const Eigen::Quaterniond& quat_des);
42 
56 inline Eigen::Vector3d LookatError(const Eigen::Vector3d& vec,
57  const Eigen::Vector3d& vec_des);
58 
83 inline Eigen::Quaterniond NearQuaternion(
84  const Eigen::Quaterniond& quat, const Eigen::Quaterniond& quat_reference);
85 
98 inline Eigen::Quaterniond NearQuaternion(
99  Eigen::Ref<const Eigen::Matrix3d> ori,
100  const Eigen::Quaterniond& quat_reference);
101 
114 inline Eigen::Quaterniond FarQuaternion(
115  const Eigen::Quaterniond& quat, const Eigen::Quaterniond& quat_reference);
116 
129 inline Eigen::Quaterniond FarQuaternion(
130  const Eigen::Ref<const Eigen::Matrix3d> ori,
131  const Eigen::Quaterniond& quat_reference);
132 
133 // Eigen::Matrix<double,4,3> AngularVelocityToQuaternionMap(const
134 // Eigen::Quaterniond& quat) {
135  // Eigen::Matrix<double,4,3> E;
136  // E << quat.w(), quat.z(), -quat.y(),
137  // -quat.z(), quat.w(), quat.x(),
138  // quat.y(), -quat.x(), quat.w(),
139  // -quat.x(), -quat.y(), -quat.z();
140  // return 0.5 * E;
141  // }
142 
143  // Eigen::Matrix<double,4,3> AngularVelocityToAngleAxisMap(const
144 // Eigen::AngleAxisd& aa) {
145  // Eigen::Matrix<double,4,3> E;
146  // E << aa.axis().transpose(),
147  // -0.5 * (std::sin(aa.angle()) / (1 - std::cos(aa.angle())) *
148  // ctrl_utils::DoubleCrossMatrix(aa.axis()) +
149  // ctrl_utils::CrossMatrix(aa.axis()));
150  // return E;
151  // }
152 
153  template <typename Derived>
154  Eigen::Vector3d Log(const Eigen::RotationBase<Derived, 3>& ori);
155 
156  inline Eigen::Matrix3d Exp(const Eigen::Vector3d& w);
157 
161  inline Eigen::Matrix3d ExpMapDerivative(const Eigen::AngleAxisd& aa);
162 
163  inline Eigen::Matrix3d LogMapDerivative(const Eigen::AngleAxisd& aa);
164 
165  template <int Cols>
166  struct ExpMapJacobianReturnType;
167 
168  template <>
170  using type = Eigen::Matrix3d;
171  };
172 
173  template <int Cols>
175  using type = Eigen::Matrix<double, 9, Cols>;
176  };
177 
194  template <typename Derived>
195  inline typename ExpMapJacobianReturnType<
196  Eigen::MatrixBase<Derived>::ColsAtCompileTime>::type
197  ExpMapJacobian(const Eigen::AngleAxisd& aa,
198  const Eigen::MatrixBase<Derived>& X);
199 
200  inline typename ExpMapJacobianReturnType<3>::type ExpMapJacobian(
201  const Eigen::AngleAxisd& aa) {
202  return ExpMapJacobian(aa, Eigen::Matrix3d::Identity());
203  }
204 
205  inline Eigen::Vector6d Log(const Eigen::Isometry3d& T);
206 
207  inline Eigen::Matrix6d ExpMapDerivative(const Eigen::Isometry3d& T);
208 
209  inline Eigen::Matrix6d LogMapDerivative(const Eigen::Isometry3d& T);
210 
212  // Implementation //
214 
215  Eigen::Vector3d OrientationError(const Eigen::Quaterniond& quat,
216  const Eigen::Quaterniond& quat_des) {
217  Eigen::Quaterniond quat_err = quat * quat_des.conjugate();
218  Eigen::AngleAxisd aa_err(quat_err); // Angle will always be between [0, pi]
219  double angle =
220  (quat_err.w() < 0) ? aa_err.angle() - 2 * M_PI : aa_err.angle();
221  return angle * aa_err.axis();
222  }
223 
224  Eigen::Vector3d LookatError(const Eigen::Vector3d& vec,
225  const Eigen::Vector3d& vec_des) {
226  Eigen::Quaterniond quat_err =
227  Eigen::Quaterniond::FromTwoVectors(vec_des, vec);
228  Eigen::AngleAxisd aa_err(quat_err);
229  double angle =
230  (quat_err.w() < 0) ? aa_err.angle() - 2 * M_PI : aa_err.angle();
231  return angle * aa_err.axis();
232  }
233 
234  Eigen::Quaterniond NearQuaternion(const Eigen::Quaterniond& quat,
235  const Eigen::Quaterniond& quat_reference) {
236  Eigen::Quaterniond result = quat;
237  if (quat.dot(quat_reference) < 0) result.coeffs() *= -1;
238  return result;
239  }
240 
241  Eigen::Quaterniond NearQuaternion(Eigen::Ref<const Eigen::Matrix3d> ori,
242  const Eigen::Quaterniond& quat_reference) {
243  Eigen::Quaterniond result(ori);
244  if (result.dot(quat_reference) < 0) result.coeffs() *= -1;
245  return result;
246  }
247 
248  Eigen::Quaterniond FarQuaternion(const Eigen::Quaterniond& quat,
249  const Eigen::Quaterniond& quat_reference) {
250  Eigen::Quaterniond result = quat;
251  if (quat.dot(quat_reference) > 0) result.coeffs() *= -1;
252  return result;
253  }
254 
255  Eigen::Quaterniond FarQuaternion(Eigen::Ref<const Eigen::Matrix3d> ori,
256  const Eigen::Quaterniond& quat_reference) {
257  Eigen::Quaterniond result(ori);
258  if (result.dot(quat_reference) > 0) result.coeffs() *= -1;
259  return result;
260  }
261 
262  template <typename Derived>
263  Eigen::Vector3d Log(const Eigen::RotationBase<Derived, 3>& ori) {
264  const Eigen::AngleAxisd aa(ori.derived());
265  return aa.angle() * aa.axis();
266  }
267 
268  Eigen::Matrix3d Exp(const Eigen::Vector3d& w) {
269  return Eigen::AngleAxisd(w.norm(), w.normalized()).toRotationMatrix();
270  }
271 
272  Eigen::Matrix3d ExpMapDerivative(const Eigen::AngleAxisd& aa) {
273  const double theta = aa.angle();
274  if (theta == 0.) {
275  return Eigen::Matrix3d::Zero();
276  } else if (theta * theta < std::numeric_limits<double>::epsilon()) {
277  return Eigen::Matrix3d::Identity();
278  }
279  return Eigen::Matrix3d::Identity() +
280  (1. - std::cos(theta)) / theta * CrossMatrix(aa.axis()) +
281  (1. - std::sin(theta) / theta) * DoubleCrossMatrix(aa.axis());
282  }
283 
284  Eigen::Matrix3d LogMapDerivative(const Eigen::AngleAxisd& aa) {
285  const double theta = aa.angle();
286  if (theta == 0.) {
287  return Eigen::Matrix3d::Zero();
288  } else if (theta * theta < std::numeric_limits<double>::epsilon()) {
289  return Eigen::Matrix3d::Identity();
290  }
291  return Eigen::Matrix3d::Identity() - 0.5 * theta * CrossMatrix(aa.axis()) +
292  (1. - 0.5 * theta * std::sin(theta) / (1. - std::cos(theta))) *
293  DoubleCrossMatrix(aa.axis());
294  }
295 
296  inline Eigen::Matrix<double, 9, 3> LogMapHessian(
297  const Eigen::AngleAxisd& aa) {
298  const double theta = aa.angle();
299  Eigen::Matrix<double, 9, 3> G;
300  if (theta == 0.) {
301  G.setZero();
302  return G;
303  } else if (theta * theta < std::numeric_limits<double>::epsilon()) {
304  G.topRows<3>().setIdentity();
305  G.middleRows<3>(3).setIdentity();
306  G.bottomRows<3>().setIdentity();
307  return G;
308  }
309  G.setZero();
310  G(2, 1) = 1.;
311  G(1, 2) = -1.;
312  G(3 + 2, 0) = -1.;
313  G(3 + 0, 2) = 1.;
314  G(6 + 1, 0) = 1.;
315  G(6 + 0, 1) = -1.;
316  Eigen::Matrix<double, 9, 3> GG;
317  const Eigen::Matrix3d w_x = ctrl_utils::CrossMatrix(theta * aa.axis());
318  GG.topRows<3>() = w_x * G.topRows<3>() + G.topRows<3>() * w_x;
319  GG.middleRows<3>(3) = w_x * G.middleRows<3>(3) + G.middleRows<3>(3) * w_x;
320  GG.bottomRows<3>() = w_x * G.bottomRows<3>() + G.bottomRows<3>() * w_x;
321  const double cos_theta = std::cos(theta);
322  const double sin_theta = std::sin(theta);
323  const double factor =
324  (1. - 0.5 * (theta * sin_theta) / (1. - cos_theta)) / (theta * theta);
325  const double dfactor =
326  -2. / (theta * theta * theta) -
327  0.5 / (theta * theta * (1. - cos_theta) * (1. - cos_theta)) *
328  (theta * (1. - cos_theta) * cos_theta -
329  sin_theta * (1. - cos_theta + theta * sin_theta));
330  const Eigen::Matrix3d w_x_w_x =
331  ctrl_utils::DoubleCrossMatrix(theta * aa.axis());
332  Eigen::Matrix<double, 9, 3> WW;
333  WW.topRows<3>() = dfactor * aa.axis()(0) * w_x_w_x;
334  WW.middleRows<3>(3) = dfactor * aa.axis()(1) * w_x_w_x;
335  WW.bottomRows<3>(3) = dfactor * aa.axis()(2) * w_x_w_x;
336  return -0.5 * G + dfactor * WW + factor * GG;
337  }
338 
339  template <typename Derived>
340  inline typename ExpMapJacobianReturnType<
341  Eigen::MatrixBase<Derived>::ColsAtCompileTime>::type
342  ExpMapJacobian(const Eigen::AngleAxisd& aa,
343  const Eigen::MatrixBase<Derived>& X) {
344  constexpr int Cols = Eigen::MatrixBase<Derived>::ColsAtCompileTime;
345  typename ExpMapJacobianReturnType<Cols>::type J;
346  const Eigen::Matrix3d dExp = ExpMapDerivative(aa);
347  const typename Eigen::MatrixBase<Derived>::PlainObject RX = aa * X;
348  for (size_t i = 0; i < 3; i++) {
349  Eigen::Map<Eigen::MatrixXd> J_i(J.data() + 3 * RX.cols() * i, 3,
350  RX.cols());
351  J_i = RX.colwise().cross(-dExp.col(i));
352  }
353  return J;
354  }
355 
356  template <int Cols>
357  inline typename ExpMapJacobianReturnType<Cols>::type ExpCoordsJacobianImpl(
358  const Eigen::Matrix3d& R, const Eigen::AngleAxisd& aa,
359  const Eigen::Matrix<double, 3, Cols>& X);
360 
361  template <>
362  inline Eigen::Matrix3d ExpCoordsJacobianImpl<1>(const Eigen::Matrix3d& R,
363  const Eigen::AngleAxisd& aa,
364  const Eigen::Vector3d& p) {
365  const double theta = aa.angle(); // theta is always positive
366  if (theta == 0.) {
367  return Eigen::Matrix3d::Zero();
368  } else if (theta < std::numeric_limits<double>::epsilon()) {
369  return -ctrl_utils::CrossMatrix(p);
370  }
371  const Eigen::Vector3d w = theta * aa.axis();
372 
373  return R * ctrl_utils::CrossMatrix(p / -(theta * theta)) *
374  (w * w.transpose() + (R.transpose() - Eigen::Matrix3d::Identity()) *
375  ctrl_utils::CrossMatrix(w));
376  }
377 
378  template <>
379  inline Eigen::Matrix<double, 9, 3> ExpCoordsJacobianImpl<3>(
380  const Eigen::Matrix3d& R, const Eigen::AngleAxisd& aa,
381  const Eigen::Matrix3d& I) {
382  Eigen::Matrix<double, 9, 3> dR_dw;
383 
384  const double theta = aa.angle(); // theta is always positive
385  if (theta == 0.) {
386  dR_dw.setZero();
387  return dR_dw;
388  } else if (theta < std::numeric_limits<double>::epsilon()) {
389  for (size_t i = 0; i < 3; i++) {
390  Eigen::Map<Eigen::Matrix3d> dR_dwi(dR_dw.col(i).data());
391  dR_dwi = ctrl_utils::CrossMatrix(Eigen::Vector3d::Unit(i));
392  }
393  return dR_dw;
394  }
395 
396  const Eigen::Vector3d w = theta * aa.axis();
397  const Eigen::Matrix3d w_cross = ctrl_utils::CrossMatrix(w);
398  const Eigen::Matrix3d R_hat = R / (theta * theta);
399  for (size_t i = 0; i < 3; i++) {
400  Eigen::Map<Eigen::Matrix3d> dR_dwi(dR_dw.col(i).data());
401  dR_dwi = (w(i) * w_cross + ctrl_utils::CrossMatrix(w.cross(
402  Eigen::Vector3d::Unit(i) - R.col(i)))) *
403  R_hat;
404  }
405  return dR_dw;
406  }
407 
408  template <typename Derived>
409  inline typename ExpMapJacobianReturnType<
410  Eigen::MatrixBase<Derived>::ColsAtCompileTime>::type
411  ExpMapJacobianOld(const Eigen::AngleAxisd& aa,
412  const Eigen::MatrixBase<Derived>& X) {
413  return ExpCoordsJacobianImpl(aa.toRotationMatrix(), aa, X.eval());
414  }
415 
416  inline typename ExpMapJacobianReturnType<3>::type ExpMapJacobianOld(
417  const Eigen::AngleAxisd& aa) {
418  return ExpCoordsJacobianImpl(aa.toRotationMatrix(), aa,
419  Eigen::Matrix3d::Identity().eval());
420  }
421 
422  // template<typename Derived>
423  // inline typename
424  // ExpMapJacobianReturnType<Eigen::MatrixBase<Derived>::ColsAtCompileTime>::type
425  // ExpMapJacobian(const Eigen::AngleAxisd& aa, const
426  // Eigen::MatrixBase<Derived>& X) {
427  // return ExpCoordsJacobianImpl(aa.toRotationMatrix(), aa, X.eval());
428  // }
429 
430  Eigen::Vector6d Log(const Eigen::Isometry3d& T) {
431  const Eigen::AngleAxisd aa(T.linear());
432  const double theta = aa.angle();
433  const Eigen::Vector3d w = theta * aa.axis();
434  const auto& p = T.translation();
435  const Eigen::Vector3d w_x_p = aa.axis().cross(p);
436  const double a =
437  1. - 0.5 * theta * std::sin(theta) / (1. - std::cos(theta));
438 
439  Eigen::Vector6d v;
440  v.head<3>() = p - 0.5 * theta * w_x_p + a * aa.axis().cross(w_x_p);
441  if (theta < 1e-5) v.head<3>().setZero();
442  v.tail<3>() = w;
443  return v;
444  }
445 
446  inline Eigen::Matrix3d ExpMapDerivativeCrossTerm(
447  const Eigen::AngleAxisd& aa, Eigen::Ref<const Eigen::Vector3d> x) {
448  const double theta = aa.angle();
449  const double theta_sq = theta * theta;
450  if (theta_sq < std::numeric_limits<double>::epsilon()) {
451  return Eigen::Matrix3d::Zero();
452  }
453  const double s_theta = std::sin(theta);
454  const double c_theta = std::cos(theta);
455  const double w_dot_u = aa.axis().dot(x);
456  const Eigen::Matrix3d x_x = CrossMatrix(x);
457  const Eigen::Matrix3d w_x = CrossMatrix(aa.axis());
458  const Eigen::Matrix3d w_x_x_x = w_x * x_x;
459  return (1. - c_theta) / theta_sq * x_x +
460  (theta - s_theta) / theta_sq * (w_x_x_x + w_x_x_x.transpose()) +
461  w_dot_u * (s_theta - 2. * (1 - c_theta) / theta) / theta * w_x +
462  w_dot_u * (-2. - c_theta + 3 * s_theta / theta) / theta *
463  DoubleCrossMatrix(aa.axis());
464  }
465 
466  Eigen::Matrix6d ExpMapDerivative(const Eigen::Isometry3d& T) {
467  const Eigen::AngleAxisd aa(T.linear());
468  const auto& x = T.translation();
469  Eigen::Matrix6d dExp;
470  const Eigen::Matrix3d dExp_w = ExpMapDerivative(aa);
471  dExp.topLeftCorner<3, 3>() = dExp_w;
472  dExp.bottomLeftCorner<3, 3>().fill(0.);
473  dExp.topRightCorner<3, 3>() = ExpMapDerivativeCrossTerm(aa, x);
474  dExp.bottomRightCorner<3, 3>() = dExp_w;
475  return dExp;
476  }
477 
478  Eigen::Matrix6d LogMapDerivative(const Eigen::Isometry3d& T) {
479  const Eigen::AngleAxisd aa(T.linear());
480  const auto& x = T.translation();
481  Eigen::Matrix6d dExp;
482  const Eigen::Matrix3d dLog_w = LogMapDerivative(aa);
483  dExp.topLeftCorner<3, 3>() = dLog_w;
484  dExp.bottomLeftCorner<3, 3>().fill(0.);
485  dExp.topRightCorner<3, 3>() =
486  -dLog_w * ExpMapDerivativeCrossTerm(aa, x) * dLog_w;
487  dExp.bottomRightCorner<3, 3>() = dLog_w;
488  return dExp;
489  }
490 
491 } // namespace ctrl_utils
492 
493 #endif // CTRL_UTILS_EUCLIDIAN_H_
Definition: ctrl_utils.cc:18
ExpMapJacobianReturnType< Eigen::MatrixBase< Derived >::ColsAtCompileTime >::type ExpMapJacobian(const Eigen::AngleAxisd &aa, const Eigen::MatrixBase< Derived > &X)
Definition: euclidian.h:342
Eigen::Quaterniond FarQuaternion(const Eigen::Quaterniond &quat, const Eigen::Quaterniond &quat_reference)
Definition: euclidian.h:248
Eigen::Matrix3d ExpMapDerivative(const Eigen::AngleAxisd &aa)
Definition: euclidian.h:272
Eigen::Vector3d OrientationError(const Eigen::Quaterniond &quat, const Eigen::Quaterniond &quat_des)
Definition: euclidian.h:215
Eigen::Quaterniond NearQuaternion(const Eigen::Quaterniond &quat, const Eigen::Quaterniond &quat_reference)
Definition: euclidian.h:234
Eigen::Vector3d LookatError(const Eigen::Vector3d &vec, const Eigen::Vector3d &vec_des)
Definition: euclidian.h:224
Definition: euclidian.h:174