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