in src/esp/io/URDFParser.cpp [1025:1167]
bool Parser::parseJoint(Joint& joint, const tinyxml2::XMLElement* config) {
// Get Joint Name
const char* name = config->Attribute("name");
if (!name) {
ESP_VERY_VERBOSE() << "Unnamed joint found";
return false;
}
joint.m_name = name;
joint.m_parentLinkToJointTransform = Mn::Matrix4(); // Identity
// Get transform from Parent Link to Joint Frame
const XMLElement* origin_xml = config->FirstChildElement("origin");
if (origin_xml) {
if (!parseTransform(joint.m_parentLinkToJointTransform, origin_xml)) {
ESP_VERY_VERBOSE() << "Malformed parent origin element for joint:"
<< joint.m_name;
return false;
}
}
// Get Parent Link
const XMLElement* parent_xml = config->FirstChildElement("parent");
if (parent_xml) {
const char* pname = parent_xml->Attribute("link");
if (!pname) {
ESP_VERY_VERBOSE() << "No parent link name specified for "
"Joint link. this might be the root?"
<< joint.m_name;
return false;
} else {
joint.m_parentLinkName = std::string(pname);
}
}
// Get Child Link
const XMLElement* child_xml = config->FirstChildElement("child");
if (child_xml) {
const char* pname = child_xml->Attribute("link");
if (!pname) {
ESP_VERY_VERBOSE() << "No child link name specified for Joint link"
<< joint.m_name;
return false;
} else {
joint.m_childLinkName = std::string(pname);
}
}
// Get Joint type
const char* type_char = config->Attribute("type");
if (!type_char) {
ESP_VERY_VERBOSE() << "Joint" << joint.m_name
<< "has no type, check to see if it's a reference.";
return false;
}
std::string type_str = type_char;
if (type_str == "spherical")
joint.m_type = SphericalJoint;
else if (type_str == "planar")
joint.m_type = PlanarJoint;
else if (type_str == "floating")
joint.m_type = FloatingJoint;
else if (type_str == "revolute")
joint.m_type = RevoluteJoint;
else if (type_str == "continuous")
joint.m_type = ContinuousJoint;
else if (type_str == "prismatic")
joint.m_type = PrismaticJoint;
else if (type_str == "fixed")
joint.m_type = FixedJoint;
else {
ESP_VERY_VERBOSE() << "Joint" << joint.m_name
<< "has unknown type:" << type_str;
return false;
}
// Get Joint Axis
if (joint.m_type != FloatingJoint && joint.m_type != FixedJoint) {
// axis
const XMLElement* axis_xml = config->FirstChildElement("axis");
if (!axis_xml) {
ESP_VERY_VERBOSE() << "W - urdfdom: no axis elemement for Joint, "
"defaulting to (1,0,0) axis"
<< joint.m_name;
joint.m_localJointAxis = Mn::Vector3(1, 0, 0);
} else {
if (axis_xml->Attribute("xyz")) {
if (!parseVector3(joint.m_localJointAxis, axis_xml->Attribute("xyz"))) {
ESP_VERY_VERBOSE()
<< "Malformed axis element:" << axis_xml->Attribute("xyz")
<< "for joint:" << joint.m_name;
return false;
}
}
}
}
// Get limit
const XMLElement* limit_xml = config->FirstChildElement("limit");
if (limit_xml) {
if (!parseJointLimits(joint, limit_xml)) {
ESP_VERY_VERBOSE() << "Could not parse limit element for joint:"
<< joint.m_name;
return false;
}
} else if (joint.m_type == RevoluteJoint) {
ESP_VERY_VERBOSE()
<< "Joint is of type REVOLUTE but it does not specify limits:"
<< joint.m_name;
return false;
} else if (joint.m_type == PrismaticJoint) {
ESP_VERY_VERBOSE() << "Joint is of type PRISMATIC without limits:"
<< joint.m_name;
return false;
}
joint.m_jointDamping = 0;
joint.m_jointFriction = 0;
// Get Dynamics
const XMLElement* prop_xml = config->FirstChildElement("dynamics");
if (prop_xml) {
// Get joint damping
const char* damping_str = prop_xml->Attribute("damping");
if (damping_str) {
joint.m_jointDamping = std::stod(damping_str);
}
// Get joint friction
const char* friction_str = prop_xml->Attribute("friction");
if (friction_str) {
joint.m_jointFriction = std::stod(friction_str);
}
if (damping_str == nullptr && friction_str == nullptr) {
ESP_VERY_VERBOSE() << "Joint dynamics element specified with "
"no damping and no friction";
return false;
}
}
return true;
}