mjcf.cpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2015-2024 CNRS INRIA
3 //
4 
5 #include <iostream>
6 #include <cstdio> // for std::tmpnam
7 
9 
13 
16 
18 
19 #include <boost/test/unit_test.hpp>
20 #include <boost/filesystem/fstream.hpp>
21 
22 namespace
23 {
24 
25  struct TemporaryFileHolder
26  {
27  TemporaryFileHolder()
28  : path(boost::filesystem::temp_directory_path() / boost::filesystem::unique_path())
29  {
30  }
31 
32  ~TemporaryFileHolder()
33  {
34  boost::filesystem::remove(path);
35  }
36 
37  TemporaryFileHolder(const TemporaryFileHolder &) = delete;
38  TemporaryFileHolder & operator=(const TemporaryFileHolder &) = delete;
39 
40  TemporaryFileHolder(TemporaryFileHolder &&) = default;
41  TemporaryFileHolder & operator=(TemporaryFileHolder &&) = default;
42 
43  std::string name() const
44  {
45  return path.string();
46  }
47 
49  };
50 
51 } // namespace
52 
53 static TemporaryFileHolder createTempFile(const std::istringstream & data)
54 {
55  TemporaryFileHolder temp_file;
56 
57  // Write the XML data to the temporary file
58  boost::filesystem::ofstream file_stream(temp_file.path);
59  if (!file_stream)
60  {
61  std::cerr << "Error opening file for writing" << std::endl;
62  exit(EXIT_FAILURE);
63  }
64  file_stream << data.rdbuf();
65  file_stream.close();
66 
67  return temp_file;
68 }
69 
72 {
73  // Check if the number of children is the same
74  if (pt1.size() != pt2.size())
75  return false;
76 
77  // Iterate over all children
78  for (auto it1 = pt1.begin(), it2 = pt2.begin(); it1 != pt1.end(); ++it1, ++it2)
79  {
80  // Compare keys
81  if (it1->first != it2->first)
82  return false;
83 
84  // Compare values
85  if (it1->second.data() != it2->second.data())
86  return false;
87 
88  // Recursively compare child trees
89  if (!comparePropertyTrees(it1->second, it2->second))
90  return false;
91  }
92 
93  return true;
94 }
95 
96 BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)
97 
98 // /// @brief Test for the inertia conversion from mjcf to pinocchio inertia
99 // /// @param
100 BOOST_AUTO_TEST_CASE(convert_inertia_fullinertia)
101 {
103  typedef pinocchio::SE3::Matrix3 Matrix3;
104  // Parse the XML
105  std::istringstream xmlData(R"(
106  <inertial mass="0.629769" pos="-0.041018 -0.00014 0.049974"
107  fullinertia="0.00315 0.00388 0.004285 8.2904e-7 0.00015 8.2299e-6"/>
108  )");
109 
110  // Create a Boost Property Tree
112  boost::property_tree::read_xml(xmlData, pt);
113 
114  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
116  MjcfGraph::UrdfVisitor visitor(model);
117 
118  MjcfGraph graph(visitor, "fakeMjcf");
119 
120  // // Try to get the "name" element using get_optional
121  pinocchio::Inertia inertia = graph.convertInertiaFromMjcf(pt.get_child("inertial"));
122 
123  Matrix3 inertia_matrix;
124  // M(1,1), M(2,2), M(3,3), M(1,2), M(1,3), M(2,3)
125  inertia_matrix << 0.00315, 8.2904e-7, 0.00015, 8.2904e-7, 0.00388, 8.2299e-6, 0.00015, 8.2299e-6,
126  0.004285;
127 
128  pinocchio::Inertia real_inertia(0.629769, Vector3(-0.041018, -0.00014, 0.049974), inertia_matrix);
129  BOOST_CHECK(inertia.isEqual(real_inertia));
130 }
131 
132 // /// @brief Test for the inertia conversion from mjcf to pinocchio inertia
133 // /// @param
134 BOOST_AUTO_TEST_CASE(convert_inertia_diaginertia)
135 {
137  typedef pinocchio::SE3::Matrix3 Matrix3;
138  // Parse the XML
139  std::istringstream xmlData(R"(
140  <inertial mass="0.629769" pos="-0.041018 -0.00014 0.049974"
141  diaginertia="0.00315 0.00388 0.004285"/>
142  )");
143 
144  // Create a Boost Property Tree
146  boost::property_tree::read_xml(xmlData, pt);
147 
148  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
150  MjcfGraph::UrdfVisitor visitor(model);
151 
152  MjcfGraph graph(visitor, "fakeMjcf");
153 
154  // // Try to get the "name" element using get_optional
155  pinocchio::Inertia inertia = graph.convertInertiaFromMjcf(pt.get_child("inertial"));
156 
157  Matrix3 inertia_matrix = Eigen::Matrix3d::Zero();
158  inertia_matrix(0, 0) = 0.00315;
159  inertia_matrix(1, 1) = 0.00388;
160  inertia_matrix(2, 2) = 0.004285;
161  pinocchio::Inertia real_inertia(0.629769, Vector3(-0.041018, -0.00014, 0.049974), inertia_matrix);
162 
163  BOOST_CHECK(inertia.isApprox(real_inertia, 1e-7));
164 }
165 
167 BOOST_AUTO_TEST_CASE(geoms_construction)
168 {
169  double pi = boost::math::constants::pi<double>();
170  // Parse the XML
171  std::istringstream xmlData(R"(<mujoco model="inertiaFromGeom">
172  <compiler inertiafromgeom="true" />
173  <worldbody>
174  <body pos="0 0 0" name="bodyCylinder">
175  <geom type="cylinder" size=".01" fromto="0 0 0 0 0 .5"/>
176  <geom type="cylinder" size=".01 0.25" pos="0 0 0" quat="1 0 0 0"/>
177  <body pos="0 0 0" name="bodyBox">
178  <geom type="box" size=".01" fromto="0 0 0 0 0 .5"/>
179  <geom type="box" size=".01 0.01 0.25" pos="0 0 0" quat="1 0 0 0"/>
180  </body>
181  <body pos="0 0 0" name="bodyCapsule">
182  <geom type="capsule" size=".01" fromto="0 0 0 0 0 .5"/>
183  <geom type="capsule" size=".01 0.25" pos="0 0 0" quat="1 0 0 0"/>
184  </body>
185  <body pos="0 0 0" name="bodySphere">
186  <geom type="sphere" size=".01 0.25" pos="0 0 0" quat="1 0 0 0"/>
187  </body>
188  <body pos="0 0 0" name="bodyEllip">
189  <geom type="ellipsoid" size=".01" fromto="0 0 0 0 0 .5"/>
190  <geom type="ellipsoid" size=".01 0.01 0.25" pos="0 0 0" quat="1 0 0 0"/>
191  </body>
192  </body>
193  </worldbody>
194  </mujoco>)");
195 
196  auto namefile = createTempFile(xmlData);
197 
198  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
199  pinocchio::Model model_m;
200  MjcfGraph::UrdfVisitor visitor(model_m);
201 
202  MjcfGraph graph(visitor, "fakeMjcf");
203  graph.parseGraphFromXML(namefile.name());
204 
205  // Test Cylinder
206  pinocchio::mjcf::details::MjcfBody bodyTest = graph.mapOfBodies.at("bodyCylinder");
207  double mass = 1000 * std::pow(0.01, 2) * 0.25 * pi * 2;
208  pinocchio::Inertia inertTest = pinocchio::Inertia::FromCylinder(mass, 0.01, 0.25 * 2);
209  Eigen::Vector2d sizeCy;
210  sizeCy << 0.01, 0.25;
211  for (const auto & geom : bodyTest.geomChildren)
212  {
213  // Check size
214  BOOST_CHECK(geom.size == sizeCy);
215  // Check inertia
216  BOOST_CHECK(geom.geomInertia.isApprox(inertTest));
217  }
218  // Test Box
219  bodyTest = graph.mapOfBodies.at("bodyBox");
220  mass = 1000 * 0.02 * 0.02 * 0.5;
221  inertTest = pinocchio::Inertia::FromBox(mass, 0.02, 0.02, 0.5);
222  Eigen::Vector3d sizeB;
223  sizeB << 0.02, 0.02, .5;
224  for (const auto & geom : bodyTest.geomChildren)
225  {
226  // Check size
227  BOOST_CHECK(geom.size == sizeB);
228  // Check inertia
229  BOOST_CHECK(geom.geomInertia.isApprox(inertTest));
230  }
231  // Test Capsule
232  bodyTest = graph.mapOfBodies.at("bodyCapsule");
233  mass = 1000 * (4.0 / 3 * pi * std::pow(0.01, 3) + 2 * pi * std::pow(0.01, 2) * 0.25);
234  inertTest = pinocchio::Inertia::FromCapsule(mass, 0.01, 0.25 * 2);
235  Eigen::Vector2d sizeCa;
236  sizeCa << 0.01, 0.25;
237  for (const auto & geom : bodyTest.geomChildren)
238  {
239  // Check size
240  BOOST_CHECK(geom.size == sizeCa);
241  // Check inertia
242  BOOST_CHECK(geom.geomInertia.isApprox(inertTest));
243  }
244  // Test Sphere
245  bodyTest = graph.mapOfBodies.at("bodySphere");
246  mass = 1000 * 4.0 / 3 * pi * std::pow(0.01, 3);
247  inertTest = pinocchio::Inertia::FromSphere(mass, 0.01);
248  Eigen::VectorXd sizeS(1);
249  sizeS << 0.01;
250  for (const auto & geom : bodyTest.geomChildren)
251  {
252  // Check size
253  BOOST_CHECK(geom.size == sizeS);
254  // Check inertia
255  BOOST_CHECK(geom.geomInertia.isApprox(inertTest));
256  }
257  // Test Ellipsoid
258  bodyTest = graph.mapOfBodies.at("bodyEllip");
259  mass = 1000 * 4.0 / 3 * pi * 0.01 * 0.01 * 0.25;
260  inertTest = pinocchio::Inertia::FromEllipsoid(mass, 0.01, 0.01, 0.25);
261  Eigen::Vector3d sizeEl;
262  sizeEl << 0.01, 0.01, 0.25;
263  for (const auto & geom : bodyTest.geomChildren)
264  {
265  // Check size
266  BOOST_CHECK(geom.size == sizeEl);
267  // Check inertia
268  BOOST_CHECK(geom.geomInertia.isApprox(inertTest));
269  }
270 }
271 
274 BOOST_AUTO_TEST_CASE(inertia_from_geom)
275 {
276  // Parse the XML
277  std::istringstream xmlData(R"(<mujoco model="inertiaFromGeom">
278  <compiler inertiafromgeom="true" />
279  <worldbody>
280  <body pos="0 0 0" name="body0">
281  <geom type="box" size=".01 .01 .01" pos="0 0 0.01"/>
282  <geom type="box" size=".01 .01 .01" pos="0 0 0.03"/>
283  </body>
284  </worldbody>
285  </mujoco>)");
286 
287  auto namefile = createTempFile(xmlData);
288 
289  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
290  pinocchio::Model model_m;
291  MjcfGraph::UrdfVisitor visitor(model_m);
292 
293  MjcfGraph graph(visitor, "fakeMjcf");
294  graph.parseGraphFromXML(namefile.name());
295  graph.parseRootTree();
296 
297  // only one inertias since only one body
298  pinocchio::Inertia inertBody = model_m.inertias[0];
299 
300  double massBigBox = 1000 * 0.02 * 0.02 * 0.04; // density * volume
301  pinocchio::Inertia inertBigBox = pinocchio::Inertia::FromBox(massBigBox, 0.02, 0.02, 0.04);
302  // Create a frame on the bottom face of BigBox and express inertia
303  Eigen::Vector3d pl;
304  pl << 0, 0, 0.02;
305  pinocchio::SE3 placementBigBox(Eigen::Matrix3d::Identity(), pl);
306  inertBigBox = placementBigBox.act(inertBigBox);
307 
308  BOOST_CHECK(inertBigBox.isApprox(inertBody));
309 }
310 
311 // /// @brief Test for the pose conversion from mjcf model to pinocchio
312 // /// @param
313 BOOST_AUTO_TEST_CASE(convert_orientation)
314 {
316  typedef pinocchio::SE3::Matrix3 Matrix3;
317 
318  std::istringstream xmlData(R"(
319  <compiler angle="radian" eulerseq="xyz"/>
320  <quaternion pos="0.3 0.2 0.5" quat="1 -1 0 0"/>
321  <axis pos="0.3 0.2 0.5" axisangle="-1 0 0 1.5707963"/>
322  <euler pos="0.3 0.2 0.5" euler="-1.57079633 0 0"/>
323  <xyaxes pos="0.3 0.2 0.5" xyaxes="1 0 0 0 0 -1"/>
324  <zaxis pos="0.3 0.2 0.5" zaxis="0 1 0"/>
325  )");
326 
327  // Create a Boost Property Tree
329  boost::property_tree::read_xml(xmlData, pt);
330 
331  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
333  MjcfGraph::UrdfVisitor visitor(model);
334 
335  MjcfGraph graph(visitor, "fakeMjcf");
336 
337  graph.parseCompiler(pt.get_child("compiler"));
338 
339  pinocchio::SE3 placement_q = graph.convertPosition(pt.get_child("quaternion"));
340  pinocchio::SE3 placement_a = graph.convertPosition(pt.get_child("axis"));
341  pinocchio::SE3 placement_e = graph.convertPosition(pt.get_child("euler"));
342  pinocchio::SE3 placement_xy = graph.convertPosition(pt.get_child("xyaxes"));
343  pinocchio::SE3 placement_z = graph.convertPosition(pt.get_child("zaxis"));
344 
345  Matrix3 rotation_matrix;
346  rotation_matrix << 1., 0., 0., 0., 0., 1., 0., -1., 0.;
347 
348  pinocchio::SE3 real_placement(rotation_matrix, Vector3(0.3, 0.2, 0.5));
349 
350  BOOST_CHECK(placement_q.isApprox(real_placement, 1e-7));
351  BOOST_CHECK(placement_e.isApprox(real_placement, 1e-7));
352  BOOST_CHECK(placement_a.isApprox(real_placement, 1e-7));
353  BOOST_CHECK(placement_xy.isApprox(real_placement, 1e-7));
354  BOOST_CHECK(placement_z.isApprox(real_placement, 1e-7));
355 }
356 
359 BOOST_AUTO_TEST_CASE(merge_default)
360 {
361  namespace pt = boost::property_tree;
362  std::istringstream xmlIn(R"(
363  <default>
364  <default class="mother">
365  <joint A="a0" B="b0" />
366  <geom A="a0" />
367  <default class="layer1">
368  <joint A="a1" C="c1" />
369  <default class="layer2">
370  <joint B="b2" />
371  <geom C="c2" />
372  </default>
373  </default>
374  <default class="layerP">
375  <joint K="b2" />
376  <site H="f1"/>
377  </default>
378  </default>
379  </default>)");
380 
381  // Create a Boost Property Tree
382  pt::ptree ptr;
383  pt::read_xml(xmlIn, ptr, pt::xml_parser::trim_whitespace);
384 
385  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
387  MjcfGraph::UrdfVisitor visitor(model);
388 
389  MjcfGraph graph(visitor, "fakeMjcf");
390  graph.parseDefault(ptr.get_child("default"), ptr, "default");
391 
392  std::unordered_map<std::string, pt::ptree> TrueMap;
393 
394  std::istringstream xml1(R"(<default class="mother">
395  <joint A="a0" B="b0" />
396  <geom A="a0" />
397  <default class="layer1">
398  <joint A="a1" C="c1" />
399  <default class="layer2">
400  <joint B="b2" />
401  <geom C="c2" />
402  </default>
403  </default>
404  <default class="layerP">
405  <joint K="b2" />
406  <site H="f1"/>
407  </default>
408  </default>)");
409  pt::ptree p1;
410  pt::read_xml(xml1, p1, pt::xml_parser::trim_whitespace);
411  BOOST_CHECK(
412  comparePropertyTrees(graph.mapOfClasses.at("mother").classElement, p1.get_child("default")));
413 
414  std::istringstream xml2(R"(<default class="layer1">
415  <joint A="a1" B="b0" C="c1" />
416  <default class="layer2">
417  <joint B="b2" />
418  <geom C="c2" />
419  </default>
420  <geom A="a0" />
421  </default>)");
422  pt::ptree p2;
423  pt::read_xml(xml2, p2, pt::xml_parser::trim_whitespace);
424  BOOST_CHECK(
425  comparePropertyTrees(graph.mapOfClasses.at("layer1").classElement, p2.get_child("default")));
426  std::string name = "layer1";
427  TrueMap.insert(std::make_pair(name, p2.get_child("default")));
428 
429  std::istringstream xml3(R"(<default class="layer2">
430  <joint A="a1" B="b2" C="c1"/>
431  <geom A="a0" C="c2"/>
432  </default>)");
433  pt::ptree p3;
434  pt::read_xml(xml3, p3, pt::xml_parser::trim_whitespace);
435  BOOST_CHECK(
436  comparePropertyTrees(graph.mapOfClasses.at("layer2").classElement, p3.get_child("default")));
437 
438  std::istringstream xml4(R"(<default class="layerP">
439  <joint A="a0" B="b0" K="b2"/>
440  <site H="f1"/>
441  <geom A="a0"/>
442  </default>)");
443  pt::ptree p4;
444  pt::read_xml(xml4, p4, pt::xml_parser::trim_whitespace);
445  BOOST_CHECK(
446  comparePropertyTrees(graph.mapOfClasses.at("layerP").classElement, p4.get_child("default")));
447 }
448 
449 #ifdef PINOCCHIO_WITH_URDFDOM
450 // @brief Test to check that default classes and child classes are taken into account
451 BOOST_AUTO_TEST_CASE(parse_default_class)
452 {
454  typedef pinocchio::SE3::Matrix3 Matrix3;
455 
457  std::string filename = PINOCCHIO_MODEL_DIR + std::string("/../unittest/models/test_mjcf.xml");
458 
459  pinocchio::Model model_m;
460  pinocchio::mjcf::buildModel(filename, model_m, contact_models);
461 
462  std::string file_u = PINOCCHIO_MODEL_DIR + std::string("/../unittest/models/test_mjcf.urdf");
463  pinocchio::Model model_u;
464  pinocchio::urdf::buildModel(file_u, model_u);
465 
467  pinocchio::Inertia inertia(0, Vector3(0.0, 0., 0.0), Matrix3::Identity());
468  idx = model_u.addJoint(
470  "joint3");
471  model_u.appendBodyToJoint(idx, inertia);
472 
473  for (size_t i = 0; i < size_t(model_m.njoints); i++)
474  BOOST_CHECK_EQUAL(model_m.joints[i], model_u.joints[i]);
475 }
476 #endif // PINOCCHIO_WITH_URDFDOM
477 
479 BOOST_AUTO_TEST_CASE(parse_dirs_no_strippath)
480 {
481 #ifdef _WIN32
482  std::istringstream xmlDataNoStrip(R"(<mujoco model="parseDirs">
483  <compiler meshdir="meshes" texturedir="textures"/>
484  <asset>
485  <texture name="testTexture" file="texture.png" type="2d"/>
486  <material name="matTest" texture="testTexture"/>
487  <mesh file="C:/auto/mesh.obj"/>
488  </asset>
489  </mujoco>)");
490 #else
491  std::istringstream xmlDataNoStrip(R"(<mujoco model="parseDirs">
492  <compiler meshdir="meshes" texturedir="textures"/>
493  <asset>
494  <texture name="testTexture" file="texture.png" type="2d"/>
495  <material name="matTest" texture="testTexture"/>
496  <mesh file="/auto/mesh.obj"/>
497  </asset>
498  </mujoco>)");
499 #endif
500 
501  auto namefile = createTempFile(xmlDataNoStrip);
502 
503  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
504  pinocchio::Model model_m;
505  MjcfGraph::UrdfVisitor visitor(model_m);
506 
507  MjcfGraph graph(visitor, "/fakeMjcf/fake.xml");
508  graph.parseGraphFromXML(namefile.name());
509 
510  // Test texture
511  pinocchio::mjcf::details::MjcfTexture text = graph.mapOfTextures.at("testTexture");
512  BOOST_CHECK_EQUAL(text.textType, "2d");
513  BOOST_CHECK_EQUAL(
514  boost::filesystem::path(text.filePath).generic_string(), "/fakeMjcf/textures/texture.png");
515  // Test Material
516  pinocchio::mjcf::details::MjcfMaterial mat = graph.mapOfMaterials.at("matTest");
517  BOOST_CHECK_EQUAL(mat.texture, "testTexture");
518  // Test Meshes
519  pinocchio::mjcf::details::MjcfMesh mesh = graph.mapOfMeshes.at("mesh");
520 #ifdef _WIN32
521  BOOST_CHECK_EQUAL(boost::filesystem::path(mesh.filePath).generic_string(), "C:/auto/mesh.obj");
522 #else
523  BOOST_CHECK_EQUAL(boost::filesystem::path(mesh.filePath).generic_string(), "/auto/mesh.obj");
524 #endif
525 }
526 
529 BOOST_AUTO_TEST_CASE(parse_dirs_strippath)
530 {
531  std::istringstream xmlDataNoStrip(R"(<mujoco model="parseDirs">
532  <compiler meshdir="meshes" texturedir="textures" strippath="true"/>
533  <asset>
534  <mesh file="/auto/mesh.obj"/>
535  </asset>
536  </mujoco>)");
537 
538  auto namefile = createTempFile(xmlDataNoStrip);
539 
540  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
541  pinocchio::Model model_m;
542  MjcfGraph::UrdfVisitor visitor(model_m);
543 
544  MjcfGraph graph(visitor, "/fakeMjcf/fake.xml");
545  graph.parseGraphFromXML(namefile.name());
546 
547  // Test Meshes
548  pinocchio::mjcf::details::MjcfMesh mesh = graph.mapOfMeshes.at("mesh");
549  BOOST_CHECK_EQUAL(
550  boost::filesystem::path(mesh.filePath).generic_string(), "/fakeMjcf/meshes/mesh.obj");
551 }
552 
553 // Test for parsing Revolute
555 {
557  typedef pinocchio::SE3::Matrix3 Matrix3;
558 
559  std::istringstream xmlData(R"(
560  <mujoco model="model_RX">
561  <worldbody>
562  <body name="link0">
563  <body name="link1" pos="0 0 0">
564  <joint name="joint1" type="hinge" axis="1 0 0"/>
565  </body>
566  </body>
567  </worldbody>
568  </mujoco>)");
569 
570  auto namefile = createTempFile(xmlData);
571 
572  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
573  pinocchio::Model model_m, modelRX;
574  MjcfGraph::UrdfVisitor visitor(model_m);
575 
576  MjcfGraph graph(visitor, "fakeMjcf");
577  graph.parseGraphFromXML(namefile.name());
578  graph.parseRootTree();
579 
581  pinocchio::Inertia inertia(0, Vector3(0.0, 0., 0.0), Matrix3::Identity());
582 
583  idx = modelRX.addJoint(0, pinocchio::JointModelRX(), pinocchio::SE3::Identity(), "rx");
584  modelRX.appendBodyToJoint(idx, inertia);
585 
586  for (size_t i = 0; i < size_t(model_m.njoints); i++)
587  BOOST_CHECK_EQUAL(model_m.joints[i], modelRX.joints[i]);
588 }
589 
590 // Test for parsing prismatic
592 {
594  typedef pinocchio::SE3::Matrix3 Matrix3;
595 
596  std::istringstream xmlData(R"(
597  <mujoco model="model_PX">
598  <worldbody>
599  <body name="link0">
600  <body name="link1" pos="0 0 0">
601  <joint name="joint1" type="slide" axis="1 0 0"/>
602  </body>
603  </body>
604  </worldbody>
605  </mujoco>)");
606 
607  auto namefile = createTempFile(xmlData);
608 
609  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
610  pinocchio::Model model_m, modelPX;
611  MjcfGraph::UrdfVisitor visitor(model_m);
612 
613  MjcfGraph graph(visitor, "fakeMjcf");
614  graph.parseGraphFromXML(namefile.name());
615  graph.parseRootTree();
616 
618  pinocchio::Inertia inertia(0, Vector3(0.0, 0., 0.0), Matrix3::Identity());
619 
620  idx = modelPX.addJoint(0, pinocchio::JointModelPX(), pinocchio::SE3::Identity(), "px");
621  modelPX.appendBodyToJoint(idx, inertia);
622 
623  for (size_t i = 0; i < size_t(model_m.njoints); i++)
624  BOOST_CHECK_EQUAL(model_m.joints[i], modelPX.joints[i]);
625 }
626 
627 // Test parsing sphere
628 BOOST_AUTO_TEST_CASE(parse_Sphere)
629 {
631  typedef pinocchio::SE3::Matrix3 Matrix3;
632 
633  std::istringstream xmlData(R"(
634  <mujoco model="model_Sphere">
635  <worldbody>
636  <body name="link0">
637  <body name="link1" pos="0 0 0">
638  <joint name="joint1" type="ball"/>
639  </body>
640  </body>
641  </worldbody>
642  </mujoco>)");
643 
644  auto namefile = createTempFile(xmlData);
645 
646  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
647  pinocchio::Model model_m, modelS;
648  MjcfGraph::UrdfVisitor visitor(model_m);
649 
650  MjcfGraph graph(visitor, "fakeMjcf");
651  graph.parseGraphFromXML(namefile.name());
652  graph.parseRootTree();
653 
655  pinocchio::Inertia inertia(0, Vector3(0.0, 0., 0.0), Matrix3::Identity());
656 
658  modelS.appendBodyToJoint(idx, inertia);
659 
660  for (size_t i = 0; i < size_t(model_m.njoints); i++)
661  BOOST_CHECK_EQUAL(model_m.joints[i], modelS.joints[i]);
662 }
663 
664 // Test parsing free flyer
666 {
668  typedef pinocchio::SE3::Matrix3 Matrix3;
669 
670  std::istringstream xmlData(R"(
671  <mujoco model="model_Free">
672  <worldbody>
673  <body name="link0">
674  <body name="link1" pos="0 0 0">
675  <freejoint name="joint1"/>
676  </body>
677  </body>
678  </worldbody>
679  </mujoco>)");
680 
681  auto namefile = createTempFile(xmlData);
682 
683  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
684  pinocchio::Model model_m, modelF;
685  MjcfGraph::UrdfVisitor visitor(model_m);
686 
687  MjcfGraph graph(visitor, "fakeMjcf");
688  graph.parseGraphFromXML(namefile.name());
689  graph.parseRootTree();
690 
692  pinocchio::Inertia inertia(0, Vector3(0.0, 0., 0.0), Matrix3::Identity());
693 
695  modelF.appendBodyToJoint(idx, inertia);
696 
697  for (size_t i = 0; i < size_t(model_m.njoints); i++)
698  BOOST_CHECK_EQUAL(model_m.joints[i], modelF.joints[i]);
699 }
700 
701 // Test for Composite RXRY
702 BOOST_AUTO_TEST_CASE(parse_composite_RXRY)
703 {
705  typedef pinocchio::SE3::Matrix3 Matrix3;
706 
707  std::istringstream xmlData(R"(
708  <mujoco model="composite_RXRY">
709  <worldbody>
710  <body name="link0">
711  <body name="link1" pos="0 0 0">
712  <joint name="joint1" type="hinge" axis="1 0 0"/>
713  <joint name="joint2" type="hinge" axis="0 1 0"/>
714  </body>
715  </body>
716  </worldbody>
717  </mujoco>)");
718 
719  auto namefile = createTempFile(xmlData);
720 
721  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
722  pinocchio::Model model_m, modelRXRY;
723  MjcfGraph::UrdfVisitor visitor(model_m);
724 
725  MjcfGraph graph(visitor, "fakeMjcf");
726  graph.parseGraphFromXML(namefile.name());
727  graph.parseRootTree();
728 
730  pinocchio::Inertia inertia(0, Vector3(0.0, 0., 0.0), Matrix3::Identity());
731 
732  pinocchio::JointModelComposite joint_model_RXRY;
733  joint_model_RXRY.addJoint(pinocchio::JointModelRX());
734  joint_model_RXRY.addJoint(pinocchio::JointModelRY());
735 
736  idx = modelRXRY.addJoint(0, joint_model_RXRY, pinocchio::SE3::Identity(), "rxry");
737  modelRXRY.appendBodyToJoint(idx, inertia);
738 
739  for (size_t i = 0; i < size_t(model_m.njoints); i++)
740  BOOST_CHECK_EQUAL(model_m.joints[i], modelRXRY.joints[i]);
741 }
742 
743 // Test for Composite PXPY
744 BOOST_AUTO_TEST_CASE(parse_composite_PXPY)
745 {
747  typedef pinocchio::SE3::Matrix3 Matrix3;
748 
749  std::istringstream xmlData(R"(
750  <mujoco model="composite_PXPY">
751  <worldbody>
752  <body name="link0">
753  <body name="link1" pos="0 0 0">
754  <joint name="joint1" type="slide" axis="1 0 0"/>
755  <joint name="joint2" type="slide" axis="0 1 0"/>
756  </body>
757  </body>
758  </worldbody>
759  </mujoco>)");
760 
761  auto namefile = createTempFile(xmlData);
762 
763  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
764  pinocchio::Model model_m, modelPXPY;
765  MjcfGraph::UrdfVisitor visitor(model_m);
766 
767  MjcfGraph graph(visitor, "fakeMjcf");
768  graph.parseGraphFromXML(namefile.name());
769  graph.parseRootTree();
770 
772  pinocchio::Inertia inertia(0, Vector3(0.0, 0., 0.0), Matrix3::Identity());
773 
774  pinocchio::JointModelComposite joint_model_PXPY;
775  joint_model_PXPY.addJoint(pinocchio::JointModelPX());
776  joint_model_PXPY.addJoint(pinocchio::JointModelPY());
777 
778  idx = modelPXPY.addJoint(0, joint_model_PXPY, pinocchio::SE3::Identity(), "pxpy");
779  modelPXPY.appendBodyToJoint(idx, inertia);
780 
781  for (size_t i = 0; i < size_t(model_m.njoints); i++)
782  BOOST_CHECK_EQUAL(model_m.joints[i], modelPXPY.joints[i]);
783 }
784 
785 // Test for Composite PXRY
786 BOOST_AUTO_TEST_CASE(parse_composite_PXRY)
787 {
789  typedef pinocchio::SE3::Matrix3 Matrix3;
790 
791  std::istringstream xmlData(R"(
792  <mujoco model="composite_PXRY">
793  <worldbody>
794  <body name="link0">
795  <body name="link1" pos="0 0 0">
796  <joint name="joint1" type="slide" axis="1 0 0"/>
797  <joint name="joint2" type="hinge" axis="0 1 0"/>
798  </body>
799  </body>
800  </worldbody>
801  </mujoco>)");
802 
803  auto namefile = createTempFile(xmlData);
804 
805  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
806  pinocchio::Model model_m, modelPXRY;
807  MjcfGraph::UrdfVisitor visitor(model_m);
808 
809  MjcfGraph graph(visitor, "fakeMjcf");
810  graph.parseGraphFromXML(namefile.name());
811  graph.parseRootTree();
812 
814  pinocchio::Inertia inertia(0, Vector3(0.0, 0., 0.0), Matrix3::Identity());
815 
816  pinocchio::JointModelComposite joint_model_PXRY;
817  joint_model_PXRY.addJoint(pinocchio::JointModelPX());
818  joint_model_PXRY.addJoint(pinocchio::JointModelRY());
819 
820  idx = modelPXRY.addJoint(0, joint_model_PXRY, pinocchio::SE3::Identity(), "pxry");
821  modelPXRY.appendBodyToJoint(idx, inertia);
822 
823  for (size_t i = 0; i < size_t(model_m.njoints); i++)
824  BOOST_CHECK_EQUAL(model_m.joints[i], modelPXRY.joints[i]);
825 }
826 
827 // Test for Composite PXSphere
828 BOOST_AUTO_TEST_CASE(parse_composite_PXSphere)
829 {
831  typedef pinocchio::SE3::Matrix3 Matrix3;
832 
833  std::istringstream xmlData(R"(
834  <mujoco model="composite_PXSphere">
835  <worldbody>
836  <body name="link0">
837  <body name="link1" pos="0 0 0">
838  <joint name="joint1" type="slide" axis="1 0 0"/>
839  <joint name="joint2" type="ball"/>
840  </body>
841  </body>
842  </worldbody>
843  </mujoco>)");
844 
845  auto namefile = createTempFile(xmlData);
846 
847  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
848  pinocchio::Model model_m, modelPXSphere;
849  MjcfGraph::UrdfVisitor visitor(model_m);
850 
851  MjcfGraph graph(visitor, "fakeMjcf");
852  graph.parseGraphFromXML(namefile.name());
853  graph.parseRootTree();
854 
856  pinocchio::Inertia inertia(0, Vector3(0.0, 0., 0.0), Matrix3::Identity());
857 
858  pinocchio::JointModelComposite joint_model_PXSphere;
859  joint_model_PXSphere.addJoint(pinocchio::JointModelPX());
860  joint_model_PXSphere.addJoint(pinocchio::JointModelSpherical());
861 
862  idx = modelPXSphere.addJoint(0, joint_model_PXSphere, pinocchio::SE3::Identity(), "pxsphere");
863  modelPXSphere.appendBodyToJoint(idx, inertia);
864 
865  for (size_t i = 0; i < size_t(model_m.njoints); i++)
866  BOOST_CHECK_EQUAL(model_m.joints[i], modelPXSphere.joints[i]);
867 }
868 
869 // Test loading a mujoco composite and compare body position with mujoco results
870 BOOST_AUTO_TEST_CASE(parse_composite_Mujoco_comparison)
871 {
872  using namespace pinocchio;
873  std::string filename =
874  PINOCCHIO_MODEL_DIR + std::string("/../unittest/models/test_composite.xml");
875 
878 
879  Data data(model);
880  Eigen::Vector3d q;
881  q << 1.57079633, 0.3, 0.5;
883 
884  FrameIndex f_id = model.getFrameId("body1");
885  SE3 pinPos = data.oMf[f_id];
886 
887  Eigen::Matrix3d refOrient;
888  refOrient << 0, -.9553, .2955, 1, 0, 0, 0, .2955, .9553;
889  Eigen::Vector3d pos;
890  pos << .8522, 2, 0.5223;
891  BOOST_CHECK(pinPos.isApprox(SE3(refOrient, pos), 1e-4));
892 
893  f_id = model.getFrameId("body2");
894  pinPos = data.oMf[f_id];
895 
896  refOrient << 0, -.9553, .2955, 1, 0, 0, 0, .2955, .9553;
897 
898  pos << .8522, 4, 0.5223;
899  BOOST_CHECK(pinPos.isApprox(SE3(refOrient, pos), 1e-4));
900 }
901 
902 // Test laoding a model with a spherical joint and verify that keyframe is valid
903 BOOST_AUTO_TEST_CASE(adding_keyframes)
904 {
905  std::istringstream xmlData(R"(
906  <mujoco model="testKeyFrame">
907  <default>
908  <position ctrllimited="true" ctrlrange="-.1 .1" kp="30"/>
909  <default class="joint">
910  <geom type="cylinder" size=".006" fromto="0 0 0 0 0 .05" rgba=".9 .6 1 1"/>
911  </default>
912  </default>
913  <worldbody>
914  <body name="body1">
915  <freejoint/>
916  <geom type="capsule" size=".01" fromto="0 0 0 .2 0 0"/>
917  <body pos=".2 0 0" name="body2">
918  <joint type="ball" damping=".1"/>
919  <geom type="capsule" size=".01" fromto="0 -.15 0 0 0 0"/>
920  </body>
921  </body>
922  </worldbody>
923  <keyframe>
924  <key name="test"
925  qpos="0 0 0.596
926  0.988015 0 0.154359 0
927  0.988015 0 0.154359 0
928  "/>
929  </keyframe>
930  </mujoco>)");
931 
932  auto namefile = createTempFile(xmlData);
933 
934  pinocchio::Model model_m;
935  pinocchio::mjcf::buildModel(namefile.name(), model_m);
936 
937  Eigen::VectorXd vect_model = model_m.referenceConfigurations.at("test");
938 
939  Eigen::VectorXd vect_ref(model_m.nq);
940  vect_ref << 0, 0, 0.596, 0, 0.154359, 0, 0.988015, 0, 0.154359, 0, 0.988015;
941 
942  BOOST_CHECK(vect_model.size() == vect_ref.size());
943  BOOST_CHECK(vect_model == vect_ref);
944 }
945 
946 // Test on which joints inertias are append
947 BOOST_AUTO_TEST_CASE(joint_and_inertias)
948 {
950  typedef pinocchio::SE3::Matrix3 Matrix3;
951 
952  std::istringstream xmlData(R"(
953  <mujoco model="testJointInertia">
954  <worldbody>
955  <body name="body1">
956  <freejoint/>
957  <inertial mass="0.629769" pos="-0.041018 -0.00014 0.049974"
958  diaginertia="0.00315 0.00388 0.004285"/>
959  </body>
960  </worldbody>
961  </mujoco>)");
962 
963  auto namefile = createTempFile(xmlData);
964 
965  pinocchio::Model model_m;
966  pinocchio::mjcf::buildModel(namefile.name(), model_m);
967 
968  BOOST_CHECK(model_m.inertias[0].isApprox(pinocchio::Inertia::Zero()));
969 
970  Matrix3 inertia_matrix = Eigen::Matrix3d::Zero();
971  inertia_matrix(0, 0) = 0.00315;
972  inertia_matrix(1, 1) = 0.00388;
973  inertia_matrix(2, 2) = 0.004285;
974  pinocchio::Inertia real_inertia(0.629769, Vector3(-0.041018, -0.00014, 0.049974), inertia_matrix);
975 
976  BOOST_CHECK(model_m.inertias[1].isApprox(real_inertia));
977 }
978 
980 {
982  typedef pinocchio::SE3::Matrix3 Matrix3;
983  std::cout << " Armature ------------ " << std::endl;
984  std::istringstream xmlData(R"(
985  <mujoco model="model_RX">
986  <default>
987  <joint armature="1" damping="1" limited="true"/>
988  </default>
989  <worldbody>
990  <body name="link0">
991  <body name="link1" pos="0 0 0">
992  <joint name="joint1" type="hinge" axis="1 0 0" armature="1.3"/>
993  <joint name="joint2" type="hinge" axis="0 1 0" armature="2.4"/>
994  <joint name="joint3" type="hinge" axis="0 0 1" armature="0.4"/>
995  <body pos=".2 0 0" name="body2">
996  <joint type="ball"/>
997  </body>
998  </body>
999  </body>
1000  </worldbody>
1001  </mujoco>)");
1002 
1003  auto namefile = createTempFile(xmlData);
1004 
1005  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
1006  pinocchio::Model model_m;
1007  MjcfGraph::UrdfVisitor visitor(model_m);
1008 
1009  MjcfGraph graph(visitor, "fakeMjcf");
1010  graph.parseGraphFromXML(namefile.name());
1011  graph.parseRootTree();
1012 
1013  Eigen::VectorXd armature_real(model_m.nv);
1014  armature_real << 1.3, 2.4, 0.4, 1, 1, 1;
1015 
1016  for (size_t i = 0; i < size_t(model_m.nv); i++)
1017  BOOST_CHECK_EQUAL(model_m.armature[i], armature_real[i]);
1018 }
1019 
1020 // Test reference positions and how it's included in keyframe
1021 BOOST_AUTO_TEST_CASE(reference_positions)
1022 {
1023  std::istringstream xmlData(R"(
1024  <mujoco model="testRefPose">
1025  <compiler angle="radian"/>
1026  <worldbody>
1027  <body name="body1">
1028  <body pos=".2 0 0" name="body2">
1029  <joint type="slide" ref="0.14"/>
1030  <body pos=".2 0 0" name="body3">
1031  <joint type="hinge" ref="0.1"/>
1032  </body>
1033  </body>
1034  </body>
1035  </worldbody>
1036  <keyframe>
1037  <key name="test" qpos=".8 .5"/>
1038  </keyframe>
1039  </mujoco>)");
1040 
1041  auto namefile = createTempFile(xmlData);
1042 
1043  pinocchio::Model model_m;
1044  pinocchio::mjcf::buildModel(namefile.name(), model_m);
1045 
1046  Eigen::VectorXd vect_model = model_m.referenceConfigurations.at("test");
1047  Eigen::VectorXd vect_ref(model_m.nq);
1048  vect_ref << 0.66, 0.4;
1049 
1050  BOOST_CHECK(vect_model.size() == vect_ref.size());
1051  BOOST_CHECK(vect_model == vect_ref);
1052 }
1053 
1054 // Test keyframe and composite joint
1055 BOOST_AUTO_TEST_CASE(keyframe_and_composite)
1056 {
1057  std::istringstream xmlData(R"(
1058  <mujoco model="keyframeComposite">
1059  <compiler angle="radian"/>
1060  <worldbody>
1061  <body name="body1">
1062  <body pos=".2 0 0" name="body2">
1063  <joint type="slide"/>
1064  <joint type="hinge"/>
1065  <body pos=".2 0 0" name="body3">
1066  <joint type="hinge"/>
1067  </body>
1068  </body>
1069  </body>
1070  </worldbody>
1071  <keyframe>
1072  <key name="test" qpos=".8 .5 .5"/>
1073  </keyframe>
1074  </mujoco>)");
1075 
1076  auto namefile = createTempFile(xmlData);
1077 
1078  pinocchio::Model model_m;
1079  pinocchio::mjcf::buildModel(namefile.name(), model_m);
1080 
1081  Eigen::VectorXd vect_model = model_m.referenceConfigurations.at("test");
1082  Eigen::VectorXd vect_ref(model_m.nq);
1083  vect_ref << 0.8, 0.5, 0.5;
1084 
1085  BOOST_CHECK(vect_model.size() == vect_ref.size());
1086  BOOST_CHECK(vect_model == vect_ref);
1087 }
1088 
1089 // Test site of mjcf model
1091 {
1093  typedef pinocchio::SE3::Matrix3 Matrix3;
1094 
1095  std::istringstream xmlData(R"(
1096  <mujoco model="site">
1097  <compiler angle="radian"/>
1098  <worldbody>
1099  <body name="body1">
1100  <body pos=".2 0 0" name="body2">
1101  <joint type="hinge"/>
1102  <body pos=".2 0 0" name="body3">
1103  <joint type="hinge"/>
1104  <site name="testSite" pos="0.03 0 -0.05"/>
1105  </body>
1106  </body>
1107  </body>
1108  </worldbody>
1109  </mujoco>)");
1110 
1111  auto namefile = createTempFile(xmlData);
1112 
1113  pinocchio::Model model_m;
1114  pinocchio::mjcf::buildModel(namefile.name(), model_m);
1115 
1116  pinocchio::Data data(model_m);
1117 
1118  Matrix3 rotation_matrix;
1119  rotation_matrix << 1., 0., 0., 0., 1., 0., 0., 0., 1.;
1120  pinocchio::SE3 real_placement(rotation_matrix, Vector3(0.03, 0, -0.05));
1121 
1122  BOOST_CHECK(model_m.frames[model_m.getFrameId("testSite")].placement.isApprox(real_placement));
1123 }
1124 
1127 BOOST_AUTO_TEST_CASE(build_model_no_root_joint)
1128 {
1129  using namespace pinocchio;
1130  const std::string filename = PINOCCHIO_MODEL_DIR + std::string("/simple_humanoid.xml");
1131 
1132  pinocchio::Model model_m;
1134 
1135  BOOST_CHECK_EQUAL(model_m.nq, 29);
1136 }
1137 
1138 BOOST_AUTO_TEST_CASE(build_model_with_root_joint_name)
1139 {
1140  const std::string filename = PINOCCHIO_MODEL_DIR + std::string("/simple_humanoid.xml");
1141  const std::string dir = PINOCCHIO_MODEL_DIR;
1142 
1145  BOOST_CHECK(model.names[1] == "root_joint");
1146 
1147  pinocchio::Model model_name;
1148  const std::string name_ = "freeFlyer_joint";
1150  BOOST_CHECK(model_name.names[1] == name_);
1151 }
1152 
1153 #ifdef PINOCCHIO_WITH_URDFDOM
1154 BOOST_AUTO_TEST_CASE(compare_to_urdf)
1157 {
1158  using namespace pinocchio;
1159  typedef typename pinocchio::Model::ConfigVectorMap ConfigVectorMap;
1160 
1161  const std::string filename = PINOCCHIO_MODEL_DIR + std::string("/simple_humanoid.xml");
1162 
1163  Model model_m;
1165 
1166  const std::string filename_urdf = PINOCCHIO_MODEL_DIR + std::string("/simple_humanoid.urdf");
1167  const std::string dir_urdf = PINOCCHIO_MODEL_DIR;
1168  pinocchio::Model model_urdf;
1169  pinocchio::urdf::buildModel(filename_urdf, pinocchio::JointModelFreeFlyer(), model_urdf);
1170 
1171  BOOST_CHECK(model_urdf.nq == model_m.nq);
1172  BOOST_CHECK(model_urdf.nv == model_m.nv);
1173  BOOST_CHECK(model_urdf.njoints == model_m.njoints);
1174  BOOST_CHECK(model_urdf.nbodies == model_m.nbodies);
1175  BOOST_CHECK(model_urdf.nframes == model_m.nframes);
1176  BOOST_CHECK(model_urdf.parents == model_m.parents);
1177  BOOST_CHECK(model_urdf.children == model_m.children);
1178  BOOST_CHECK(model_urdf.names == model_m.names);
1179  BOOST_CHECK(model_urdf.subtrees == model_m.subtrees);
1180  BOOST_CHECK(model_urdf.gravity == model_m.gravity);
1181  BOOST_CHECK(model_urdf.name == model_m.name);
1182  BOOST_CHECK(model_urdf.idx_qs == model_m.idx_qs);
1183  BOOST_CHECK(model_urdf.nqs == model_m.nqs);
1184  BOOST_CHECK(model_urdf.idx_vs == model_m.idx_vs);
1185  BOOST_CHECK(model_urdf.nvs == model_m.nvs);
1186 
1187  typename ConfigVectorMap::const_iterator it = model_m.referenceConfigurations.begin();
1188  typename ConfigVectorMap::const_iterator it_model_urdf =
1189  model_urdf.referenceConfigurations.begin();
1190  for (long k = 0; k < (long)model_m.referenceConfigurations.size(); ++k)
1191  {
1192  std::advance(it, k);
1193  std::advance(it_model_urdf, k);
1194  BOOST_CHECK(it->second.size() == it_model_urdf->second.size());
1195  BOOST_CHECK(it->second == it_model_urdf->second);
1196  }
1197 
1198  BOOST_CHECK(model_urdf.armature.size() == model_m.armature.size());
1199 
1200  BOOST_CHECK(model_urdf.armature == model_m.armature);
1201  BOOST_CHECK(model_urdf.friction.size() == model_m.friction.size());
1202  BOOST_CHECK(model_urdf.friction == model_m.friction);
1203 
1204  BOOST_CHECK(model_urdf.damping.size() == model_m.damping.size());
1205 
1206  BOOST_CHECK(model_urdf.damping == model_m.damping);
1207 
1208  BOOST_CHECK(model_urdf.rotorInertia.size() == model_m.rotorInertia.size());
1209 
1210  BOOST_CHECK(model_urdf.rotorInertia == model_m.rotorInertia);
1211 
1212  BOOST_CHECK(model_urdf.rotorGearRatio.size() == model_m.rotorGearRatio.size());
1213 
1214  BOOST_CHECK(model_urdf.rotorGearRatio == model_m.rotorGearRatio);
1215 
1216  BOOST_CHECK(model_urdf.effortLimit.size() == model_m.effortLimit.size());
1217  BOOST_CHECK(model_urdf.effortLimit == model_m.effortLimit);
1218  // Cannot test velocity limit since it does not exist in mjcf
1219 
1220  BOOST_CHECK(model_urdf.lowerPositionLimit.size() == model_m.lowerPositionLimit.size());
1221  BOOST_CHECK(model_urdf.lowerPositionLimit == model_m.lowerPositionLimit);
1222 
1223  BOOST_CHECK(model_urdf.upperPositionLimit.size() == model_m.upperPositionLimit.size());
1224  BOOST_CHECK(model_urdf.upperPositionLimit == model_m.upperPositionLimit);
1225 
1226  for (size_t k = 1; k < model_m.inertias.size(); ++k)
1227  {
1228  BOOST_CHECK(model_urdf.inertias[k].isApprox(model_m.inertias[k]));
1229  }
1230 
1231  for (size_t k = 1; k < model_urdf.jointPlacements.size(); ++k)
1232  {
1233  BOOST_CHECK(model_urdf.jointPlacements[k] == model_m.jointPlacements[k]);
1234  }
1235 
1236  BOOST_CHECK(model_urdf.joints == model_m.joints);
1237 
1238  BOOST_CHECK(model_urdf.frames.size() == model_m.frames.size());
1239  for (size_t k = 1; k < model_urdf.frames.size(); ++k)
1240  {
1241  BOOST_CHECK(model_urdf.frames[k] == model_m.frames[k]);
1242  }
1243 }
1244 #endif // PINOCCHIO_WITH_URDFDOM
1245 
1246 #if defined(PINOCCHIO_WITH_HPP_FCL)
1247 BOOST_AUTO_TEST_CASE(test_geometry_parsing)
1248 {
1249  typedef pinocchio::Model Model;
1251 
1252  // Parse the XML
1253  std::istringstream xmlData(R"(<mujoco model="inertiaFromGeom">
1254  <compiler inertiafromgeom="true" />
1255  <worldbody>
1256  <body pos="0 0 0" name="bodyCylinder">
1257  <geom type="cylinder" size=".01 0.25" pos="0 0 0" quat="1 0 0 0"/>
1258  <body pos="0 0 0" name="bodyBox">
1259  <geom type="box" size=".01 0.01 0.25" pos="0 0 0" quat="1 0 0 0"/>
1260  </body>
1261  <body pos="0 0 0" name="bodyCapsule">
1262  <geom type="capsule" size=".01 0.25" pos="0 0 0" quat="1 0 0 0"/>
1263  </body>
1264  <body pos="0 0 0" name="bodySphere">
1265  <geom type="sphere" size=".01" pos="0 0 0" quat="1 0 0 0"/>
1266  </body>
1267  <body pos="0 0 0" name="bodyEllip">
1268  <geom type="ellipsoid" size=".01 0.01 0.25" pos="0 0 0" quat="1 0 0 0"/>
1269  </body>
1270  </body>
1271  </worldbody>
1272  </mujoco>)");
1273 
1274  auto namefile = createTempFile(xmlData);
1275 
1276  Model model_m;
1277  pinocchio::mjcf::buildModel(namefile.name(), model_m);
1278 
1279  GeometryModel geomModel_m;
1280  pinocchio::mjcf::buildGeom(model_m, namefile.name(), pinocchio::COLLISION, geomModel_m);
1281 
1282  BOOST_CHECK(geomModel_m.ngeoms == 5);
1283 
1284  auto * cyl = dynamic_cast<hpp::fcl::Cylinder *>(geomModel_m.geometryObjects.at(0).geometry.get());
1285  BOOST_REQUIRE(cyl);
1286  BOOST_CHECK(cyl->halfLength == 0.25);
1287  BOOST_CHECK(cyl->radius == 0.01);
1288 
1289  auto * cap = dynamic_cast<hpp::fcl::Capsule *>(geomModel_m.geometryObjects.at(2).geometry.get());
1290  BOOST_REQUIRE(cap);
1291  BOOST_CHECK(cap->halfLength == 0.25);
1292  BOOST_CHECK(cap->radius == 0.01);
1293 
1294  auto * s = dynamic_cast<hpp::fcl::Sphere *>(geomModel_m.geometryObjects.at(3).geometry.get());
1295  BOOST_REQUIRE(s);
1296  BOOST_CHECK(s->radius == 0.01);
1297 
1298  auto * b = dynamic_cast<hpp::fcl::Box *>(geomModel_m.geometryObjects.at(1).geometry.get());
1299  BOOST_REQUIRE(b);
1300  Eigen::Vector3d sides;
1301  sides << 0.01, 0.01, 0.25;
1302  BOOST_CHECK(b->halfSide == sides);
1303 
1304  auto * e = dynamic_cast<hpp::fcl::Ellipsoid *>(geomModel_m.geometryObjects.at(4).geometry.get());
1305  BOOST_REQUIRE(e);
1306  BOOST_CHECK(e->radii == sides);
1307 }
1308 #endif // if defined(PINOCCHIO_WITH_HPP_FCL)
1309 
1310 BOOST_AUTO_TEST_CASE(test_contact_parsing)
1311 {
1313  std::string filename = PINOCCHIO_MODEL_DIR + std::string("/../unittest/models/closed_chain.xml");
1314 
1317 
1318  BOOST_CHECK_EQUAL(contact_models.size(), 4);
1319  BOOST_CHECK_EQUAL(
1320  contact_models[0].joint1_placement.translation(), pinocchio::SE3::Vector3(0.50120, 0, 0));
1321  BOOST_CHECK_EQUAL(
1322  contact_models[1].joint1_placement.translation(), pinocchio::SE3::Vector3(0.35012, 0, 0));
1323  BOOST_CHECK_EQUAL(
1324  contact_models[2].joint1_placement.translation(), pinocchio::SE3::Vector3(0.50120, 0, 0));
1325  BOOST_CHECK_EQUAL(
1326  contact_models[3].joint1_placement.translation(), pinocchio::SE3::Vector3(0.35012, 0, 0));
1327  for (const auto & cm : contact_models)
1328  {
1329  BOOST_CHECK(cm.joint2_placement.isApprox(cm.joint1_placement.inverse()));
1330  }
1331 }
1332 
1333 BOOST_AUTO_TEST_CASE(test_default_eulerseq)
1334 {
1335  std::istringstream xmlData(R"(<mujoco model="arm">
1336  <compiler angle="radian" />
1337  <worldbody>
1338  <body name="base">
1339  <body name="body" pos="0 0 0.01" euler="1.57 0 0">
1340  </body>
1341  </body>
1342  </worldbody>
1343  </mujoco>)");
1344 
1345  auto namefile = createTempFile(xmlData);
1346 
1347  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
1348  pinocchio::Model model_m;
1349  MjcfGraph::UrdfVisitor visitor(model_m);
1350 
1351  MjcfGraph graph(visitor, "fakeMjcf");
1352  graph.parseGraphFromXML(namefile.name());
1353  graph.parseRootTree();
1354 
1356  Eigen::AngleAxisd(1.57, Eigen::Vector3d::UnitX()).toRotationMatrix(),
1357  Eigen::Vector3d(0.0, 0.0, 0.01));
1358 
1359  BOOST_CHECK(graph.mapOfBodies["body"].bodyPlacement.isApprox(placement));
1360 }
1361 
1364 BOOST_AUTO_TEST_CASE(parse_mesh_with_vertices)
1365 {
1366  std::istringstream xmlDataNoStrip(R"(<mujoco model="parseVertices">
1367  <asset>
1368  <mesh name="chasis" scale=".01 .006 .0015"
1369  vertex=" 9 2 0
1370  -10 10 10
1371  9 -2 0
1372  10 3 -10
1373  10 -3 -10
1374  -8 10 -10
1375  -10 -10 10
1376  -8 -10 -10
1377  -5 0 20"/>
1378  </asset>
1379  </mujoco>)");
1380 
1381  auto namefile = createTempFile(xmlDataNoStrip);
1382 
1383  typedef ::pinocchio::mjcf::details::MjcfGraph MjcfGraph;
1384  pinocchio::Model model_m;
1385  MjcfGraph::UrdfVisitor visitor(model_m);
1386 
1387  MjcfGraph graph(visitor, "/fakeMjcf/fake.xml");
1388  graph.parseGraphFromXML(namefile.name());
1389 
1390  // Test Meshes
1391  pinocchio::mjcf::details::MjcfMesh mesh = graph.mapOfMeshes.at("chasis");
1392  BOOST_CHECK_EQUAL(mesh.scale, Eigen::Vector3d(0.01, 0.006, 0.0015));
1393  Eigen::MatrixX3d vertices(9, 3);
1394  vertices << 9, 2, 0, -10, 10, 10, 9, -2, 0, 10, 3, -10, 10, -3, -10, -8, 10, -10, -10, -10, 10,
1395  -8, -10, -10, -5, 0, 20;
1396  BOOST_CHECK_EQUAL(mesh.vertices.rows(), 9);
1397  for (auto i = 0; i < mesh.vertices.rows(); ++i)
1398  {
1399  BOOST_CHECK(mesh.vertices.row(i) == vertices.row(i));
1400  }
1401 }
1402 
1403 BOOST_AUTO_TEST_CASE(test_get_unknown_size_vector_from_stream)
1404 {
1406  BOOST_CHECK(v.size() == 0);
1407 
1409  BOOST_CHECK(v1.size() == 3);
1410  Eigen::VectorXd expected(3);
1411  expected << 1, 2, 3;
1412  BOOST_CHECK(v1 == expected);
1413 
1415  4 5 6)");
1416  BOOST_CHECK(v2.size() == 6);
1417  Eigen::VectorXd expected2(6);
1418  expected2 << 1, 2, 3, 4, 5, 6;
1419  BOOST_CHECK(v2 == expected2);
1420 
1422  4 5 6
1423  7 8 9
1424  )");
1425  BOOST_CHECK(v3.size() == 9);
1426  Eigen::VectorXd expected3(9);
1427  expected3 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
1428  BOOST_CHECK(v3 == expected3);
1429 }
1430 
1431 BOOST_AUTO_TEST_SUITE_END()
meshcat-viewer.mesh
mesh
Definition: meshcat-viewer.py:54
pinocchio::InertiaTpl< context::Scalar, context::Options >
pinocchio::InertiaTpl::isEqual
bool isEqual(const InertiaTpl &Y2) const
Definition: spatial/inertia.hpp:620
display-shapes-meshcat.placement
placement
Definition: display-shapes-meshcat.py:24
pinocchio::FrameIndex
Index FrameIndex
Definition: multibody/fwd.hpp:28
frames.hpp
pinocchio::ModelTpl::names
std::vector< std::string > names
Name of the joints.
Definition: multibody/model.hpp:142
pinocchio::InertiaTpl< context::Scalar, context::Options >::FromEllipsoid
static InertiaTpl FromEllipsoid(const Scalar mass, const Scalar x, const Scalar y, const Scalar z)
Computes the Inertia of an ellipsoid defined by its mass and main semi-axis dimensions (x,...
Definition: spatial/inertia.hpp:389
quadrotor-ocp.path
string path
Definition: quadrotor-ocp.py:11
pinocchio::SE3Tpl< context::Scalar, context::Options >::Vector3
traits< SE3Tpl >::Vector3 Vector3
Definition: spatial/se3-tpl.hpp:55
pinocchio::ModelTpl::frames
FrameVector frames
Vector of operational frames registered on the model.
Definition: multibody/model.hpp:176
pinocchio::DataTpl
Definition: context/generic.hpp:25
pinocchio::mjcf::details::MjcfTexture::textType
std::string textType
Definition: mjcf-graph.hpp:220
pinocchio::ModelTpl::jointPlacements
SE3Vector jointPlacements
Vector of joint placements: placement of a joint i wrt its parent joint frame.
Definition: multibody/model.hpp:116
pinocchio::mjcf::details::MjcfMesh
All informations related to a mesh are stored here.
Definition: mjcf-graph.hpp:206
pinocchio::ModelTpl::lowerPositionLimit
ConfigVectorType lowerPositionLimit
Lower joint configuration limit.
Definition: multibody/model.hpp:170
pinocchio::mjcf::details::UrdfVisitor
pinocchio::urdf::details::UrdfVisitor< double, 0, ::pinocchio::JointCollectionDefaultTpl > UrdfVisitor
Definition: mjcf-graph.cpp:18
mjcf.hpp
pinocchio::SE3Tpl
Definition: context/casadi.hpp:29
inverse-kinematics.i
int i
Definition: inverse-kinematics.py:17
mjcf-graph.hpp
model.hpp
hpp::fcl::Sphere
setup.data
data
Definition: cmake/cython/setup.in.py:48
simulation-closed-kinematic-chains.joint1_placement
joint1_placement
Definition: simulation-closed-kinematic-chains.py:54
boost
pinocchio::ModelTpl::joints
JointModelVector joints
Vector of joint models.
Definition: multibody/model.hpp:119
pinocchio::JointModelFreeFlyerTpl
Definition: multibody/joint/fwd.hpp:110
pinocchio::mjcf::details::MjcfMaterial
All informations related to material are stored here.
Definition: mjcf-graph.hpp:228
pinocchio::ModelTpl::name
std::string name
Model name.
Definition: multibody/model.hpp:197
pinocchio::python::context::Model
ModelTpl< Scalar, Options > Model
Definition: bindings/python/context/generic.hpp:63
pinocchio::JointModelCompositeTpl::addJoint
JointModelDerived & addJoint(const JointModelBase< JointModel > &jmodel, const SE3 &placement=SE3::Identity())
Add a joint to the vector of joints.
Definition: joint-composite.hpp:278
hpp::fcl::Cylinder
pinocchio::ModelTpl::addJoint
JointIndex addJoint(const JointIndex parent, const JointModel &joint_model, const SE3 &joint_placement, const std::string &joint_name)
Add a joint to the kinematic tree with infinite bounds.
b
Vec3f b
pinocchio::ModelTpl::rotorInertia
TangentVectorType rotorInertia
Vector of rotor inertia parameters.
Definition: multibody/model.hpp:152
anymal-simulation.model
model
Definition: anymal-simulation.py:8
pinocchio::ModelTpl::inertias
InertiaVector inertias
Vector of spatial inertias supported by each joint.
Definition: multibody/model.hpp:113
pinocchio::SE3Tpl< context::Scalar, context::Options >::Matrix3
traits< SE3Tpl >::Matrix3 Matrix3
Definition: spatial/se3-tpl.hpp:56
pinocchio::InertiaTpl< context::Scalar, context::Options >::Zero
static InertiaTpl Zero()
Definition: spatial/inertia.hpp:337
pinocchio::ModelTpl::JointIndex
pinocchio::JointIndex JointIndex
Definition: multibody/model.hpp:67
pinocchio::ModelTpl::referenceConfigurations
ConfigVectorMap referenceConfigurations
Map of reference configurations, indexed by user given names.
Definition: multibody/model.hpp:145
pinocchio::ModelTpl::subtrees
std::vector< IndexVector > subtrees
Vector of joint subtrees. subtree[j] corresponds to the subtree supported by the joint j....
Definition: multibody/model.hpp:188
pinocchio::GeometryModel::geometryObjects
GeometryObjectVector geometryObjects
Vector of GeometryObjects used for collision computations.
Definition: multibody/geometry.hpp:217
hpp::fcl::Ellipsoid
pinocchio::mjcf::details::MjcfBody::geomChildren
std::vector< MjcfGeom > geomChildren
Definition: mjcf-graph.hpp:110
joint-configuration.hpp
pinocchio::JointModelPrismaticTpl
Definition: multibody/joint/fwd.hpp:89
pinocchio::ModelTpl::nqs
std::vector< int > nqs
Vector of dimension of the joint configuration subspace.
Definition: multibody/model.hpp:125
pinocchio::ModelTpl::nvs
std::vector< int > nvs
Dimension of the *i*th joint tangent subspace.
Definition: multibody/model.hpp:131
pinocchio::ModelTpl::appendBodyToJoint
void appendBodyToJoint(const JointIndex joint_index, const Inertia &Y, const SE3 &body_placement=SE3::Identity())
Append a body to a given joint of the kinematic tree.
pinocchio::RigidConstraintModelTpl
Definition: algorithm/constraints/fwd.hpp:14
pinocchio::ModelTpl::children
std::vector< IndexVector > children
Vector of children index. Chidren of the i*th joint, denoted *mu(i) corresponds to the set (i==parent...
Definition: multibody/model.hpp:139
pinocchio::ModelTpl::idx_qs
std::vector< int > idx_qs
Vector of starting index of the *i*th joint in the configuration space.
Definition: multibody/model.hpp:122
pinocchio::mjcf::details::MjcfTexture::filePath
std::string filePath
Definition: mjcf-graph.hpp:222
filename
filename
pinocchio::ModelTpl::getFrameId
FrameIndex getFrameId(const std::string &name, const FrameType &type=(FrameType)(JOINT|FIXED_JOINT|BODY|OP_FRAME|SENSOR)) const
Returns the index of a frame given by its name.
urdf.hpp
mat
mat
cartpole.v
v
Definition: cartpole.py:153
pinocchio::ModelTpl::rotorGearRatio
TangentVectorType rotorGearRatio
Vector of rotor gear ratio parameters.
Definition: multibody/model.hpp:155
pinocchio::ModelTpl::armature
VectorXs armature
Vector of armature values expressed at the joint level This vector may contain the contribution of ro...
Definition: multibody/model.hpp:149
pinocchio::InertiaTpl< context::Scalar, context::Options >::FromCapsule
static InertiaTpl FromCapsule(const Scalar mass, const Scalar radius, const Scalar height)
Computes the Inertia of a capsule defined by its mass, radius and length along the Z axis....
Definition: spatial/inertia.hpp:439
comparePropertyTrees
static bool comparePropertyTrees(const boost::property_tree::ptree &pt1, const boost::property_tree::ptree &pt2)
Definition: mjcf.cpp:70
pinocchio::urdf::buildModel
ModelTpl< Scalar, Options, JointCollectionTpl > & buildModel(const std::string &filename, const typename ModelTpl< Scalar, Options, JointCollectionTpl >::JointModel &rootJoint, const std::string &rootJointName, ModelTpl< Scalar, Options, JointCollectionTpl > &model, const bool verbose=false)
Build the model from a URDF file with a particular joint as root of the model tree inside the model g...
pinocchio::JointModelSphericalTpl
Definition: multibody/joint/fwd.hpp:73
pos
pos
pinocchio::ModelTpl::nframes
int nframes
Number of operational frames.
Definition: multibody/model.hpp:110
pinocchio::context::Vector3
Eigen::Matrix< Scalar, 3, 1, Options > Vector3
Definition: context/generic.hpp:53
pinocchio::mjcf::details::ptree
boost::property_tree::ptree ptree
Definition: mjcf-graph.cpp:15
pinocchio::ModelTpl::nbodies
int nbodies
Number of bodies.
Definition: multibody/model.hpp:107
pinocchio::ModelTpl::friction
TangentVectorType friction
Vector of joint friction parameters.
Definition: multibody/model.hpp:158
setup.name
name
Definition: cmake/cython/setup.in.py:179
hpp::fcl::Capsule
pinocchio::GeometryModel::ngeoms
Index ngeoms
The number of GeometryObjects.
Definition: multibody/geometry.hpp:214
pinocchio::framesForwardKinematics
void framesForwardKinematics(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< ConfigVectorType > &q)
First calls the forwardKinematics on the model, then computes the placement of each frame....
pinocchio::mjcf::buildGeom
GeometryModel & buildGeom(ModelTpl< Scalar, Options, JointCollectionTpl > &model, const std::string &filename, const GeometryType type, GeometryModel &geom_model, ::hpp::fcl::MeshLoaderPtr mesh_loader=::hpp::fcl::MeshLoaderPtr())
Build The GeometryModel from a Mjcf file.
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(convert_inertia_fullinertia)
Definition: mjcf.cpp:100
PINOCCHIO_STD_VECTOR_WITH_EIGEN_ALLOCATOR
#define PINOCCHIO_STD_VECTOR_WITH_EIGEN_ALLOCATOR(T)
Definition: container/aligned-vector.hpp:13
inverse-kinematics-3d.it
int it
Definition: inverse-kinematics-3d.py:17
pinocchio::JointModelRevoluteTpl
Definition: multibody/joint/fwd.hpp:33
anymal-simulation.mass
mass
Definition: anymal-simulation.py:62
pinocchio::ModelTpl::gravity
Motion gravity
Spatial gravity of the model.
Definition: multibody/model.hpp:191
pinocchio::q
JointCollectionTpl const Eigen::MatrixBase< ConfigVectorType > & q
Definition: joint-configuration.hpp:1083
p1
tuple p1
pinocchio::toRotationMatrix
void toRotationMatrix(const Eigen::MatrixBase< Vector3 > &axis, const Scalar &cos_value, const Scalar &sin_value, const Eigen::MatrixBase< Matrix3 > &res)
Computes a rotation matrix from a vector and values of sin and cos orientations values.
Definition: rotation.hpp:26
quadrotor-ocp.cm
cm
Definition: quadrotor-ocp.py:22
pinocchio::JointModelCompositeTpl
Definition: multibody/joint/fwd.hpp:141
pinocchio::mjcf::buildModel
ModelTpl< Scalar, Options, JointCollectionTpl > & buildModel(const std::string &filename, ModelTpl< Scalar, Options, JointCollectionTpl > &model, const bool verbose=false)
Build the model from a MJCF file with a fixed joint as root of the model tree.
createTempFile
static TemporaryFileHolder createTempFile(const std::istringstream &data)
Definition: mjcf.cpp:53
pinocchio::ModelTpl::damping
TangentVectorType damping
Vector of joint damping parameters.
Definition: multibody/model.hpp:161
pinocchio::ModelTpl::nv
int nv
Dimension of the velocity vector space.
Definition: multibody/model.hpp:101
pinocchio::ModelTpl::ConfigVectorMap
std::map< std::string, ConfigVectorType > ConfigVectorMap
Map between a string (key) and a configuration vector.
Definition: multibody/model.hpp:90
pinocchio::SE3Tpl::Identity
static SE3Tpl Identity()
Definition: spatial/se3-tpl.hpp:136
graph
Definition: graph.py:1
pinocchio::mjcf::details::MjcfBody
All Bodies informations extracted from mjcf model.
Definition: mjcf-graph.hpp:89
joints.hpp
pinocchio::ModelTpl::effortLimit
TangentVectorType effortLimit
Vector of maximal joint torques.
Definition: multibody/model.hpp:164
pinocchio::InertiaTpl< context::Scalar, context::Options >::FromBox
static InertiaTpl FromBox(const Scalar mass, const Scalar x, const Scalar y, const Scalar z)
Computes the Inertia of a box defined by its mass and main dimensions (x,y,z).
Definition: spatial/inertia.hpp:423
pinocchio::GeometryModel
Definition: multibody/geometry.hpp:50
pinocchio::ModelTpl::parents
std::vector< JointIndex > parents
Vector of parent joint indexes. The parent of joint i, denoted li, corresponds to li==parents[i].
Definition: multibody/model.hpp:135
contact-cholesky.contact_models
list contact_models
Definition: contact-cholesky.py:22
pinocchio::COLLISION
@ COLLISION
Definition: multibody/geometry-object.hpp:27
pinocchio::InertiaTpl< context::Scalar, context::Options >::FromSphere
static InertiaTpl FromSphere(const Scalar mass, const Scalar radius)
Computes the Inertia of a sphere defined by its mass and its radius.
Definition: spatial/inertia.hpp:374
pinocchio::ModelTpl::idx_vs
std::vector< int > idx_vs
Starting index of the *i*th joint in the tangent configuration space.
Definition: multibody/model.hpp:128
pinocchio::ModelTpl
Definition: context/generic.hpp:20
pinocchio::ModelTpl::upperPositionLimit
ConfigVectorType upperPositionLimit
Upper joint configuration limit.
Definition: multibody/model.hpp:173
pinocchio::InertiaTpl< context::Scalar, context::Options >::FromCylinder
static InertiaTpl FromCylinder(const Scalar mass, const Scalar radius, const Scalar length)
Computes the Inertia of a cylinder defined by its mass, radius and length along the Z axis.
Definition: spatial/inertia.hpp:406
pinocchio::mjcf::details::internal::getUnknownSizeVectorFromStream
Eigen::VectorXd getUnknownSizeVectorFromStream(const std::string &str)
Definition: mjcf-graph.hpp:567
operator=
AABB & operator=(const AABB &other)=default
pinocchio::ModelTpl::nq
int nq
Dimension of the configuration vector representation.
Definition: multibody/model.hpp:98
pinocchio::mjcf::details::MjcfTexture
All informations related to a texture are stored here.
Definition: mjcf-graph.hpp:217
pinocchio::model
JointCollectionTpl & model
Definition: joint-configuration.hpp:1082
pinocchio
Main pinocchio namespace.
Definition: timings.cpp:27
pinocchio::ModelTpl::njoints
int njoints
Number of joints.
Definition: multibody/model.hpp:104
hpp::fcl::Box
PINOCCHIO_MODEL_DIR
#define PINOCCHIO_MODEL_DIR
Definition: build-reduced-model.cpp:11


pinocchio
Author(s):
autogenerated on Tue Jan 7 2025 03:41:46