Skip to content

Commit f360776

Browse files
authored
Use //link/inertial/density for auto-inertials (#1335)
The density precedence for Collisions is now: 1. Density explicitly set in //collision/density or by Collision::SetDensity. 2. Density explicitly set in //link/inertial/density or by Link::SetDensity. 3. Default density in Collision::DensityDefault(). * Fix density handling in Collision::ToElement * Add Link auto_inertia_params to API Pass //link/inertial/auto_inertia_params ElementPtr to Collision::CalculateInertial and use it if the Collision does not have auto_inertia_params of its own. Also add a test for precedence of AutoInertiaParams. * Mesh: don't warn if FilePath is not set The FilePath refers to the SDFormat file that the Mesh object was parsed from, not the Mesh file itself, so remove the unrelated warning. Signed-off-by: Steve Peters <[email protected]>
1 parent 3e0d533 commit f360776

File tree

9 files changed

+570
-35
lines changed

9 files changed

+570
-35
lines changed

include/sdf/Collision.hh

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define SDF_COLLISION_HH_
1919

2020
#include <memory>
21+
#include <optional>
2122
#include <string>
2223
#include <gz/math/Pose3.hh>
2324
#include <gz/math/Vector3.hh>
@@ -78,6 +79,11 @@ namespace sdf
7879
/// \param[in] _name Name of the collision.
7980
public: void SetName(const std::string &_name);
8081

82+
/// \brief Get the default density of a collision if its density is not
83+
/// specified.
84+
/// \return Default density.
85+
public: static double DensityDefault();
86+
8187
/// \brief Get the density of the collision.
8288
/// \return Density of the collision.
8389
public: double Density() const;
@@ -145,13 +151,32 @@ namespace sdf
145151
/// \brief Calculate and return the MassMatrix for the collision
146152
/// \param[out] _errors A vector of Errors objects. Each errors contains an
147153
/// Error code and a message. An empty errors vector indicates no errors
148-
/// \param[in] _config Custom parser configuration
149154
/// \param[out] _inertial An inertial object which will be set with the
150155
/// calculated inertial values
156+
/// \param[in] _config Custom parser configuration
151157
public: void CalculateInertial(sdf::Errors &_errors,
152158
gz::math::Inertiald &_inertial,
153159
const ParserConfig &_config);
154160

161+
/// \brief Calculate and return the MassMatrix for the collision
162+
/// \param[out] _errors A vector of Errors objects. Each errors contains an
163+
/// Error code and a message. An empty errors vector indicates no errors
164+
/// \param[out] _inertial An inertial object which will be set with the
165+
/// calculated inertial values
166+
/// \param[in] _config Custom parser configuration
167+
/// \param[in] _density An optional density value to override the default
168+
/// collision density. This value is used instead of DefaultDensity()
169+
// if this collision's density has not been explicitly set.
170+
/// \param[in] _autoInertiaParams An ElementPtr to the auto_inertia_params
171+
/// element to be used if the auto_inertia_params have not been set in this
172+
/// collision.
173+
public: void CalculateInertial(
174+
sdf::Errors &_errors,
175+
gz::math::Inertiald &_inertial,
176+
const ParserConfig &_config,
177+
const std::optional<double> &_density,
178+
sdf::ElementPtr _autoInertiaParams);
179+
155180
/// \brief Get a pointer to the SDF element that was used during
156181
/// load.
157182
/// \return SDF element pointer. The value will be nullptr if Load has

include/sdf/Link.hh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define SDF_LINK_HH_
1919

2020
#include <memory>
21+
#include <optional>
2122
#include <string>
2223
#include <gz/math/Inertial.hh>
2324
#include <gz/math/Pose3.hh>
@@ -79,6 +80,27 @@ namespace sdf
7980
/// \param[in] _name Name of the link.
8081
public: void SetName(const std::string &_name);
8182

83+
/// \brief Get the density of the inertial if it has been set.
84+
/// \return Density of the inertial if it has been set,
85+
/// otherwise std::nullopt.
86+
public: std::optional<double> Density() const;
87+
88+
/// \brief Set the density of the inertial.
89+
/// \param[in] _density Density of the inertial.
90+
public: void SetDensity(double _density);
91+
92+
/// \brief Get the ElementPtr to the <auto_inertia_params> element
93+
/// This element can be used as a parent element to hold user-defined
94+
/// params for the custom moment of inertia calculator.
95+
/// \return ElementPtr object for the <auto_inertia_params> element.
96+
public: sdf::ElementPtr AutoInertiaParams() const;
97+
98+
/// \brief Function to set the auto inertia params using a
99+
/// sdf ElementPtr object
100+
/// \param[in] _autoInertiaParams ElementPtr to <auto_inertia_params>
101+
/// element
102+
public: void SetAutoInertiaParams(const sdf::ElementPtr _autoInertiaParams);
103+
82104
/// \brief Get the number of visuals.
83105
/// \return Number of visuals contained in this Link object.
84106
public: uint64_t VisualCount() const;

src/Collision.cc

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,10 @@ class sdf::Collision::Implementation
4949
/// \brief The collision's surface parameters.
5050
public: sdf::Surface surface;
5151

52-
/// \brief Density of the collision. Default is 1000.0
53-
public: double density{1000.0};
52+
/// \brief Density of the collision if it has been set.
53+
public: std::optional<double> density;
5454

55-
/// \brief True if density was set during load from sdf.
56-
public: bool densitySetAtLoad = false;
57-
58-
/// \brief SDF element pointer to <moi_calculator_params> tag
55+
/// \brief SDF element pointer to <auto_inertia_params> tag
5956
public: sdf::ElementPtr autoInertiaParams{nullptr};
6057

6158
/// \brief The SDF element pointer used during load.
@@ -130,7 +127,6 @@ Errors Collision::Load(ElementPtr _sdf, const ParserConfig &_config)
130127
if (_sdf->HasElement("density"))
131128
{
132129
this->dataPtr->density = _sdf->Get<double>("density");
133-
this->dataPtr->densitySetAtLoad = true;
134130
}
135131

136132
// Load the auto_inertia_params element
@@ -155,10 +151,20 @@ void Collision::SetName(const std::string &_name)
155151
this->dataPtr->name = _name;
156152
}
157153

154+
/////////////////////////////////////////////////
155+
double Collision::DensityDefault()
156+
{
157+
return 1000.0;
158+
}
159+
158160
/////////////////////////////////////////////////
159161
double Collision::Density() const
160162
{
161-
return this->dataPtr->density;
163+
if (this->dataPtr->density)
164+
{
165+
return *this->dataPtr->density;
166+
}
167+
return DensityDefault();
162168
}
163169

164170
/////////////////////////////////////////////////
@@ -256,23 +262,59 @@ void Collision::CalculateInertial(
256262
gz::math::Inertiald &_inertial,
257263
const ParserConfig &_config)
258264
{
259-
// Check if density was not set during load & send a warning
260-
// about the default value being used
261-
if (!this->dataPtr->densitySetAtLoad)
265+
this->CalculateInertial(
266+
_errors, _inertial, _config, std::nullopt, ElementPtr());
267+
}
268+
269+
/////////////////////////////////////////////////
270+
void Collision::CalculateInertial(
271+
sdf::Errors &_errors,
272+
gz::math::Inertiald &_inertial,
273+
const ParserConfig &_config,
274+
const std::optional<double> &_density,
275+
sdf::ElementPtr _autoInertiaParams)
276+
{
277+
// Order of precedence for density:
278+
double density;
279+
// 1. Density explicitly set in this collision, either from the
280+
// `//collision/density` element or from Collision::SetDensity.
281+
if (this->dataPtr->density)
282+
{
283+
density = *this->dataPtr->density;
284+
}
285+
// 2. Density passed into this function, which likely comes from the
286+
// `//link/inertial/density` element or from Link::SetDensity.
287+
else if (_density)
288+
{
289+
density = *_density;
290+
}
291+
// 3. DensityDefault value.
292+
else
262293
{
294+
// If density was not explicitly set, send a warning
295+
// about the default value being used
296+
density = DensityDefault();
263297
Error densityMissingErr(
264298
ErrorCode::ELEMENT_MISSING,
265299
"Collision is missing a <density> child element. "
266-
"Using a default density value of 1000.0 kg/m^3. "
300+
"Using a default density value of " +
301+
std::to_string(DensityDefault()) + " kg/m^3. "
267302
);
268303
enforceConfigurablePolicyCondition(
269304
_config.WarningsPolicy(), densityMissingErr, _errors
270305
);
271306
}
272307

308+
// If this Collision's auto inertia params have not been set, then use the
309+
// params passed into this function.
310+
sdf::ElementPtr autoInertiaParams = this->dataPtr->autoInertiaParams;
311+
if (!autoInertiaParams)
312+
{
313+
autoInertiaParams = _autoInertiaParams;
314+
}
273315
auto geomInertial =
274316
this->dataPtr->geom.CalculateInertial(_errors, _config,
275-
this->dataPtr->density, this->dataPtr->autoInertiaParams);
317+
density, autoInertiaParams);
276318

277319
if (!geomInertial)
278320
{
@@ -309,6 +351,7 @@ sdf::ElementPtr Collision::Element() const
309351
return this->dataPtr->sdf;
310352
}
311353

354+
/////////////////////////////////////////////////
312355
sdf::ElementPtr Collision::ToElement() const
313356
{
314357
sdf::Errors errors;
@@ -335,8 +378,11 @@ sdf::ElementPtr Collision::ToElement(sdf::Errors &_errors) const
335378
poseElem->Set<gz::math::Pose3d>(_errors, this->RawPose());
336379

337380
// Set the density
338-
sdf::ElementPtr densityElem = elem->GetElement("density", _errors);
339-
densityElem->Set<double>(this->Density());
381+
if (this->dataPtr->density.has_value())
382+
{
383+
sdf::ElementPtr densityElem = elem->GetElement("density", _errors);
384+
densityElem->Set<double>(this->Density());
385+
}
340386

341387
// Set the geometry
342388
elem->InsertElement(this->dataPtr->geom.ToElement(_errors), true);

src/Collision_TEST.cc

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ TEST(DOMcollision, Construction)
3838
EXPECT_EQ(nullptr, collision.Element());
3939
EXPECT_TRUE(collision.Name().empty());
4040
EXPECT_EQ(collision.Density(), 1000.0);
41+
EXPECT_EQ(collision.DensityDefault(), 1000.0);
4142

4243
collision.SetName("test_collison");
4344
EXPECT_EQ(collision.Name(), "test_collison");
@@ -58,12 +59,12 @@ TEST(DOMcollision, Construction)
5859
EXPECT_DOUBLE_EQ(collision.Density(), 1240.0);
5960

6061
EXPECT_EQ(collision.AutoInertiaParams(), nullptr);
61-
sdf::ElementPtr autoInertialParamsElem(new sdf::Element());
62-
autoInertialParamsElem->SetName("auto_inertial_params");
63-
collision.SetAutoInertiaParams(autoInertialParamsElem);
64-
EXPECT_EQ(collision.AutoInertiaParams(), autoInertialParamsElem);
62+
sdf::ElementPtr autoInertiaParamsElem(new sdf::Element());
63+
autoInertiaParamsElem->SetName("auto_inertia_params");
64+
collision.SetAutoInertiaParams(autoInertiaParamsElem);
65+
EXPECT_EQ(collision.AutoInertiaParams(), autoInertiaParamsElem);
6566
EXPECT_EQ(collision.AutoInertiaParams()->GetName(),
66-
autoInertialParamsElem->GetName());
67+
autoInertiaParamsElem->GetName());
6768

6869
collision.SetRawPose({-10, -20, -30, GZ_PI, GZ_PI, GZ_PI});
6970
EXPECT_EQ(gz::math::Pose3d(-10, -20, -30, GZ_PI, GZ_PI, GZ_PI),
@@ -420,6 +421,8 @@ TEST(DOMCollision, ToElement)
420421

421422
sdf::ElementPtr elem = collision.ToElement();
422423
ASSERT_NE(nullptr, elem);
424+
// Expect no density element
425+
EXPECT_FALSE(elem->HasElement("density"));
423426

424427
sdf::Collision collision2;
425428
collision2.Load(elem);
@@ -434,6 +437,19 @@ TEST(DOMCollision, ToElement)
434437
ASSERT_NE(nullptr, surface2->Friction());
435438
ASSERT_NE(nullptr, surface2->Friction()->ODE());
436439
EXPECT_DOUBLE_EQ(1.23, surface2->Friction()->ODE()->Mu());
440+
441+
// Now set density in collision
442+
const double kDensity = 1234.5;
443+
collision.SetDensity(kDensity);
444+
sdf::ElementPtr elemWithDensity = collision.ToElement();
445+
ASSERT_NE(nullptr, elemWithDensity);
446+
// Expect density element
447+
ASSERT_TRUE(elemWithDensity->HasElement("density"));
448+
EXPECT_DOUBLE_EQ(kDensity, elemWithDensity->Get<double>("density"));
449+
450+
sdf::Collision collision3;
451+
collision3.Load(elem);
452+
EXPECT_DOUBLE_EQ(kDensity, collision.Density());
437453
}
438454

439455
/////////////////////////////////////////////////

src/Link.cc

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ class sdf::Link::Implementation
6969
/// \brief The projectors specified in this link.
7070
public: std::vector<Projector> projectors;
7171

72+
/// \brief Density of the inertial which will be used for auto-inertial
73+
/// calculations if the collision density has not been set.
74+
public: std::optional<double> density;
75+
76+
/// \brief SDF element pointer to <auto_inertia_params> tag
77+
public: sdf::ElementPtr autoInertiaParams{nullptr};
78+
7279
/// \brief The inertial information for this link.
7380
public: gz::math::Inertiald inertial {{1.0,
7481
gz::math::Vector3d::One, gz::math::Vector3d::Zero},
@@ -180,6 +187,18 @@ Errors Link::Load(ElementPtr _sdf, const ParserConfig &_config)
180187
{
181188
sdf::ElementPtr inertialElem = _sdf->GetElement("inertial");
182189

190+
if (inertialElem->HasElement("density"))
191+
{
192+
this->dataPtr->density = inertialElem->Get<double>("density");
193+
}
194+
195+
// Load the auto_inertia_params element
196+
if (inertialElem->HasElement("auto_inertia_params"))
197+
{
198+
this->dataPtr->autoInertiaParams =
199+
inertialElem->GetElement("auto_inertia_params");
200+
}
201+
183202
if (inertialElem->Get<bool>("auto"))
184203
{
185204
this->dataPtr->autoInertia = true;
@@ -309,6 +328,30 @@ void Link::SetName(const std::string &_name)
309328
this->dataPtr->name = _name;
310329
}
311330

331+
/////////////////////////////////////////////////
332+
std::optional<double> Link::Density() const
333+
{
334+
return this->dataPtr->density;
335+
}
336+
337+
/////////////////////////////////////////////////
338+
void Link::SetDensity(double _density)
339+
{
340+
this->dataPtr->density = _density;
341+
}
342+
343+
/////////////////////////////////////////////////
344+
sdf::ElementPtr Link::AutoInertiaParams() const
345+
{
346+
return this->dataPtr->autoInertiaParams;
347+
}
348+
349+
/////////////////////////////////////////////////
350+
void Link::SetAutoInertiaParams(const sdf::ElementPtr _autoInertiaParams)
351+
{
352+
this->dataPtr->autoInertiaParams = _autoInertiaParams;
353+
}
354+
312355
/////////////////////////////////////////////////
313356
uint64_t Link::VisualCount() const
314357
{
@@ -620,7 +663,9 @@ void Link::ResolveAutoInertials(sdf::Errors &_errors,
620663
for (sdf::Collision &collision : this->dataPtr->collisions)
621664
{
622665
gz::math::Inertiald collisionInertia;
623-
collision.CalculateInertial(_errors, collisionInertia, _config);
666+
collision.CalculateInertial(_errors, collisionInertia, _config,
667+
this->dataPtr->density,
668+
this->dataPtr->autoInertiaParams);
624669
totalInertia = totalInertia + collisionInertia;
625670
}
626671

@@ -942,6 +987,11 @@ sdf::ElementPtr Link::ToElement() const
942987
inertiaElem->GetElement("iyz")->Set(massMatrix.Iyz());
943988
inertiaElem->GetElement("izz")->Set(massMatrix.Izz());
944989

990+
if (this->dataPtr->density.has_value())
991+
{
992+
inertialElem->GetElement("density")->Set(*this->dataPtr->density);
993+
}
994+
945995
if (this->dataPtr->inertial.FluidAddedMass().has_value())
946996
{
947997
auto addedMass = this->dataPtr->inertial.FluidAddedMass().value();

0 commit comments

Comments
 (0)