pinocchio  2.1.3
spatial/inertia.hpp
1 //
2 // Copyright (c) 2015-2018 CNRS
3 // Copyright (c) 2016 Wandercraft, 86 rue de Paris 91400 Orsay, France.
4 //
5 
6 #ifndef __pinocchio_inertia_hpp__
7 #define __pinocchio_inertia_hpp__
8 
9 #include <iostream>
10 
11 #include "pinocchio/math/fwd.hpp"
12 #include "pinocchio/spatial/symmetric3.hpp"
13 #include "pinocchio/spatial/force.hpp"
14 #include "pinocchio/spatial/motion.hpp"
15 #include "pinocchio/spatial/skew.hpp"
16 
17 namespace pinocchio
18 {
19 
20  template< class Derived>
22  {
23  protected:
24 
25  typedef Derived Derived_t;
26  SPATIAL_TYPEDEF_TEMPLATE(Derived_t);
27 
28  public:
29  Derived_t & derived() { return *static_cast<Derived_t*>(this); }
30  const Derived_t & derived() const { return *static_cast<const Derived_t*>(this); }
31 
32  Scalar mass() const { return static_cast<const Derived_t*>(this)->mass(); }
33  Scalar & mass() { return static_cast<const Derived_t*>(this)->mass(); }
34  const Vector3 & lever() const { return static_cast<const Derived_t*>(this)->lever(); }
35  Vector3 & lever() { return static_cast<const Derived_t*>(this)->lever(); }
36  const Symmetric3 & inertia() const { return static_cast<const Derived_t*>(this)->inertia(); }
37  Symmetric3 & inertia() { return static_cast<const Derived_t*>(this)->inertia(); }
38 
39  Matrix6 matrix() const { return derived().matrix_impl(); }
40  operator Matrix6 () const { return matrix(); }
41 
42  Derived_t& operator= (const Derived_t& clone){return derived().__equl__(clone);}
43  bool operator==(const Derived_t & other) const {return derived().isEqual(other);}
44  bool operator!=(const Derived_t & other) const { return !(*this == other); }
45 
46  Derived_t& operator+= (const Derived_t & Yb) { return derived().__pequ__(Yb); }
47  Derived_t operator+(const Derived_t & Yb) const { return derived().__plus__(Yb); }
48 
49  template<typename MotionDerived>
51  operator*(const MotionDense<MotionDerived> & v) const
52  { return derived().__mult__(v); }
53 
54  Scalar vtiv(const Motion & v) const { return derived().vtiv_impl(v); }
55  Matrix6 variation(const Motion & v) const { return derived().variation_impl(v); }
56 
64  template<typename M6>
65  static void vxi(const Motion & v, const Derived & I, const Eigen::MatrixBase<M6> & Iout)
66  {
67  EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(M6, Matrix6);
68  Derived::vxi_impl(v,I,Iout);
69  }
70 
71  Matrix6 vxi(const Motion & v) const
72  {
73  Matrix6 Iout;
74  vxi(v,derived(),Iout);
75  return Iout;
76  }
77 
85  template<typename M6>
86  static void ivx(const Motion & v, const Derived & I, const Eigen::MatrixBase<M6> & Iout)
87  {
88  EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(M6, Matrix6);
89  Derived::ivx_impl(v,I,Iout);
90  }
91 
92  Matrix6 ivx(const Motion & v) const
93  {
94  Matrix6 Iout;
95  ivx(v,derived(),Iout);
96  return Iout;
97  }
98 
99  void setZero() { derived().setZero(); }
100  void setIdentity() { derived().setIdentity(); }
101  void setRandom() { derived().setRandom(); }
102 
103  bool isApprox (const Derived & other, const Scalar & prec = Eigen::NumTraits<Scalar>::dummy_precision()) const
104  { return derived().isApprox_impl(other, prec); }
105 
107  Derived_t se3Action(const SE3 & M) const { return derived().se3Action_impl(M); }
108 
110  Derived_t se3ActionInverse(const SE3 & M) const { return derived().se3ActionInverse_impl(M); }
111 
112  void disp(std::ostream & os) const { static_cast<const Derived_t*>(this)->disp_impl(os); }
113  friend std::ostream & operator << (std::ostream & os,const InertiaBase<Derived_t> & X)
114  {
115  X.disp(os);
116  return os;
117  }
118 
119  }; // class InertiaBase
120 
121 
122  template<typename T, int U>
123  struct traits< InertiaTpl<T, U> >
124  {
125  typedef T Scalar;
126  typedef Eigen::Matrix<T,3,1,U> Vector3;
127  typedef Eigen::Matrix<T,4,1,U> Vector4;
128  typedef Eigen::Matrix<T,6,1,U> Vector6;
129  typedef Eigen::Matrix<T,3,3,U> Matrix3;
130  typedef Eigen::Matrix<T,4,4,U> Matrix4;
131  typedef Eigen::Matrix<T,6,6,U> Matrix6;
132  typedef Matrix6 ActionMatrix_t;
133  typedef Vector3 Angular_t;
134  typedef Vector3 Linear_t;
135  typedef const Vector3 ConstAngular_t;
136  typedef const Vector3 ConstLinear_t;
137  typedef Eigen::Quaternion<T,U> Quaternion_t;
138  typedef SE3Tpl<T,U> SE3;
139  typedef ForceTpl<T,U> Force;
140  typedef MotionTpl<T,U> Motion;
142  enum {
143  LINEAR = 0,
144  ANGULAR = 3
145  };
146  }; // traits InertiaTpl
147 
148  template<typename _Scalar, int _Options>
149  class InertiaTpl : public InertiaBase< InertiaTpl< _Scalar, _Options > >
150  {
151  public:
152  friend class InertiaBase< InertiaTpl< _Scalar, _Options > >;
153  SPATIAL_TYPEDEF_TEMPLATE(InertiaTpl);
154  enum { Options = _Options };
155  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
156 
157  typedef typename Symmetric3::AlphaSkewSquare AlphaSkewSquare;
158 
159  public:
160  // Constructors
161  InertiaTpl()
162  {}
163 
164  InertiaTpl(const Scalar mass, const Vector3 & com, const Matrix3 & rotational_inertia)
165  : m_mass(mass), m_com(com), m_inertia(rotational_inertia)
166  {}
167 
168  InertiaTpl(const Matrix6 & I6)
169  {
170  assert((I6 - I6.transpose()).isMuchSmallerThan(I6));
171  mass() = I6(LINEAR, LINEAR);
172  const Matrix3 & mc_cross = I6.template block <3,3> (ANGULAR,LINEAR);
173  lever() = unSkew(mc_cross);
174  lever() /= mass();
175 
176  Matrix3 I3 (mc_cross * mc_cross);
177  I3 /= mass();
178  I3 += I6.template block<3,3>(ANGULAR,ANGULAR);
179  inertia() = Symmetric3(I3);
180  }
181 
182  InertiaTpl(Scalar mass, const Vector3 & com, const Symmetric3 & rotational_inertia)
183  : m_mass(mass), m_com(com), m_inertia(rotational_inertia)
184  {}
185 
186  InertiaTpl(const InertiaTpl & clone) // Clone constructor for std::vector
187  : m_mass(clone.mass()), m_com(clone.lever()), m_inertia(clone.inertia())
188  {}
189 
190  template<int O2>
191  InertiaTpl(const InertiaTpl<Scalar,O2> & clone)
192  : m_mass(clone.mass())
193  , m_com(clone.lever())
194  , m_inertia(clone.inertia().matrix())
195  {}
196 
197  // Initializers
198  static InertiaTpl Zero()
199  {
200  return InertiaTpl(0.,
201  Vector3::Zero(),
202  Symmetric3::Zero());
203  }
204 
205  void setZero() { mass() = 0.; lever().setZero(); inertia().setZero(); }
206 
207  static InertiaTpl Identity()
208  {
209  return InertiaTpl(1.,
210  Vector3::Zero(),
211  Symmetric3::Identity());
212  }
213 
214  void setIdentity () { mass() = 1.; lever().setZero(); inertia().setIdentity(); }
215 
216  static InertiaTpl Random()
217  {
218  // We have to shoot "I" definite positive and not only symmetric.
219  return InertiaTpl(Eigen::internal::random<Scalar>()+1,
220  Vector3::Random(),
221  Symmetric3::RandomPositive());
222  }
223 
224  static InertiaTpl FromEllipsoid(
225  const Scalar m, const Scalar x, const Scalar y, const Scalar z)
226  {
227  Scalar a = m * (y*y + z*z) / 5;
228  Scalar b = m * (x*x + z*z) / 5;
229  Scalar c = m * (y*y + x*x) / 5;
230  return InertiaTpl(m, Vector3::Zero(), Symmetric3(a, 0, b, 0, 0, c));
231  }
232 
233  static InertiaTpl FromCylinder(
234  const Scalar m, const Scalar r, const Scalar l)
235  {
236  Scalar a = m * (r*r / 4 + l*l / 12);
237  Scalar c = m * (r*r / 2);
238  return InertiaTpl(m, Vector3::Zero(), Symmetric3(a, 0, a, 0, 0, c));
239  }
240 
241  static InertiaTpl FromBox(
242  const Scalar m, const Scalar x, const Scalar y, const Scalar z)
243  {
244  Scalar a = m * (y*y + z*z) / 12;
245  Scalar b = m * (x*x + z*z) / 12;
246  Scalar c = m * (y*y + x*x) / 12;
247  return InertiaTpl(m, Vector3::Zero(), Symmetric3(a, 0, b, 0, 0, c));
248  }
249 
250  void setRandom()
251  {
252  mass() = static_cast<Scalar>(std::rand())/static_cast<Scalar>(RAND_MAX);
253  lever().setRandom(); inertia().setRandom();
254  }
255 
256  Matrix6 matrix_impl() const
257  {
258  Matrix6 M;
259 
260  M.template block<3,3>(LINEAR, LINEAR ).setZero();
261  M.template block<3,3>(LINEAR, LINEAR ).diagonal().fill (mass());
262  M.template block<3,3>(ANGULAR,LINEAR ) = alphaSkew(mass(),lever());
263  M.template block<3,3>(LINEAR, ANGULAR) = -M.template block<3,3>(ANGULAR, LINEAR);
264  M.template block<3,3>(ANGULAR,ANGULAR) = (inertia() - AlphaSkewSquare(mass(),lever())).matrix();
265 
266  return M;
267  }
268 
269  // Arithmetic operators
270  InertiaTpl & __equl__(const InertiaTpl & clone)
271  {
272  mass()=clone.mass(); lever()=clone.lever(); inertia()=clone.inertia();
273  return *this;
274  }
275 
276  // Requiered by std::vector boost::python bindings.
277  bool isEqual( const InertiaTpl& Y2 ) const
278  {
279  return (mass()==Y2.mass()) && (lever()==Y2.lever()) && (inertia()==Y2.inertia());
280  }
281 
282  bool isApprox_impl(const InertiaTpl & other, const Scalar & prec = Eigen::NumTraits<Scalar>::dummy_precision()) const
283  {
284  using math::fabs;
285  return fabs(mass() - other.mass()) <= prec
286  && lever().isApprox(other.lever(),prec)
287  && inertia().isApprox(other.inertia(),prec);
288  }
289 
290  InertiaTpl __plus__(const InertiaTpl & Yb) const
291  {
292  /* Y_{a+b} = ( m_a+m_b,
293  * (m_a*c_a + m_b*c_b ) / (m_a + m_b),
294  * I_a + I_b - (m_a*m_b)/(m_a+m_b) * AB_x * AB_x )
295  */
296 
297  const Scalar & mab = mass()+Yb.mass();
298  const Scalar mab_inv = 1./mab;
299  const Vector3 & AB = (lever()-Yb.lever()).eval();
300  return InertiaTpl(mab,
301  (mass()*lever()+Yb.mass()*Yb.lever())*mab_inv,
302  inertia()+Yb.inertia() - (mass()*Yb.mass()*mab_inv)* typename Symmetric3::SkewSquare(AB));
303  }
304 
305  InertiaTpl& __pequ__(const InertiaTpl & Yb)
306  {
307  const InertiaTpl& Ya = *this;
308  const Scalar & mab = Ya.mass()+Yb.mass();
309  const Scalar mab_inv = 1./mab;
310  const Vector3 & AB = (Ya.lever()-Yb.lever()).eval();
311  lever() *= (mass()*mab_inv); lever() += (Yb.mass()*mab_inv)*Yb.lever(); //c *= mab_inv;
312  inertia() += Yb.inertia(); inertia() -= (Ya.mass()*Yb.mass()*mab_inv)* typename Symmetric3::SkewSquare(AB);
313  mass() = mab;
314  return *this;
315  }
316 
317  template<typename MotionDerived>
319  __mult__(const MotionDense<MotionDerived> & v) const
320  {
322  ReturnType f;
323  __mult__(v,f);
324  return f;
325  }
326 
327  template<typename MotionDerived, typename ForceDerived>
328  void __mult__(const MotionDense<MotionDerived> & v, ForceDense<ForceDerived> & f) const
329  {
330  f.linear().noalias() = mass()*(v.linear() - lever().cross(v.angular()));
331  Symmetric3::rhsMult(inertia(),v.angular(),f.angular());
332  f.angular() += lever().cross(f.linear());
333 // f.angular().noalias() = c.cross(f.linear()) + I*v.angular();
334  }
335 
336  Scalar vtiv_impl(const Motion & v) const
337  {
338  const Vector3 cxw (lever().cross(v.angular()));
339  Scalar res = mass() * (v.linear().squaredNorm() - 2.*v.linear().dot(cxw));
340  const Vector3 mcxcxw (-mass()*lever().cross(cxw));
341  res += v.angular().dot(mcxcxw);
342  res += inertia().vtiv(v.angular());
343 
344  return res;
345  }
346 
347  Matrix6 variation(const Motion & v) const
348  {
349  Matrix6 res;
350  const Motion mv(v*mass());
351 
352  res.template block<3,3>(LINEAR,ANGULAR) = -skew(mv.linear()) - skewSquare(mv.angular(),lever()) + skewSquare(lever(),mv.angular());
353  res.template block<3,3>(ANGULAR,LINEAR) = res.template block<3,3>(LINEAR,ANGULAR).transpose();
354 
355 // res.template block<3,3>(LINEAR,LINEAR) = mv.linear()*c.transpose(); // use as temporary variable
356 // res.template block<3,3>(ANGULAR,ANGULAR) = res.template block<3,3>(LINEAR,LINEAR) - res.template block<3,3>(LINEAR,LINEAR).transpose();
357  res.template block<3,3>(ANGULAR,ANGULAR) = -skewSquare(mv.linear(),lever()) - skewSquare(lever(),mv.linear());
358 
359  res.template block<3,3>(LINEAR,LINEAR) = (inertia() - AlphaSkewSquare(mass(),lever())).matrix();
360 
361  res.template block<3,3>(ANGULAR,ANGULAR) -= res.template block<3,3>(LINEAR,LINEAR) * skew(v.angular());
362  res.template block<3,3>(ANGULAR,ANGULAR) += cross(v.angular(),res.template block<3,3>(LINEAR,LINEAR));
363 
364  res.template block<3,3>(LINEAR,LINEAR).setZero();
365  return res;
366  }
367 
368  template<typename M6>
369  static void vxi_impl(const Motion & v, const InertiaTpl & I, const Eigen::MatrixBase<M6> & Iout)
370  {
371  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(M6,6,6);
372  M6 & Iout_ = const_cast<Eigen::MatrixBase<M6> &>(Iout).derived();
373 
374  // Block 1,1
375  alphaSkew(I.mass(),v.angular(),Iout_.template block<3,3>(LINEAR,LINEAR));
376 // Iout_.template block<3,3>(LINEAR,LINEAR) = alphaSkew(I.mass(),v.angular());
377  const Vector3 mc(I.mass()*I.lever());
378 
379  // Block 1,2
380  skewSquare(-v.angular(),mc,Iout_.template block<3,3>(LINEAR,ANGULAR));
381 
382 
384  alphaSkew(I.mass(),v.linear(),Iout_.template block<3,3>(ANGULAR,LINEAR));
385  Iout_.template block<3,3>(ANGULAR,LINEAR) -= Iout_.template block<3,3>(LINEAR,ANGULAR);
386 
388  skewSquare(-v.linear(),mc,Iout_.template block<3,3>(ANGULAR,ANGULAR));
389 
390  // TODO: I do not why, but depending on the CPU, these three lines can give
391  // wrong output.
392  // typename Symmetric3::AlphaSkewSquare mcxcx(I.mass(),I.lever());
393  // const Symmetric3 I_mcxcx(I.inertia() - mcxcx);
394  // Iout_.template block<3,3>(ANGULAR,ANGULAR) += I_mcxcx.vxs(v.angular());
395  Symmetric3 mcxcx(typename Symmetric3::AlphaSkewSquare(I.mass(),I.lever()));
396  Iout_.template block<3,3>(ANGULAR,ANGULAR) += I.inertia().vxs(v.angular());
397  Iout_.template block<3,3>(ANGULAR,ANGULAR) -= mcxcx.vxs(v.angular());
398 
399  }
400 
401  template<typename M6>
402  static void ivx_impl(const Motion & v, const InertiaTpl & I, const Eigen::MatrixBase<M6> & Iout)
403  {
404  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(M6,6,6);
405  M6 & Iout_ = const_cast<Eigen::MatrixBase<M6> &>(Iout).derived();
406 
407  // Block 1,1
408  alphaSkew(I.mass(),v.angular(),Iout_.template block<3,3>(LINEAR,LINEAR));
409 
410  // Block 2,1
411  const Vector3 mc(I.mass()*I.lever());
412  skewSquare(mc,v.angular(),Iout_.template block<3,3>(ANGULAR,LINEAR));
413 
414  // Block 1,2
415  alphaSkew(I.mass(),v.linear(),Iout_.template block<3,3>(LINEAR,ANGULAR));
416 
417  // Block 2,2
418  cross(-I.lever(),Iout_.template block<3,3>(ANGULAR,LINEAR),Iout_.template block<3,3>(ANGULAR,ANGULAR));
419  Iout_.template block<3,3>(ANGULAR,ANGULAR) += I.inertia().svx(v.angular());
420  for(int k = 0; k < 3; ++k)
421  Iout_.template block<3,3>(ANGULAR,ANGULAR).col(k) += I.lever().cross(Iout_.template block<3,3>(LINEAR,ANGULAR).col(k));
422 
423  // Block 1,2
424  Iout_.template block<3,3>(LINEAR,ANGULAR) -= Iout_.template block<3,3>(ANGULAR,LINEAR);
425 
426  }
427 
428  // Getters
429  Scalar mass() const { return m_mass; }
430  const Vector3 & lever() const { return m_com; }
431  const Symmetric3 & inertia() const { return m_inertia; }
432 
433  Scalar & mass() { return m_mass; }
434  Vector3 & lever() { return m_com; }
435  Symmetric3 & inertia() { return m_inertia; }
436 
438  InertiaTpl se3Action_impl(const SE3 & M) const
439  {
440  /* The multiplication RIR' has a particular form that could be used, however it
441  * does not seems to be more efficient, see http://stackoverflow.m_comom/questions/
442  * 13215467/eigen-best-way-to-evaluate-asa-transpose-and-store-the-result-in-a-symmetric .*/
443  return InertiaTpl(mass(),
444  M.translation()+M.rotation()*lever(),
445  inertia().rotate(M.rotation()));
446  }
447 
449  InertiaTpl se3ActionInverse_impl(const SE3 & M) const
450  {
451  return InertiaTpl(mass(),
452  M.rotation().transpose()*(lever()-M.translation()),
453  inertia().rotate(M.rotation().transpose()) );
454  }
455 
456  Force vxiv( const Motion& v ) const
457  {
458  const Vector3 & mcxw = mass()*lever().cross(v.angular());
459  const Vector3 & mv_mcxw = mass()*v.linear()-mcxw;
460  return Force( v.angular().cross(mv_mcxw),
461  v.angular().cross(lever().cross(mv_mcxw)+inertia()*v.angular())-v.linear().cross(mcxw) );
462  }
463 
464  void disp_impl(std::ostream & os) const
465  {
466  os
467  << " m = " << mass() << "\n"
468  << " c = " << lever().transpose() << "\n"
469  << " I = \n" << inertia().matrix() << "";
470  }
471 
473  template<typename NewScalar>
475  {
476  return InertiaTpl<NewScalar,Options>(static_cast<NewScalar>(mass()),
477  lever().template cast<NewScalar>(),
478  inertia().template cast<NewScalar>());
479  }
480 
481  protected:
482  Scalar m_mass;
483  Vector3 m_com;
484  Symmetric3 m_inertia;
485 
486  }; // class InertiaTpl
487 
488 } // namespace pinocchio
489 
490 #endif // ifndef __pinocchio_inertia_hpp__
void unSkew(const Eigen::MatrixBase< Matrix3 > &M, const Eigen::MatrixBase< Vector3 > &v)
Inverse of skew operator. From a given skew-symmetric matrix M of dimension 3x3, it extracts the supp...
Definition: skew.hpp:82
Derived_t se3Action(const SE3 &M) const
aI = aXb.act(bI)
InertiaTpl< NewScalar, Options > cast() const
static void vxi(const Motion &v, const Derived &I, const Eigen::MatrixBase< M6 > &Iout)
Time variation operator. It computes the time derivative of an inertia I corresponding to the formula...
InertiaTpl se3ActionInverse_impl(const SE3 &M) const
bI = aXb.actInv(aI)
static void ivx(const Motion &v, const Derived &I, const Eigen::MatrixBase< M6 > &Iout)
Time variation operator. It computes the time derivative of an inertia I corresponding to the formula...
void cross(const Eigen::MatrixBase< Vector3 > &v, const Eigen::MatrixBase< Matrix3xIn > &Min, const Eigen::MatrixBase< Matrix3xOut > &Mout)
Applies the cross product onto the columns of M.
Definition: skew.hpp:211
ConstAngularType angular() const
Return the angular part of the force vector.
Definition: force-base.hpp:40
static void vxs(const Eigen::MatrixBase< Vector3 > &v, const Symmetric3Tpl &S3, const Eigen::MatrixBase< Matrix3 > &M)
Performs the operation . This operation is equivalent to applying the cross product of v on each colu...
void skewSquare(const Eigen::MatrixBase< V1 > &u, const Eigen::MatrixBase< V2 > &v, const Eigen::MatrixBase< Matrix3 > &C)
Computes the square cross product linear operator C(u,v) such that for any vector w...
Definition: skew.hpp:166
Main pinocchio namespace.
Definition: treeview.dox:24
static void svx(const Eigen::MatrixBase< Vector3 > &v, const Symmetric3Tpl &S3, const Eigen::MatrixBase< Matrix3 > &M)
Performs the operation .
InertiaTpl se3Action_impl(const SE3 &M) const
aI = aXb.act(bI)
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
Common traits structure to fully define base classes for CRTP.
Definition: spatial/fwd.hpp:29
Derived_t se3ActionInverse(const SE3 &M) const
bI = aXb.actInv(aI)
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:21
ConstLinearType linear() const
Return the linear part of the force vector.
Definition: force-base.hpp:47