pinocchio 4.1.0
A fast and flexible implementation of Rigid Body Dynamics algorithms and their analytical derivatives
Loading...
Searching...
No Matches
inertia.hpp
1//
2// Copyright (c) 2015-2018 CNRS
3// Copyright (c) 2018-2025 INRIA
4// Copyright (c) 2016 Wandercraft, 86 rue de Paris 91400 Orsay, France.
5//
6
7#pragma once
8
9#include <eigenpy/exception.hpp>
10#include <eigenpy/eigenpy.hpp>
11#include <eigenpy/memory.hpp>
12#include <boost/python/tuple.hpp>
13
14#include "pinocchio/spatial.hpp"
15
16#include "pinocchio/bindings/python/utils/cast.hpp"
17#include <eigenpy/copyable.hpp>
18#include "pinocchio/bindings/python/utils/printable.hpp"
19
20namespace pinocchio
21{
22 namespace python
23 {
24 namespace bp = boost::python;
25
26 template<typename Inertia>
27 struct InertiaPythonVisitor : public boost::python::def_visitor<InertiaPythonVisitor<Inertia>>
28 {
29 static constexpr int Options = Inertia::Options;
30 typedef typename Inertia::Scalar Scalar;
31 typedef typename Inertia::Vector3 Vector3;
32 typedef typename Inertia::Matrix3 Matrix3;
33 typedef typename Inertia::Vector6 Vector6;
34 typedef typename Inertia::Matrix6 Matrix6;
35
36 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1, Options> VectorXs;
37 typedef MotionTpl<Scalar, Options> Motion;
38 typedef ForceTpl<Scalar, Options> Force;
39
40 public:
41 template<class PyClass>
42 void visit(PyClass & cl) const
43 {
44 static const Scalar dummy_precision = Eigen::NumTraits<Scalar>::dummy_precision();
45 cl.def(
46 "__init__",
47 bp::make_constructor(
48 &InertiaPythonVisitor::makeFromMCI, bp::default_call_policies(),
49 bp::args("mass", "lever", "inertia")),
50 "Initialize from mass, lever and 3d inertia.")
51
52 .def(bp::init<>(bp::arg("self"), "Default constructor."))
53 .def(bp::init<const Inertia &>((bp::arg("self"), bp::arg("clone")), "Copy constructor"))
54
55 .add_property(
56 "mass", &InertiaPythonVisitor::getMass, &InertiaPythonVisitor::setMass,
57 "Mass of the Spatial Inertia.")
58 .add_property(
59 "lever",
60 bp::make_function(
61 (typename Inertia::Vector3 & (Inertia::*)()) & Inertia::lever,
62 bp::return_internal_reference<>()),
63 &InertiaPythonVisitor::setLever,
64 "Center of mass location of the Spatial Inertia. It corresponds to the location of the "
65 "center of mass regarding to the frame where the Spatial Inertia is expressed.")
66 .add_property(
67 "inertia", &InertiaPythonVisitor::getInertia, &InertiaPythonVisitor::setInertia,
68 "Rotational part of the Spatial Inertia, i.e. a symmetric matrix representing the "
69 "rotational inertia around the center of mass.")
70
71 .def("matrix", (Matrix6 (Inertia::*)() const) & Inertia::matrix, bp::arg("self"))
72 .def("inverse", (Matrix6 (Inertia::*)() const) & Inertia::inverse, bp::arg("self"))
73 .def(
74 "se3Action", &Inertia::template se3Action<Scalar, Options>, bp::args("self", "M"),
75 "Returns the result of the action of M on *this.")
76 .def(
77 "se3ActionInverse", &Inertia::template se3ActionInverse<Scalar, Options>,
78 bp::args("self", "M"), "Returns the result of the action of the inverse of M on *this.")
79
80 .def(
81 "setIdentity", &Inertia::setIdentity, bp::arg("self"),
82 "Set *this to be the Identity inertia.")
83 .def(
84 "setZero", &Inertia::setZero, bp::arg("self"),
85 "Set all the components of *this to zero.")
86 .def(
87 "setRandom", &Inertia::setRandom, bp::arg("self"),
88 "Set all the components of *this to random values.")
89
90 .def(bp::self + bp::self)
91 .def(bp::self += bp::self)
92 .def(bp::self - bp::self)
93 .def(bp::self -= bp::self)
94 .def(bp::self * bp::other<Motion>())
95
96 .add_property("np", (Matrix6 (Inertia::*)() const) & Inertia::matrix)
97 .def(
98 "vxiv", &Inertia::template vxiv<Motion>, bp::args("self", "v"),
99 "Returns the result of v x Iv.")
100 .def(
101 "vtiv", &Inertia::template vtiv<Motion>, bp::args("self", "v"),
102 "Returns the result of v.T * Iv.")
103 .def(
104 "vxi",
105 (Matrix6 (Inertia::*)(const MotionDense<Motion> &) const)
106 & Inertia::template vxi<Motion>,
107 bp::args("self", "v"), "Returns the result of v x* I, a 6x6 matrix.")
108 .def(
109 "ivx",
110 (Matrix6 (Inertia::*)(const MotionDense<Motion> &) const)
111 & Inertia::template ivx<Motion>,
112 bp::args("self", "v"), "Returns the result of I vx, a 6x6 matrix.")
113 .def(
114 "variation",
115 (Matrix6 (Inertia::*)(const MotionDense<Motion> &) const)
116 & Inertia::template variation<Motion>,
117 bp::args("self", "v"), "Returns the time derivative of the inertia.")
118
119#ifndef PINOCCHIO_PYTHON_SKIP_COMPARISON_OPERATIONS
120 .def(bp::self == bp::self)
121 .def(bp::self != bp::self)
122#endif
123
124#ifndef PINOCCHIO_PYTHON_SKIP_COMPARISON_OPERATIONS
125 .def(
126 "isApprox", &Inertia::isApprox,
127 (bp::arg("self"), bp::arg("other"), bp::arg("prec") = dummy_precision),
128 "Returns true if *this is approximately equal to other, within the precision given by "
129 "prec.")
130
131 .def(
132 "isZero", &Inertia::isZero, (bp::arg("self"), bp::arg("prec") = dummy_precision),
133 "Returns true if *this is approximately equal to the zero Inertia, within the "
134 "precision given by prec.")
135#endif
136
137 .def("Identity", &Inertia::Identity, "Returns the identity Inertia.")
138 .staticmethod("Identity")
139 .def("Zero", &Inertia::Zero, "Returns the zero Inertia.")
140 .staticmethod("Zero")
141 .def("Random", &Inertia::Random, "Returns a random Inertia.")
142 .staticmethod("Random")
143
144 .def(
145 "toDynamicParameters", &InertiaPythonVisitor::toDynamicParameters_proxy,
146 bp::arg("self"),
147 "Returns the representation of the matrix as a vector of dynamic parameters."
148 "\nThe parameters are given as v = [m, mc_x, mc_y, mc_z, I_{xx}, I_{xy}, I_{yy}, "
149 "I_{xz}, I_{yz}, I_{zz}]^T "
150 "where I = I_C + mS^T(c)S(c) and I_C has its origin at the barycenter")
151 .def(
152 "FromDynamicParameters", &InertiaPythonVisitor::fromDynamicParameters_proxy,
153 bp::args("dynamic_parameters"),
154 "Builds and inertia matrix from a vector of dynamic parameters."
155 "\nThe parameters are given as dynamic_parameters = [m, mc_x, mc_y, mc_z, I_{xx}, "
156 "I_{xy}, I_{yy}, I_{xz}, I_{yz}, I_{zz}]^T "
157 "where I = I_C + mS^T(c)S(c) and I_C has its origin at the barycenter.")
158 .staticmethod("FromDynamicParameters")
159
160 .def(
161 "FromSphere", &Inertia::FromSphere, bp::args("mass", "radius"),
162 "Returns the Inertia of a sphere defined by a given mass and radius.")
163 .staticmethod("FromSphere")
164 .def(
165 "FromEllipsoid", &Inertia::FromEllipsoid,
166 bp::args("mass", "length_x", "length_y", "length_z"),
167 "Returns the Inertia of an ellipsoid shape defined by a mass and given dimensions the "
168 "semi-axis of values length_{x,y,z}.")
169 .staticmethod("FromEllipsoid")
170 .def(
171 "FromCylinder", &Inertia::FromCylinder, bp::args("mass", "radius", "length"),
172 "Returns the Inertia of a cylinder defined by its mass, radius and length along the Z "
173 "axis.")
174 .staticmethod("FromCylinder")
175 .def(
176 "FromBox", &Inertia::FromBox, bp::args("mass", "length_x", "length_y", "length_z"),
177 "Returns the Inertia of a box shape with a mass and of dimension the semi axis of "
178 "length_{x,y,z}.")
179 .staticmethod("FromBox")
180 .def(
181 "FromCapsule", &Inertia::FromCapsule, bp::args("mass", "radius", "height"),
182 "Computes the Inertia of a capsule defined by its mass, radius and length along the Z "
183 "axis. Assumes a uniform density.")
184 .staticmethod("FromCapsule")
185
186 .def(
187 "FromPseudoInertia", &Inertia::FromPseudoInertia, bp::args("pseudo_inertia"),
188 "Returns the Inertia created from a pseudo inertia object.")
189 .staticmethod("FromPseudoInertia")
190
191 .def(
192 "toPseudoInertia", &Inertia::toPseudoInertia, bp::arg("self"),
193 "Returns the pseudo inertia representation of the inertia.")
194
195 .def(
196 "FromLogCholeskyParameters", &Inertia::FromLogCholeskyParameters,
197 bp::args("log_cholesky_parameters"),
198 "Returns the Inertia created from log Cholesky parameters.")
199 .staticmethod("FromLogCholeskyParameters")
200
201 .def("__array__", (Matrix6 (Inertia::*)() const) & Inertia::matrix)
202 .def(
203 "__array__", &__array__,
204 (bp::arg("self"), bp::arg("dtype") = bp::object(), bp::arg("copy") = bp::object()))
205#ifndef PINOCCHIO_PYTHON_NO_SERIALIZATION
206 .def_pickle(Pickle())
207#endif
208 ;
209 }
210
211 static Scalar getMass(const Inertia & self)
212 {
213 return self.mass();
214 }
215 static void setMass(Inertia & self, Scalar mass)
216 {
217 self.mass() = mass;
218 }
219
220 static void setLever(Inertia & self, const Vector3 & lever)
221 {
222 self.lever() = lever;
223 }
224
225 static Matrix3 getInertia(const Inertia & self)
226 {
227 return self.inertia().matrix();
228 }
229 // static void setInertia(Inertia & self, const Vector6 & minimal_inertia) {
230 // self.inertia().data() = minimal_inertia; }
231 static void setInertia(Inertia & self, const Matrix3 & symmetric_inertia)
232 {
233 if (!check_expression_if_real<Scalar>(
234 isZero(symmetric_inertia - symmetric_inertia.transpose())))
235 throw eigenpy::Exception("The 3d inertia should be symmetric.");
236 self.inertia().data() << symmetric_inertia(0, 0), symmetric_inertia(1, 0),
237 symmetric_inertia(1, 1), symmetric_inertia(0, 2), symmetric_inertia(1, 2),
238 symmetric_inertia(2, 2);
239 }
240
241 static VectorXs toDynamicParameters_proxy(const Inertia & self)
242 {
243 return self.toDynamicParameters();
244 }
245
246 static Inertia fromDynamicParameters_proxy(const VectorXs & params)
247 {
248 if (params.rows() != 10 || params.cols() != 1)
249 {
250 std::ostringstream shape;
251 shape << "(" << params.rows() << ", " << params.cols() << ")";
252 throw std::invalid_argument(
253 "Wrong size: params" + shape.str() + " but should have the following shape (10, 1)");
254 }
255 return Inertia::FromDynamicParameters(params);
256 }
257
258 static Inertia *
259 makeFromMCI(const Scalar & mass, const Vector3 & lever, const Matrix3 & inertia)
260 {
261#ifndef PINOCCHIO_PYTHON_SKIP_COMPARISON_OPERATIONS
262 if (!inertia.isApprox(inertia.transpose()))
263 throw eigenpy::Exception("The 3d inertia should be symmetric.");
264 if (
265 (Vector3::UnitX().transpose() * inertia * Vector3::UnitX() < 0)
266 || (Vector3::UnitY().transpose() * inertia * Vector3::UnitY() < 0)
267 || (Vector3::UnitZ().transpose() * inertia * Vector3::UnitZ() < 0))
268 throw eigenpy::Exception("The 3d inertia should be positive.");
269#endif
270 return new Inertia(mass, lever, inertia);
271 }
272
273 static void expose()
274 {
275 typedef ::boost::python::detail::not_specified HolderType;
276 bp::class_<Inertia, HolderType>(
277 "Inertia",
278 "This class represenses a sparse version of a Spatial Inertia and its is defined by its "
279 "mass, its center of mass location and the rotational inertia expressed around this "
280 "center of mass.\n\n"
281 "Supported operations ...",
282 bp::no_init)
286 .def(::eigenpy::CopyableVisitor<Inertia>())
288 }
289
290 private:
291 static Matrix6 __array__(const Inertia & self, bp::object, bp::object)
292 {
293 return self.matrix();
294 }
295
296 struct Pickle : bp::pickle_suite
297 {
298 static boost::python::tuple getinitargs(const Inertia & I)
299 {
300 return bp::make_tuple(I.mass(), (Vector3)I.lever(), I.inertia().matrix());
301 }
302
303 static bool getstate_manages_dict()
304 {
305 return true;
306 }
307 };
308
309 }; // struct InertiaPythonVisitor
310
311 template<typename PseudoInertia>
313 : public boost::python::def_visitor<PseudoInertiaPythonVisitor<PseudoInertia>>
314 {
315 static constexpr int Options = PseudoInertia::Options;
316 typedef typename PseudoInertia::Scalar Scalar;
317 typedef typename PseudoInertia::Vector3 Vector3;
318 typedef typename PseudoInertia::Matrix3 Matrix3;
319 typedef typename PseudoInertia::Vector10 Vector10;
320 typedef typename PseudoInertia::Matrix4 Matrix4;
321 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1, Options> VectorXs;
322
323 public:
324 template<class PyClass>
325 void visit(PyClass & cl) const
326 {
327 cl.def(
328 bp::init<const Scalar &, const Vector3 &, const Matrix3 &>(
329 (bp::arg("self"), bp::arg("mass"), bp::arg("h"), bp::arg("sigma")),
330 "Initialize from mass, vector part of the pseudo inertia and matrix part of the "
331 "pseudo inertia."))
332 .def(
333 bp::init<const PseudoInertia &>(
334 (bp::arg("self"), bp::arg("clone")), "Copy constructor"))
335 .add_property(
336 "mass", &PseudoInertiaPythonVisitor::getMass, &PseudoInertiaPythonVisitor::setMass,
337 "Mass of the Pseudo Inertia.")
338 .add_property(
339 "h", &PseudoInertiaPythonVisitor::getH, &PseudoInertiaPythonVisitor::setH,
340 "Vector part of the Pseudo Inertia.")
341 .add_property(
342 "sigma", &PseudoInertiaPythonVisitor::getSigma, &PseudoInertiaPythonVisitor::setSigma,
343 "Matrix part of the Pseudo Inertia.")
344
345 .def(
346 "toMatrix", &PseudoInertia::toMatrix, bp::arg("self"),
347 "Returns the pseudo inertia as a 4x4 matrix.")
348 .def(
349 "toDynamicParameters", &PseudoInertiaPythonVisitor::toDynamicParameters_proxy,
350 bp::arg("self"), "Returns the dynamic parameters representation.")
351 .def(
352 "toInertia", &PseudoInertia::toInertia, bp::arg("self"),
353 "Returns the inertia representation.")
354 .def(
355 "FromDynamicParameters", &PseudoInertiaPythonVisitor::fromDynamicParameters_proxy,
356 bp::args("dynamic_parameters"),
357 "Builds a pseudo inertia matrix from a vector of dynamic parameters."
358 "\nThe parameters are given as dynamic_parameters = [m, h_x, h_y, h_z, I_{xx}, "
359 "I_{xy}, I_{yy}, I_{xz}, I_{yz}, I_{zz}]^T.")
360 .staticmethod("FromDynamicParameters")
361
362 .def(
363 "FromMatrix", &PseudoInertia::FromMatrix, bp::args("pseudo_inertia_matrix"),
364 "Returns the Pseudo Inertia from a 4x4 matrix.")
365 .staticmethod("FromMatrix")
366
367 .def(
368 "FromInertia", &PseudoInertia::FromInertia, bp::args("inertia"),
369 "Returns the Pseudo Inertia from an Inertia object.")
370 .staticmethod("FromInertia")
371
372 .def("__array__", &PseudoInertia::toMatrix)
373 .def(
374 "__array__", &__array__,
375 (bp::arg("self"), bp::arg("dtype") = bp::object(), bp::arg("copy") = bp::object()))
376#ifndef PINOCCHIO_PYTHON_NO_SERIALIZATION
377 .def_pickle(Pickle())
378#endif
379 ;
380 }
381
382 static Scalar getMass(const PseudoInertia & self)
383 {
384 return self.mass;
385 }
386 static void setMass(PseudoInertia & self, Scalar mass)
387 {
388 self.mass = mass;
389 }
390
391 static Vector3 getH(const PseudoInertia & self)
392 {
393 return self.h;
394 }
395 static void setH(PseudoInertia & self, const Vector3 & h)
396 {
397 self.h = h;
398 }
399
400 static Matrix3 getSigma(const PseudoInertia & self)
401 {
402 return self.sigma;
403 }
404 static void setSigma(PseudoInertia & self, const Matrix3 & sigma)
405 {
406 self.sigma = sigma;
407 }
408
409 static VectorXs toDynamicParameters_proxy(const PseudoInertia & self)
410 {
411 return self.toDynamicParameters();
412 }
413
414 static PseudoInertia fromDynamicParameters_proxy(const VectorXs & params)
415 {
416 if (params.rows() != 10 || params.cols() != 1)
417 {
418 std::ostringstream shape;
419 shape << "(" << params.rows() << ", " << params.cols() << ")";
420 throw std::invalid_argument(
421 "Wrong size: params" + shape.str() + " but should have the following shape (10, 1)");
422 }
423 return PseudoInertia::FromDynamicParameters(params);
424 }
425
426 static void expose()
427 {
428 typedef ::boost::python::detail::not_specified HolderType;
429 bp::class_<PseudoInertia, HolderType>(
430 "PseudoInertia",
431 "This class represents a pseudo inertia matrix and it is defined by its mass, vector "
432 "part, and 3x3 matrix part.\n\n"
433 "Supported operations ...",
434 bp::no_init)
436 .def(::eigenpy::CopyableVisitor<PseudoInertia>())
440 }
441
442 private:
443 static Matrix4 __array__(const PseudoInertia & self, bp::object, bp::object)
444 {
445 return self.toMatrix();
446 }
447
448 struct Pickle : bp::pickle_suite
449 {
450 static boost::python::tuple getinitargs(const PseudoInertia & pi)
451 {
452 return bp::make_tuple(pi.mass, pi.h, pi.sigma);
453 }
454
455 static bool getstate_manages_dict()
456 {
457 return true;
458 }
459 };
460
461 }; // struct PseudoInertiaPythonVisitor
462
463 template<typename LogCholeskyParameters>
465 : public boost::python::def_visitor<LogCholeskyParametersPythonVisitor<LogCholeskyParameters>>
466 {
467 static constexpr int Options = LogCholeskyParameters::Options;
468 typedef typename LogCholeskyParameters::Scalar Scalar;
469 typedef typename LogCholeskyParameters::Vector10 Vector10;
470 typedef typename LogCholeskyParameters::Matrix10 Matrix10;
471 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1, Options> VectorXs;
472 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Options> MatrixXs;
473
474 public:
475 template<class PyClass>
476 void visit(PyClass & cl) const
477 {
478 cl.def(
479 "__init__",
480 bp::make_constructor(
481 &LogCholeskyParametersPythonVisitor::makeFromParameters, bp::default_call_policies(),
482 bp::args("log_cholesky_parameters")),
483 "Initialize from log cholesky parameters.")
484 .def(
485 bp::init<const LogCholeskyParameters &>(
486 (bp::arg("self"), bp::arg("clone")), "Copy constructor"))
487
488 .add_property(
489 "parameters", &LogCholeskyParametersPythonVisitor::getParameters,
490 &LogCholeskyParametersPythonVisitor::setParameters, "Log Cholesky parameters.")
491
492 .def(
493 "toDynamicParameters", &LogCholeskyParametersPythonVisitor::toDynamicParameters_proxy,
494 bp::arg("self"), "Returns the dynamic parameters representation.")
495 .def(
496 "toPseudoInertia", &LogCholeskyParameters::toPseudoInertia, bp::arg("self"),
497 "Returns the Pseudo Inertia representation.")
498 .def(
499 "toInertia", &LogCholeskyParameters::toInertia, bp::arg("self"),
500 "Returns the Inertia representation.")
501 .def(
502 "calculateJacobian", &LogCholeskyParametersPythonVisitor::calculateJacobian_proxy,
503 bp::arg("self"), "Calculates the Jacobian of the log Cholesky parameters.")
504
505 .def("__array__", &LogCholeskyParametersPythonVisitor::getParameters)
506 .def(
507 "__array__", &__array__,
508 (bp::arg("self"), bp::arg("dtype") = bp::object(), bp::arg("copy") = bp::object()))
509#ifndef PINOCCHIO_PYTHON_NO_SERIALIZATION
510 .def_pickle(Pickle())
511#endif
512 ;
513 }
514
515 static LogCholeskyParameters * makeFromParameters(const VectorXs & params)
516 {
517 if (params.rows() != 10 || params.cols() != 1)
518 {
519 std::ostringstream shape;
520 shape << "(" << params.rows() << ", " << params.cols() << ")";
521 throw std::invalid_argument(
522 "Wrong size: params" + shape.str() + " but should have the following shape (10, 1)");
523 }
524 return new LogCholeskyParameters(params);
525 }
526
527 static VectorXs getParameters(const LogCholeskyParameters & self)
528 {
529 return self.parameters;
530 }
531 static void setParameters(LogCholeskyParameters & self, const Vector10 & parameters)
532 {
533 self.parameters = parameters;
534 }
535
536 static VectorXs toDynamicParameters_proxy(const LogCholeskyParameters & self)
537 {
538 return self.toDynamicParameters();
539 }
540
541 static MatrixXs calculateJacobian_proxy(const LogCholeskyParameters & self)
542 {
543 return self.calculateJacobian();
544 }
545
546 static void expose()
547 {
548 typedef ::boost::python::detail::not_specified HolderType;
549 bp::class_<LogCholeskyParameters, HolderType>(
550 "LogCholeskyParameters",
551 "This class represents log Cholesky parameters.\n\n"
552 "Supported operations ...",
553 bp::no_init)
555 .def(::eigenpy::CopyableVisitor<LogCholeskyParameters>())
558 .def(
560 LogCholeskyParameters, ::pinocchio::LogCholeskyParameters>());
561 }
562
563 private:
564 static VectorXs __array__(const LogCholeskyParameters & self, bp::object, bp::object)
565 {
566 return self.parameters;
567 }
568
569 struct Pickle : bp::pickle_suite
570 {
571 static boost::python::tuple getinitargs(const LogCholeskyParameters & lcp)
572 {
573 return bp::make_tuple(lcp.parameters);
574 }
575
576 static bool getstate_manages_dict()
577 {
578 return true;
579 }
580 };
581
582 }; // struct LogCholeskyParametersPythonVisitor
583
584 } // namespace python
585} // namespace pinocchio
Main pinocchio namespace.
Definition treeview.dox:11
Add the Python method cast.
Definition cast.hpp:23
Set the Python method str and repr to use the overloading operator<<.
Definition printable.hpp:21