GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/pinocchio/bindings/python/multibody/model.hpp Lines: 77 97 79.4 %
Date: 2024-04-26 13:14:21 Branches: 99 238 41.6 %

Line Branch Exec Source
1
//
2
// Copyright (c) 2015-2021 CNRS INRIA
3
// Copyright (c) 2015 Wandercraft, 86 rue de Paris 91400 Orsay, France.
4
//
5
6
#ifndef __pinocchio_python_multibody_model_hpp__
7
#define __pinocchio_python_multibody_model_hpp__
8
9
#include <eigenpy/eigen-to-python.hpp>
10
11
#include "pinocchio/multibody/model.hpp"
12
#include "pinocchio/serialization/model.hpp"
13
14
#include <boost/python/overloads.hpp>
15
#include <eigenpy/memory.hpp>
16
#include <eigenpy/exception.hpp>
17
18
#include "pinocchio/algorithm/check.hpp"
19
#include "pinocchio/bindings/python/serialization/serializable.hpp"
20
#include "pinocchio/bindings/python/utils/printable.hpp"
21
#include "pinocchio/bindings/python/utils/copyable.hpp"
22
#include "pinocchio/bindings/python/utils/std-map.hpp"
23
#include "pinocchio/bindings/python/utils/pickle-map.hpp"
24
#include "pinocchio/bindings/python/utils/std-vector.hpp"
25
26
#if EIGENPY_VERSION_AT_MOST(2,8,1)
27
EIGENPY_DEFINE_STRUCT_ALLOCATOR_SPECIALIZATION(pinocchio::Model)
28
#endif
29
30
namespace pinocchio
31
{
32
  namespace python
33
  {
34
    namespace bp = boost::python;
35
36
50
    BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(getFrameId_overload,Model::getFrameId,1,2)
37
19
    BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(existFrame_overload,Model::existFrame,1,2)
38
19
    BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(addJointFrame_overload,Model::addJointFrame,1,2)
39
40
    template<typename Model>
41
    struct PickleModel : bp::pickle_suite
42
    {
43
      static bp::tuple getinitargs(const Model &)
44
      {
45
        return bp::make_tuple();
46
      }
47
48
      static bp::tuple getstate(const Model & model)
49
      {
50
        const std::string str(model.saveToString());
51
        return bp::make_tuple(bp::str(str));
52
      }
53
54
      static void setstate(Model & model, bp::tuple tup)
55
      {
56
        if(bp::len(tup) == 0 || bp::len(tup) > 1)
57
        {
58
          throw eigenpy::Exception("Pickle was not able to reconstruct the model from the loaded data.\n"
59
                                   "The pickle data structure contains too many elements.");
60
        }
61
62
        bp::object py_obj = tup[0];
63
        boost::python::extract<std::string> obj_as_string(py_obj.ptr());
64
        if(obj_as_string.check())
65
        {
66
          const std::string str = obj_as_string;
67
          model.loadFromString(str);
68
        }
69
        else
70
        {
71
          throw eigenpy::Exception("Pickle was not able to reconstruct the model from the loaded data.\n"
72
                                   "The entry is not a string.");
73
        }
74
75
      }
76
77
19
      static bool getstate_manages_dict() { return true; }
78
79
    };
80
81
    template<typename Model>
82
    struct ModelPythonVisitor
83
    : public bp::def_visitor< ModelPythonVisitor<Model> >
84
    {
85
    public:
86
      typedef typename Model::Scalar Scalar;
87
88
      typedef typename Model::Index Index;
89
      typedef typename Model::JointIndex JointIndex;
90
      typedef typename Model::FrameIndex FrameIndex;
91
      typedef typename Model::IndexVector IndexVector;
92
93
      typedef typename Model::SE3 SE3;
94
      typedef typename Model::Motion Motion;
95
      typedef typename Model::Force Force;
96
      typedef typename Model::Frame Frame;
97
      typedef typename Model::Inertia Inertia;
98
99
      typedef typename Model::Data Data;
100
101
      typedef typename Model::VectorXs VectorXs;
102
103
38
      BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(addFrame_overload,Model::addFrame,1,2)
104
105
    public:
106
107
      /* --- Exposing C++ API to python through the handler ----------------- */
108
      template<class PyClass>
109
19
      void visit(PyClass& cl) const
110
      {
111
19
        cl
112
        .def(bp::init<>(bp::arg("self"),
113
                        "Default constructor. Constructs an empty model."))
114
115
        // Class Members
116

19
        .add_property("nq", &Model::nq)
117
19
        .add_property("nv", &Model::nv)
118
19
        .add_property("njoints", &Model::njoints)
119
19
        .add_property("nbodies", &Model::nbodies)
120
19
        .add_property("nframes", &Model::nframes)
121
19
        .add_property("inertias",&Model::inertias)
122
19
        .add_property("jointPlacements",&Model::jointPlacements)
123
19
        .add_property("joints",&Model::joints)
124
19
        .add_property("idx_qs",&Model::idx_qs)
125
19
        .add_property("nqs",&Model::nqs)
126
19
        .add_property("idx_vs",&Model::idx_vs)
127
19
        .add_property("nvs",&Model::nvs)
128
19
        .add_property("parents",&Model::parents)
129
19
        .add_property("names",&Model::names)
130
19
        .def_readwrite("name",&Model::name)
131
19
        .def_readwrite("referenceConfigurations", &Model::referenceConfigurations)
132
133
19
        .def_readwrite("rotorInertia",&Model::rotorInertia,
134
                       "Vector of rotor inertia parameters.")
135
19
        .def_readwrite("rotorGearRatio",&Model::rotorGearRatio,
136
                       "Vector of rotor gear ratio parameters.")
137
19
        .def_readwrite("friction",&Model::friction,
138
                       "Vector of joint friction parameters.")
139
19
        .def_readwrite("damping",&Model::damping,
140
                       "Vector of joint damping parameters.")
141
19
        .def_readwrite("effortLimit",&Model::effortLimit,
142
                       "Joint max effort.")
143
19
        .def_readwrite("velocityLimit",&Model::velocityLimit,
144
                       "Joint max velocity.")
145
19
        .def_readwrite("lowerPositionLimit",&Model::lowerPositionLimit,
146
                       "Limit for joint lower position.")
147
19
        .def_readwrite("upperPositionLimit",&Model::upperPositionLimit,
148
                       "Limit for joint upper position.")
149
150
19
        .def_readwrite("frames",&Model::frames,
151
                       "Vector of frames contained in the model.")
152
153
19
        .def_readwrite("supports",
154
                       &Model::supports,
155
                       "Vector of supports. supports[j] corresponds to the list of joints on the path between\n"
156
                       "the current *j* to the root of the kinematic tree.")
157
158
19
        .def_readwrite("subtrees",
159
                       &Model::subtrees,
160
                       "Vector of subtrees. subtree[j] corresponds to the subtree supported by the joint j.")
161
162
19
        .def_readwrite("gravity",&Model::gravity,
163
                       "Motion vector corresponding to the gravity field expressed in the world Frame.")
164
165
        // Class Methods
166
19
        .def("addJoint",&ModelPythonVisitor::addJoint0,
167
             bp::args("self","parent_id","joint_model","joint_placement","joint_name"),
168
             "Adds a joint to the kinematic tree. The joint is defined by its placement relative to its parent joint and its name.")
169

38
        .def("addJoint",&ModelPythonVisitor::addJoint1,
170
             bp::args("self","parent_id","joint_model","joint_placement","joint_name",
171
                      "max_effort","max_velocity","min_config","max_config"),
172
             "Adds a joint to the kinematic tree with given bounds. The joint is defined by its placement relative to its parent joint and its name."
173
             "This signature also takes as input effort, velocity limits as well as the bounds on the joint configuration.")
174

38
        .def("addJoint",&ModelPythonVisitor::addJoint2,
175
             bp::args("self","parent_id","joint_model","joint_placement","joint_name",
176
                      "max_effort","max_velocity","min_config","max_config",
177
                      "friction","damping"),
178
             "Adds a joint to the kinematic tree with given bounds. The joint is defined by its placement relative to its parent joint and its name.\n"
179
             "This signature also takes as input effort, velocity limits as well as the bounds on the joint configuration.\n"
180
             "The user should also provide the friction and damping related to the joint.")
181

38
        .def("addJointFrame", &Model::addJointFrame,
182
             addJointFrame_overload(bp::args("self","joint_id", "frame_id"),
183
                                    "Add the joint provided by its joint_id as a frame to the frame tree.\n"
184
                                    "The frame_id may be optionally provided."))
185

38
        .def("appendBodyToJoint",&Model::appendBodyToJoint,
186
             bp::args("self","joint_id","body_inertia","body_placement"),
187
             "Appends a body to the joint given by its index. The body is defined by its inertia, its relative placement regarding to the joint and its name.")
188
189

38
        .def("addBodyFrame", &Model::addBodyFrame, bp::args("self","body_name", "parentJoint", "body_placement", "previous_frame"), "add a body to the frame tree")
190

38
        .def("getBodyId",&Model::getBodyId, bp::args("self","name"), "Return the index of a frame of type BODY given by its name")
191

38
        .def("existBodyName", &Model::existBodyName, bp::args("self","name"), "Check if a frame of type BODY exists, given its name")
192

38
        .def("getJointId",&Model::getJointId, bp::args("self","name"), "Return the index of a joint given by its name")
193

38
        .def("existJointName", &Model::existJointName, bp::args("self","name"), "Check if a joint given by its name exists")
194
195

38
        .def("getFrameId",&Model::getFrameId,getFrameId_overload(bp::args("self","name","type"),"Returns the index of the frame given by its name and its type. If the frame is not in the frames vector, it returns the current size of the frames vector."))
196
197

38
        .def("existFrame",&Model::existFrame,existFrame_overload(bp::args("self","name","type"),"Returns true if the frame given by its name exists inside the Model with the given type."))
198
199

38
        .def("addFrame",&Model::addFrame,
200

19
             addFrame_overload((bp::arg("self"), bp::arg("frame"), bp::arg("append_inertia") = true),
201
                               "Add a frame to the vector of frames. If append_inertia set to True, "
202
                               "the inertia value contained in frame will be added to the inertia supported by the parent joint."))
203
204



57
        .def("createData",
205
             &ModelPythonVisitor::createData,bp::arg("self"),
206
             "Create a Data object for the given model.")
207
208

38
        .def("check",(bool (Model::*)(const Data &) const) &Model::check,bp::args("self","data"),
209
             "Check consistency of data wrt model.")
210

38
        .def("hasConfigurationLimit",&Model::hasConfigurationLimit, bp::args("self"), "Returns list of boolean if joints have configuration limit.")
211
38
        .def("hasConfigurationLimitInTangent",&Model::hasConfigurationLimitInTangent, bp::args("self"), "Returns list of boolean if joints have configuration limit in tangent space  .")
212
213

57
        .def(bp::self == bp::self)
214

57
        .def(bp::self != bp::self)
215
        ;
216
19
      }
217
218
2
      static JointIndex addJoint0(Model & model,
219
                                  JointIndex parent_id,
220
                                  const JointModel & jmodel,
221
                                  const SE3 & joint_placement,
222
                                  const std::string & joint_name)
223
      {
224
2
        return model.addJoint(parent_id,jmodel,joint_placement,joint_name);
225
      }
226
227
      static JointIndex addJoint1(Model & model,
228
                                  JointIndex parent_id,
229
                                  const JointModel & jmodel,
230
                                  const SE3 & joint_placement,
231
                                  const std::string & joint_name,
232
                                  const VectorXs & max_effort,
233
                                  const VectorXs & max_velocity,
234
                                  const VectorXs & min_config,
235
                                  const VectorXs & max_config)
236
      {
237
        return model.addJoint(parent_id,jmodel,joint_placement,joint_name,
238
                              max_effort,max_velocity,min_config,max_config);
239
      }
240
241
      static JointIndex addJoint2(Model & model,
242
                                  JointIndex parent_id,
243
                                  const JointModel & jmodel,
244
                                  const SE3 & joint_placement,
245
                                  const std::string & joint_name,
246
                                  const VectorXs & max_effort,
247
                                  const VectorXs & max_velocity,
248
                                  const VectorXs & min_config,
249
                                  const VectorXs & max_config,
250
                                  const VectorXs & friction,
251
                                  const VectorXs & damping)
252
      {
253
        return model.addJoint(parent_id,jmodel,joint_placement,joint_name,
254
                              max_effort,max_velocity,min_config,max_config,
255
                              friction,damping);
256
      }
257
258
21
      static Data createData(const Model & model) { return Data(model); }
259
260
      ///
261
      /// \brief Provide equivalent to python list index function for
262
      ///        vectors.
263
      ///
264
      /// \param[in] x The input vector.
265
      /// \param[in] v The value of to look for in the vector.
266
      ///
267
      /// \return The index of the matching element of the vector. If
268
      ///         no element is found, return the size of the vector.
269
      ///
270
      template<typename T>
271
      static Index index(std::vector<T> const& x,
272
                                typename std::vector<T>::value_type const& v)
273
      {
274
        Index i = 0;
275
        for(typename std::vector<T>::const_iterator it = x.begin(); it != x.end(); ++it, ++i)
276
        {
277
          if(*it == v)
278
          {
279
            return i;
280
          }
281
        }
282
        return x.size();
283
      }
284
285
      /* --- Expose --------------------------------------------------------- */
286
19
      static void expose()
287
      {
288
        typedef typename Model::ConfigVectorMap ConfigVectorMap;
289
        typedef bp::map_indexing_suite<ConfigVectorMap,false> map_indexing_suite;
290

19
        StdVectorPythonVisitor<Index>::expose("StdVec_Index");
291
19
        serialize< std::vector<Index> >();
292

19
        StdVectorPythonVisitor<IndexVector>::expose("StdVec_IndexVector");
293
19
        serialize< std::vector<IndexVector> >();
294

19
        StdVectorPythonVisitor<std::string>::expose("StdVec_StdString");
295
19
        serialize< std::vector<std::string> >();
296

19
        StdVectorPythonVisitor<bool>::expose("StdVec_Bool");
297
19
        serialize< std::vector<bool> >();
298

19
        StdVectorPythonVisitor<Scalar>::expose("StdVec_Double");
299
19
        serialize< std::vector<Scalar> >();
300
        bp::class_<typename Model::ConfigVectorMap>("StdMap_String_VectorXd")
301
          .def(map_indexing_suite())
302
19
          .def_pickle(PickleMap<typename Model::ConfigVectorMap>())
303

19
          .def(details::overload_base_get_item_for_std_map<typename Model::ConfigVectorMap>());
304
305
        bp::class_<Model>("Model",
306
                          "Articulated Rigid Body model",
307
                          bp::no_init)
308
        .def(ModelPythonVisitor())
309
19
        .def(SerializableVisitor<Model>())
310
19
        .def(PrintableVisitor<Model>())
311
19
        .def(CopyableVisitor<Model>())
312

19
        .def_pickle(PickleModel<Model>())
313
        ;
314
19
      }
315
    };
316
317
  }} // namespace pinocchio::python
318
319
#endif // ifndef __pinocchio_python_multibody_model_hpp__