LCOV - code coverage report
Current view: top level - src/rdl/rdl_urdfreader/tests - UrdfReaderTests.cpp (source / functions) Hit Total Coverage
Test: projectcoverage.info Lines: 457 464 98.5 %
Date: 2024-12-13 18:04:46 Functions: 42 42 100.0 %
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // Copyright (c) 2017 Jordan Lack <jlack1987@gmail.com>
       2                 :            : // Copyright (c) 2011-2016 Martin Felis <martin.felis@iwr.uni-heidelberg.de>
       3                 :            : // RDL - Robot Dynamics Library
       4                 :            : // Licensed under the zlib license. See LICENSE for more details.
       5                 :            : 
       6                 :            : #include <fstream>
       7                 :            : #include <gtest/gtest.h>
       8                 :            : #include <ament_index_cpp/get_package_share_directory.hpp>
       9                 :            : 
      10                 :            : #include <rdl_dynamics/Dynamics.hpp>
      11                 :            : #include <rdl_dynamics/Kinematics.hpp>
      12                 :            : #include <rdl_dynamics/Model.hpp>
      13                 :            : #include <rdl_dynamics/rdl_utils.hpp>
      14                 :            : #include <rdl_urdfreader/urdfreader.hpp>
      15                 :            : 
      16                 :            : const double E_MINUS_14 = 1.0e-14;
      17                 :            : 
      18                 :            : class UrdfReaderTests : public testing::Test
      19                 :            : {
      20                 :            :   public:
      21                 :         18 :     UrdfReaderTests()
      22                 :         18 :     {
      23                 :         18 :         srand(time(nullptr));
      24                 :         18 :     }
      25                 :            : 
      26                 :         18 :     void SetUp()
      27                 :            :     {
      28                 :         18 :     }
      29                 :            : 
      30                 :         18 :     void TearDown()
      31                 :            :     {
      32                 :         18 :     }
      33                 :            : 
      34                 :          8 :     std::string getFileContents(const std::string& filename)
      35                 :            :     {
      36                 :          8 :         std::ifstream model_file(filename);
      37                 :          8 :         if (!model_file)
      38                 :            :         {
      39                 :          0 :             std::cerr << "Error opening file '" << filename << "'." << std::endl;
      40                 :          0 :             abort();
      41                 :            :         }
      42                 :            : 
      43                 :            :         // reserve memory for the contents of the file
      44                 :          8 :         std::string model_xml_string;
      45                 :          8 :         model_file.seekg(0, std::ios::end);
      46                 :          8 :         model_xml_string.reserve(model_file.tellg());
      47                 :          8 :         model_file.seekg(0, std::ios::beg);
      48                 :          8 :         model_xml_string.assign((std::istreambuf_iterator<char>(model_file)), std::istreambuf_iterator<char>());
      49                 :            : 
      50                 :          8 :         model_file.close();
      51                 :         16 :         return model_xml_string;
      52                 :          8 :     }
      53                 :            : };
      54                 :            : 
      55                 :          2 : TEST_F(UrdfReaderTests, q_index_two_chains)
      56                 :            : {
      57                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model());
      58                 :          2 :     std::string path_to_urdf = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/simple_two_chain_bot.urdf";
      59                 :            : 
      60                 :          1 :     std::string contents = getFileContents(path_to_urdf);
      61                 :          1 :     std::vector<unsigned int> q_indices;
      62                 :          1 :     std::vector<std::string> joint_names, body_names;
      63                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::parseJointAndBodyNamesFromString(contents, joint_names, body_names));
      64                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::parseJointAndQIndex(contents, q_indices));
      65                 :            : 
      66                 :          1 :     EXPECT_EQ(q_indices.size(), (unsigned int)3);
      67                 :          1 :     EXPECT_STREQ(joint_names[0].c_str(), "test_robot_shoulder_lift_joint");
      68                 :          1 :     EXPECT_STREQ(body_names[0].c_str(), "test_robot_upper_arm_link");
      69                 :          1 :     EXPECT_EQ(q_indices[std::distance(joint_names.begin(), std::find(joint_names.begin(), joint_names.end(), "test_robot_shoulder_lift_joint"))], (unsigned int)0);
      70                 :            : 
      71                 :          1 :     EXPECT_STREQ(joint_names[1].c_str(), "test_robot_elbow_joint");
      72                 :          1 :     EXPECT_STREQ(body_names[1].c_str(), "test_robot_forearm_link");
      73                 :          1 :     EXPECT_EQ(q_indices[std::distance(joint_names.begin(), std::find(joint_names.begin(), joint_names.end(), "test_robot_elbow_joint"))], (unsigned int)1);
      74                 :            : 
      75                 :          1 :     EXPECT_STREQ(joint_names[2].c_str(), "test_robot_shoulder_pan_joint");
      76                 :          1 :     EXPECT_STREQ(body_names[2].c_str(), "test_robot_shoulder_link");
      77                 :          1 :     EXPECT_EQ(q_indices[std::distance(joint_names.begin(), std::find(joint_names.begin(), joint_names.end(), "test_robot_shoulder_pan_joint"))], (unsigned int)2);
      78                 :          1 : }
      79                 :            : 
      80                 :          2 : TEST_F(UrdfReaderTests, testFirstJointFixedNonTrivialTransform)
      81                 :            : {
      82                 :          2 :     std::string file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/first_joint_fixed_non_trivial_xform.urdf";
      83                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model());
      84                 :            : 
      85                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(file_path, model));
      86                 :            : 
      87                 :          1 :     RobotDynamics::Math::VectorNd q = RobotDynamics::Math::VectorNd::Zero(model->q_size);
      88                 :          1 :     RobotDynamics::Math::VectorNd qdot = RobotDynamics::Math::VectorNd::Zero(model->qdot_size);
      89                 :          1 :     RobotDynamics::Math::VectorNd qddot = RobotDynamics::Math::VectorNd::Zero(model->qdot_size);
      90                 :            : 
      91                 :          1 :     ASSERT_EQ(model->q_size, (unsigned int)1);
      92                 :          1 :     ASSERT_EQ(model->qdot_size, (unsigned int)1);
      93                 :            : 
      94                 :          1 :     RobotDynamics::updateKinematics(*model, q, qdot, qddot);
      95                 :          3 :     RobotDynamics::ReferenceFramePtr frame = model->referenceFrameMap["j1_link"];
      96                 :            : 
      97                 :          1 :     EXPECT_TRUE(model->referenceFrameMap["j1_link"]->getInverseTransformToRoot().r.isApprox(RobotDynamics::Math::Vector3d(0.0, 0.16, 0.8377), 1e-4));
      98                 :          1 : }
      99                 :            : 
     100                 :          2 : TEST_F(UrdfReaderTests, testFixedArm)
     101                 :            : {
     102                 :          2 :     std::string file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/test_robot_arm.urdf";
     103                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model());
     104                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(file_path, model));
     105                 :            : 
     106                 :            :     // First body in URDf is a fixed joint body, so it'll get mashed together with the root body
     107                 :          1 :     EXPECT_EQ(model->mBodies[0].mMass, 4.);
     108                 :          1 :     EXPECT_TRUE(model->mBodies[0].mCenterOfMass.isApprox(RobotDynamics::Math::Vector3d(0., 0., 0.), 1e-14));
     109                 :            : 
     110                 :          1 :     EXPECT_EQ(model->Ib_c[0].Ixx, 0.0061063308908);
     111                 :          1 :     EXPECT_EQ(model->Ib_c[0].Iyx, 0.0);
     112                 :          1 :     EXPECT_EQ(model->Ib_c[0].Izx, 0.0);
     113                 :          1 :     EXPECT_EQ(model->Ib_c[0].Iyy, 0.0061063308908);
     114                 :          1 :     EXPECT_EQ(model->Ib_c[0].Izy, 0.0);
     115                 :          1 :     EXPECT_EQ(model->Ib_c[0].Izz, 0.01125);
     116                 :            : 
     117                 :          1 :     unsigned int id = model->GetBodyId("test_robot_shoulder_link");
     118                 :          1 :     EXPECT_EQ(model->mBodies[id].mMass, 7.778);
     119                 :          1 :     EXPECT_TRUE(model->mBodies[id].mCenterOfMass.isApprox(RobotDynamics::Math::Vector3d(0., 0.01, 0.), 1e-14));
     120                 :            : 
     121                 :          1 :     EXPECT_EQ(model->Ib_c[id].Ixx, 0.0314743125769);
     122                 :          1 :     EXPECT_EQ(model->Ib_c[id].Iyx, 0.);
     123                 :          1 :     EXPECT_EQ(model->Ib_c[id].Izx, 0.);
     124                 :          1 :     EXPECT_EQ(model->Ib_c[id].Iyy, 0.0314743125769);
     125                 :          1 :     EXPECT_EQ(model->Ib_c[id].Izy, 0.);
     126                 :          1 :     EXPECT_EQ(model->Ib_c[id].Izz, 0.021875625);
     127                 :            : 
     128                 :          1 :     id = model->GetParentBodyId(model->GetBodyId("gripper_right_finger_link"));
     129                 :          1 :     EXPECT_EQ(model->GetBodyId("gripper_right_knuckle_link"), id);
     130                 :            : 
     131                 :          1 :     EXPECT_EQ(model->mJoints[1].mJointType, RobotDynamics::JointTypePrismatic);
     132                 :          1 :     EXPECT_EQ(model->GetBodyId("test_robot_shoulder_link"), model->lambda[model->GetBodyId("test_robot_upper_arm_link")]);
     133                 :          1 : }
     134                 :            : 
     135                 :          2 : TEST_F(UrdfReaderTests, testNegative1DofJointAxes)
     136                 :            : {
     137                 :          2 :     std::string file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/test_robot_arm.urdf";
     138                 :          2 :     std::string file_path_2 = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/test_robot_arm_neg_jnt_axes.urdf";
     139                 :          2 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model()), model_neg_axes(new RobotDynamics::Model());
     140                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(file_path, model));
     141                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(file_path_2, model_neg_axes));
     142                 :            : 
     143                 :          2 :     RobotDynamics::Math::VectorNd q = RobotDynamics::Math::VectorNd::Zero(model->q_size);
     144                 :          2 :     RobotDynamics::Math::VectorNd q_neg = RobotDynamics::Math::VectorNd::Zero(model->q_size);
     145                 :          2 :     RobotDynamics::Math::VectorNd qd = RobotDynamics::Math::VectorNd::Zero(model->qdot_size);
     146                 :          2 :     RobotDynamics::Math::VectorNd qd_neg = RobotDynamics::Math::VectorNd::Zero(model->qdot_size);
     147                 :          2 :     RobotDynamics::Math::VectorNd qdd = RobotDynamics::Math::VectorNd::Zero(model->qdot_size);
     148                 :          2 :     RobotDynamics::Math::VectorNd qdd_neg = RobotDynamics::Math::VectorNd::Zero(model->qdot_size);
     149                 :          2 :     RobotDynamics::Math::VectorNd tau = RobotDynamics::Math::VectorNd::Zero(model->qdot_size);
     150                 :          2 :     RobotDynamics::Math::VectorNd tau_neg = RobotDynamics::Math::VectorNd::Zero(model->qdot_size);
     151                 :            : 
     152                 :         13 :     for (int i = 0; i < q.size(); i++)
     153                 :            :     {
     154                 :         12 :         q[i] = 0.4 * M_PI * static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
     155                 :         12 :         qd[i] = 0.5 * M_PI * static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
     156                 :         12 :         tau[i] = 0.5 * M_PI * static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
     157                 :         12 :         qdd[i] = 0.5 * M_PI * static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
     158                 :            :     }
     159                 :            : 
     160                 :          1 :     q_neg = -q;
     161                 :          1 :     qd_neg = -qd;
     162                 :          1 :     qdd_neg = -qdd;
     163                 :          1 :     tau_neg = -tau;
     164                 :            : 
     165                 :          1 :     RobotDynamics::updateKinematics(*model, q, qd, qdd);
     166                 :          1 :     RobotDynamics::updateKinematics(*model_neg_axes, q_neg, qd_neg, qdd_neg);
     167                 :            : 
     168                 :         14 :     for (unsigned int i = 0; i < model->mBodies.size(); i++)
     169                 :            :     {
     170                 :         13 :         EXPECT_TRUE(model->v[i].isApprox(model_neg_axes->v[i], 1e-14));
     171                 :         13 :         EXPECT_TRUE(model->a[i].isApprox(model_neg_axes->a[i], 1e-14));
     172                 :            :     }
     173                 :            : 
     174                 :          1 :     RobotDynamics::forwardDynamics(*model, q, qd, tau, qdd);
     175                 :          1 :     RobotDynamics::forwardDynamics(*model_neg_axes, q_neg, qd_neg, tau_neg, qdd_neg);
     176                 :            : 
     177                 :          1 :     EXPECT_TRUE(qdd.isApprox(-qdd_neg, 1e-14));
     178                 :            : 
     179                 :          1 :     RobotDynamics::inverseDynamics(*model, q, qd, qdd, tau);
     180                 :          1 :     RobotDynamics::inverseDynamics(*model_neg_axes, q_neg, qd_neg, qdd_neg, tau_neg);
     181                 :            : 
     182                 :          1 :     EXPECT_TRUE(tau.isApprox(-tau_neg, 1e-14));
     183                 :          1 : }
     184                 :            : 
     185                 :          2 : TEST_F(UrdfReaderTests, testJointBodyMap)
     186                 :            : {
     187                 :          2 :     std::string file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/test_robot_arm.urdf";
     188                 :          1 :     std::map<std::string, std::string> jointBodyMap;
     189                 :            : 
     190                 :          1 :     ASSERT_TRUE(RobotDynamics::Urdf::parseJointBodyNameMapFromFile(file_path, jointBodyMap));
     191                 :            : 
     192                 :          2 :     EXPECT_STREQ(jointBodyMap["test_robot_elbow_joint"].c_str(), "test_robot_forearm_link");
     193                 :          1 :     EXPECT_TRUE(jointBodyMap.find("test_robot_ee_fixed_joint") == jointBodyMap.end());  // It's fixed, so shouldn't be here
     194                 :          2 :     EXPECT_STREQ(jointBodyMap["test_robot_shoulder_pan_joint"].c_str(), "test_robot_shoulder_link");
     195                 :            : 
     196                 :          2 :     std::string contents = getFileContents(file_path);
     197                 :          2 :     std::vector<unsigned int> q_indices;
     198                 :          1 :     RobotDynamics::Urdf::parseJointAndQIndex(contents, q_indices);
     199                 :          1 :     EXPECT_EQ(q_indices.size(), (unsigned int)12);
     200                 :            :     // EXPECT_TRUE(q_indices[0] == 0);
     201                 :          1 : }
     202                 :            : 
     203                 :          2 : TEST_F(UrdfReaderTests, testFloatingBaseRobot)
     204                 :            : {
     205                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model());
     206                 :          2 :     std::string path_to_urdf = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/floating_base_robot.urdf";
     207                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(path_to_urdf, model));
     208                 :            : 
     209                 :          1 :     EXPECT_NEAR(model->mBodies[2].mMass, 4., 1e-14);
     210                 :          1 :     EXPECT_TRUE(model->mBodies[2].mCenterOfMass.isApprox(RobotDynamics::Math::Vector3d(0.3, 0.2, 0.1), 1e-14));
     211                 :            : 
     212                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Ixx, 0.1, 1e-14);
     213                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Iyx, 0., 1e-14);
     214                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Izx, 0., 1e-14);
     215                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Iyy, 0.2, 1e-14);
     216                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Izy, 0., 1e-14);
     217                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Izz, 0.3, 1e-14);
     218                 :            : 
     219                 :          1 :     EXPECT_EQ(model->mJoints[1].mJointType, RobotDynamics::JointTypeTranslationXYZ);
     220                 :          1 :     EXPECT_EQ(model->mJoints[2].mJointType, RobotDynamics::JointTypeSpherical);
     221                 :          1 : }
     222                 :            : 
     223                 :          2 : TEST_F(UrdfReaderTests, testFloatingBaseRobotDeduceFloatingBase)
     224                 :            : {
     225                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model());
     226                 :          2 :     std::string path_to_urdf = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/floating_base_robot.urdf";
     227                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(path_to_urdf, model));
     228                 :            : 
     229                 :          1 :     EXPECT_NEAR(model->mBodies[2].mMass, 4., 1e-14);
     230                 :          1 :     EXPECT_TRUE(model->mBodies[2].mCenterOfMass.isApprox(RobotDynamics::Math::Vector3d(0.3, 0.2, 0.1), 1e-14));
     231                 :            : 
     232                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Ixx, 0.1, 1e-14);
     233                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Iyx, 0., 1e-14);
     234                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Izx, 0., 1e-14);
     235                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Iyy, 0.2, 1e-14);
     236                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Izy, 0., 1e-14);
     237                 :          1 :     EXPECT_NEAR(model->Ib_c[2].Izz, 0.3, 1e-14);
     238                 :            : 
     239                 :          1 :     EXPECT_EQ(model->mJoints[1].mJointType, RobotDynamics::JointTypeTranslationXYZ);
     240                 :          1 :     EXPECT_EQ(model->mJoints[2].mJointType, RobotDynamics::JointTypeSpherical);
     241                 :          1 : }
     242                 :            : 
     243                 :          2 : TEST_F(UrdfReaderTests, testRobotWithFloatingJoint)
     244                 :            : {
     245                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model());
     246                 :          2 :     std::string path_to_urdf = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/floating_joint_robot.urdf";
     247                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(path_to_urdf, model));
     248                 :            : 
     249                 :          1 :     EXPECT_EQ(model->mJoints[1].mJointType, RobotDynamics::JointTypeTranslationXYZ);
     250                 :          1 :     EXPECT_EQ(model->mJoints[2].mJointType, RobotDynamics::JointTypeEulerXYZ);
     251                 :            : 
     252                 :          2 :     std::string contents = getFileContents(path_to_urdf);
     253                 :          2 :     std::vector<unsigned int> q_indices;
     254                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::parseJointAndQIndex(contents, q_indices));
     255                 :            : 
     256                 :          1 :     EXPECT_EQ(q_indices.size(), (unsigned int)1);
     257                 :          1 :     EXPECT_EQ(q_indices[0], (unsigned int)6);
     258                 :          1 : }
     259                 :            : 
     260                 :          2 : TEST_F(UrdfReaderTests, testRobotSingleBodyFloatingBase)
     261                 :            : {
     262                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model());
     263                 :          2 :     std::string path_to_urdf = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/single_body_floating_base.urdf";
     264                 :          1 :     ASSERT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(path_to_urdf, model));
     265                 :            : 
     266                 :          2 :     std::string contents = getFileContents(path_to_urdf);
     267                 :          2 :     std::vector<unsigned int> q_indices;
     268                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::parseJointAndQIndex(contents, q_indices));
     269                 :            : 
     270                 :          1 :     EXPECT_EQ(q_indices.size(), (unsigned int)0);
     271                 :          1 : }
     272                 :            : 
     273                 :          2 : TEST_F(UrdfReaderTests, rotated_inertial)
     274                 :            : {
     275                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model());
     276                 :          2 :     std::string path_to_urdf = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/rotated_inertial.urdf";
     277                 :          1 :     ASSERT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(path_to_urdf, model));
     278                 :            : 
     279                 :          1 :     RobotDynamics::Math::Matrix3d I1 = RobotDynamics::Math::Matrix3dIdentity;
     280                 :          1 :     I1(0, 0) = 0.03;
     281                 :          1 :     I1(1, 1) = 0.03;
     282                 :          1 :     I1(2, 2) = 0.02;
     283                 :          1 :     EXPECT_TRUE(I1.isApprox(model->mBodies[1].mInertia, 1.e-10));
     284                 :            : 
     285                 :          1 :     RobotDynamics::Math::Matrix3d I2 = RobotDynamics::Math::Matrix3dIdentity;
     286                 :          1 :     I2(0, 0) = 0.03;
     287                 :          1 :     I2(1, 1) = 0.02;
     288                 :          1 :     I2(2, 2) = 0.03;
     289                 :          1 :     EXPECT_TRUE(I2.isApprox(model->mBodies[2].mInertia, 1.e-10));
     290                 :            : 
     291                 :          1 :     RobotDynamics::Math::Matrix3d I3 = RobotDynamics::Math::Matrix3dIdentity;
     292                 :          1 :     I3(0, 0) = 0.02;
     293                 :          1 :     I3(1, 1) = 0.03;
     294                 :          1 :     I3(2, 2) = 0.03;
     295                 :          1 :     EXPECT_TRUE(I3.isApprox(model->mBodies[3].mInertia, 1.e-10));
     296                 :          1 : }
     297                 :            : 
     298                 :          2 : TEST_F(UrdfReaderTests, rotated_inertial_floating_base)
     299                 :            : {
     300                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model());
     301                 :          2 :     std::string path_to_urdf = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/floating_base_rotated_inertial.urdf";
     302                 :          1 :     ASSERT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(path_to_urdf, model));
     303                 :            : 
     304                 :          1 :     RobotDynamics::Math::Matrix3d I1 = RobotDynamics::Math::Matrix3dIdentity;
     305                 :          1 :     I1(0, 0) = 0.03;
     306                 :          1 :     I1(1, 1) = 0.03;
     307                 :          1 :     I1(2, 2) = 0.02;
     308                 :          1 :     EXPECT_TRUE(I1.isApprox(model->mBodies[2].mInertia, 1.e-10));
     309                 :            : 
     310                 :          1 :     RobotDynamics::Math::Matrix3d I2 = RobotDynamics::Math::Matrix3dIdentity;
     311                 :          1 :     I2(0, 0) = 0.03;
     312                 :          1 :     I2(1, 1) = 0.02;
     313                 :          1 :     I2(2, 2) = 0.03;
     314                 :          1 :     EXPECT_TRUE(I2.isApprox(model->mBodies[3].mInertia, 1.e-10));
     315                 :            : 
     316                 :          1 :     RobotDynamics::Math::Matrix3d I3 = RobotDynamics::Math::Matrix3dIdentity;
     317                 :          1 :     I3(0, 0) = 0.02;
     318                 :          1 :     I3(1, 1) = 0.03;
     319                 :          1 :     I3(2, 2) = 0.03;
     320                 :          1 :     EXPECT_TRUE(I3.isApprox(model->mBodies[4].mInertia, 1.e-10));
     321                 :          1 : }
     322                 :            : 
     323                 :          4 : RobotDynamics::Math::SpatialMatrix reorgAddedInertia(const RobotDynamics::Math::SpatialMatrix& in)
     324                 :            : {
     325                 :          4 :     RobotDynamics::Math::SpatialMatrix out;
     326                 :          4 :     out.block<3, 3>(0, 0) = in.block<3, 3>(3, 3);
     327                 :          4 :     out.block<3, 3>(3, 0) = in.block<3, 3>(0, 3);
     328                 :          4 :     out.block<3, 3>(0, 3) = in.block<3, 3>(3, 0);
     329                 :          4 :     out.block<3, 3>(3, 3) = in.block<3, 3>(0, 0);
     330                 :          4 :     return out;
     331                 :            : }
     332                 :            : 
     333                 :          2 : TEST_F(UrdfReaderTests, parseHydrodynamicsParameters)
     334                 :            : {
     335                 :          2 :     std::string file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/test_robot_arm_hydro.urdf";
     336                 :          1 :     RobotDynamics::Model model;
     337                 :          1 :     std::map<std::string, RobotDynamics::Urdf::hydro::BodyHydroData> data;
     338                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::hydro::parseHydrodynamicsParameters(getFileContents(file_path).c_str(), data, false));
     339                 :            : 
     340                 :          1 :     EXPECT_FALSE(data["gripper_right_finger_link"].hasHydro);
     341                 :            : 
     342                 :          0 :     RobotDynamics::Math::SpatialMatrix I(1., 0., 0., 1.03, 0., 0., 0., 183., 0., 0., 0., 0., 0., 0., 184., 0., 0., 11.133, 0., 0., 0., 2., 0., 0., 0., 2.033, 0., 0., 44.,
     343                 :          1 :                                          0., 0., 1.94, 0., 0., 0., 45.311);
     344                 :            : 
     345                 :          2 :     EXPECT_TRUE(data["gripper_left_finger_tip_link"].hasHydro);
     346                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].volume, 0.003);
     347                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].centerOfBuoyancy.x(), 0.01);
     348                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].centerOfBuoyancy.y(), 0.21);
     349                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].centerOfBuoyancy.z(), -0.03);
     350                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].linearDrag[3], 1.);
     351                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].linearDrag[4], 2.);
     352                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].linearDrag[5], 3.);
     353                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].linearDrag[0], 4.);
     354                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].linearDrag[1], 5.);
     355                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].linearDrag[2], 6.);
     356                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].quadraticDrag[3], -1.);
     357                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].quadraticDrag[4], -2.);
     358                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].quadraticDrag[5], -3.);
     359                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].quadraticDrag[0], -4.);
     360                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].quadraticDrag[1], -5.);
     361                 :          2 :     EXPECT_EQ(data["gripper_left_finger_tip_link"].quadraticDrag[2], -6.);
     362                 :          1 :     EXPECT_TRUE(reorgAddedInertia(I).isApprox(data["gripper_left_finger_tip_link"].addedMassMatrix, E_MINUS_14));
     363                 :            : 
     364                 :          0 :     I = RobotDynamics::Math::SpatialMatrix(1., 0., 0., 0., 0., 0., 0., 183., 0., 0., 0., 0., 0., 0., 184., 0., 0., 0.01, 0., 0., 0., 2., 0., 0., 0., 0., 0., 0., 44., 0.,
     365                 :          1 :                                            11., 0., 0., 0., 0., 45.);
     366                 :          2 :     EXPECT_TRUE(data["gripper_right_finger_tip_link"].hasHydro);
     367                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].volume, 0.00005);
     368                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].centerOfBuoyancy.x(), 0.11);
     369                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].centerOfBuoyancy.y(), 1.21);
     370                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].centerOfBuoyancy.z(), -0.13);
     371                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].linearDrag[3], 10.);
     372                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].linearDrag[4], 20.);
     373                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].linearDrag[5], 30.);
     374                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].linearDrag[0], 40.);
     375                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].linearDrag[1], 50.);
     376                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].linearDrag[2], 60.);
     377                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].quadraticDrag[3], -10.);
     378                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].quadraticDrag[4], -20.);
     379                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].quadraticDrag[5], -30.);
     380                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].quadraticDrag[0], -40.);
     381                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].quadraticDrag[1], -50.);
     382                 :          2 :     EXPECT_EQ(data["gripper_right_finger_tip_link"].quadraticDrag[2], -60.);
     383                 :          1 :     EXPECT_TRUE(reorgAddedInertia(I).isApprox(data["gripper_right_finger_tip_link"].addedMassMatrix, E_MINUS_14));
     384                 :            : 
     385                 :          0 :     I = RobotDynamics::Math::SpatialMatrix(1., 0., 0., 0., 0., 0., 0., 183., 0., 33.1, 0., 0., 0., 0., 184., 0., 0., 0., 0., 0., 0., 2., 3.11, 0., 0., 0., 0., 0., 44.,
     386                 :          1 :                                            0., 0., 0., 0., 0., 0., 45.);
     387                 :            : 
     388                 :          2 :     EXPECT_TRUE(data["gripper_right_inner_knuckle_link"].hasHydro);
     389                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].volume, 0.1);
     390                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].centerOfBuoyancy.x(), 0.01);
     391                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].centerOfBuoyancy.y(), 0.21);
     392                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].centerOfBuoyancy.z(), -0.03);
     393                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].linearDrag[0], 0.);
     394                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].linearDrag[1], 0.);
     395                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].linearDrag[2], 0.);
     396                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].linearDrag[3], 0.);
     397                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].linearDrag[4], 0.);
     398                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].linearDrag[5], 0.);
     399                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].quadraticDrag[0], 0.);
     400                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].quadraticDrag[1], 0.);
     401                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].quadraticDrag[2], 0.);
     402                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].quadraticDrag[3], 0.);
     403                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].quadraticDrag[4], 0.);
     404                 :          2 :     EXPECT_EQ(data["gripper_right_inner_knuckle_link"].quadraticDrag[5], 0.);
     405                 :          1 :     EXPECT_TRUE(reorgAddedInertia(I).isApprox(data["gripper_right_inner_knuckle_link"].addedMassMatrix, E_MINUS_14));
     406                 :            : 
     407                 :          1 :     I.setZero();
     408                 :          2 :     EXPECT_TRUE(data["gripper_left_finger_link"].hasHydro);
     409                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].volume, 0.1);
     410                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].centerOfBuoyancy.x(), 0.01);
     411                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].centerOfBuoyancy.y(), 0.21);
     412                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].centerOfBuoyancy.z(), -0.03);
     413                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].linearDrag[0], 0.);
     414                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].linearDrag[1], 0.);
     415                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].linearDrag[2], 0.);
     416                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].linearDrag[3], 0.);
     417                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].linearDrag[4], 0.);
     418                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].linearDrag[5], 0.);
     419                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].quadraticDrag[0], 0.);
     420                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].quadraticDrag[1], 0.);
     421                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].quadraticDrag[2], 0.);
     422                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].quadraticDrag[3], 0.);
     423                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].quadraticDrag[4], 0.);
     424                 :          2 :     EXPECT_EQ(data["gripper_left_finger_link"].quadraticDrag[5], 0.);
     425                 :          1 :     EXPECT_TRUE(data["gripper_left_finger_link"].addedMassMatrix.isZero(E_MINUS_14));
     426                 :            : 
     427                 :          0 :     I = RobotDynamics::Math::SpatialMatrix(1., 0., 0., 0., 0., 0., 0., 183., 0., 0., 0., 0., 0., 0., 184., 0., 0., 0., 0., 0., 0., 2., 0., 0., 0., 0., 0., 0., 44., 0.,
     428                 :          1 :                                            0., 0., 0., 0., 0., 45.);
     429                 :            : 
     430                 :          2 :     EXPECT_TRUE(data["gripper_left_knuckle_link"].hasHydro);
     431                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].volume, 0.);
     432                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].centerOfBuoyancy.x(), 0.);
     433                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].centerOfBuoyancy.y(), 0.);
     434                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].centerOfBuoyancy.z(), 0.);
     435                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].linearDrag[0], 0.);
     436                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].linearDrag[1], 0.);
     437                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].linearDrag[2], 0.);
     438                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].linearDrag[3], 0.);
     439                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].linearDrag[4], 0.);
     440                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].linearDrag[5], 0.);
     441                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].quadraticDrag[0], 0.);
     442                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].quadraticDrag[1], 0.);
     443                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].quadraticDrag[2], 0.);
     444                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].quadraticDrag[3], 0.);
     445                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].quadraticDrag[4], 0.);
     446                 :          2 :     EXPECT_EQ(data["gripper_left_knuckle_link"].quadraticDrag[5], 0.);
     447                 :          1 :     EXPECT_TRUE(reorgAddedInertia(I).isApprox(data["gripper_left_knuckle_link"].addedMassMatrix, E_MINUS_14));
     448                 :          1 : }
     449                 :            : 
     450                 :          2 : TEST_F(UrdfReaderTests, parseHydrodynamicsParametersFailureCases)
     451                 :            : {
     452                 :          2 :     std::string file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/invalid_hydro_added_mass.urdf";
     453                 :          1 :     std::map<std::string, RobotDynamics::Urdf::hydro::BodyHydroData> data;
     454                 :          1 :     EXPECT_FALSE(RobotDynamics::Urdf::hydro::parseHydrodynamicsParameters(getFileContents(file_path).c_str(), data, false));
     455                 :            : 
     456                 :          1 :     file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/invalid_drag_block.urdf";
     457                 :          1 :     EXPECT_FALSE(RobotDynamics::Urdf::hydro::parseHydrodynamicsParameters(getFileContents(file_path).c_str(), data, false));
     458                 :            : 
     459                 :          1 :     file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/invalid_xml.urdf";
     460                 :          1 :     EXPECT_FALSE(RobotDynamics::Urdf::hydro::parseHydrodynamicsParameters(getFileContents(file_path).c_str(), data, false));
     461                 :          1 : }
     462                 :            : 
     463                 :          2 : TEST_F(UrdfReaderTests, checkHydroBodiesHaveCorrectHydroInfo)
     464                 :            : {
     465                 :          2 :     std::string file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/test_robot_arm_hydro.urdf";
     466                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model());
     467                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(file_path, model));
     468                 :            : 
     469                 :          0 :     RobotDynamics::Math::SpatialMatrix I(2., 0., 0., 0., 0., 0., 0., 44., 0., 0., 0., 0., 0., 0., 45., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 183.0, 0., 0.,
     470                 :          1 :                                          0., 0., 0., 0., 184.);
     471                 :            : 
     472                 :          1 :     EXPECT_EQ(model->mBodies[model->GetBodyId("test_robot_shoulder_link")].volume, 0.1);
     473                 :          1 :     EXPECT_EQ(model->mBodies[model->GetBodyId("test_robot_shoulder_link")].mCenterOfBuoyancy.x(), 0.1101);
     474                 :          1 :     EXPECT_EQ(model->mBodies[model->GetBodyId("test_robot_shoulder_link")].mCenterOfBuoyancy.y(), 0.121);
     475                 :          1 :     EXPECT_EQ(model->mBodies[model->GetBodyId("test_robot_shoulder_link")].mCenterOfBuoyancy.z(), -0.013);
     476                 :            : 
     477                 :          1 :     EXPECT_TRUE(I.isApprox(model->mBodies[model->GetBodyId("gripper_left_knuckle_link")].addedMassMatrix, E_MINUS_14));
     478                 :          1 : }
     479                 :            : 
     480                 :            : /**
     481                 :            :  * The following unit test comes from running a simulation and comparing Adot with a numerically differentiated A matrix. The error
     482                 :            :  * between the two was never really greater than about 1.e-4 which seemed sufficient to me so I copied the matrices over here and
     483                 :            :  * made this test which until a better test method is found will have to do.
     484                 :            :  */
     485                 :          2 : TEST_F(UrdfReaderTests, centroidalMomentumMatrixDot)
     486                 :            : {
     487                 :          2 :     std::string file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/test_centroidal_momentum_robot.urdf";
     488                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model());
     489                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(file_path, model));
     490                 :          1 :     model->gravity = RobotDynamics::Math::MotionVector(0., 0., 0., 0., 0., -9.81);
     491                 :            : 
     492                 :          2 :     RobotDynamics::Math::VectorNd q(model->q_size), qdot(model->qdot_size);
     493                 :            : 
     494                 :          1 :     q << 2843548.033249, -209909.31618248, -28.737112471808, 0.013866084594564, -0.018922989600583, -0.27902392880053, 46.988201887017, 167.71435783402,
     495                 :          1 :         0.012894144231981, 0.003644780816261, 0.023437157143762, 0.17174982556876, -272.04399437984, -607.14717812687, 330.80048156122, -356.5405073459, 389.03904152552,
     496                 :          1 :         0.0014068227420712, -177.3187382107, 0.95999755172569;
     497                 :          1 :     qdot << 0.72356305088634, -0.27922136265996, -0.074898891065314, 0.057378004355399, 0.027501228787648, -0.11882428506134, 1.5988661473426e-05, 8.1292436215699e-06,
     498                 :          1 :         0.0004935993483221, -1.2482539961087e-05, 4.493479337845e-06, 2.1550289263633e-05, -5.527300395089e-06, 2.0919225428219e-05, 2.0919225428732e-05,
     499                 :          1 :         1.500606255915e-05, 7.1466266552134e-06, -0.0050623463209877, -1.1308026111878e-06;
     500                 :          1 :     RobotDynamics::updateKinematicsCustom(*model, &q, &qdot, nullptr);
     501                 :            : 
     502                 :          2 :     RobotDynamics::Math::MatrixNd adot(6, model->qdot_size), a(6, model->qdot_size), adot2(6, model->qdot_size), a2(6, model->qdot_size);
     503                 :          1 :     RobotDynamics::Math::SpatialVector adotv(81.38892596978, 134.45726399483, 41.428640871662, 75.132338829693, -60.321498882245, 47.201591640815);
     504                 :          1 :     RobotDynamics::Utils::calcCentroidalMomentumMatrix(*model, q, a, false);
     505                 :          1 :     RobotDynamics::Utils::calcCentroidalMomentumMatrixDot(*model, q, qdot, adot, false);
     506                 :            : 
     507                 :          1 :     EXPECT_TRUE(adotv.isApprox(adot * qdot, 1.e-7));
     508                 :            : 
     509                 :          1 :     RobotDynamics::Utils::calcCentroidalMomentumMatrixAndMatrixDot(*model, q, qdot, a2, adot2, false);
     510                 :          1 :     EXPECT_TRUE(a.isApprox(a2, 1.e-14));
     511                 :          1 :     EXPECT_TRUE(adot.isApprox(adot2, 1.e-14));
     512                 :            : 
     513                 :          1 :     q << 2843555.7426166, -209906.42505932, -31.984289527845, -0.019318359864448, 0.084947029667317, 0.38843943516417, 261.52886515801, -370.40405071333, 0.5104959350258,
     514                 :          1 :         1.1892981440042, -0.74378863055244, 0.88420467075226, 265.39312387749, -419.37422448213, 507.66603672344, -672.60712542416, 608.34632442873, 7.2151029691512e-06,
     515                 :          1 :         241.8163217398, 0.91734704901263;
     516                 :          1 :     qdot << 0.90780498518421, 0.37795991108503, -0.12286976779791, 0.016129512038977, 0.011259829695686, 0.10567671184028, 1.7140545707062e-05, 1.0042944296275e-05,
     517                 :          1 :         0.06211524064157, 0.12779617820982, -0.088022453340217, 0.096940404958886, -4.9915274408924e-06, 2.3314482437527e-05, 2.3314482437333e-05, 1.5741349596001e-05,
     518                 :          1 :         8.6437310570578e-06, -0.0021085140258945, -1.6102261528733e-06;
     519                 :          1 :     RobotDynamics::updateKinematicsCustom(*model, &q, &qdot, nullptr);
     520                 :            : 
     521                 :          1 :     adotv << 29.80644161631, -26.852723901131, 4.1278484858571, 47.672589300394, 48.762586239518, -22.769718014228;
     522                 :          1 :     RobotDynamics::Utils::calcCentroidalMomentumMatrix(*model, q, a, false);
     523                 :          1 :     RobotDynamics::Utils::calcCentroidalMomentumMatrixDot(*model, q, qdot, adot, false);
     524                 :            : 
     525                 :          1 :     EXPECT_TRUE(adotv.isApprox(adot * qdot, 1.e-7));
     526                 :          1 :     RobotDynamics::Utils::calcCentroidalMomentumMatrixAndMatrixDot(*model, q, qdot, a2, adot2, false);
     527                 :          1 :     EXPECT_TRUE(a.isApprox(a2, 1.e-14));
     528                 :          1 :     EXPECT_TRUE(adot.isApprox(adot2, 1.e-14));
     529                 :          1 : }
     530                 :            : 
     531                 :          2 : TEST_F(UrdfReaderTests, eulerzyx_coordinates_for_floating_base)
     532                 :            : {
     533                 :          2 :     std::string file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/test_centroidal_momentum_robot.urdf";
     534                 :          2 :     RobotDynamics::ModelPtr euler_model(new RobotDynamics::Model()), fb_model(new RobotDynamics::Model());
     535                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(file_path, euler_model, RobotDynamics::JointTypeEulerZYX));
     536                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(file_path, fb_model));
     537                 :            : 
     538                 :          2 :     RobotDynamics::Math::VectorNd q_eul(euler_model->q_size), qdot_eul(euler_model->qdot_size);
     539                 :          2 :     RobotDynamics::Math::VectorNd q_fb(fb_model->q_size), qdot_fb(fb_model->qdot_size);
     540                 :            : 
     541                 :            :     // randomize the fb state
     542                 :         20 :     for (int i = 0; i < q_eul.size(); ++i)
     543                 :            :     {
     544                 :         19 :         q_eul[i] = M_PI * (static_cast<double>(rand()) / static_cast<double>(RAND_MAX)) - M_PI_2;
     545                 :         19 :         qdot_eul[i] = M_PI * (static_cast<double>(rand()) / static_cast<double>(RAND_MAX)) - M_PI_2;
     546                 :         19 :         q_fb[i] = q_eul[i];
     547                 :         19 :         qdot_fb[i] = qdot_eul[i];
     548                 :            :     }
     549                 :            : 
     550                 :          1 :     unsigned int euler_base_link_id = euler_model->GetBodyId("base_link");
     551                 :          1 :     unsigned int fb_base_link_id = fb_model->GetBodyId("base_link");
     552                 :            : 
     553                 :            :     // now fix the base link orientation bits since they have different orientation coordinates for the base link
     554                 :          1 :     RobotDynamics::Math::Quaternion o(RobotDynamics::Math::XeulerZYX(q_eul[3], q_eul[4], q_eul[5]).E);
     555                 :          1 :     fb_model->SetQuaternion(fb_base_link_id, o, q_fb);
     556                 :            : 
     557                 :          1 :     RobotDynamics::Math::Vector3d w = RobotDynamics::Math::angular_velocity_from_zyx_angle_rates(RobotDynamics::Math::Vector3d(q_eul[3], q_eul[4], q_eul[5]),
     558                 :          2 :                                                                                                  RobotDynamics::Math::Vector3d(qdot_eul[3], qdot_eul[4], qdot_eul[5]));
     559                 :            : 
     560                 :          1 :     qdot_fb[3] = w[0];
     561                 :          1 :     qdot_fb[4] = w[1];
     562                 :          1 :     qdot_fb[5] = w[2];
     563                 :            :     // now update both kinematics and check that they are the same
     564                 :          1 :     RobotDynamics::updateKinematicsCustom(*euler_model, &q_eul, &qdot_eul);
     565                 :          1 :     RobotDynamics::updateKinematicsCustom(*fb_model, &q_fb, &qdot_fb);
     566                 :            : 
     567                 :         17 :     for (size_t i = 0; i < fb_model->bodyFrames.size(); ++i)
     568                 :            :     {
     569                 :         16 :         EXPECT_TRUE(fb_model->bodyFrames[i]->getTransformToRoot().toMatrix().isApprox(euler_model->bodyFrames[i]->getTransformToRoot().toMatrix(), 1.e-14));
     570                 :            :     }
     571                 :            : 
     572                 :         17 :     for (size_t i = 0; i < fb_model->bodyCenteredFrames.size(); ++i)
     573                 :            :     {
     574                 :         16 :         EXPECT_TRUE(
     575                 :         16 :             fb_model->bodyCenteredFrames[i]->getTransformToRoot().toMatrix().isApprox(euler_model->bodyCenteredFrames[i]->getTransformToRoot().toMatrix(), 1.e-14));
     576                 :            :     }
     577                 :          1 :     EXPECT_TRUE(fb_model->v[fb_base_link_id].isApprox(euler_model->v[euler_base_link_id], 1.e-14));
     578                 :          1 : }
     579                 :            : 
     580                 :          2 : TEST_F(UrdfReaderTests, eulerxyz_coordinates_for_floating_base)
     581                 :            : {
     582                 :          2 :     std::string file_path = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/test_centroidal_momentum_robot.urdf";
     583                 :          2 :     RobotDynamics::ModelPtr euler_model(new RobotDynamics::Model()), fb_model(new RobotDynamics::Model());
     584                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(file_path, euler_model, RobotDynamics::JointTypeEulerXYZ));
     585                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(file_path, fb_model));
     586                 :            : 
     587                 :          2 :     RobotDynamics::Math::VectorNd q_eul(euler_model->q_size), qdot_eul(euler_model->qdot_size);
     588                 :          2 :     RobotDynamics::Math::VectorNd q_fb(fb_model->q_size), qdot_fb(fb_model->qdot_size);
     589                 :            : 
     590                 :            :     // randomize the fb state
     591                 :         20 :     for (int i = 0; i < q_eul.size(); ++i)
     592                 :            :     {
     593                 :         19 :         q_eul[i] = M_PI * (static_cast<double>(rand()) / static_cast<double>(RAND_MAX)) - M_PI_2;
     594                 :         19 :         qdot_eul[i] = M_PI * (static_cast<double>(rand()) / static_cast<double>(RAND_MAX)) - M_PI_2;
     595                 :         19 :         q_fb[i] = q_eul[i];
     596                 :         19 :         qdot_fb[i] = qdot_eul[i];
     597                 :            :     }
     598                 :            : 
     599                 :          1 :     unsigned int euler_base_link_id = euler_model->GetBodyId("base_link");
     600                 :          1 :     unsigned int fb_base_link_id = fb_model->GetBodyId("base_link");
     601                 :            : 
     602                 :            :     // now fix the base link orientation bits since they have different orientation coordinates for the base link
     603                 :          1 :     RobotDynamics::Math::Quaternion o(RobotDynamics::Math::XeulerXYZ(q_eul[3], q_eul[4], q_eul[5]).E);
     604                 :          1 :     fb_model->SetQuaternion(fb_base_link_id, o, q_fb);
     605                 :            : 
     606                 :          1 :     RobotDynamics::Math::Vector3d w = RobotDynamics::Math::angular_velocity_from_xyz_angle_rates(RobotDynamics::Math::Vector3d(q_eul[3], q_eul[4], q_eul[5]),
     607                 :          2 :                                                                                                  RobotDynamics::Math::Vector3d(qdot_eul[3], qdot_eul[4], qdot_eul[5]));
     608                 :            : 
     609                 :          1 :     qdot_fb[3] = w[0];
     610                 :          1 :     qdot_fb[4] = w[1];
     611                 :          1 :     qdot_fb[5] = w[2];
     612                 :            :     // now update both kinematics and check that they are the same
     613                 :          1 :     RobotDynamics::updateKinematicsCustom(*euler_model, &q_eul, &qdot_eul);
     614                 :          1 :     RobotDynamics::updateKinematicsCustom(*fb_model, &q_fb, &qdot_fb);
     615                 :            : 
     616                 :         17 :     for (size_t i = 0; i < fb_model->bodyFrames.size(); ++i)
     617                 :            :     {
     618                 :         16 :         EXPECT_TRUE(fb_model->bodyFrames[i]->getTransformToRoot().toMatrix().isApprox(euler_model->bodyFrames[i]->getTransformToRoot().toMatrix(), 1.e-14));
     619                 :            :     }
     620                 :            : 
     621                 :         17 :     for (size_t i = 0; i < fb_model->bodyCenteredFrames.size(); ++i)
     622                 :            :     {
     623                 :         16 :         EXPECT_TRUE(
     624                 :         16 :             fb_model->bodyCenteredFrames[i]->getTransformToRoot().toMatrix().isApprox(euler_model->bodyCenteredFrames[i]->getTransformToRoot().toMatrix(), 1.e-14));
     625                 :            :     }
     626                 :          1 :     EXPECT_TRUE(fb_model->v[fb_base_link_id].isApprox(euler_model->v[euler_base_link_id], 1.e-14));
     627                 :          1 : }
     628                 :            : 
     629                 :          2 : TEST_F(UrdfReaderTests, load_ros_params_from_file)
     630                 :            : {
     631                 :          2 :     std::string filepath = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/config/load_ros_params_from_file.yaml";
     632                 :          1 :     rclcpp::NodeOptions options;
     633                 :          4 :     options.arguments({ "--ros-args", "--params-file", filepath.c_str() });
     634                 :            : 
     635                 :          1 :     rclcpp::Node::SharedPtr n = rclcpp::Node::make_shared("load_ros_params_from_file", options);
     636                 :          1 :     RobotDynamics::ModelPtr model(new RobotDynamics::Model(n));
     637                 :          2 :     std::string path_to_urdf = ament_index_cpp::get_package_share_directory("rdl_urdfreader") + "/tests/urdf/floating_base_robot.urdf";
     638                 :          1 :     EXPECT_TRUE(RobotDynamics::Urdf::urdfReadFromFile(path_to_urdf, model));
     639                 :          1 :     model->setupRosParameters();
     640                 :            : 
     641                 :          1 :     EXPECT_NEAR(model->mass, 17.778, 1.e-14);
     642                 :          1 :     EXPECT_NEAR(model->volume, 1.1, 1.e-14);
     643                 :          1 : }
     644                 :            : 
     645                 :          1 : int main(int argc, char** argv)
     646                 :            : {
     647                 :          1 :     ::testing::InitGoogleTest(&argc, argv);
     648                 :          1 :     ::testing::FLAGS_gtest_death_test_style = "threadsafe";
     649                 :          1 :     rclcpp::init(argc, argv);
     650                 :          1 :     return RUN_ALL_TESTS();
     651                 :            : }

Generated by: LCOV version 1.14