pinocchio  UNKNOWN
parsers/urdf/model.cpp
1 //
2 // Copyright (c) 2015-2018 CNRS
3 // Copyright (c) 2015 Wandercraft, 86 rue de Paris 91400 Orsay, France.
4 //
5 // This file is part of Pinocchio
6 // Pinocchio is free software: you can redistribute it
7 // and/or modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation, either version
9 // 3 of the License, or (at your option) any later version.
10 //
11 // Pinocchio is distributed in the hope that it will be
12 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // General Lesser Public License for more details. You should have
15 // received a copy of the GNU Lesser General Public License along with
16 // Pinocchio If not, see
17 // <http://www.gnu.org/licenses/>.
18 
19 #include "pinocchio/math/matrix.hpp"
20 #include "pinocchio/parsers/urdf.hpp"
21 #include "pinocchio/parsers/urdf/utils.hpp"
22 #include "pinocchio/multibody/model.hpp"
23 
24 #include <urdf_model/model.h>
25 #include <urdf_parser/urdf_parser.h>
26 
27 #include <sstream>
28 #include <boost/foreach.hpp>
29 #include <limits>
30 
31 namespace se3
32 {
33  namespace urdf
34  {
35  namespace details
36  {
37  const FrameType JOINT_OR_FIXED_JOINT = (FrameType) (JOINT | FIXED_JOINT);
38  const double infty = std::numeric_limits<double>::infinity();
39 
40  FrameIndex getParentJointFrame(const ::urdf::LinkConstSharedPtr link, const Model & model)
41  {
42  assert(link && link->getParent());
43 
44  FrameIndex id;
45  if (!link->getParent()->parent_joint) {
46  if (model.existFrame("root_joint", JOINT_OR_FIXED_JOINT))
47  id = model.getFrameId ("root_joint", JOINT_OR_FIXED_JOINT);
48  else
49  id = 0;
50  } else {
51  if (model.existFrame(link->getParent()->parent_joint->name, JOINT_OR_FIXED_JOINT))
52  id = model.getFrameId (link->getParent()->parent_joint->name, JOINT_OR_FIXED_JOINT);
53  else
54  throw std::invalid_argument ("Model does not have any joints named "
55  + link->getParent()->parent_joint->name);
56  }
57 
58  const Frame & f = model.frames[id];
59  if (f.type == JOINT || f.type == FIXED_JOINT)
60  return id;
61  throw std::invalid_argument ("Parent frame is not a JOINT neither a FIXED_JOINT");
62  }
63 
64  void appendBodyToJoint(Model & model, const FrameIndex fid,
65  const ::urdf::InertialConstSharedPtr Y_ptr,
66  const SE3 & placement,
67  const std::string & body_name)
68  {
69  const Frame& frame = model.frames[fid];
70  const SE3& p = frame.placement * placement;
71  if (frame.parent > 0
72  && Y_ptr
73  && Y_ptr->mass > Eigen::NumTraits<double>::epsilon()) {
74  model.appendBodyToJoint(frame.parent, convertFromUrdf(*Y_ptr), p);
75  }
76  model.addBodyFrame(body_name, frame.parent, p, (int)fid);
77  // Reference to model.frames[fid] can has changed because the vector
78  // may have been reallocated.
79  if (model.frames[fid].parent > 0) {
80  assert (!hasNaN(model.inertias[model.frames[fid].parent].lever())
81  && !hasNaN(model.inertias[model.frames[fid].parent].inertia().data()));
82  }
83  }
84 
88  template<typename JointModel>
89  void addJointAndBody(Model & model, const JointModelBase<JointModel> & jmodel,
90  const FrameIndex & parentFrameId,
91  const SE3 & joint_placement, const std::string & joint_name,
92  const ::urdf::InertialConstSharedPtr Y,
93  const std::string & body_name,
94  const typename JointModel::TangentVector_t & max_effort = JointModel::TangentVector_t::Constant( infty),
95  const typename JointModel::TangentVector_t & max_velocity = JointModel::TangentVector_t::Constant( infty),
96  const typename JointModel::ConfigVector_t & min_config = JointModel::ConfigVector_t ::Constant(-infty),
97  const typename JointModel::ConfigVector_t & max_config = JointModel::ConfigVector_t ::Constant( infty))
98  {
99  Model::JointIndex idx;
100  const Frame & frame = model.frames[parentFrameId];
101 
102  idx = model.addJoint(frame.parent,jmodel,
103  frame.placement * joint_placement,
104  joint_name,
105  max_effort,max_velocity,min_config,max_config
106  );
107  int res (model.addJointFrame(idx, (int)parentFrameId));
108  if (res == -1) {
109  std::ostringstream oss;
110  oss << joint_name << " already inserted as a frame. Current frames "
111  "are [";
112  for (container::aligned_vector<Frame>::const_iterator it =
113  model.frames.begin (); it != model.frames.end (); ++it) {
114  oss << "\"" << it->name << "\",";
115  }
116  oss << "]";
117  throw std::runtime_error (oss.str ().c_str ());
118  }
119  FrameIndex jointFrameId = (FrameIndex) res; // C-style cast to remove polluting compilation warning. This is Bad practice. See issue #323 (rework indexes)
120  appendBodyToJoint(model, jointFrameId, Y, SE3::Identity(), body_name);
121  }
122 
126  void addFixedJointAndBody(Model & model, const FrameIndex& parentFrameId,
127  const SE3 & joint_placement, const std::string & joint_name,
128  const ::urdf::InertialConstSharedPtr Y,
129  const std::string & body_name)
130  {
131  const Frame & frame = model.frames[parentFrameId];
132 
133  int fid = model.addFrame(
134  Frame (joint_name, frame.parent, parentFrameId,
135  frame.placement * joint_placement, FIXED_JOINT)
136  );
137  if (fid < 0)
138  throw std::invalid_argument ("Fixed joint " + joint_name + " could not be added.");
139  appendBodyToJoint(model, (FrameIndex)fid, Y, SE3::Identity(), body_name);
140  }
141 
145  void addJointAndBody(Model & model,
147  const Model::JointIndex parent_id,
148  const SE3 & joint_placement, const std::string & joint_name,
149  const ::urdf::InertialConstSharedPtr Y,
150  const std::string & body_name)
151  {
152  Model::JointIndex idx;
153 
154  idx = model.addJoint(parent_id,jmodel,
155  joint_placement,joint_name);
156 
157  appendBodyToJoint(model,idx,Y,SE3::Identity(),body_name);
158  }
159 
167  void parseTree(::urdf::LinkConstSharedPtr link, Model & model, bool verbose) throw (std::invalid_argument)
168  {
169 
170  // Parent joint of the current body
171  const ::urdf::JointConstSharedPtr joint =
172  ::urdf::const_pointer_cast< ::urdf::Joint>(link->parent_joint);
173 
174  if(joint) // if the link is not the root of the tree
175  {
176  assert(link->getParent());
177 
178  const std::string & joint_name = joint->name;
179  const std::string & link_name = link->name;
180  const std::string & parent_link_name = link->getParent()->name;
181  std::ostringstream joint_info;
182 
183  FrameIndex parentFrameId = getParentJointFrame(link, model);
184 
185  // Transformation from the parent link to the joint origin
186  const SE3 jointPlacement = convertFromUrdf(joint->parent_to_joint_origin_transform);
187 
188  const ::urdf::InertialSharedPtr Y =
189  ::urdf::const_pointer_cast< ::urdf::Inertial>(link->inertial);
190 
191  switch(joint->type)
192  {
193  case ::urdf::Joint::FLOATING:
194  {
195  joint_info << "joint FreeFlyer";
196  addJointAndBody(model,JointModelFreeFlyer(),
197  parentFrameId,jointPlacement,joint->name,
198  Y,link->name);
199 
200  break;
201  }
202  case ::urdf::Joint::REVOLUTE:
203  {
204  joint_info << "joint REVOLUTE with axis";
205 
206  typedef JointModelRX::ConfigVector_t ConfigVector_t;
207  typedef JointModelRX::TangentVector_t TangentVector_t;
208 
209  TangentVector_t max_effort;
210  TangentVector_t max_velocity;
211  ConfigVector_t lower_position;
212  ConfigVector_t upper_position;
213 
214  if (joint->limits)
215  {
216  max_effort << joint->limits->effort;
217  max_velocity << joint->limits->velocity;
218  lower_position << joint->limits->lower;
219  upper_position << joint->limits->upper;
220  }
221  // else
222  // assert(false && "Joint bounds information missing.");
223 
224  CartesianAxis axis = extractCartesianAxis(joint->axis);
225 
226  switch(axis)
227  {
228  case AXIS_X:
229  {
230  joint_info << " along X";
231  addJointAndBody(model,JointModelRX(),
232  parentFrameId,jointPlacement,joint->name,
233  Y,link->name,
234  max_effort,max_velocity,
235  lower_position, upper_position);
236  break;
237  }
238  case AXIS_Y:
239  {
240  joint_info << " along Y";
241  addJointAndBody(model,JointModelRY(),
242  parentFrameId,jointPlacement,joint->name,
243  Y,link->name,
244  max_effort,max_velocity,
245  lower_position, upper_position);
246  break;
247  }
248  case AXIS_Z:
249  {
250  joint_info << " along Z";
251  addJointAndBody(model,JointModelRZ(),
252  parentFrameId,jointPlacement,joint->name,
253  Y,link->name,
254  max_effort,max_velocity,
255  lower_position, upper_position);
256  break;
257  }
258  case AXIS_UNALIGNED:
259  {
260  SE3::Vector3 joint_axis(SE3::Vector3::Zero());
261  joint_axis << joint->axis.x,joint->axis.y,joint->axis.z;
262  joint_info << " unaligned along (" << joint_axis.transpose() << ")";
263 
264  addJointAndBody(model,JointModelRevoluteUnaligned(joint_axis.normalized()),
265  parentFrameId,jointPlacement,joint->name,
266  Y,link->name,
267  max_effort,max_velocity,
268  lower_position, upper_position);
269  break;
270  }
271  default:
272  {
273  assert(false && "The axis type of the revolute joint is of wrong type.");
274  break;
275  }
276  }
277  break;
278  }
279  case ::urdf::Joint::CONTINUOUS: // Revolute joint with no joint limits
280  {
281  joint_info << "joint CONTINUOUS with axis";
282 
283  typedef JointModelRUBX::ConfigVector_t ConfigVector_t;
284  typedef JointModelRUBX::TangentVector_t TangentVector_t;
285 
286  TangentVector_t max_effort;
287  TangentVector_t max_velocity;
288  const ConfigVector_t::Scalar u = 1.01;
289  ConfigVector_t lower_position(-u, -u);
290  ConfigVector_t upper_position( u, u);
291 
292  if (joint->limits)
293  {
294  max_effort << joint->limits->effort;
295  max_velocity << joint->limits->velocity;
296  }
297 
298  CartesianAxis axis = extractCartesianAxis(joint->axis);
299 
300  switch(axis)
301  {
302  case AXIS_X:
303  {
304  joint_info << " along X";
305  addJointAndBody(model,JointModelRUBX(),
306  parentFrameId,jointPlacement,joint->name,
307  Y,link->name,
308  max_effort,max_velocity,
309  lower_position, upper_position);
310  break;
311  }
312  case AXIS_Y:
313  {
314  joint_info << " along Y";
315  addJointAndBody(model,JointModelRUBY(),
316  parentFrameId,jointPlacement,joint->name,
317  Y,link->name,
318  max_effort,max_velocity,
319  lower_position, upper_position);
320  break;
321  }
322  case AXIS_Z:
323  {
324  joint_info << " along Z";
325  addJointAndBody(model,JointModelRUBZ(),
326  parentFrameId,jointPlacement,joint->name,
327  Y,link->name,
328  max_effort,max_velocity,
329  lower_position, upper_position);
330  break;
331  }
332  case AXIS_UNALIGNED:
333  {
334  SE3::Vector3 joint_axis(SE3::Vector3::Zero());
335  joint_axis << joint->axis.x,joint->axis.y,joint->axis.z;
336  joint_info << " unaligned along (" << joint_axis.transpose() << ")";
337 
338  addJointAndBody(model,JointModelRevoluteUnaligned(joint_axis.normalized()),
339  parentFrameId,jointPlacement,joint->name,
340  Y,link->name,
341  max_effort,max_velocity);
342  break;
343  }
344  default:
345  {
346  assert(false && "The axis type of the revolute joint is of wrong type.");
347  break;
348  }
349  }
350  break;
351  }
352  case ::urdf::Joint::PRISMATIC:
353  {
354  joint_info << "joint PRISMATIC with axis";
355 
356  typedef JointModelRX::ConfigVector_t ConfigVector_t;
357  typedef JointModelRX::TangentVector_t TangentVector_t;
358 
359  TangentVector_t max_effort;
360  TangentVector_t max_velocity;
361  ConfigVector_t lower_position;
362  ConfigVector_t upper_position;
363 
364  if (joint->limits)
365  {
366  max_effort << joint->limits->effort;
367  max_velocity << joint->limits->velocity;
368  lower_position << joint->limits->lower;
369  upper_position << joint->limits->upper;
370  }
371 
372  CartesianAxis axis = extractCartesianAxis(joint->axis);
373  switch(axis)
374  {
375  case AXIS_X:
376  {
377  joint_info << " along X";
378  addJointAndBody(model,JointModelPX(),
379  parentFrameId,jointPlacement,joint->name,
380  Y,link->name,
381  max_effort,max_velocity,
382  lower_position, upper_position);
383  break;
384  }
385  case AXIS_Y:
386  {
387  joint_info << " along Y";
388  addJointAndBody(model,JointModelPY(),
389  parentFrameId,jointPlacement,joint->name,
390  Y,link->name,
391  max_effort,max_velocity,
392  lower_position, upper_position);
393  break;
394  }
395  case AXIS_Z:
396  {
397  joint_info << " along Z";
398  addJointAndBody(model,JointModelPZ(),
399  parentFrameId,jointPlacement,joint->name,
400  Y,link->name,
401  max_effort,max_velocity,
402  lower_position, upper_position);
403  break;
404  }
405  case AXIS_UNALIGNED:
406  {
407  SE3::Vector3 joint_axis(SE3::Vector3::Zero());
408  joint_axis << joint->axis.x,joint->axis.y,joint->axis.z;
409  joint_info << " unaligned along (" << joint_axis.transpose() << ")";
410 
411  addJointAndBody(model,JointModelPrismaticUnaligned(joint_axis.normalized()),
412  parentFrameId,jointPlacement,joint->name,
413  Y,link->name,
414  max_effort,max_velocity,
415  lower_position, upper_position);
416  break;
417  }
418  default:
419  {
420  assert(false && "The axis type of the prismatic joint is of wrong type.");
421  break;
422  }
423  }
424  break;
425  }
426  case ::urdf::Joint::PLANAR:
427  {
428  joint_info << "joint PLANAR with normal axis along Z";
429 
430  typedef JointModelPlanar::ConfigVector_t ConfigVector_t;
431  typedef JointModelPlanar::TangentVector_t TangentVector_t;
432 
433  TangentVector_t max_effort;
434  TangentVector_t max_velocity;
435  ConfigVector_t lower_position;
436  ConfigVector_t upper_position;
437 
438  if (joint->limits)
439  {
440  max_effort << joint->limits->effort;
441  max_velocity << joint->limits->velocity;
442  lower_position << joint->limits->lower;
443  upper_position << joint->limits->upper;
444  }
445 
446  addJointAndBody(model,JointModelPlanar(),
447  parentFrameId,jointPlacement,joint->name,
448  Y,link->name,
449  max_effort,max_velocity,
450  lower_position, upper_position);
451 
452  break;
453  }
454  case ::urdf::Joint::FIXED:
455  {
456  // In case of fixed joint, if link has inertial tag:
457  // -add the inertia of the link to his parent in the model
458  // Otherwise do nothing.
459  // In all cases:
460  // -let all the children become children of parent
461  // -inform the parser of the offset to apply
462  // -add fixed body in model to display it in gepetto-viewer
463 
464  joint_info << "fixed joint";
465  addFixedJointAndBody(model, parentFrameId, jointPlacement,
466  joint_name, Y, link_name);
467 
468  break;
469  }
470  default:
471  {
472  const std::string exception_message ("The type of joint " + joint_name + " is not supported.");
473  throw std::invalid_argument(exception_message);
474  break;
475  }
476  }
477 
478  if (verbose)
479  {
480  const Inertia YY = (!Y) ? Inertia::Zero() : convertFromUrdf(*Y);
481  std::cout << "Adding Body" << std::endl;
482  std::cout << "\"" << link_name << "\" connected to " << "\"" << parent_link_name << "\" throw joint " << "\"" << joint_name << "\"" << std::endl;
483  std::cout << "joint type: " << joint_info.str() << std::endl;
484  std::cout << "joint placement:\n" << jointPlacement;
485  std::cout << "body info: " << std::endl;
486  std::cout << " " << "mass: " << YY.mass() << std::endl;
487  std::cout << " " << "lever: " << YY.lever().transpose() << std::endl;
488  std::cout << " " << "inertia elements (Ixx,Iyx,Iyy,Izx,Izy,Izz): " << YY.inertia().data().transpose() << std::endl << std::endl;
489  }
490  }
491  else if (link->getParent())
492  {
493  const std::string exception_message (link->name + " - joint information missing.");
494  throw std::invalid_argument(exception_message);
495  }
496 
497 
498  BOOST_FOREACH(::urdf::LinkConstSharedPtr child, link->child_links)
499  {
500  parseTree(child, model, verbose);
501  }
502  }
503 
512  void parseRootTree (::urdf::LinkConstSharedPtr root_link, Model & model, const bool verbose) throw (std::invalid_argument)
513  {
514  addFixedJointAndBody(model, 0, SE3::Identity(), "root_joint",
515  root_link->inertial, root_link->name);
516 
517  BOOST_FOREACH(::urdf::LinkConstSharedPtr child, root_link->child_links)
518  {
519  parseTree(child, model, verbose);
520  }
521 
522  // Inertias might be zero due to the URDF file. This is not a bug. However, it would lead to some
523  // algorithms of Pinocchio not to work.
524  // TODO: add an algorithm or a method in model to check the validity of the value wrt to the algorithms the user want to use.
525  // See also #306 on GitHub.
526  }
527 
537  template <typename D>
538  void parseRootTree (::urdf::LinkConstSharedPtr root_link, Model & model, const JointModelBase<D> & root_joint, const bool verbose) throw (std::invalid_argument)
539  {
540  addJointAndBody(model,root_joint,
541  0,SE3::Identity(),"root_joint",
542  root_link->inertial,root_link->name);
543 
544  BOOST_FOREACH(::urdf::LinkConstSharedPtr child, root_link->child_links)
545  {
546  parseTree(child, model, verbose);
547  }
548 
549  // FIXME: See fixme in previous parseRootTree definition
550  }
551  } // namespace details
552 
556  struct ParseRootTreeVisitor : public boost::static_visitor<>
557  {
558  ::urdf::LinkConstSharedPtr m_root_link;
559  Model & m_model;
560  const bool m_verbose;
561 
562  ParseRootTreeVisitor(::urdf::LinkConstSharedPtr root_link, Model & model, const bool verbose)
563  : m_root_link(root_link)
564  , m_model(model)
565  , m_verbose(verbose)
566  {}
567 
568  template<typename Derived>
569  void operator()(const JointModelBase<Derived> & root_joint) const
570  {
571  details::parseRootTree(m_root_link,m_model,root_joint,m_verbose);
572  }
573 
574  static void run(::urdf::LinkConstSharedPtr root_link, Model & model, const JointModelVariant & root_joint, const bool verbose)
575  {
576  boost::apply_visitor(ParseRootTreeVisitor(root_link,model,verbose),root_joint);
577  }
578  }; // struct ParseRootTreeVisitor
579 
580  Model& buildModel(const std::string & filename,
581  const JointModelVariant & root_joint,
582  Model & model,
583  const bool verbose)
584  throw (std::invalid_argument)
585  {
586  ::urdf::ModelInterfaceSharedPtr urdfTree = ::urdf::parseURDFFile (filename);
587 
588  if (urdfTree)
589  {
590  return buildModel (urdfTree, root_joint, model, verbose);
591  }
592  else
593  {
594  const std::string exception_message ("The file " + filename + " does not contain a valid URDF model.");
595  throw std::invalid_argument(exception_message);
596  }
597  return model;
598  }
599 
600  Model& buildModel(const std::string & filename, Model& model,const bool verbose)
601  throw (std::invalid_argument)
602  {
603  ::urdf::ModelInterfaceSharedPtr urdfTree = ::urdf::parseURDFFile (filename);
604  if (urdfTree)
605  {
606  return buildModel (urdfTree, model, verbose);
607  }
608  else
609  {
610  const std::string exception_message ("The file " + filename + " does not contain a valid URDF model.");
611  throw std::invalid_argument(exception_message);
612  }
613 
614  return model;
615  }
616 
617  Model & buildModelFromXML(const std::string & xmlStream,
618  const JointModelVariant & rootJoint,
619  Model & model,
620  const bool verbose) throw (std::invalid_argument)
621  {
622  ::urdf::ModelInterfaceSharedPtr urdfTree = ::urdf::parseURDF(xmlStream);
623 
624  if (urdfTree)
625  return buildModel(urdfTree, rootJoint, model, verbose);
626  else
627  {
628  const std::string exception_message ("The XML stream does not contain a valid URDF model.");
629  throw std::invalid_argument(exception_message);
630  }
631 
632  return model;
633  }
634 
635  Model & buildModelFromXML(const std::string & xmlStream,
636  Model & model,
637  const bool verbose) throw (std::invalid_argument)
638  {
639  ::urdf::ModelInterfaceSharedPtr urdfTree = ::urdf::parseURDF(xmlStream);
640 
641  if (urdfTree)
642  return buildModel(urdfTree, model, verbose);
643  else
644  {
645  const std::string exception_message ("The XML stream does not contain a valid URDF model.");
646  throw std::invalid_argument(exception_message);
647  }
648 
649  return model;
650  }
651 
652  Model& buildModel(const ::urdf::ModelInterfaceSharedPtr & urdfTree,
653  const JointModelVariant & root_joint,
654  Model & model,
655  const bool verbose)
656  {
657  assert(urdfTree);
658  model.name = urdfTree->getName();
659  ParseRootTreeVisitor::run(urdfTree->getRoot(),model,root_joint,verbose);
660  return model;
661  }
662 
663  Model& buildModel(const ::urdf::ModelInterfaceSharedPtr & urdfTree,
664  Model& model,
665  const bool verbose)
666  {
667  assert(urdfTree);
668  model.name = urdfTree->getName();
669  details::parseRootTree(urdfTree->getRoot(),model,verbose);
670  return model;
671  }
672 
673  } // namespace urdf
674 } // namespace se3
std::string name
Model name;.
Definition: model.hpp:112
Call parse root tree templated function.
Definition: types.hpp:42
JointIndex id(const JointModelVariant &jmodel)
Visit a JointModelVariant through JointIdVisitor to get the index of the joint in the kinematic chain...
FrameType
Enum on the possible types of frame.
Definition: frame.hpp:31