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

Add policy for handling CalculateInertial failures (backport #1543) #1546

Merged
merged 1 commit into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 28 additions & 0 deletions include/sdf/ParserConfig.hh
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ enum class ConfigureResolveAutoInertials
SAVE_CALCULATION_IN_ELEMENT,
};

/// \enum CalculateInertialFailurePolicyType
/// \brief Configuration options of how CalculateInertial() failures should
/// be handled.
enum class CalculateInertialFailurePolicyType
{
/// \brief If this value is used, failures of Geometry::CalculateInertial()
/// will result in a LINK_INERTIA_INVALID error with no inertial values
/// written.
ERR,

/// \brief If this value is used, failures of Geometry::CalculateInertial()
/// will result in default inertial values used and a WARNING.
WARN_AND_USE_DEFAULT_INERTIAL,
};

// Forward declare private data class.
class ParserConfigPrivate;

Expand Down Expand Up @@ -192,6 +207,19 @@ class SDFORMAT_VISIBLE ParserConfig
public: void SetCalculateInertialConfiguration(
ConfigureResolveAutoInertials _configuration);

/// \brief Get the current policy for handling failures of the
/// CalculateInertial() function. By default an error is reported.
/// \return Current set value of the CalculateInertialFailurePolicyType enum
public: CalculateInertialFailurePolicyType
CalculateInertialFailurePolicy() const;

/// \brief Set the policy for handling failures of the CalculateInertial()
/// function
/// \param[in] _policy The policy to set for handling failures of the
/// CalculateInertial() function
public: void SetCalculateInertialFailurePolicy(
CalculateInertialFailurePolicyType _policy);

/// \brief Registers a custom model parser.
/// \param[in] _modelParser Callback as described in
/// sdf/InterfaceElements.hh.
Expand Down
24 changes: 21 additions & 3 deletions src/Collision.cc
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,27 @@ void Collision::CalculateInertial(

if (!geomInertial)
{
_errors.push_back({ErrorCode::LINK_INERTIA_INVALID,
"Inertia Calculated for collision: " +
this->dataPtr->name + " is invalid."});
if (_config.CalculateInertialFailurePolicy() ==
CalculateInertialFailurePolicyType::WARN_AND_USE_DEFAULT_INERTIAL)
{
Error err(
sdf::ErrorCode::WARNING,
"Inertia Calculated for collision: " + this->dataPtr->name +
" is invalid, using default inertial values.");
enforceConfigurablePolicyCondition(_config.WarningsPolicy(), err,
_errors);

using namespace gz::math;
_inertial = Inertiald(MassMatrix3d(1, Vector3d::One, Vector3d::Zero),
Pose3d::Zero);
}
else if (_config.CalculateInertialFailurePolicy() ==
CalculateInertialFailurePolicyType::ERR)
{
_errors.push_back({ErrorCode::LINK_INERTIA_INVALID,
"Inertia Calculated for collision: " +
this->dataPtr->name + " is invalid."});
}
}
else
{
Expand Down
55 changes: 55 additions & 0 deletions src/Collision_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,61 @@ TEST(DOMCollision, CalculateInertialPoseNotRelativeToLink)
EXPECT_EQ(expectedInertial.Pose(), link->Inertial().Pose());
}

/////////////////////////////////////////////////
TEST(DOMCollision, CollisionCalculateInertialFailurePolicy)
{
sdf::Collision collision;

sdf::ElementPtr sdf(new sdf::Element());
collision.Load(sdf);

const sdf::ParserConfig sdfParserConfig;
sdf::Geometry geom;
sdf::Mesh mesh;
geom.SetType(sdf::GeometryType::MESH);
geom.SetMeshShape(mesh);
collision.SetGeom(geom);

sdf::ParserConfig config;
sdf::Errors errors;
sdf::CustomInertiaCalcProperties inertiaCalcProps;

// Custom inertia calculator that returns null inertial
auto customMeshInertiaCalculator = [](
sdf::Errors &,
const sdf::CustomInertiaCalcProperties &)
-> std::optional<gz::math::Inertiald>
{
return std::nullopt;
};
config.RegisterCustomInertiaCalc(customMeshInertiaCalculator);

// With default inertial failure policy, there should be an error when the
// mesh inertial calculator returns null inertial values.
gz::math::Inertiald collisionInertial;
collision.CalculateInertial(errors, collisionInertial, config);
ASSERT_EQ(1u, errors.size()) << errors;
EXPECT_EQ(errors[0].Code(), sdf::ErrorCode::LINK_INERTIA_INVALID);
const gz::math::Inertiald empty;
EXPECT_EQ(empty, collisionInertial);

// Set inertial failure policy to use default inertial values on failure and
// verify that there are no more errors.
errors.clear();
config.SetCalculateInertialFailurePolicy(
sdf::CalculateInertialFailurePolicyType::WARN_AND_USE_DEFAULT_INERTIAL);
collision.CalculateInertial(errors, collisionInertial, config);
EXPECT_TRUE(errors.empty()) << errors;

// Verify default inertial values are returned.
gz::math::Inertiald defaultInertial;
defaultInertial.SetMassMatrix(
gz::math::MassMatrix3d(1.0,
gz::math::Vector3d::One,
gz::math::Vector3d::Zero));
EXPECT_EQ(collisionInertial, defaultInertial);
}

/////////////////////////////////////////////////
TEST(DOMCollision, ToElement)
{
Expand Down
19 changes: 19 additions & 0 deletions src/ParserConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ class sdf::ParserConfig::Implementation
/// to behave behave differently than the `warningsPolicy`.
public: std::optional<EnforcementPolicy> deprecatedElementsPolicy;

/// \brief Policy that is set for handling failures of the
/// CalculateInertial() function. By default errors are reported.
public: CalculateInertialFailurePolicyType calculateInertialFailurePolicy =
CalculateInertialFailurePolicyType::ERR;

/// \brief Configuration that is set for the CalculateInertial() function
/// By default it is set to SAVE_CALCULATION to preserve the behavior of
/// Root::Load() generating complete inertial information.
Expand Down Expand Up @@ -167,6 +172,20 @@ EnforcementPolicy ParserConfig::DeprecatedElementsPolicy() const
this->dataPtr->warningsPolicy);
}

/////////////////////////////////////////////////
CalculateInertialFailurePolicyType
ParserConfig::CalculateInertialFailurePolicy() const
{
return this->dataPtr->calculateInertialFailurePolicy;
}

/////////////////////////////////////////////////
void ParserConfig::SetCalculateInertialFailurePolicy(
CalculateInertialFailurePolicyType _policy)
{
this->dataPtr->calculateInertialFailurePolicy = _policy;
}

/////////////////////////////////////////////////
ConfigureResolveAutoInertials
ParserConfig::CalculateInertialConfiguration() const
Expand Down
8 changes: 8 additions & 0 deletions src/ParserConfig_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ TEST(ParserConfig, Construction)
EXPECT_EQ(sdf::ConfigureResolveAutoInertials::SAVE_CALCULATION_IN_ELEMENT,
config.CalculateInertialConfiguration());

EXPECT_EQ(sdf::CalculateInertialFailurePolicyType::ERR,
config.CalculateInertialFailurePolicy());
config.SetCalculateInertialFailurePolicy(
sdf::CalculateInertialFailurePolicyType::WARN_AND_USE_DEFAULT_INERTIAL);
EXPECT_EQ(
sdf::CalculateInertialFailurePolicyType::WARN_AND_USE_DEFAULT_INERTIAL,
config.CalculateInertialFailurePolicy());

EXPECT_FALSE(config.URDFPreserveFixedJoint());
EXPECT_FALSE(config.StoreResolvedURIs());
}
Expand Down
Loading