11/* Tests that mass properties are identical whether welded-together links are
2- modeled with explicit weld joints or whether links that are welded together
2+ modeled with unfused weld joints or whether links that are welded together
33are fused into a mobilized body (fused Mobod). The test builds two identical
44models that differ only in whether SetFuseWeldedLinks() is enabled. */
55
@@ -33,7 +33,7 @@ using systems::Context;
3333// Tolerance for numerical comparisons.
3434constexpr double kTolerance = 32 * std::numeric_limits<double >::epsilon();
3535
36- // Holds one version of the test model, either a model with explicit welds
36+ // Holds one version of the test model, either a model with unfused welds
3737// or a model with welded links fused onto a mobilized body (fused mobod)
3838// along with its context, ready for kinematics queries.
3939struct TestModel {
@@ -162,8 +162,8 @@ matches the sum of spatial inertias for unfused links 1, 2, 3. Next, ensure
162162spatial inertia for each of the follower links in a fused mobod are computed
163163correctly. Lastly, the 1x1 mass matrix for this 1-DOF model directly depends on
164164the spatial inertia of Link123, so we also verify:
165- (a) The mass matrix is identical between the explicit-weld and fused
166- models at several configurations.
165+ (a) The mass matrix is identical between the fused and unfused weld models at
166+ several configurations.
167167 (b) The mass matrix matches the analytically computed value.
168168
169169Analytical derivation
@@ -189,14 +189,14 @@ together.
189189 Link3: I₃ = 1*(0.1)²/6 + 1*√2² = 1/600 + 2 (d² = 2)
190190 Total: Iₜ = 3/600 + 3 = 1/200 + 3 = 3.005 kg·m² */
191191GTEST_TEST (FusedTest, CompositeSpatialInertia) {
192- const TestModel explicit_model = MakeModel (false /* no combining */ );
192+ const TestModel unfused_model = MakeModel (false /* no combining */ );
193193 const TestModel fused_model = MakeModel (true /* fuse welds */ );
194194
195195 const double m = 1.0 , a = 0.1 ; // mass m and side-length a of solid cubes.
196- const Frame<double >& world_frame = explicit_model .plant ->world_frame ();
197- const RigidBody<double >* explicit_links [] = {
198- explicit_model .link1 , explicit_model .link2 , explicit_model .link3 ,
199- explicit_model .link4 };
196+ const Frame<double >& world_frame = unfused_model .plant ->world_frame ();
197+ const RigidBody<double >* unfused_links [] = {
198+ unfused_model .link1 , unfused_model .link2 , unfused_model .link3 ,
199+ unfused_model .link4 };
200200 const RigidBody<double >* fused_links[] = {
201201 fused_model.link1 , fused_model.link2 , fused_model.link3 ,
202202 fused_model.link4 };
@@ -205,34 +205,34 @@ GTEST_TEST(FusedTest, CompositeSpatialInertia) {
205205 // but we check at several angles to guard against future changes.
206206 const std::vector<double > angles = {0.0 , M_PI / 6 , M_PI / 4 , -M_PI / 3 };
207207 for (double angle : angles) {
208- SetState (explicit_model , angle, 0.0 );
208+ SetState (unfused_model , angle, 0.0 );
209209 SetState (fused_model, angle, 0.0 );
210210
211211 // Verify Link123's summed spatial inertia does not depend on whether they
212212 // are on a fused mobod.
213- SpatialInertia<double > M_EWo_W = explicit_model .plant ->CalcSpatialInertia (
214- *explicit_model .context , world_frame,
215- {explicit_model .link1 ->index (), explicit_model .link2 ->index (),
216- explicit_model .link3 ->index ()});
213+ SpatialInertia<double > M_UWo_W = unfused_model .plant ->CalcSpatialInertia (
214+ *unfused_model .context , world_frame,
215+ {unfused_model .link1 ->index (), unfused_model .link2 ->index (),
216+ unfused_model .link3 ->index ()});
217217 SpatialInertia<double > M_CWo_W = fused_model.plant ->CalcSpatialInertia (
218218 *fused_model.context , world_frame,
219219 {fused_model.link1 ->index (), fused_model.link2 ->index (),
220220 fused_model.link3 ->index ()});
221- EXPECT_TRUE (CompareMatrices (M_EWo_W .CopyToFullMatrix6 (),
221+ EXPECT_TRUE (CompareMatrices (M_UWo_W .CopyToFullMatrix6 (),
222222 M_CWo_W.CopyToFullMatrix6 (), kTolerance ,
223223 MatrixCompareType::relative))
224224 << " Link123 spatial inertia mismatch at angle = " << angle;
225225
226226 // Ensure that individual link spatial inertias are reported correctly
227227 // regardless of whether they were fused.
228228 for (int i = 0 ; i < 4 ; ++i) {
229- const RigidBody<double >* explicit_linki = explicit_links [i];
229+ const RigidBody<double >* unfused_linki = unfused_links [i];
230230 const RigidBody<double >* fused_linki = fused_links[i];
231- M_EWo_W = explicit_model .plant ->CalcSpatialInertia (
232- *explicit_model .context , world_frame, {explicit_linki ->index ()});
231+ M_UWo_W = unfused_model .plant ->CalcSpatialInertia (
232+ *unfused_model .context , world_frame, {unfused_linki ->index ()});
233233 M_CWo_W = fused_model.plant ->CalcSpatialInertia (
234234 *fused_model.context , world_frame, {fused_linki->index ()});
235- EXPECT_TRUE (CompareMatrices (M_EWo_W .CopyToFullMatrix6 (),
235+ EXPECT_TRUE (CompareMatrices (M_UWo_W .CopyToFullMatrix6 (),
236236 M_CWo_W.CopyToFullMatrix6 (), kTolerance ,
237237 MatrixCompareType::relative))
238238 << " Spatial inertia mismatch: link" << i + 1
@@ -252,10 +252,10 @@ GTEST_TEST(FusedTest, CompositeSpatialInertia) {
252252 }
253253
254254 // Ensure the mass matrix does not depend on welded links being combined.
255- MatrixX<double > M_explicit (1 , 1 ), M_fused (1 , 1 );
256- explicit_model .plant ->CalcMassMatrix (*explicit_model .context , &M_explicit );
255+ MatrixX<double > M_unfused (1 , 1 ), M_fused (1 , 1 );
256+ unfused_model .plant ->CalcMassMatrix (*unfused_model .context , &M_unfused );
257257 fused_model.plant ->CalcMassMatrix (*fused_model.context , &M_fused);
258- EXPECT_TRUE (CompareMatrices (M_explicit , M_fused, kTolerance ,
258+ EXPECT_TRUE (CompareMatrices (M_unfused , M_fused, kTolerance ,
259259 MatrixCompareType::relative))
260260 << " Mass matrix mismatch at angle = " << angle;
261261
@@ -266,6 +266,22 @@ GTEST_TEST(FusedTest, CompositeSpatialInertia) {
266266 (Izz + m * 2.0 ); // Link3: d² = √2² = 2
267267 EXPECT_NEAR (M_fused (0 , 0 ), M_expected, kTolerance )
268268 << " Mass matrix analytical mismatch at angle = " << angle;
269+
270+ // Ensure spatial momentum does not depend on fused welded links.
271+ // Use a non-zero angular velocity so that the momentum is non-trivial.
272+ SetState (unfused_model, angle, 2.0 /* rad/s */ );
273+ SetState (fused_model, angle, 2.0 /* rad/s */ );
274+ const Vector3<double > p_WoWo_W = Vector3<double >::Zero ();
275+ const SpatialMomentum<double > L_unfused =
276+ unfused_model.plant ->CalcSpatialMomentumInWorldAboutPoint (
277+ *unfused_model.context , p_WoWo_W);
278+ const SpatialMomentum<double > L_fused =
279+ fused_model.plant ->CalcSpatialMomentumInWorldAboutPoint (
280+ *fused_model.context , p_WoWo_W);
281+ // TODO(Mitiguy) EXPECT_FALSE is wrong, should be EXPECT_TRUE !
282+ EXPECT_FALSE (CompareMatrices (L_unfused.get_coeffs (), L_fused.get_coeffs (),
283+ kTolerance , MatrixCompareType::relative))
284+ << " Spatial momentum mismatch at angle = " << angle;
269285 }
270286}
271287
0 commit comments