Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

URDF->SDF handle links with no inertia or small mass #1238

Merged
merged 47 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
a7d8a24
Adding tests that catch warnings when urdf have no inertia element, o…
aaronchongth Feb 8, 2023
15845d8
Promote link inertia and mass related urdf2sdf sdfdbg to sdfwarn with…
aaronchongth Feb 9, 2023
bcd9459
Added flag for converting urdf links with small or no mass to frames
aaronchongth Feb 10, 2023
90bfe5f
Converts urdf links with small or no mass to frames, added tests
aaronchongth Feb 10, 2023
09e148e
Adding warning when conversion happens, added tests for small masses,…
aaronchongth Feb 10, 2023
053f70e
Fix cpplint errors
aaronchongth Feb 10, 2023
c5f757d
Adding integration test
aaronchongth Feb 14, 2023
9b0aca3
Fix lint
aaronchongth Feb 14, 2023
d829d50
Use camelCase
aaronchongth Feb 16, 2023
089b8a7
Added URDFMinimumAllowedLinkMass
aaronchongth Feb 16, 2023
4887eae
Fix tests expecting warnings when converting to frames
aaronchongth Feb 17, 2023
cb6d540
Adding inline contains and notContains to test_utils
aaronchongth Feb 17, 2023
d4de275
Using RedirectConsoleStream and ScopeExit
aaronchongth Feb 17, 2023
ecdad41
Refactor to use Root::LoadSdfString
aaronchongth Feb 17, 2023
2d01243
Removing debug message when converted frame is from a root link
aaronchongth Feb 17, 2023
1e5a2da
Added attached_to for frames during conversion, using < instead of ma…
aaronchongth Feb 21, 2023
27bf7b7
Update brief of URDFSetConvertLinkWithNoMassToFrame to mention case o…
aaronchongth Feb 21, 2023
d0a2770
Remove stale commentted code
aaronchongth Feb 21, 2023
2f86ca7
Update comment about the errors we are expecting
aaronchongth Feb 21, 2023
e1b488b
Convert to frame by default, remove minimal mass option, refactor imp…
aaronchongth Feb 28, 2023
a880d4f
Only convert to frame when parent joint is fixed, attaches and transf…
aaronchongth Mar 1, 2023
bfb68c8
Rephrased conversion error, modified unit tests
aaronchongth Mar 1, 2023
dff421c
prints zero mass errors as well when conversion to frame fails
aaronchongth Mar 2, 2023
dd687c3
integration tests that mimic the unit tests
aaronchongth Mar 2, 2023
3d2bf35
Added integration test with valid and invalid use of force torque sen…
aaronchongth Mar 2, 2023
c53243c
Merge branch 'sdf12' into aaron/urdf-inertia-handling
aaronchongth Mar 2, 2023
c9a7f4b
Fix lint
aaronchongth Mar 2, 2023
d29328b
Fix joint reduction logic, more specific error messages, more targete…
aaronchongth Mar 6, 2023
a575e1c
Convert joints to frames when converting links, attach them to conver…
aaronchongth Mar 6, 2023
99db618
Integration tests with child fixed links as well
aaronchongth Mar 6, 2023
0e8c8fb
Change sdferr to sdfwarn, no way to use ParserConfig::WarningsPolicy …
aaronchongth Mar 6, 2023
86ac8a6
Merge branch 'sdf12' into aaron/urdf-inertia-handling
aaronchongth Mar 6, 2023
5d2d26c
sdferr to sdfwarn for the case where conversion to frame is attempted
aaronchongth Mar 7, 2023
b495dd9
Removing case within converting to frame, where parent joint turns in…
aaronchongth Mar 7, 2023
a53f9c7
Reduced scope of implementation, more specific warning messages
aaronchongth Mar 14, 2023
0479650
Remove mention of parser config in warning, since that is not typical…
aaronchongth Mar 14, 2023
432a1cb
Integration tests revisited and modified, removed printouts
aaronchongth Mar 14, 2023
d9c9cb4
Test case showing ParserConfig::URDFSetPreserveFixedJoint(true) overr…
aaronchongth Mar 15, 2023
8976110
Merge branch 'sdf12' into aaron/urdf-inertia-handling
aaronchongth Mar 15, 2023
774d86b
Use sdf::testing::contains instead of local contains functions in tes…
aaronchongth Mar 15, 2023
b290786
Remove unused InitSDF, added TODO for warning when joints are convert…
aaronchongth Mar 16, 2023
bb9fa63
Cleaned up if else cases
aaronchongth Mar 16, 2023
509bb50
Using << operator of Errors
aaronchongth Mar 16, 2023
a0d457a
Replacing placeholder url with expected URL for the documentation fro…
aaronchongth Mar 16, 2023
ba52e6f
URL to tutorial as a constant, removing checking URL from test, just …
aaronchongth Mar 17, 2023
94382d7
Refactored fixed child joint logic as it is never reached
aaronchongth Mar 20, 2023
6aa625c
Reduce number of if statements, renaming to only check if parent join…
aaronchongth Mar 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions include/sdf/ParserConfig.hh
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,25 @@ class SDFORMAT_VISIBLE ParserConfig
/// \brief Get the preserveFixedJoint flag value.
public: bool URDFPreserveFixedJoint() const;

/// \brief Set the minimum allowed URDF link mass when converting to SDF.
/// Default value as 1e-6.
public: void URDFSetMinimumAllowedLinkMass(double _minimumAllowedLinkMass);

/// \brief Get the minimum allowed URDF link mass when converting to SDF.
/// Default value as 1e-6.
public: double URDFMinimumAllowedLinkMass() const;

/// \brief Set the convertLinkWithNoMassToFrame flag value, which determines
/// whether to convert URDF links with small (equal to or less than
aaronchongth marked this conversation as resolved.
Show resolved Hide resolved
/// URDFMinimumAllowedLinkMass) or no mass to frames in SDF.
public: void URDFSetConvertLinkWithNoMassToFrame(
bool _convertLinkWithNoMassToFrame);

/// \brief Get the convertLinkWithNoMassToFrame flag value, which determines
/// whether to convert URDF links with small (equal to or less than
/// URDFMinimumAllowedLinkMass) or no mass to frames in SDF.
public: bool URDFConvertLinkWithNoMassToFrame() const;

/// \brief Private data pointer.
IGN_UTILS_IMPL_PTR(dataPtr)
};
Expand Down
32 changes: 32 additions & 0 deletions src/ParserConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ class sdf::ParserConfig::Implementation
/// reading the SDF/URDF file.
public: bool preserveFixedJoint = false;

/// \brief Minimum allowed URDF link mass when converting to SDF.
public: double minimumAllowedLinkMass = 1e-6;

/// \brief Flag to convert of links with small (equal to or less than
/// minimumAllowedLinkMass) or no mass in URDF to frames in SDF.
public: bool convertLinkWithNoMassToFrame = false;

/// \brief Flag to use <include> tags within ToElement methods instead of
/// the fully included model.
public: bool toElementUseIncludeTag = true;
Expand Down Expand Up @@ -173,3 +180,28 @@ bool ParserConfig::URDFPreserveFixedJoint() const
{
return this->dataPtr->preserveFixedJoint;
}

/////////////////////////////////////////////////
void ParserConfig::URDFSetMinimumAllowedLinkMass(double _minimumAllowedLinkMass)
{
this->dataPtr->minimumAllowedLinkMass = _minimumAllowedLinkMass;
}

/////////////////////////////////////////////////
double ParserConfig::URDFMinimumAllowedLinkMass() const
{
return this->dataPtr->minimumAllowedLinkMass;
}

/////////////////////////////////////////////////
void ParserConfig::URDFSetConvertLinkWithNoMassToFrame(
bool _convertLinkWithNoMassToFrame)
{
this->dataPtr->convertLinkWithNoMassToFrame = _convertLinkWithNoMassToFrame;
}

/////////////////////////////////////////////////
bool ParserConfig::URDFConvertLinkWithNoMassToFrame() const
{
return this->dataPtr->convertLinkWithNoMassToFrame;
}
130 changes: 106 additions & 24 deletions src/parser_urdf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,19 @@ void AddTransform(tinyxml2::XMLElement *_elem,
const gz::math::Pose3d &_transform);

/// create SDF from URDF link
void CreateSDF(tinyxml2::XMLElement *_root, urdf::LinkConstSharedPtr _link);
void CreateSDF(tinyxml2::XMLElement *_root, urdf::LinkConstSharedPtr _link,
const ParserConfig& _parserConfig);

/// create SDF Link block based on URDF
void CreateLink(tinyxml2::XMLElement *_root, urdf::LinkConstSharedPtr _link,
const gz::math::Pose3d &_currentTransform);

/// create SDF Frame block based on a URDF link with small (less than
/// ParserConfig::URDFMinimumAllowedLinkMass) or no mass
void CreateFrameFromLink(tinyxml2::XMLElement *_root,
urdf::LinkConstSharedPtr _link,
const gz::math::Pose3d &_currentTransform);

/// reduced fixed joints: apply appropriate frame updates in joint
/// inside urdf extensions when doing fixed joint reduction
void ReduceSDFExtensionJointFrameReplace(
Expand Down Expand Up @@ -2661,40 +2668,68 @@ void URDF2SDF::ListSDFExtensions(const std::string &_reference)

////////////////////////////////////////////////////////////////////////////////
void CreateSDF(tinyxml2::XMLElement *_root,
urdf::LinkConstSharedPtr _link)
{
// must have an <inertial> block and cannot have zero mass.
// allow det(I) == zero, in the case of point mass geoms.
urdf::LinkConstSharedPtr _link,
const ParserConfig& _parserConfig)
{
// Links with a mass of less than or equal to
// ParserConfig::URDFMinimumAllowedLinkMass will considered a link with zero
// mass.
// Links with zero mass or without an <inertial> block will be ignored, unless
// ParserConfig::URDFConvertLinkWithNoMassToFrame is true, in which case they
// will be converted into frames.
// allow det(I) == zero, in the case of point mass geoms.
// @todo: keyword "world" should be a constant defined somewhere else
if (_link->name != "world" &&
((!_link->inertial) || gz::math::equal(_link->inertial->mass, 0.0)))
((!_link->inertial) ||
gz::math::equal(_link->inertial->mass, 0.0,
_parserConfig.URDFMinimumAllowedLinkMass())) &&
!_parserConfig.URDFConvertLinkWithNoMassToFrame())
{
std::stringstream inertiaIssue;
if (_link->inertial && gz::math::equal(_link->inertial->mass, 0.0,
_parserConfig.URDFMinimumAllowedLinkMass()))
{
inertiaIssue << "a mass value of less than or equal to "
<< _parserConfig.URDFMinimumAllowedLinkMass();
}
else
{
inertiaIssue << "no inertia defined";
}

if (!_link->child_links.empty())
{
sdfdbg << "urdf2sdf: link[" << _link->name
<< "] has no inertia, ["
<< static_cast<int>(_link->child_links.size())
<< "] children links ignored.\n";
sdfwarn << "urdf2sdf: link[" << _link->name
<< "] has "
<< inertiaIssue.str()
<< ", ["
<< static_cast<int>(_link->child_links.size())
<< "] children links ignored.\n";
}

if (!_link->child_joints.empty())
{
sdfdbg << "urdf2sdf: link[" << _link->name
<< "] has no inertia, ["
<< static_cast<int>(_link->child_links.size())
<< "] children joints ignored.\n";
sdfwarn << "urdf2sdf: link[" << _link->name
<< "] has "
<< inertiaIssue.str()
<< ", ["
<< static_cast<int>(_link->child_links.size())
<< "] children joints ignored.\n";
}

if (_link->parent_joint)
{
sdfdbg << "urdf2sdf: link[" << _link->name
<< "] has no inertia, "
<< "parent joint [" << _link->parent_joint->name
<< "] ignored.\n";
sdfwarn << "urdf2sdf: link[" << _link->name
<< "] has "
<< inertiaIssue.str()
<< ", parent joint [" << _link->parent_joint->name
<< "] ignored.\n";
}

sdfdbg << "urdf2sdf: link[" << _link->name
<< "] has no inertia, not modeled in sdf\n";
sdfwarn << "urdf2sdf: link[" << _link->name
<< "] has "
<< inertiaIssue.str()
<< ", not modeled in sdf\n";
return;
azeey marked this conversation as resolved.
Show resolved Hide resolved
}

Expand All @@ -2704,13 +2739,23 @@ void CreateSDF(tinyxml2::XMLElement *_root,
(!_link->parent_joint ||
!FixedJointShouldBeReduced(_link->parent_joint)))
{
CreateLink(_root, _link, gz::math::Pose3d::Zero);
if (((!_link->inertial) ||
gz::math::equal(_link->inertial->mass, 0.0,
aaronchongth marked this conversation as resolved.
Show resolved Hide resolved
_parserConfig.URDFMinimumAllowedLinkMass())) &&
_parserConfig.URDFConvertLinkWithNoMassToFrame())
{
CreateFrameFromLink(_root, _link, gz::math::Pose3d::Zero);
}
else
{
CreateLink(_root, _link, gz::math::Pose3d::Zero);
}
}

// recurse into children
for (unsigned int i = 0 ; i < _link->child_links.size() ; ++i)
{
CreateSDF(_root, _link->child_links[i]);
CreateSDF(_root, _link->child_links[i], _parserConfig);
}
}

Expand Down Expand Up @@ -2793,6 +2838,43 @@ void CreateLink(tinyxml2::XMLElement *_root,
_root->LinkEndChild(elem);
}

////////////////////////////////////////////////////////////////////////////////
void CreateFrameFromLink(tinyxml2::XMLElement *_root,
urdf::LinkConstSharedPtr _link,
const gz::math::Pose3d &_currentTransform)
{
// create new body
tinyxml2::XMLElement *elem = _root->GetDocument()->NewElement("frame");

// set body name
elem->SetAttribute("name", _link->name.c_str());

// compute global transform
gz::math::Pose3d localTransform;
// this is the transform from parent link to current _link
// this transform does not exist for the root link
if (_link->parent_joint)
{
tinyxml2::XMLElement *pose = _root->GetDocument()->NewElement("pose");
pose->SetAttribute("relative_to", _link->parent_joint->name.c_str());
aaronchongth marked this conversation as resolved.
Show resolved Hide resolved
elem->LinkEndChild(pose);
}
else
{
if (_currentTransform != gz::math::Pose3d::Zero)
{
// create origin tag for this element
AddTransform(elem, _currentTransform);
}
}

// make a <joint:...> block
CreateJoint(_root, _link, _currentTransform);

// add body to document
_root->LinkEndChild(elem);
}

////////////////////////////////////////////////////////////////////////////////
void CreateCollisions(tinyxml2::XMLElement* _elem,
urdf::LinkConstSharedPtr _link)
Expand Down Expand Up @@ -3306,13 +3388,13 @@ void URDF2SDF::InitModelString(const std::string &_urdfStr,
child = rootLink->child_links.begin();
child != rootLink->child_links.end(); ++child)
{
CreateSDF(robot, (*child));
CreateSDF(robot, (*child), _config);
}
}
else
{
// convert, starting from root link
CreateSDF(robot, rootLink);
CreateSDF(robot, rootLink, _config);
}

// insert the extensions without reference into <robot> root level
Expand Down
Loading