@@ -727,12 +727,15 @@ TEST(DOMLink, ResolveAutoInertialsWithMultipleCollisions)
727
727
// ///////////////////////////////////////////////
728
728
TEST (DOMLink, InertialValuesGivenWithAutoSetToTrue)
729
729
{
730
+ // A model with link inertial auto set to true.
731
+ // The inertia matrix is specified but should be ignored.
732
+ // <mass> is not speicifed so the inertial values should be computed
733
+ // based on the collision density value.
730
734
std::string sdf = " <?xml version=\" 1.0\" ?>"
731
735
" <sdf version=\" 1.11\" >"
732
736
" <model name='compound_model'>"
733
737
" <link name='compound_link'>"
734
738
" <inertial auto='true'>"
735
- " <mass>4.0</mass>"
736
739
" <pose>1 1 1 2 2 2</pose>"
737
740
" <inertia>"
738
741
" <ixx>1</ixx>"
@@ -763,12 +766,169 @@ TEST(DOMLink, InertialValuesGivenWithAutoSetToTrue)
763
766
root.ResolveAutoInertials (errors, sdfParserConfig);
764
767
EXPECT_TRUE (errors.empty ());
765
768
766
- EXPECT_NE ( 4 .0 , link ->Inertial ().MassMatrix ().Mass ());
769
+ EXPECT_EQ ( 2 .0 , link ->Inertial ().MassMatrix ().Mass ());
767
770
EXPECT_EQ (gz::math::Pose3d::Zero, link ->Inertial ().Pose ());
768
771
EXPECT_EQ (gz::math::Vector3d (0.33333 , 0.33333 , 0.33333 ),
769
772
link ->Inertial ().MassMatrix ().DiagonalMoments ());
770
773
}
771
774
775
+ // ///////////////////////////////////////////////
776
+ TEST (DOMLink, ResolveAutoInertialsWithMass)
777
+ {
778
+ // A model with link inertial auto set to true.
779
+ // The inertia matrix is specified but should be ignored.
780
+ // <mass> is specified - the auto computed inertial values should
781
+ // be scaled based on the desired mass.
782
+ std::string sdf = " <?xml version=\" 1.0\" ?>"
783
+ " <sdf version=\" 1.11\" >"
784
+ " <model name='compound_model'>"
785
+ " <link name='compound_link'>"
786
+ " <inertial auto='true'>"
787
+ " <mass>4.0</mass>"
788
+ " <pose>1 1 1 2 2 2</pose>"
789
+ " <inertia>"
790
+ " <ixx>1</ixx>"
791
+ " <iyy>1</iyy>"
792
+ " <izz>1</izz>"
793
+ " </inertia>"
794
+ " </inertial>"
795
+ " <collision name='box_collision'>"
796
+ " <density>2.0</density>"
797
+ " <geometry>"
798
+ " <box>"
799
+ " <size>1 1 1</size>"
800
+ " </box>"
801
+ " </geometry>"
802
+ " </collision>"
803
+ " </link>"
804
+ " </model>"
805
+ " </sdf>" ;
806
+
807
+ sdf::Root root;
808
+ const sdf::ParserConfig sdfParserConfig;
809
+ sdf::Errors errors = root.LoadSdfString (sdf, sdfParserConfig);
810
+ EXPECT_TRUE (errors.empty ());
811
+ EXPECT_NE (nullptr , root.Element ());
812
+
813
+ const sdf::Model *model = root.Model ();
814
+ const sdf::Link *link = model->LinkByIndex (0 );
815
+ root.ResolveAutoInertials (errors, sdfParserConfig);
816
+ EXPECT_TRUE (errors.empty ());
817
+
818
+ EXPECT_DOUBLE_EQ (4.0 , link ->Inertial ().MassMatrix ().Mass ());
819
+ EXPECT_EQ (gz::math::Pose3d::Zero, link ->Inertial ().Pose ());
820
+ EXPECT_EQ (gz::math::Vector3d (0.66666 , 0.66666 , 0.66666 ),
821
+ link ->Inertial ().MassMatrix ().DiagonalMoments ());
822
+ }
823
+
824
+ // ///////////////////////////////////////////////
825
+ TEST (DOMLink, ResolveAutoInertialsWithMassAndMultipleCollisions)
826
+ {
827
+ // A model with link inertial auto set to true.
828
+ // The inertia matrix is specified but should be ignored.
829
+ // <mass> is specified - the auto computed inertial values should
830
+ // be scaled based on the desired mass.
831
+ // The model contains two collisions with different sizes and densities
832
+ // and a lumped center of mass at the link origin.
833
+ std::string sdf = " <?xml version=\" 1.0\" ?>"
834
+ " <sdf version=\" 1.11\" >"
835
+ " <model name='compound_model'>"
836
+ " <link name='compound_link'>"
837
+ " <inertial auto='true'>"
838
+ " <mass>12.0</mass>"
839
+ " <pose>1 1 1 2 2 2</pose>"
840
+ " <inertia>"
841
+ " <ixx>1</ixx>"
842
+ " <iyy>1</iyy>"
843
+ " <izz>1</izz>"
844
+ " </inertia>"
845
+ " </inertial>"
846
+ " <collision name='cube_collision'>"
847
+ " <pose>0.0 0.0 0.5 0 0 0</pose>"
848
+ " <density>4.0</density>"
849
+ " <geometry>"
850
+ " <box>"
851
+ " <size>1 1 1</size>"
852
+ " </box>"
853
+ " </geometry>"
854
+ " </collision>"
855
+ " <collision name='box_collision'>"
856
+ " <pose>0.0 0.0 -1.0 0 0 0</pose>"
857
+ " <density>1.0</density>"
858
+ " <geometry>"
859
+ " <box>"
860
+ " <size>1 1 2</size>"
861
+ " </box>"
862
+ " </geometry>"
863
+ " </collision>"
864
+ " </link>"
865
+ " </model>"
866
+ " </sdf>" ;
867
+
868
+ sdf::Root root;
869
+ const sdf::ParserConfig sdfParserConfig;
870
+ sdf::Errors errors = root.LoadSdfString (sdf, sdfParserConfig);
871
+ EXPECT_TRUE (errors.empty ());
872
+ EXPECT_NE (nullptr , root.Element ());
873
+
874
+ const sdf::Model *model = root.Model ();
875
+ const sdf::Link *link = model->LinkByIndex (0 );
876
+ root.ResolveAutoInertials (errors, sdfParserConfig);
877
+ EXPECT_TRUE (errors.empty ());
878
+
879
+ // Expect mass value from //inertial/mass
880
+ EXPECT_DOUBLE_EQ (12.0 , link ->Inertial ().MassMatrix ().Mass ());
881
+
882
+ // Inertial values based on density before scaling to match specified mass
883
+ //
884
+ // Collision geometries:
885
+ //
886
+ // --------- z = 1
887
+ // | |
888
+ // | c | cube on top, side length 1.0, density 4.0
889
+ // | |
890
+ // |-------| z = 0
891
+ // | |
892
+ // | |
893
+ // | |
894
+ // | c | box on bottom, size 1x1x2, density 1.0
895
+ // | |
896
+ // | |
897
+ // | |
898
+ // --------- z = -2
899
+ //
900
+ // Top cube: volume = 1.0, mass = 4.0, center of mass z = 0.5
901
+ // Bottom box: volume = 2.0, mass = 2.0, center of mass z = -1.0
902
+ //
903
+ // Total mass from density: 6.0
904
+ // Lumped center of mass z = (4.0 * 0.5 + 2.0 * (-1.0)) / 6.0 = 0.0
905
+ EXPECT_EQ (gz::math::Pose3d::Zero, link ->Inertial ().Pose ());
906
+
907
+ // Moment of inertia at center of each shape
908
+ // Top cube: Ixx = Iyy = Izz = 4.0 / 12 * (1*1 + 1*1) = 8/12 = 2/3
909
+ // Bottom box: Ixx = Iyy = 2.0 / 12 * (1*1 + 2*2) = 10/12 = 5/6
910
+ // Izz = 2.0 / 12 * (1*1 + 1*1) = 4/12 = 1/3
911
+ //
912
+ // Lumped moment of inertia at lumped center of mass
913
+ // Ixx = sum(Ixx_i + mass_i * center_of_mass_z_i^2) for i in [top, bottom]
914
+ // Iyy = Ixx
915
+ // Izz = Izz_top + Izz_bottom
916
+ //
917
+ // Ixx = Iyy = (2/3 + 4.0 * 0.5 * 0.5) + (5/6 + 2.0 * (-1.0) * (-1.0))
918
+ // = (2/3 + 1) + (5/6 + 2.0)
919
+ // = 5/3 + 17/6
920
+ // = 27/6 = 9/2 = 4.5
921
+ //
922
+ // Izz = 2/3 + 1/3 = 1.0
923
+
924
+ // Then scale the inertias according to the specified mass of 12.0
925
+ // mass_ratio = 12.0 / 6.0 = 2.0
926
+ // Ixx = Iyy = mass_ratio * Ixx_unscaled = 2.0 * 4.5 = 9.0
927
+ // Izz = mass_ratio * Izz_unscaled = 2.0 * 1.0 = 2.0
928
+ EXPECT_EQ (gz::math::Vector3d (9.0 , 9.0 , 2.0 ),
929
+ link ->Inertial ().MassMatrix ().DiagonalMoments ());
930
+ }
931
+
772
932
// ///////////////////////////////////////////////
773
933
TEST (DOMLink, ResolveAutoInertialsCalledWithAutoFalse)
774
934
{
0 commit comments