pinocchio  UNKNOWN
special-euclidean.hpp
1 //
2 // Copyright (c) 2016-2018 CNRS
3 //
4 // This file is part of Pinocchio
5 // Pinocchio is free software: you can redistribute it
6 // and/or modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation, either version
8 // 3 of the License, or (at your option) any later version.
9 //
10 // Pinocchio is distributed in the hope that it will be
11 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Lesser Public License for more details. You should have
14 // received a copy of the GNU Lesser General Public License along with
15 // Pinocchio If not, see
16 // <http://www.gnu.org/licenses/>.
17 
18 #ifndef __se3_special_euclidean_operation_hpp__
19 #define __se3_special_euclidean_operation_hpp__
20 
21 #include <limits>
22 
23 #include <pinocchio/macros.hpp>
24 #include "pinocchio/spatial/fwd.hpp"
25 #include "pinocchio/spatial/se3.hpp"
26 #include "pinocchio/multibody/liegroup/operation-base.hpp"
27 
28 #include "pinocchio/multibody/liegroup/vector-space.hpp"
29 #include "pinocchio/multibody/liegroup/cartesian-product.hpp"
30 #include "pinocchio/multibody/liegroup/special-orthogonal.hpp"
31 
32 namespace se3
33 {
34  template<int N> struct SpecialEuclideanOperation {};
35  template<int N> struct traits<SpecialEuclideanOperation<N> > {};
36 
37  template<> struct traits<SpecialEuclideanOperation<2> > {
38  typedef double Scalar;
39  enum {
40  NQ = 4,
41  NV = 3
42  };
43  };
44 
45  // SE(2)
46  template<>
47  struct SpecialEuclideanOperation<2> : public LieGroupBase <SpecialEuclideanOperation<2> >
48  {
52 
53  SE3_LIE_GROUP_PUBLIC_INTERFACE(SpecialEuclideanOperation);
54  typedef Eigen::Matrix<Scalar,2,2> Matrix2;
55  typedef Eigen::Matrix<Scalar,2,1> Vector2;
56 
57  template <typename Tangent_t>
58  static void exp (const Eigen::MatrixBase<Tangent_t>& v, Matrix2& R, Vector2& t)
59  {
60  EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(TangentVector_t,Tangent_t);
61 
62  const Scalar & omega = v(2);
63  Scalar cv,sv; SINCOS(omega, &sv, &cv);
64  R << cv, -sv, sv, cv;
65 
66  if (std::fabs (omega) > 1e-14) {
67  Vector2 vcross (-v(1), v(0));
68  vcross /= omega;
69  t = vcross - R * vcross;
70  } else {
71  t = v.template head<2>();
72  }
73  }
74 
75  template <typename Matrix_t>
76  static void toInverseActionMatrix (const Matrix2& R, const Vector2& t, const Eigen::MatrixBase<Matrix_t>& M)
77  {
78  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Matrix_t, 3, 3);
79  Matrix_t& Mout = const_cast <Matrix_t&> (M.derived());
80  Mout.template topLeftCorner<2,2>().noalias() = R.transpose();
81  Vector2 tinv (R.transpose() * t);
82  Mout.template topRightCorner<2,1>() << - tinv(1), tinv(0);
83  Mout.template bottomLeftCorner<1,2>().setZero();
84  Mout(2,2) = 1;
85  }
86 
87  template <typename Tangent_t>
88  static void log (const Matrix2& R, const Vector2& p,
89  const Eigen::MatrixBase<Tangent_t>& v)
90  {
91  EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(TangentVector_t,Tangent_t);
92  Tangent_t& vout = const_cast< Tangent_t& >(v.derived());
93 
94  Scalar t = SO2_t::log(R);
95  const Scalar tabs = std::fabs(t);
96  const Scalar t2 = t*t;
97  Scalar alpha;
98  if (tabs < 1e-4) {
99  alpha = 1 - t2/12 - t2*t2/720;
100  } else {
101  Scalar st,ct; SINCOS (tabs, &st, &ct);
102  alpha = tabs*st/(2*(1-ct));
103  }
104 
105  Matrix2 sk; sk << 0, -t/2, t/2, 0;
106  vout.template head<2>().noalias() = alpha * p - sk * p;
107  vout(2) = t;
108  }
109 
110  template <typename JacobianOut_t>
111  static void Jlog (const Matrix2& R, const Vector2& p,
112  const Eigen::MatrixBase<JacobianOut_t>& J)
113  {
114  EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(JacobianOut_t, JacobianMatrix_t);
115  JacobianOut_t& Jout = const_cast< JacobianOut_t& >(J.derived());
116 
117  Scalar t = SO2_t::log(R);
118  const Scalar tabs = std::fabs(t);
119  Scalar alpha, alpha_dot;
120  if (tabs < 1e-4) {
121  alpha = 1 - t*t/12;
122  alpha_dot = - t / 6 - t*t*t / 180;
123  } else {
124  Scalar st,ct; SINCOS (t, &st, &ct);
125  Scalar inv_2_1_ct = 0.5 / (1-ct);
126  // t * sin(t) / (2 * (1 - cos(t)) )
127  alpha = t*st*inv_2_1_ct;
128  // [ ( 1 - cos(t) ) * sin(t) + t * cos(t) - 1 ] / (2 * (1 - cos(t))^2 )
129  alpha_dot = (st-t) * inv_2_1_ct;
130  }
131 
132  Matrix2 V;
133  V(0,0) = V(1,1) = alpha;
134  V(1,0) = - t / 2;
135  V(0,1) = - V(1,0);
136 
137  Jout.template topLeftCorner <2,2>() = V * R;
138  Jout.template topRightCorner<2,1>() << alpha_dot*p[0] + p[1]/2, -p(0)/2 + alpha_dot*p(1);
139  Jout.template bottomLeftCorner<1,2>().setZero();
140  Jout(2,2) = 1;
141  }
142 
147  Index nq () const
148  {
149  return NQ;
150  }
152  Index nv () const
153  {
154  return NV;
155  }
156 
157  ConfigVector_t neutral () const
158  {
159  ConfigVector_t n; n.setZero (); n [2] = 1;
160  return n;
161  }
162 
163  std::string name () const
164  {
165  return std::string ("SE(2)");
166  }
167 
168  template <class ConfigL_t, class ConfigR_t, class Tangent_t>
169  static void difference_impl(const Eigen::MatrixBase<ConfigL_t> & q0,
170  const Eigen::MatrixBase<ConfigR_t> & q1,
171  const Eigen::MatrixBase<Tangent_t> & d)
172  {
173  if (q0 == q1) {
174  (const_cast <Eigen::MatrixBase<Tangent_t> &> (d)).setZero ();
175  return;
176  }
177  Matrix2 R0, R1; Vector2 t0, t1;
178  forwardKinematics(R0, t0, q0);
179  forwardKinematics(R1, t1, q1);
180  Matrix2 R (R0.transpose() * R1);
181  Vector2 t (R0.transpose() * (t1 - t0));
182 
183  log (R, t, d);
184  }
185 
186  template <class ConfigL_t, class ConfigR_t, class JacobianLOut_t, class JacobianROut_t>
187  static void Jdifference_impl(const Eigen::MatrixBase<ConfigL_t> & q0,
188  const Eigen::MatrixBase<ConfigR_t> & q1,
189  const Eigen::MatrixBase<JacobianLOut_t>& J0,
190  const Eigen::MatrixBase<JacobianROut_t>& J1)
191  {
192  Matrix2 R0, R1; Vector2 t0, t1;
193  forwardKinematics(R0, t0, q0);
194  forwardKinematics(R1, t1, q1);
195  Matrix2 R (R0.transpose() * R1);
196  Vector2 t (R0.transpose() * (t1 - t0));
197 
198  Jlog (R, t, J1);
199 
200  // pcross = [ y1-y0, - (x1 - x0) ]
201  Vector2 pcross (q1(1) - q0(1), q0(0) - q1(0));
202 
203  JacobianLOut_t& J0v = const_cast< JacobianLOut_t& > (J0.derived());
204  J0v.template topLeftCorner <2,2> ().noalias() = - R.transpose();
205  J0v.template topRightCorner<2,1> ().noalias() = R1.transpose() * pcross;
206  J0v.template bottomLeftCorner <1,2> ().setZero();
207  J0v (2,2) = -1;
208  J0v.applyOnTheLeft(J1);
209  }
210 
211  template <class ConfigIn_t, class Velocity_t, class ConfigOut_t>
212  static void integrate_impl(const Eigen::MatrixBase<ConfigIn_t> & q,
213  const Eigen::MatrixBase<Velocity_t> & v,
214  const Eigen::MatrixBase<ConfigOut_t> & qout)
215  {
216  ConfigOut_t& out = const_cast< ConfigOut_t& >(qout.derived());
217 
218  Matrix2 R0, R;
219  Vector2 t0, t;
220  forwardKinematics(R0, t0, q);
221  exp(v, R, t);
222 
223  out.template head<2>().noalias() = R0 * t + t0;
224  out.template tail<2>().noalias() = R0 * R.col(0);
225  }
226 
227  template <class Config_t, class Tangent_t, class JacobianOut_t>
228  static void dIntegrate_dq_impl(const Eigen::MatrixBase<Config_t > & /*q*/,
229  const Eigen::MatrixBase<Tangent_t> & v,
230  const Eigen::MatrixBase<JacobianOut_t>& J)
231  {
232  JacobianOut_t& Jout = const_cast< JacobianOut_t& >(J.derived());
233 
234  Matrix2 R;
235  Vector2 t;
236  exp(v, R, t);
237 
238  toInverseActionMatrix (R, t, Jout);
239  }
240 
241  template <class Config_t, class Tangent_t, class JacobianOut_t>
242  static void dIntegrate_dv_impl(const Eigen::MatrixBase<Config_t > & /*q*/,
243  const Eigen::MatrixBase<Tangent_t> & v,
244  const Eigen::MatrixBase<JacobianOut_t>& J)
245  {
246  JacobianOut_t& Jout = const_cast< JacobianOut_t& >(J.derived());
247  // TODO sparse version
248  MotionTpl<Scalar,0> nu; nu.toVector() << v.template head<2>(), 0, 0, 0, v[2];
249  Eigen::Matrix<Scalar,6,6> Jtmp6;
250  Jexp6(nu, Jtmp6);
251  Jout << Jtmp6. topLeftCorner<2,2>(), Jtmp6. topRightCorner<2,1>(),
252  Jtmp6.bottomLeftCorner<1,2>(), Jtmp6.bottomRightCorner<1,1>();
253  }
254 
255  // interpolate_impl use default implementation.
256  // template <class ConfigL_t, class ConfigR_t, class ConfigOut_t>
257  // static void interpolate_impl(const Eigen::MatrixBase<ConfigL_t> & q0,
258  // const Eigen::MatrixBase<ConfigR_t> & q1,
259  // const Scalar& u,
260  // const Eigen::MatrixBase<ConfigOut_t>& qout)
261 
262  // template <class ConfigL_t, class ConfigR_t>
263  // static double squaredDistance_impl(const Eigen::MatrixBase<ConfigL_t> & q0,
264  // const Eigen::MatrixBase<ConfigR_t> & q1)
265  template <class Config_t>
266  static void normalize_impl (const Eigen::MatrixBase<Config_t>& qout)
267  {
268  Config_t& qout_ = (const_cast< Eigen::MatrixBase<Config_t>& >(qout)).derived();
269  qout_.template tail<2>().normalize();
270  }
271 
272  template <class Config_t>
273  void random_impl (const Eigen::MatrixBase<Config_t>& qout) const
274  {
275  R2crossSO2_t().random(qout);
276  }
277 
278  template <class ConfigL_t, class ConfigR_t, class ConfigOut_t>
279  void randomConfiguration_impl(const Eigen::MatrixBase<ConfigL_t> & lower,
280  const Eigen::MatrixBase<ConfigR_t> & upper,
281  const Eigen::MatrixBase<ConfigOut_t> & qout)
282  const
283  {
284  R2crossSO2_t ().randomConfiguration(lower, upper, qout);
285  }
286 
287  template <class ConfigL_t, class ConfigR_t>
288  static bool isSameConfiguration_impl(const Eigen::MatrixBase<ConfigL_t> & q0,
289  const Eigen::MatrixBase<ConfigR_t> & q1,
290  const Scalar & prec)
291  {
292  return R2crossSO2_t().isSameConfiguration(q0, q1, prec);
293  }
294 
295  private:
296  template<typename V>
297  static void forwardKinematics(Matrix2 & R, Vector2 & t, const Eigen::MatrixBase<V>& q)
298  {
299  EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(ConfigVector_t,V);
300 
301  const double& c_theta = q(2),
302  s_theta = q(3);
303 
304  R << c_theta, -s_theta, s_theta, c_theta;
305  t = q.template head<2>();
306  }
307  }; // struct SpecialEuclideanOperation<2>
308 
309  template<> struct traits<SpecialEuclideanOperation<3> > {
310  typedef double Scalar;
311  enum {
312  NQ = 7,
313  NV = 6
314  };
315  };
316 
318  template<>
319  struct SpecialEuclideanOperation<3> : public LieGroupBase <SpecialEuclideanOperation<3> >
320  {
322 
323  SE3_LIE_GROUP_PUBLIC_INTERFACE(SpecialEuclideanOperation);
324 
325  typedef Eigen::Quaternion<Scalar> Quaternion_t;
326  typedef Eigen::Map< Quaternion_t> QuaternionMap_t;
327  typedef Eigen::Map<const Quaternion_t> ConstQuaternionMap_t;
328  typedef SE3 Transformation_t;
329 
334  Index nq () const
335  {
336  return NQ;
337  }
339  Index nv () const
340  {
341  return NV;
342  }
343 
344  ConfigVector_t neutral () const
345  {
346  ConfigVector_t n; n.setZero (); n [6] = 1;
347  return n;
348  }
349 
350  std::string name () const
351  {
352  return std::string ("SE(3)");
353  }
354 
355  template <class ConfigL_t, class ConfigR_t, class Tangent_t>
356  static void difference_impl(const Eigen::MatrixBase<ConfigL_t> & q0,
357  const Eigen::MatrixBase<ConfigR_t> & q1,
358  const Eigen::MatrixBase<Tangent_t> & d)
359  {
360  if (q0 == q1) {
361  (const_cast < Eigen::MatrixBase<Tangent_t>& > (d)).setZero ();
362  return;
363  }
364  ConstQuaternionMap_t p0 (q0.derived().template tail<4>().data());
365  ConstQuaternionMap_t p1 (q1.derived().template tail<4>().data());
366  const_cast < Eigen::MatrixBase<Tangent_t>& > (d)
367  = log6( SE3(p0.matrix(), q0.derived().template head<3>()).inverse()
368  * SE3(p1.matrix(), q1.derived().template head<3>())).toVector();
369  }
370 
371  template <class ConfigL_t, class ConfigR_t, class JacobianLOut_t, class JacobianROut_t>
372  static void Jdifference_impl(const Eigen::MatrixBase<ConfigL_t> & q0,
373  const Eigen::MatrixBase<ConfigR_t> & q1,
374  const Eigen::MatrixBase<JacobianLOut_t>& J0,
375  const Eigen::MatrixBase<JacobianROut_t>& J1)
376  {
377  ConstQuaternionMap_t p0 (q0.derived().template tail<4>().data());
378  ConstQuaternionMap_t p1 (q1.derived().template tail<4>().data());
379  SE3::Matrix3 R0 (p0.matrix()),
380  R1 (p1.matrix());
381  SE3 M ( SE3(R0, q0.derived().template head<3>()).inverse()
382  * SE3(R1, q1.derived().template head<3>()));
383 
384  Jlog6 (M, J1);
385 
386  SE3::Vector3 p1_p0 (q1.derived().template head<3>()
387  - q0.derived().template head<3>());
388 
389  JacobianLOut_t& J0v = const_cast< JacobianLOut_t& > (J0.derived());
390  J0v.template topLeftCorner <3,3> ().noalias() = - M.rotation().transpose();
391  J0v.template topRightCorner<3,3> ().noalias() = R1.transpose() * skew (p1_p0) * R0;
392  J0v.template bottomLeftCorner <3,3> ().setZero();
393  J0v.template bottomRightCorner<3,3> ().noalias() = - M.rotation().transpose();
394  J0v.applyOnTheLeft(J1);
395  }
396 
397  template <class ConfigIn_t, class Velocity_t, class ConfigOut_t>
398  static void integrate_impl(const Eigen::MatrixBase<ConfigIn_t> & q,
399  const Eigen::MatrixBase<Velocity_t> & v,
400  const Eigen::MatrixBase<ConfigOut_t> & qout)
401  {
402  ConfigOut_t& out = (const_cast< Eigen::MatrixBase<ConfigOut_t>& >(qout)).derived();
403  ConstQuaternionMap_t quat(q.derived().template tail<4>().data());
404  QuaternionMap_t res_quat (out.template tail<4>().data());
405 
406  SE3 M0 (quat.matrix(), q.derived().template head<3>());
407  SE3 M1 (M0 * exp6(Motion(v)));
408 
409  out.template head<3>() = M1.translation();
410  res_quat = M1.rotation();
411  // Norm of qs might be epsilon-different to 1, so M1.rotation might be epsilon-different to a rotation matrix.
412  // It is then safer to re-normalized after converting M1.rotation to quaternion.
413  firstOrderNormalize(res_quat);
414  }
415 
416  template <class Config_t, class Tangent_t, class JacobianOut_t>
417  static void dIntegrate_dq_impl(const Eigen::MatrixBase<Config_t > & /*q*/,
418  const Eigen::MatrixBase<Tangent_t> & v,
419  const Eigen::MatrixBase<JacobianOut_t>& J)
420  {
421  JacobianOut_t& Jout = const_cast< JacobianOut_t& >(J.derived());
422  Jout = exp6(v).inverse().toActionMatrix();
423  }
424 
425  template <class Config_t, class Tangent_t, class JacobianOut_t>
426  static void dIntegrate_dv_impl(const Eigen::MatrixBase<Config_t > & /*q*/,
427  const Eigen::MatrixBase<Tangent_t> & v,
428  const Eigen::MatrixBase<JacobianOut_t>& J)
429  {
430  Jexp6(MotionRef<Tangent_t>(v), J.derived());
431  }
432 
433  // interpolate_impl use default implementation.
434  // template <class ConfigL_t, class ConfigR_t, class ConfigOut_t>
435  // static void interpolate_impl(const Eigen::MatrixBase<ConfigL_t> & q0,
436  // const Eigen::MatrixBase<ConfigR_t> & q1,
437  // const Scalar& u,
438  // const Eigen::MatrixBase<ConfigOut_t>& qout)
439  // {
440  // }
441 
442  template <class ConfigL_t, class ConfigR_t>
443  static double squaredDistance_impl(const Eigen::MatrixBase<ConfigL_t> & q0,
444  const Eigen::MatrixBase<ConfigR_t> & q1)
445  {
446  TangentVector_t t;
447  difference_impl(q0, q1, t);
448  return t.squaredNorm();
449  }
450 
451  template <class Config_t>
452  static void normalize_impl (const Eigen::MatrixBase<Config_t>& qout)
453  {
454  Config_t& qout_ = (const_cast< Eigen::MatrixBase<Config_t>& >(qout)).derived();
455  qout_.template tail<4>().normalize();
456  }
457 
458  template <class Config_t>
459  void random_impl (const Eigen::MatrixBase<Config_t>& qout) const
460  {
461  R3crossSO3_t().random(qout);
462  }
463 
464  template <class ConfigL_t, class ConfigR_t, class ConfigOut_t>
465  void randomConfiguration_impl(const Eigen::MatrixBase<ConfigL_t> & lower,
466  const Eigen::MatrixBase<ConfigR_t> & upper,
467  const Eigen::MatrixBase<ConfigOut_t> & qout)
468  const
469  {
470  R3crossSO3_t ().randomConfiguration(lower, upper, qout);
471  }
472 
473  template <class ConfigL_t, class ConfigR_t>
474  static bool isSameConfiguration_impl(const Eigen::MatrixBase<ConfigL_t> & q0,
475  const Eigen::MatrixBase<ConfigR_t> & q1,
476  const Scalar & prec)
477  {
478  return R3crossSO3_t().isSameConfiguration(q0, q1, prec);
479  }
480  }; // struct SpecialEuclideanOperation<3>
481 
482 } // namespace se3
483 
484 #endif // ifndef __se3_special_euclidean_operation_hpp__
Index nv() const
Get dimension of Lie Group tangent space.
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
SE3Tpl inverse() const
aXb = bXa.inverse()
Definition: se3.hpp:212
std::string name(const LieGroupVariant &lg)
Visit a LieGroupVariant to get the name of it.
void skew(const Eigen::MatrixBase< Vector3 > &v, const Eigen::MatrixBase< Matrix3 > &M)
Computes the skew representation of a given 3d vector, i.e. the antisymmetric matrix representation o...
Definition: skew.hpp:34
Eigen::VectorXd neutral(const Model &model)
Return the neutral configuration element related to the model configuration space.
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
Index nv() const
Get dimension of Lie Group tangent space.
void normalize(const Model &model, Eigen::VectorXd &q)
Normalize a configuration.
void forwardKinematics(const Model &model, Data &data, const Eigen::VectorXd &q)
Update the joint placements according to the current joint configuration.
Definition: kinematics.hxx:106
void firstOrderNormalize(const Eigen::QuaternionBase< D > &q)
Definition: quaternion.hpp:88