pinocchio  UNKNOWN
explog.hpp
1 //
2 // Copyright (c) 2015-2018 CNRS
3 // Copyright (c) 2015 Wandercraft, 86 rue de Paris 91400 Orsay, France.
4 //
5 // This file is part of Pinocchio
6 // Pinocchio is free software: you can redistribute it
7 // and/or modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation, either version
9 // 3 of the License, or (at your option) any later version.
10 //
11 // Pinocchio is distributed in the hope that it will be
12 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // General Lesser Public License for more details. You should have
15 // received a copy of the GNU Lesser General Public License along with
16 // Pinocchio If not, see
17 // <http://www.gnu.org/licenses/>.
18 
19 #ifndef __spatial_explog_hpp__
20 #define __spatial_explog_hpp__
21 
22 #include <Eigen/Geometry>
23 
24 #include "pinocchio/macros.hpp"
25 #include "pinocchio/math/fwd.hpp"
26 #include "pinocchio/math/sincos.hpp"
27 #include "pinocchio/spatial/motion.hpp"
28 #include "pinocchio/spatial/skew.hpp"
29 #include "pinocchio/spatial/se3.hpp"
30 
31 namespace se3
32 {
41  template<typename Vector3Like>
42  typename Eigen::Matrix<typename Vector3Like::Scalar,3,3,EIGEN_PLAIN_TYPE(Vector3Like)::Options>
43  exp3(const Eigen::MatrixBase<Vector3Like> & v)
44  {
45  EIGEN_STATIC_ASSERT_VECTOR_ONLY(Vector3Like);
46  assert(v.size() == 3);
47 
48  typedef typename Vector3Like::Scalar Scalar;
49  typedef typename EIGEN_PLAIN_TYPE(Vector3Like) Vector3LikePlain;
50  typedef Eigen::Matrix<Scalar,3,3,Vector3LikePlain::Options> Matrix3;
51 
52  const Scalar t2 = v.squaredNorm();
53 
54  const Scalar t = std::sqrt(t2);
55  if(t > Eigen::NumTraits<Scalar>::dummy_precision())
56  {
57  Scalar ct,st; SINCOS(t,&st,&ct);
58  const Scalar alpha_vxvx = (1 - ct)/t2;
59  const Scalar alpha_vx = (st)/t;
60  Matrix3 res(alpha_vxvx * v * v.transpose());
61  res.coeffRef(0,1) -= alpha_vx * v[2]; res.coeffRef(1,0) += alpha_vx * v[2];
62  res.coeffRef(0,2) += alpha_vx * v[1]; res.coeffRef(2,0) -= alpha_vx * v[1];
63  res.coeffRef(1,2) -= alpha_vx * v[0]; res.coeffRef(2,1) += alpha_vx * v[0];
64  res.diagonal().array() += ct;
65 
66  return res;
67  }
68  else
69  {
70  const Scalar alpha_vxvx = Scalar(1)/Scalar(2) - t2/24;
71  const Scalar alpha_vx = Scalar(1) - t2/6;
72  Matrix3 res(alpha_vxvx * v * v.transpose());
73  res.coeffRef(0,1) -= alpha_vx * v[2]; res.coeffRef(1,0) += alpha_vx * v[2];
74  res.coeffRef(0,2) += alpha_vx * v[1]; res.coeffRef(2,0) -= alpha_vx * v[1];
75  res.coeffRef(1,2) -= alpha_vx * v[0]; res.coeffRef(2,1) += alpha_vx * v[0];
76  res.diagonal().array() += Scalar(1) - t2/2;
77 
78  return res;
79  }
80  }
81 
89  template<typename Matrix3Like, typename S2>
90  Eigen::Matrix<typename Matrix3Like::Scalar,3,1,Eigen::internal::traits<Matrix3Like>::Options>
91  log3(const Eigen::MatrixBase<Matrix3Like> & R, S2 & theta)
92  {
93  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Matrix3Like,3,3);
94  typedef typename Matrix3Like::Scalar Scalar;
95  typedef Eigen::Matrix<Scalar,3,1,Eigen::internal::traits<Matrix3Like>::Options> Vector3;
96 
97  const Scalar PI_value = PI<Scalar>();
98 
99  Vector3 res;
100  const Scalar tr = R.trace();
101  if (tr > Scalar(3)) theta = 0; // acos((3-1)/2)
102  else if (tr < Scalar(-1)) theta = PI_value; // acos((-1-1)/2)
103  else theta = acos((tr - Scalar(1))/Scalar(2));
104  assert(theta == theta && "theta contains some NaN"); // theta != NaN
105 
106  // From runs of hpp-constraints/tests/logarithm.cc: 1e-6 is too small.
107  if (theta < PI_value - 1e-2)
108  {
109  const Scalar t = ((theta > 1e-6)? theta / sin(theta) : Scalar(1)) / Scalar(2);
110  res(0) = t * (R (2, 1) - R (1, 2));
111  res(1) = t * (R (0, 2) - R (2, 0));
112  res(2) = t * (R (1, 0) - R (0, 1));
113  }
114  else
115  {
116  // 1e-2: A low value is not required since the computation is
117  // using explicit formula. However, the precision of this method
118  // is the square root of the precision with the antisymmetric
119  // method (Nominal case).
120  const Scalar cphi = cos(theta - PI_value);
121  const Scalar beta = theta*theta / ( Scalar(1) + cphi );
122  Vector3 tmp((R.diagonal().array() + cphi) * beta);
123  res(0) = (R (2, 1) > R (1, 2) ? Scalar(1) : Scalar(-1)) * (tmp[0] > Scalar(0) ? sqrt(tmp[0]) : Scalar(0));
124  res(1) = (R (0, 2) > R (2, 0) ? Scalar(1) : Scalar(-1)) * (tmp[1] > Scalar(0) ? sqrt(tmp[1]) : Scalar(0));
125  res(2) = (R (1, 0) > R (0, 1) ? Scalar(1) : Scalar(-1)) * (tmp[2] > Scalar(0) ? sqrt(tmp[2]) : Scalar(0));
126  }
127 
128  return res;
129  }
130 
139  template<typename Matrix3Like>
140  Eigen::Matrix<typename Matrix3Like::Scalar,3,1,Eigen::internal::traits<Matrix3Like>::Options>
141  log3(const Eigen::MatrixBase<Matrix3Like> & R)
142  {
143  typename Matrix3Like::Scalar theta;
144  return log3(R.derived(), theta);
145  }
146 
153  template<typename Vector3Like, typename Matrix3Like>
154  void Jexp3(const Eigen::MatrixBase<Vector3Like> & r,
155  const Eigen::MatrixBase<Matrix3Like> & Jexp)
156  {
157  Matrix3Like & Jout = const_cast<Matrix3Like &>(Jexp.derived());
158  typedef typename Matrix3Like::Scalar Scalar;
159 
160  Scalar n = r.norm(),a,b,c;
161 
162  if (n < 1e-6) {
163  Scalar n2 = n;
164 
165  a = Scalar(1) - n/Scalar(6) + n2/Scalar(120);
166  b = - Scalar(1)/Scalar(2) + n/Scalar(24) - n2/Scalar(720);
167  c = Scalar(1)/Scalar(6) - n/Scalar(120) + n2/Scalar(5040);
168  } else
169  {
170  Scalar n_inv = Scalar(1.)/n;
171  Scalar n2_inv = n_inv * n_inv;
172  Scalar cn,sn; SINCOS(n,&sn,&cn);
173 
174  a = sn*n_inv;
175  b = - (1-cn)*n2_inv;
176  c = n2_inv * (1 - a);
177  }
178 
179  Jout.setZero ();
180  Jout.diagonal().setConstant(a);
181 
182  Jout(0,1) = -b*r[2]; Jout(1,0) = -Jout(0,1);
183  Jout(0,2) = b*r[1]; Jout(2,0) = -Jout(0,2);
184  Jout(1,2) = -b*r[0]; Jout(2,1) = -Jout(1,2);
185 
186  Jout.noalias() += c * r * r.transpose();
187  }
188 
189  template<typename Scalar, typename Vector3Like, typename Matrix3Like>
190  void Jlog3(const Scalar & theta,
191  const Eigen::MatrixBase<Vector3Like> & log,
192  const Eigen::MatrixBase<Matrix3Like> & Jlog)
193  {
194  Matrix3Like & Jout = const_cast<Matrix3Like &>(Jlog.derived());
195  typedef typename Matrix3Like::Scalar Scalar3;
196 
197  if (theta < 1e-6)
198  Jout.setIdentity();
199  else
200  {
201  // Jlog = alpha I
202  Scalar ct,st; SINCOS(theta,&st,&ct);
203  const Scalar st_1mct = st/(Scalar(1)-ct);
204 
205  Jout.setZero ();
206  Jout.diagonal().setConstant (theta*st_1mct);
207 
208  // Jlog += r_{\times}/2
209  Jout(0,1) = -log(2); Jout(1,0) = log(2);
210  Jout(0,2) = log(1); Jout(2,0) = -log(1);
211  Jout(1,2) = -log(0); Jout(2,1) = log(0);
212  Jout /= Scalar3(2);
213 
214  const Scalar alpha = Scalar(1)/(theta*theta) - st_1mct/(Scalar(2)*theta);
215  Jout += alpha * log * log.transpose();
216  }
217  }
218 
219  template<typename Matrix3Like1, typename Matrix3Like2>
220  void Jlog3(const Eigen::MatrixBase<Matrix3Like1> & R,
221  const Eigen::MatrixBase<Matrix3Like2> & Jlog)
222  {
223  typedef typename Matrix3Like1::Scalar Scalar;
224  typedef Eigen::Matrix<Scalar,3,1,Eigen::internal::traits<Matrix3Like1>::Options> Vector3;
225 
226  Scalar t;
227  Vector3 w(log3(R,t));
228  Jlog3(t,w,Jlog);
229  }
230 
239  template<typename MotionDerived>
242  {
243  typedef typename MotionDerived::Scalar Scalar;
244  enum { Options = Eigen::internal::traits<typename MotionDerived::Vector3>::Options };
245 
246  typedef SE3Tpl<Scalar,Options> SE3;
247 
248  const typename MotionDerived::ConstAngularType & w = nu.angular();
249  const typename MotionDerived::ConstLinearType & v = nu.linear();
250 
251  const Scalar t2 = w.squaredNorm();
252 
253  SE3 res;
254  typename SE3::Linear_t & trans = res.translation();
255  typename SE3::Angular_t & rot = res.rotation();
256 
257  const Scalar t = std::sqrt(t2);
258  if(t > 1e-4)
259  {
260  Scalar ct,st; SINCOS(t,&st,&ct);
261 
262  const Scalar inv_t2 = Scalar(1)/t2;
263  const Scalar alpha_wxv = (Scalar(1) - ct)*inv_t2;
264  const Scalar alpha_v = (st)/t;
265  const Scalar alpha_w = (Scalar(1) - alpha_v)*inv_t2 * w.dot(v);
266 
267  // Linear
268  trans.noalias() = (alpha_v*v + alpha_w*w + alpha_wxv*w.cross(v));
269 
270  // Rotational
271  rot.noalias() = alpha_wxv * w * w.transpose();
272  rot.coeffRef(0,1) -= alpha_v * w[2]; rot.coeffRef(1,0) += alpha_v * w[2];
273  rot.coeffRef(0,2) += alpha_v * w[1]; rot.coeffRef(2,0) -= alpha_v * w[1];
274  rot.coeffRef(1,2) -= alpha_v * w[0]; rot.coeffRef(2,1) += alpha_v * w[0];
275  rot.diagonal().array() += ct;
276  }
277  else
278  {
279  const Scalar alpha_wxv = Scalar(1)/Scalar(2) - t2/24;
280  const Scalar alpha_v = Scalar(1) - t2/6;
281  const Scalar alpha_w = (Scalar(1)/Scalar(6) - t2/120) * w.dot(v);
282 
283  // Linear
284  trans.noalias() = (alpha_v*v + alpha_w*w + alpha_wxv*w.cross(v));
285 
286  // Rotational
287  rot.noalias() = alpha_wxv * w * w.transpose();
288  rot.coeffRef(0,1) -= alpha_v * w[2]; rot.coeffRef(1,0) += alpha_v * w[2];
289  rot.coeffRef(0,2) += alpha_v * w[1]; rot.coeffRef(2,0) -= alpha_v * w[1];
290  rot.coeffRef(1,2) -= alpha_v * w[0]; rot.coeffRef(2,1) += alpha_v * w[0];
291  rot.diagonal().array() += Scalar(1) - t2/2;
292  }
293 
294  return res;
295  }
296 
305  template<typename Vector6Like>
307  exp6(const Eigen::MatrixBase<Vector6Like> & v)
308  {
309  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector6Like,6);
311  return exp6(nu);
312  }
313 
322  template <typename Scalar, int Options>
325  {
326  typedef SE3Tpl<Scalar,Options> SE3;
328  typedef typename SE3::Vector3 Vector3;
329 
330  const typename SE3::ConstAngular_t & R = M.rotation();
331  const typename SE3::ConstLinear_t & p = M.translation();
332 
333  Scalar t;
334  Vector3 w(log3(R,t));
335  const Scalar t2 = t*t;
336  Scalar alpha, beta;
337  if (std::fabs(t) < 1e-4)
338  {
339  alpha = Scalar(1) - t2/Scalar(12) - t2*t2/Scalar(720);
340  beta = Scalar(1)/Scalar(12) + t2/Scalar(720);
341  } else
342  {
343  Scalar st,ct; SINCOS(t,&st,&ct);
344  alpha = t*st/(Scalar(2)*(Scalar(1)-ct));
345  beta = Scalar(1)/t2 - st/(Scalar(2)*t*(Scalar(1)-ct));
346  }
347 
348  return Motion(alpha * p - alphaSkew(0.5, w) * p + beta * w.dot(p) * w,
349  w);
350  }
351 
360  template<typename D>
362  log6(const Eigen::MatrixBase<D> & M)
363  {
364  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(D, 4, 4);
365  typedef typename SE3Tpl<typename D::Scalar,D::Options>::Vector3 Vector3;
366  typedef typename SE3Tpl<typename D::Scalar,D::Options>::Matrix3 Matrix3;
367 
368  Matrix3 rot(M.template block<3,3>(0,0));
369  Vector3 trans(M.template block<3,1>(0,3));
371  return log6(m);
372  }
373 
376  template<typename MotionDerived, typename Matrix6Like>
378  const Eigen::MatrixBase<Matrix6Like> & Jexp)
379  {
380  typedef typename MotionDerived::Scalar Scalar;
381  typedef typename MotionDerived::Vector3 Vector3;
382  typedef Eigen::Matrix<Scalar, 3, 3, Vector3::Options> Matrix3;
383  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Matrix6Like,6,6);
384  Matrix6Like & Jout = const_cast<Matrix6Like &> (Jexp.derived());
385 
386  const typename MotionDerived::ConstLinearType & v = nu.linear();
387  const typename MotionDerived::ConstAngularType & w = nu.angular();
388  const Scalar t = w.norm();
389 
390  // Matrix3 J3;
391  // Jexp3(w, J3);
392  Jexp3(w, Jout.template bottomRightCorner<3,3>());
393  Jout.template topLeftCorner<3,3>() = Jout.template bottomRightCorner<3,3>();
394 
395  const Scalar t2 = t*t;
396  Scalar beta, beta_dot_over_theta;
397  if (t < 1e-4) {
398  beta = Scalar(1)/Scalar(12) + t2/Scalar(720);
399  beta_dot_over_theta = Scalar(1)/Scalar(360);
400  } else {
401  const Scalar tinv = Scalar(1)/t,
402  t2inv = tinv*tinv;
403  Scalar st,ct; SINCOS (t, &st, &ct);
404  const Scalar inv_2_2ct = Scalar(1)/(Scalar(2)*(Scalar(1)-ct));
405 
406  beta = t2inv - st*tinv*inv_2_2ct;
407  beta_dot_over_theta = -Scalar(2)*t2inv*t2inv +
408  (Scalar(1) + st*tinv) * t2inv * inv_2_2ct;
409  }
410 
411  Vector3 p (Jout.template topLeftCorner<3,3>().transpose() * v);
412  Scalar wTp (w.dot (p));
413  Matrix3 J (alphaSkew(.5, p) +
414  (beta_dot_over_theta*wTp) *w*w.transpose()
415  - (t2*beta_dot_over_theta+Scalar(2)*beta)*p*w.transpose()
416  + wTp * beta * Matrix3::Identity()
417  + beta *w*p.transpose());
418 
419  Jout.template topRightCorner<3,3>().noalias() =
420  - Jout.template topLeftCorner<3,3>() * J;
421  Jout.template bottomLeftCorner<3,3>().setZero();
422  }
423 
442  template<typename Scalar, int Options, typename Matrix6Like>
444  const Eigen::MatrixBase<Matrix6Like> & Jlog)
445  {
446  typedef SE3Tpl<Scalar,Options> SE3;
447  typedef typename SE3::Vector3 Vector3;
448  typedef typename SE3::Matrix3 Matrix3;
449  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Matrix6Like,6,6);
450  Matrix6Like & value = const_cast<Matrix6Like &> (Jlog.derived());
451 
452  const typename SE3::ConstAngular_t & R = M.rotation();
453  const typename SE3::ConstLinear_t & p = M.translation();
454 
455  Scalar t;
456  Vector3 w(log3(R,t));
457 
458  Matrix3 J3;
459  Jlog3(t, w, J3);
460 
461  const Scalar t2 = t*t;
462  Scalar beta, beta_dot_over_theta;
463  if (t < 1e-4)
464  {
465  beta = Scalar(1)/Scalar(12) + t2/Scalar(720);
466  beta_dot_over_theta = Scalar(1)/Scalar(360);
467  }
468  else
469  {
470  const Scalar tinv = Scalar(1)/t,
471  t2inv = tinv*tinv;
472  Scalar st,ct; SINCOS (t, &st, &ct);
473  const Scalar inv_2_2ct = Scalar(1)/(Scalar(2)*(Scalar(1)-ct));
474 
475  beta = t2inv - st*tinv*inv_2_2ct;
476  beta_dot_over_theta = -Scalar(2)*t2inv*t2inv +
477  (Scalar(1) + st*tinv) * t2inv * inv_2_2ct;
478  }
479 
480  Scalar wTp (w.dot (p));
481 
482  Matrix3 J ((alphaSkew(.5, p) +
483  (beta_dot_over_theta*wTp)*w*w.transpose()
484  - (t2*beta_dot_over_theta+Scalar(2)*beta)*p*w.transpose()
485  + wTp * beta * Matrix3::Identity()
486  + beta * w*p.transpose()
487  ) * J3);
488 
489  value << J3 , J,
490  Matrix3::Zero(), J3;
491  }
492 } // namespace se3
493 
494 #endif //#ifndef __spatial_explog_hpp__
EIGEN_PLAIN_TYPE(Matrix3x) cross(const Eigen
Applies the cross product onto the columns of M.
Definition: skew.hpp:227
void Jexp3(const Eigen::MatrixBase< Vector3Like > &r, const Eigen::MatrixBase< Matrix3Like > &Jexp)
Derivative of .
Definition: explog.hpp:154
void Jexp6(const MotionDense< MotionDerived > &nu, const Eigen::MatrixBase< Matrix6Like > &Jexp)
Derivative of exp6 Computed as the inverse of Jlog6.
Definition: explog.hpp:377
MotionTpl< Scalar, Options > log6(const SE3Tpl< Scalar, Options > &M)
Log: SE3 -> se3.
Definition: explog.hpp:324
void alphaSkew(const Scalar alpha, const Eigen::MatrixBase< Vector3 > &v, const Eigen::MatrixBase< Matrix3 > &M)
Computes the skew representation of a given 3d vector multiplied by a given scalar. i.e. the antisymmetric matrix representation of the cross product operator ( )
Definition: skew.hpp:116
Eigen::Matrix< typename Matrix3Like::Scalar, 3, 1, Eigen::internal::traits< Matrix3Like >::Options > log3(const Eigen::MatrixBase< Matrix3Like > &R, S2 &theta)
Same as log3.
Definition: explog.hpp:91
SE3Tpl< typename MotionDerived::Scalar, Eigen::internal::traits< typename MotionDerived::Vector3 >::Options > exp6(const MotionDense< MotionDerived > &nu)
Exp: se3 -> SE3.
Definition: explog.hpp:241
void Jlog6(const SE3Tpl< Scalar, Options > &M, const Eigen::MatrixBase< Matrix6Like > &Jlog)
Derivative of log6 and .
Definition: explog.hpp:443
Eigen::Matrix< typename Vector3Like::Scalar, 3, 3, EIGEN_PLAIN_TYPE(Vector3Like)::Options > exp3(const Eigen::MatrixBase< Vector3Like > &v)
Exp: so3 -> SO3.
Definition: explog.hpp:43