16 typedef pinocchio::urdf::details::
17 UrdfVisitor<double, 0, ::pinocchio::JointCollectionDefaultTpl>
21 static const std::array<std::string, 3>
ELEMENTS = {
"joint",
"geom",
"site"};
29 dst.put(ptree::path_type(
v.first),
v.second.data());
37 for (
const std::string & el :
ELEMENTS)
39 std::string
path = el +
".<xmlattr>";
44 const ptree & attr_current = current.get_child(
path, default_value);
49 current.put_child(
path, attr_parent);
56 auto n = el.get_optional<std::string>(
"<xmlattr>.name");
61 if (filePath.extension().empty())
62 throw std::invalid_argument(
"Cannot find extension for one of the mesh/texture");
64 auto st = filePath.stem();
68 throw std::invalid_argument(
"Cannot find a name for one of the mesh.texture");
74 const std::string & dir,
75 const std::string & modelPath,
78 namespace fs = boost::filesystem;
81 if (filePath.is_absolute() && !strippath)
90 if (meshPath.is_absolute())
95 return (mainPath.parent_path() / meshPath /
filename);
107 Eigen::Matrix3d aa1 =
109 Eigen::Matrix3d aa2 =
111 Eigen::Matrix3d aa3 =
114 return aa1 * aa2 * aa3;
117 template<
int Nq,
int Nv>
120 typedef UrdfVisitor::Vector Vector;
121 const double infty = std::numeric_limits<double>::infinity();
124 ret.
maxEffort = Vector::Constant(Nv, infty);
125 ret.
maxVel = Vector::Constant(Nv, infty);
126 ret.
maxConfig = Vector::Constant(Nq, 1.01);
127 ret.
minConfig = Vector::Constant(Nq, -1.01);
128 ret.
friction = Vector::Constant(Nv, 0.);
129 ret.
damping = Vector::Constant(Nv, 0.);
137 template<
int Nq,
int Nv>
170 if (!use_limits && el.get_optional<std::string>(
"<xmlattr>.range"))
171 throw std::invalid_argument(
"Range limit is specified but it was not specify to use it.");
174 auto type_s = el.get_optional<std::string>(
"<xmlattr>.type");
179 auto ax = el.get_optional<std::string>(
"<xmlattr>.axis");
181 axis = internal::getVectorFromStream<3>(*
ax);
184 auto range_ = el.get_optional<std::string>(
"<xmlattr>.range");
187 Eigen::Vector2d rangeT = internal::getVectorFromStream<2>(*range_);
192 range_ = el.get_optional<std::string>(
"<xmlattr>.actuatorfrcrange");
195 Eigen::Vector2d rangeT = internal::getVectorFromStream<2>(*range_);
200 auto value = el.get_optional<
double>(
"<xmlattr>.springref");
205 value = el.get_optional<
double>(
"<xmlattr>.damping");
209 value = el.get_optional<
double>(
"<xmlattr>.armature");
214 value = el.get_optional<
double>(
"<xmlattr>.frictionloss");
218 value = el.get_optional<
double>(
"<xmlattr>.ref");
226 throw std::invalid_argument(
227 "Reference position can only be used with hinge or slide joints.");
234 bool use_limit =
true;
236 auto name_s = el.get_optional<std::string>(
"<xmlattr>.name");
247 auto use_ls = el.get_optional<std::string>(
"<xmlattr>.limited");
248 use_limit = *use_ls ==
"true";
259 if (
auto joint_p = classE.
classElement.get_child_optional(
"joint"))
263 auto cl_s = el.get_optional<std::string>(
"<xmlattr>.class");
266 std::string className = *cl_s;
268 if (
auto joint_p = classE.
classElement.get_child_optional(
"joint"))
281 auto pos = el.get_optional<std::string>(
"<xmlattr>.pos");
283 placement.translation() = internal::getVectorFromStream<3>(*
pos);
287 auto rot_s = el.get_optional<std::string>(
"<xmlattr>.quat");
290 Eigen::Vector4d
quat = internal::getVectorFromStream<4>(*rot_s);
293 quaternion.normalize();
294 placement.rotation() = quaternion.toRotationMatrix();
297 else if ((rot_s = el.get_optional<std::string>(
"<xmlattr>.axisangle")))
299 Eigen::Vector4d axis_angle = internal::getVectorFromStream<4>(*rot_s);
301 double angle = axis_angle(3);
304 placement.rotation() = angleAxis.toRotationMatrix();
307 else if ((rot_s = el.get_optional<std::string>(
"<xmlattr>.euler")))
309 Eigen::Vector3d angles = internal::getVectorFromStream<3>(*rot_s);
313 else if ((rot_s = el.get_optional<std::string>(
"<xmlattr>.xyaxes")))
315 Eigen::Matrix<double, 6, 1> xyaxes = internal::getVectorFromStream<6>(*rot_s);
317 Eigen::Vector3d xAxis = xyaxes.head(3);
319 Eigen::Vector3d yAxis = xyaxes.tail(3);
322 double d = xAxis.dot(yAxis);
326 Eigen::Vector3d zAxis = xAxis.cross(yAxis);
336 else if ((rot_s = el.get_optional<std::string>(
"<xmlattr>.zaxis")))
338 Eigen::Vector3d zaxis = internal::getVectorFromStream<3>(*rot_s);
341 Eigen::Quaterniond::FromTwoVectors(Eigen::Vector3d::UnitZ(), zaxis).toRotationMatrix();
351 throw std::invalid_argument(
"Mass of body is not supposed to be negative");
354 auto com_s = el.get_optional<std::string>(
"<xmlattr>.pos");
356 com = internal::getVectorFromStream<3>(*com_s);
358 com = Inertia::Vector3::Zero();
362 Inertia::Matrix3 I = Eigen::Matrix3d::Identity();
364 auto inertia_s = el.get_optional<std::string>(
"<xmlattr>.diaginertia");
367 Eigen::Vector3d inertiaDiag = internal::getVectorFromStream<3>(*inertia_s);
368 I = inertiaDiag.asDiagonal();
371 else if ((inertia_s = el.get_optional<std::string>(
"<xmlattr>.fullinertia")))
375 inertiaStream >> I(0, 0);
376 inertiaStream >> I(1, 1);
377 inertiaStream >> I(2, 2);
378 inertiaStream >> I(0, 1);
379 inertiaStream >> I(0, 2);
380 inertiaStream >> I(1, 2);
388 for (
int i = 0;
i < 3;
i++)
396 const boost::optional<std::string> & childClass,
397 const std::string & parentName)
400 auto chcl_s = childClass;
403 throw std::invalid_argument(
"Cannot get inertia from geom and no inertia was found");
405 bool usegeominertia =
false;
407 usegeominertia =
true;
410 usegeominertia =
true;
415 if (
v.first ==
"<xmlattr>")
418 auto name_s =
v.second.get_optional<std::string>(
"name");
422 currentBody.
bodyName = parentName +
"Bis";
429 if (
auto chcl_st =
v.second.get_optional<std::string>(
"childclass"))
438 auto cl_s =
v.second.get_optional<std::string>(
"class");
445 if (
v.first ==
"inertial" && !usegeominertia)
449 if (
v.first ==
"geom")
452 currentGeom.
fill(
v.second, currentBody, *
this);
457 if (
v.first ==
"joint")
460 currentJoint.
fill(
v.second, currentBody, *
this);
463 if (
v.first ==
"freejoint")
467 auto jointName =
v.second.get_optional<std::string>(
"<xmlattr>.name");
475 if (
v.first ==
"site")
478 currentSite.
fill(
v.second, currentBody, *
this);
481 if (
v.first ==
"body")
493 inert_temp += geom.geomPlacement.act(geom.geomInertia);
502 namespace fs = boost::filesystem;
504 auto file = el.get_optional<std::string>(
"<xmlattr>.file");
505 auto name_ = el.get_optional<std::string>(
"<xmlattr>.name");
506 auto type = el.get_optional<std::string>(
"<xmlattr>.type");
515 std::cout <<
"Warning - Only texture with files are supported" << std::endl;
517 throw std::invalid_argument(
"Textures need a name.");
528 auto str_v = el.get_optional<std::string>(
"<xmlattr>.type");
532 if ((str_v = el.get_optional<std::string>(
"<xmlattr>.gridsize")))
533 text.
gridsize = internal::getVectorFromStream<2>(*str_v);
542 auto n = el.get_optional<std::string>(
"<xmlattr>.name");
546 throw std::invalid_argument(
"Material was given without a name");
549 auto cl_s = el.get_optional<std::string>(
"<xmlattr>.class");
552 std::string className = *cl_s;
554 if (
auto mat_p = classE.
classElement.get_child_optional(
"material"))
555 mat.goThroughElement(*mat_p);
558 mat.goThroughElement(el);
565 namespace fs = boost::filesystem;
568 auto file = el.get_optional<std::string>(
"<xmlattr>.file");
570 throw std::invalid_argument(
"Only meshes with files are supported");
578 auto scale = el.get_optional<std::string>(
"<xmlattr>.scale");
580 mesh.scale = internal::getVectorFromStream<3>(*scale);
589 if (
v.first ==
"mesh")
592 if (
v.first ==
"material")
595 if (
v.first ==
"texture")
598 if (
v.first ==
"hfield")
599 throw std::invalid_argument(
"hfields are not supported yet");
605 boost::optional<std::string> nameClass;
608 if (
v.first ==
"<xmlattr>")
610 nameClass =
v.second.get_optional<std::string>(
"class");
617 mapOfClasses.insert(std::make_pair(*nameClass, classDefault));
620 throw std::invalid_argument(
"Class does not have a name. Cannot parse model.");
622 if (
v.first ==
"default")
630 auto auto_s = el.get_optional<std::string>(
"<xmlattr>.autolimits");
632 if (*auto_s ==
"true")
636 auto strip_s = el.get_optional<std::string>(
"<xmlattr>.strippath");
638 if (*strip_s ==
"true")
642 auto dir = el.get_optional<std::string>(
"<xmlattr>.assetdir");
649 if ((dir = el.get_optional<std::string>(
"<xmlattr>.meshdir")))
652 if ((dir = el.get_optional<std::string>(
"<xmlattr>.texturedir")))
655 auto value_v = el.get_optional<
double>(
"<xmlattr>.boundmass");
659 if ((value_v = el.get_optional<
double>(
"<xmlattr>.boundinertia")))
662 auto in_g = el.get_optional<std::string>(
"<xmlattr>.inertiafromgeom");
667 else if (*in_g ==
"false")
672 auto angle_s = el.get_optional<std::string>(
"<xmlattr>.angle");
674 if (*angle_s ==
"radian")
677 auto eulerS = el.get_optional<std::string>(
"<xmlattr>.eulerseq");
680 std::string eulerseq = *eulerS;
681 if (eulerseq.find_first_not_of(
"xyzXYZ") != std::string::npos || eulerseq.size() != 3)
682 throw std::invalid_argument(
683 "Model tried to use euler angles but euler sequence is wrong");
687 for (std::size_t
i = 0;
i < eulerseq.size();
i++)
711 throw std::invalid_argument(
"Euler Axis does not exist");
723 if (
v.first ==
"key")
725 auto nameKey =
v.second.get_optional<std::string>(
"<xmlattr>.name");
728 auto configVectorS =
v.second.get_optional<std::string>(
"<xmlattr>.qpos");
731 Eigen::VectorXd configVector =
733 mapOfConfigs.insert(std::make_pair(*nameKey, configVector));
744 std::string
type =
v.first;
750 if (
type !=
"connect")
760 auto body1 =
v.second.get_optional<std::string>(
"<xmlattr>.body1");
764 throw std::invalid_argument(
"Equality constraint needs a first body");
767 auto body2 =
v.second.get_optional<std::string>(
"<xmlattr>.body2");
772 auto name =
v.second.get_optional<std::string>(
"<xmlattr>.name");
779 auto anchor =
v.second.get_optional<std::string>(
"<xmlattr>.anchor");
781 eq.
anchor = internal::getVectorFromStream<3>(*anchor);
790 if (
pt.get_child_optional(
"mujoco"))
791 el =
pt.get_child(
"mujoco");
793 throw std::invalid_argument(
"This is not a standard mujoco model. Cannot parse it.");
798 if (
v.first ==
"<xmlattr>")
800 auto n_s =
v.second.get_optional<std::string>(
"model");
804 throw std::invalid_argument(
"Model is missing a name. Cannot parse it");
807 if (
v.first ==
"compiler")
810 if (
v.first ==
"default")
813 if (
v.first ==
"asset")
816 if (
v.first ==
"keyframe")
819 if (
v.first ==
"worldbody")
821 boost::optional<std::string> childClass;
825 if (
v.first ==
"equality")
834 boost::property_tree::read_xml(xmlStr,
pt);
838 template<
typename TypeX,
typename TypeY,
typename TypeZ,
typename TypeUnaligned>
841 if (
axis.isApprox(Eigen::Vector3d::UnitX()))
843 else if (
axis.isApprox(Eigen::Vector3d::UnitY()))
845 else if (
axis.isApprox(Eigen::Vector3d::UnitZ()))
848 return TypeUnaligned(
axis.normalized());
864 UrdfVisitor::JointType jType;
871 jType = UrdfVisitor::FLOATING;
877 jType = UrdfVisitor::PRISMATIC;
883 jType = UrdfVisitor::SPHERICAL;
889 jType = UrdfVisitor::REVOLUTE;
892 throw std::invalid_argument(
"Unknown joint type");
895 jType, joint.
axis, parentFrameId, jointInParent, joint.
jointName, inert, bodyInJoint,
926 std::string jointName = nameOfBody +
"_fixed";
927 urdfVisitor << jointName <<
" being parsed." <<
'\n';
929 urdfVisitor.addFixedJointAndBody(parentFrameId, bodyPose, jointName, inert, nameOfBody);
933 bool composite =
false;
934 SE3 jointPlacement, firstJointPlacement, prevJointPlacement =
SE3::Identity();
938 std::string jointName;
945 jointName =
"Composite_" + firstOne.
jointName;
961 if (joint.jointType ==
"free")
962 throw std::invalid_argument(
"Joint Composite trying to be created with a freeFlyer");
964 SE3 jointInParent = bodyPose * joint.jointPlacement;
965 bodyInJoint = joint.jointPlacement.
inverse();
968 firstJointPlacement = jointInParent;
973 jointPlacement = prevJointPlacement.
inverse() * jointInParent;
974 if (joint.jointType ==
"slide")
977 createJoint<JointModelPX, JointModelPY, JointModelPZ, JointModelPrismaticUnaligned>(
981 rangeCompo = rangeCompo.
concatenate<1, 1>(joint.range);
983 else if (joint.jointType ==
"ball")
986 rangeCompo = rangeCompo.
concatenate<4, 3>(joint.range.setDimension<4, 3>());
988 else if (joint.jointType ==
"hinge")
991 createJoint<JointModelRX, JointModelRY, JointModelRZ, JointModelRevoluteUnaligned>(
994 rangeCompo = rangeCompo.
concatenate<1, 1>(joint.range);
997 throw std::invalid_argument(
"Unknown joint type trying to be parsed.");
999 prevJointPlacement = jointInParent;
1004 frame.parentJoint, jointM,
frame.placement * firstJointPlacement, jointName,
1008 urdfVisitor.appendBodyToJoint(jointFrameId, inert, bodyInJoint, nameOfBody);
1026 if (joint.jointType ==
"free")
1031 else if (joint.jointType ==
"ball")
1036 else if (joint.jointType ==
"slide" || joint.jointType ==
"hinge")
1048 if (keyframe.size() == model_nq)
1050 Eigen::VectorXd qpos(model_nq);
1051 for (std::size_t
i = 1;
i <
urdfVisitor.model.joints.size();
i++)
1054 int idx_q = joint.idx_q();
1055 int nq = joint.nq();
1057 Eigen::VectorXd qpos_j = keyframe.segment(
idx_q,
nq);
1059 if (joint.shortname() ==
"JointModelFreeFlyer")
1061 Eigen::Vector4d new_quat(qpos_j(4), qpos_j(5), qpos_j(6), qpos_j(3));
1062 qpos_j.tail(4) = new_quat;
1064 else if (joint.shortname() ==
"JointModelSpherical")
1066 Eigen::Vector4d new_quat(qpos_j(1), qpos_j(2), qpos_j(3), qpos_j(0));
1069 else if (joint.shortname() ==
"JointModelComposite")
1071 for (
const auto & joint_ : boost::get<JointModelComposite>(joint.toVariant()).joints)
1073 int idx_q_ = joint_.idx_q() -
idx_q;
1074 int nq_ = joint_.nq();
1075 if (joint_.shortname() ==
"JointModelSpherical")
1077 Eigen::Vector4d new_quat(
1078 qpos_j(idx_q_ + 1), qpos_j(idx_q_ + 2), qpos_j(idx_q_ + 3), qpos_j(idx_q_));
1079 qpos_j.segment(idx_q_, nq_) = new_quat;
1082 qpos_j.segment(idx_q_, nq_) -=
q_ref.segment(idx_q_, nq_);
1088 qpos.segment(
idx_q,
nq) = qpos_j;
1091 urdfVisitor.model.referenceConfigurations.insert(std::make_pair(keyName, qpos));
1094 throw std::invalid_argument(
"Keyframe size does not match model size");