pinocchio  2.1.3
explog.hpp
1 //
2 // Copyright (c) 2015-2018 CNRS INRIA
3 // Copyright (c) 2015 Wandercraft, 86 rue de Paris 91400 Orsay, France.
4 //
5 
6 #ifndef __spatial_explog_hpp__
7 #define __spatial_explog_hpp__
8 
9 #include <Eigen/Geometry>
10 
11 #include "pinocchio/fwd.hpp"
12 #include "pinocchio/math/fwd.hpp"
13 #include "pinocchio/math/sincos.hpp"
14 #include "pinocchio/math/taylor-expansion.hpp"
15 #include "pinocchio/spatial/motion.hpp"
16 #include "pinocchio/spatial/skew.hpp"
17 #include "pinocchio/spatial/se3.hpp"
18 
19 namespace pinocchio
20 {
29  template<typename Vector3Like>
30  typename Eigen::Matrix<typename Vector3Like::Scalar,3,3,PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like)::Options>
31  exp3(const Eigen::MatrixBase<Vector3Like> & v)
32  {
33  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Vector3Like, v, 3, 1);
34 
35  typedef typename Vector3Like::Scalar Scalar;
36  typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) Vector3LikePlain;
37  typedef Eigen::Matrix<Scalar,3,3,Vector3LikePlain::Options> Matrix3;
38 
39  const Scalar t2 = v.squaredNorm();
40 
41  const Scalar t = math::sqrt(t2);
42  if(t > TaylorSeriesExpansion<Scalar>::template precision<3>())
43  {
44  Scalar ct,st; SINCOS(t,&st,&ct);
45  const Scalar alpha_vxvx = (1 - ct)/t2;
46  const Scalar alpha_vx = (st)/t;
47  Matrix3 res(alpha_vxvx * v * v.transpose());
48  res.coeffRef(0,1) -= alpha_vx * v[2]; res.coeffRef(1,0) += alpha_vx * v[2];
49  res.coeffRef(0,2) += alpha_vx * v[1]; res.coeffRef(2,0) -= alpha_vx * v[1];
50  res.coeffRef(1,2) -= alpha_vx * v[0]; res.coeffRef(2,1) += alpha_vx * v[0];
51  res.diagonal().array() += ct;
52 
53  return res;
54  }
55  else
56  {
57  const Scalar alpha_vxvx = Scalar(1)/Scalar(2) - t2/24;
58  const Scalar alpha_vx = Scalar(1) - t2/6;
59  Matrix3 res(alpha_vxvx * v * v.transpose());
60  res.coeffRef(0,1) -= alpha_vx * v[2]; res.coeffRef(1,0) += alpha_vx * v[2];
61  res.coeffRef(0,2) += alpha_vx * v[1]; res.coeffRef(2,0) -= alpha_vx * v[1];
62  res.coeffRef(1,2) -= alpha_vx * v[0]; res.coeffRef(2,1) += alpha_vx * v[0];
63  res.diagonal().array() += Scalar(1) - t2/2;
64 
65  return res;
66  }
67  }
68 
76  template<typename Matrix3Like>
77  Eigen::Matrix<typename Matrix3Like::Scalar,3,1,PINOCCHIO_EIGEN_PLAIN_TYPE(Matrix3Like)::Options>
78  log3(const Eigen::MatrixBase<Matrix3Like> & R,
79  typename Matrix3Like::Scalar & theta)
80  {
81  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Matrix3Like, R, 3, 3);
82 
83  typedef typename Matrix3Like::Scalar Scalar;
84  typedef Eigen::Matrix<Scalar,3,1,PINOCCHIO_EIGEN_PLAIN_TYPE(Matrix3Like)::Options> Vector3;
85 
86  static const Scalar PI_value = PI<Scalar>();
87 
88  Vector3 res;
89  const Scalar tr = R.trace();
90  if (tr > Scalar(3)) theta = 0; // acos((3-1)/2)
91  else if (tr < Scalar(-1)) theta = PI_value; // acos((-1-1)/2)
92  else theta = acos((tr - Scalar(1))/Scalar(2));
93  assert(theta == theta && "theta contains some NaN"); // theta != NaN
94 
95  // From runs of hpp-constraints/tests/logarithm.cc: 1e-6 is too small.
96  if (theta < PI_value - 1e-2)
97  {
98  const Scalar t = ((theta > TaylorSeriesExpansion<Scalar>::template precision<3>())
99  ? theta / sin(theta)
100  : Scalar(1)) / Scalar(2);
101  res(0) = t * (R (2, 1) - R (1, 2));
102  res(1) = t * (R (0, 2) - R (2, 0));
103  res(2) = t * (R (1, 0) - R (0, 1));
104  }
105  else
106  {
107  // 1e-2: A low value is not required since the computation is
108  // using explicit formula. However, the precision of this method
109  // is the square root of the precision with the antisymmetric
110  // method (Nominal case).
111  const Scalar cphi = cos(theta - PI_value);
112  const Scalar beta = theta*theta / ( Scalar(1) + cphi );
113  Vector3 tmp((R.diagonal().array() + cphi) * beta);
114  res(0) = (R (2, 1) > R (1, 2) ? Scalar(1) : Scalar(-1)) * (tmp[0] > Scalar(0) ? sqrt(tmp[0]) : Scalar(0));
115  res(1) = (R (0, 2) > R (2, 0) ? Scalar(1) : Scalar(-1)) * (tmp[1] > Scalar(0) ? sqrt(tmp[1]) : Scalar(0));
116  res(2) = (R (1, 0) > R (0, 1) ? Scalar(1) : Scalar(-1)) * (tmp[2] > Scalar(0) ? sqrt(tmp[2]) : Scalar(0));
117  }
118 
119  return res;
120  }
121 
130  template<typename Matrix3Like>
131  Eigen::Matrix<typename Matrix3Like::Scalar,3,1,PINOCCHIO_EIGEN_PLAIN_TYPE(Matrix3Like)::Options>
132  log3(const Eigen::MatrixBase<Matrix3Like> & R)
133  {
134  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Matrix3Like, R, 3, 3);
135 
136  typename Matrix3Like::Scalar theta;
137  return log3(R.derived(),theta);
138  }
139 
148  template<typename Vector3Like, typename Matrix3Like>
149  void Jexp3(const Eigen::MatrixBase<Vector3Like> & r,
150  const Eigen::MatrixBase<Matrix3Like> & Jexp)
151  {
152  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Vector3Like, r , 3, 1);
153  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Matrix3Like, Jexp, 3, 3);
154 
155  Matrix3Like & Jout = const_cast<Matrix3Like &>(Jexp.derived());
156  typedef typename Matrix3Like::Scalar Scalar;
157 
158  Scalar n2 = r.squaredNorm(),a,b,c;
159  Scalar n = math::sqrt(n2);
160 
161  if (n < TaylorSeriesExpansion<Scalar>::template precision<3>())
162  {
163  a = Scalar(1) - n2/Scalar(6);
164  b = - Scalar(1)/Scalar(2) - n2/Scalar(24);
165  c = Scalar(1)/Scalar(6) - n2/Scalar(120);
166  }
167  else
168  {
169  Scalar n_inv = Scalar(1)/n;
170  Scalar n2_inv = n_inv * n_inv;
171  Scalar cn,sn; SINCOS(n,&sn,&cn);
172 
173  a = sn*n_inv;
174  b = - (1-cn)*n2_inv;
175  c = n2_inv * (1 - a);
176  }
177 
178  Jout.diagonal().setConstant(a);
179 
180  Jout(0,1) = -b*r[2]; Jout(1,0) = -Jout(0,1);
181  Jout(0,2) = b*r[1]; Jout(2,0) = -Jout(0,2);
182  Jout(1,2) = -b*r[0]; Jout(2,1) = -Jout(1,2);
183 
184  Jout.noalias() += c * r * r.transpose();
185  }
186 
187  template<typename Scalar, typename Vector3Like, typename Matrix3Like>
188  void Jlog3(const Scalar & theta,
189  const Eigen::MatrixBase<Vector3Like> & log,
190  const Eigen::MatrixBase<Matrix3Like> & Jlog)
191  {
192  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Vector3Like, log, 3, 1);
193  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Matrix3Like, Jlog, 3, 3);
194 
195  Matrix3Like & Jout = const_cast<Matrix3Like &>(Jlog.derived());
196 
197  if (theta < TaylorSeriesExpansion<Scalar>::template precision<3>())
198  {
199  const Scalar alpha = Scalar(1)/Scalar(12) + theta*theta / Scalar(720);
200  Jout.noalias() = alpha * log * log.transpose();
201 
202  Jout.diagonal().array() += Scalar(0.5) * (2 - theta*theta / Scalar(6));
203 
204  // Jlog += r_{\times}/2
205  addSkew(0.5 * log, Jlog);
206  }
207  else
208  {
209  // Jlog = alpha I
210  Scalar ct,st; SINCOS(theta,&st,&ct);
211  const Scalar st_1mct = st/(Scalar(1)-ct);
212 
213  const Scalar alpha = Scalar(1)/(theta*theta) - st_1mct/(Scalar(2)*theta);
214  Jout.noalias() = alpha * log * log.transpose();
215 
216  Jout.diagonal().array() += Scalar(0.5) * (theta*st_1mct);
217 
218  // Jlog += r_{\times}/2
219  addSkew(0.5 * log, Jlog);
220  }
221  }
222 
223  template<typename Matrix3Like1, typename Matrix3Like2>
224  void Jlog3(const Eigen::MatrixBase<Matrix3Like1> & R,
225  const Eigen::MatrixBase<Matrix3Like2> & Jlog)
226  {
227  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Matrix3Like1, R, 3, 3);
228  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Matrix3Like2, Jlog, 3, 3);
229 
230  typedef typename Matrix3Like1::Scalar Scalar;
231  typedef Eigen::Matrix<Scalar,3,1,PINOCCHIO_EIGEN_PLAIN_TYPE(Matrix3Like1)::Options> Vector3;
232 
233  Scalar t;
234  Vector3 w(log3(R,t));
235  Jlog3(t,w,Jlog);
236  }
237 
246  template<typename MotionDerived>
249  {
250  typedef typename MotionDerived::Scalar Scalar;
251  enum { Options = PINOCCHIO_EIGEN_PLAIN_TYPE(typename MotionDerived::Vector3)::Options };
252 
253  typedef SE3Tpl<Scalar,Options> SE3;
254 
255  const typename MotionDerived::ConstAngularType & w = nu.angular();
256  const typename MotionDerived::ConstLinearType & v = nu.linear();
257 
258  const Scalar t2 = w.squaredNorm();
259 
260  SE3 res;
261  typename SE3::LinearType & trans = res.translation();
262  typename SE3::AngularType & rot = res.rotation();
263 
264  const Scalar t = math::sqrt(t2);
265  if(t < TaylorSeriesExpansion<Scalar>::template precision<3>())
266  {
267  // Taylor expansion
268  const Scalar alpha_wxv = Scalar(1)/Scalar(2) - t2/24;
269  const Scalar alpha_v = Scalar(1) - t2/6;
270  const Scalar alpha_w = (Scalar(1)/Scalar(6) - t2/120)*w.dot(v);
271 
272  // Linear
273  trans.noalias() = (alpha_v*v + alpha_w*w + alpha_wxv*w.cross(v));
274 
275  // Rotational
276  rot.noalias() = alpha_wxv * w * w.transpose();
277  rot.coeffRef(0,1) -= alpha_v * w[2]; rot.coeffRef(1,0) += alpha_v * w[2];
278  rot.coeffRef(0,2) += alpha_v * w[1]; rot.coeffRef(2,0) -= alpha_v * w[1];
279  rot.coeffRef(1,2) -= alpha_v * w[0]; rot.coeffRef(2,1) += alpha_v * w[0];
280  rot.diagonal().array() += Scalar(1) - t2/2;
281  }
282  else
283  {
284  Scalar ct,st; SINCOS(t,&st,&ct);
285 
286  const Scalar inv_t2 = Scalar(1)/t2;
287  const Scalar alpha_wxv = (Scalar(1) - ct)*inv_t2;
288  const Scalar alpha_v = (st)/t;
289  const Scalar alpha_w = (Scalar(1) - alpha_v)*inv_t2 * w.dot(v);
290 
291  // Linear
292  trans.noalias() = (alpha_v*v + alpha_w*w + alpha_wxv*w.cross(v));
293 
294  // Rotational
295  rot.noalias() = alpha_wxv * w * w.transpose();
296  rot.coeffRef(0,1) -= alpha_v * w[2]; rot.coeffRef(1,0) += alpha_v * w[2];
297  rot.coeffRef(0,2) += alpha_v * w[1]; rot.coeffRef(2,0) -= alpha_v * w[1];
298  rot.coeffRef(1,2) -= alpha_v * w[0]; rot.coeffRef(2,1) += alpha_v * w[0];
299  rot.diagonal().array() += ct;
300  }
301 
302  return res;
303  }
304 
313  template<typename Vector6Like>
315  exp6(const Eigen::MatrixBase<Vector6Like> & v)
316  {
317  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Vector6Like, v, 6, 1);
318 
319  MotionRef<const Vector6Like> nu(v.derived());
320  return exp6(nu);
321  }
322 
331  template <typename Scalar, int Options>
334  {
335  typedef SE3Tpl<Scalar,Options> SE3;
337  typedef typename SE3::Vector3 Vector3;
338 
339  typename SE3::ConstAngularRef R = M.rotation();
340  typename SE3::ConstLinearRef p = M.translation();
341 
342  Scalar t;
343  Vector3 w(log3(R,t)); // t in [0,π]
344  const Scalar t2 = t*t;
345  Scalar alpha, beta;
346  if (t < TaylorSeriesExpansion<Scalar>::template precision<3>())
347  {
348  alpha = Scalar(1) - t2/Scalar(12) - t2*t2/Scalar(720);
349  beta = Scalar(1)/Scalar(12) + t2/Scalar(720);
350  }
351  else
352  {
353  Scalar st,ct; SINCOS(t,&st,&ct);
354  alpha = t*st/(Scalar(2)*(Scalar(1)-ct));
355  beta = Scalar(1)/t2 - st/(Scalar(2)*t*(Scalar(1)-ct));
356  }
357 
358  return Motion(alpha * p - 0.5 * w.cross(p) + beta * w.dot(p) * w,
359  w);
360  }
361 
370  template<typename Matrix4Like>
372  log6(const Eigen::MatrixBase<Matrix4Like> & M)
373  {
374  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Matrix4Like, M, 4, 4);
375 
377  return log6(m);
378  }
379 
382  template<typename MotionDerived, typename Matrix6Like>
384  const Eigen::MatrixBase<Matrix6Like> & Jexp)
385  {
386  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Matrix6Like, Jexp, 6, 6);
387 
388  typedef typename MotionDerived::Scalar Scalar;
389  typedef typename MotionDerived::Vector3 Vector3;
390  typedef Eigen::Matrix<Scalar, 3, 3, Vector3::Options> Matrix3;
391  Matrix6Like & Jout = const_cast<Matrix6Like &> (Jexp.derived());
392 
393  const typename MotionDerived::ConstLinearType & v = nu.linear();
394  const typename MotionDerived::ConstAngularType & w = nu.angular();
395  const Scalar t2 = w.squaredNorm();
396  const Scalar t = math::sqrt(t2);
397 
398  // Matrix3 J3;
399  // Jexp3(w, J3);
400  Jexp3(w, Jout.template bottomRightCorner<3,3>());
401  Jout.template topLeftCorner<3,3>() = Jout.template bottomRightCorner<3,3>();
402 
403  Scalar beta, beta_dot_over_theta;
404  if (t < TaylorSeriesExpansion<Scalar>::template precision<3>())
405  {
406  beta = Scalar(1)/Scalar(12) + t2/Scalar(720);
407  beta_dot_over_theta = Scalar(1)/Scalar(360);
408  }
409  else
410  {
411  const Scalar tinv = Scalar(1)/t,
412  t2inv = tinv*tinv;
413  Scalar st,ct; SINCOS (t, &st, &ct);
414  const Scalar inv_2_2ct = Scalar(1)/(Scalar(2)*(Scalar(1)-ct));
415 
416  beta = t2inv - st*tinv*inv_2_2ct;
417  beta_dot_over_theta = -Scalar(2)*t2inv*t2inv +
418  (Scalar(1) + st*tinv) * t2inv * inv_2_2ct;
419  }
420 
421  Vector3 p (Jout.template topLeftCorner<3,3>().transpose() * v);
422  Scalar wTp (w.dot (p));
423  Matrix3 J (alphaSkew(.5, p) +
424  (beta_dot_over_theta*wTp) *w*w.transpose()
425  - (t2*beta_dot_over_theta+Scalar(2)*beta)*p*w.transpose()
426  + wTp * beta * Matrix3::Identity()
427  + beta *w*p.transpose());
428 
429  Jout.template topRightCorner<3,3>().noalias() =
430  - Jout.template topLeftCorner<3,3>() * J;
431  Jout.template bottomLeftCorner<3,3>().setZero();
432  }
433 
454  template<typename Scalar, int Options, typename Matrix6Like>
456  const Eigen::MatrixBase<Matrix6Like> & Jlog)
457  {
458  PINOCCHIO_ASSERT_MATRIX_SPECIFIC_SIZE (Matrix6Like, Jlog, 6, 6);
459 
460  typedef SE3Tpl<Scalar,Options> SE3;
461  typedef typename SE3::Vector3 Vector3;
462  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Matrix6Like,6,6);
463  Matrix6Like & value = const_cast<Matrix6Like &> (Jlog.derived());
464 
465  typename SE3::ConstAngularRef R = M.rotation();
466  typename SE3::ConstLinearRef p = M.translation();
467 
468  Scalar t;
469  Vector3 w(log3(R,t));
470 
471  // value is decomposed as following:
472  // value = [ A, B;
473  // C, D ]
474  typedef Eigen::Block<Matrix6Like,3,3,Matrix6Like::IsRowMajor> Block33;
475  Block33 A = value.template topLeftCorner<3,3>();
476  Block33 B = value.template topRightCorner<3,3>();
477  Block33 C = value.template bottomLeftCorner<3,3>();
478  Block33 D = value.template bottomRightCorner<3,3>();
479 
480  Jlog3(t, w, A);
481  D = A;
482 
483  const Scalar t2 = t*t;
484  Scalar beta, beta_dot_over_theta;
485  if(t < TaylorSeriesExpansion<Scalar>::template precision<3>())
486  {
487  beta = Scalar(1)/Scalar(12) + t2/Scalar(720);
488  beta_dot_over_theta = Scalar(1)/Scalar(360);
489  }
490  else
491  {
492  const Scalar tinv = Scalar(1)/t,
493  t2inv = tinv*tinv;
494  Scalar st,ct; SINCOS (t, &st, &ct);
495  const Scalar inv_2_2ct = Scalar(1)/(Scalar(2)*(Scalar(1)-ct));
496 
497  beta = t2inv - st*tinv*inv_2_2ct;
498  beta_dot_over_theta = -Scalar(2)*t2inv*t2inv +
499  (Scalar(1) + st*tinv) * t2inv * inv_2_2ct;
500  }
501 
502  Scalar wTp = w.dot(p);
503 
504  Vector3 v3_tmp((beta_dot_over_theta*wTp)*w - (t2*beta_dot_over_theta+Scalar(2)*beta)*p);
505  // C can be treated as a temporary variable
506  C.noalias() = v3_tmp * w.transpose();
507  C.noalias() += beta * w * p.transpose();
508  C.diagonal().array() += wTp * beta;
509  addSkew(.5*p,C);
510 
511  B.noalias() = C * A;
512  C.setZero();
513  }
514 } // namespace pinocchio
515 
516 #include "pinocchio/spatial/explog-quaternion.hpp"
517 
518 #endif //#ifndef __spatial_explog_hpp__
Eigen::Matrix< typename Matrix3Like::Scalar, 3, 1, Matrix3Like::Options > log3(const Eigen::MatrixBase< Matrix3Like > &R, typename Matrix3Like::Scalar &theta)
Same as log3.
Definition: explog.hpp:78
Eigen::Matrix< typename Vector3Like::Scalar, 3, 3, Vector3Like::Options > exp3(const Eigen::MatrixBase< Vector3Like > &v)
Exp: so3 -> SO3.
Definition: explog.hpp:31
void Jlog6(const SE3Tpl< Scalar, Options > &M, const Eigen::MatrixBase< Matrix6Like > &Jlog)
Derivative of log6 where and .
Definition: explog.hpp:455
Helper struct to retrieve some useful information for a Taylor series expansion according to the a gi...
MotionTpl< Scalar, Options > log6(const SE3Tpl< Scalar, Options > &M)
Log: SE3 -> se3.
Definition: explog.hpp:333
void SINCOS(const Scalar &a, Scalar *sa, Scalar *ca)
Computes sin/cos values of a given input scalar.
Definition: sincos.hpp:28
void Jexp3(const Eigen::MatrixBase< Vector3Like > &r, const Eigen::MatrixBase< Matrix3Like > &Jexp)
Derivative of .
Definition: explog.hpp:149
void Jexp6(const MotionDense< MotionDerived > &nu, const Eigen::MatrixBase< Matrix6Like > &Jexp)
Derivative of exp6 Computed as the inverse of Jlog6.
Definition: explog.hpp:383
void addSkew(const Eigen::MatrixBase< Vector3Like > &v, const Eigen::MatrixBase< Matrix3Like > &M)
Add skew matrix represented by a 3d vector to a given matrix, i.e. add the antisymmetric matrix repre...
Definition: skew.hpp:60
Main pinocchio namespace.
Definition: treeview.dox:24
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:124
SE3Tpl< typename MotionDerived::Scalar, typename MotionDerived::Vector3::Options > exp6(const MotionDense< MotionDerived > &nu)
Exp: se3 -> SE3.
Definition: explog.hpp:248