@@ -61,7 +61,8 @@ Eigen::VectorXd makeVector(const std::vector<double>& values)
61
61
62
62
// Checks the validity of state.getJacobian() at the given 'joint_values' and 'joint_velocities'.
63
63
void checkJacobian (moveit::core::RobotState& state, const moveit::core::JointModelGroup& joint_model_group,
64
- const Eigen::VectorXd& joint_values, const Eigen::VectorXd& joint_velocities)
64
+ const Eigen::VectorXd& joint_values, const Eigen::VectorXd& joint_velocities,
65
+ const moveit::core::LinkModel* reference_link = nullptr )
65
66
{
66
67
// Using the Jacobian, compute the Cartesian velocity vector at which the end-effector would move, with the given
67
68
// joint velocities.
@@ -73,9 +74,36 @@ void checkJacobian(moveit::core::RobotState& state, const moveit::core::JointMod
73
74
const moveit::core::LinkModel* root_link_model = root_joint_model->getParentLinkModel ();
74
75
const Eigen::Isometry3d root_pose_world = state.getGlobalLinkTransform (root_link_model).inverse ();
75
76
76
- const Eigen::Isometry3d tip_pose_initial =
77
- root_pose_world * state.getGlobalLinkTransform (joint_model_group.getLinkModels ().back ());
78
- const Eigen::MatrixXd jacobian = state.getJacobian (&joint_model_group);
77
+ if (!reference_link)
78
+ {
79
+ reference_link = joint_model_group.getLinkModels ().back ();
80
+ }
81
+ const Eigen::Isometry3d tip_pose_initial = root_pose_world * state.getGlobalLinkTransform (reference_link);
82
+ Eigen::MatrixXd jacobian;
83
+ state.getJacobian (&joint_model_group, reference_link, Eigen::Vector3d::Zero (), jacobian);
84
+
85
+ // Verify that only elements of the Jacobian contain values that correspond to joints that are being used based on the reference link.
86
+ const std::vector<const moveit::core::JointModel*>& joint_models = joint_model_group.getJointModels ();
87
+ auto it = std::find_if (joint_models.begin (), joint_models.end (), [&](const moveit::core::JointModel* jm) {
88
+ return jm->getParentLinkModel () == reference_link;
89
+ });
90
+ if (it != joint_models.end ())
91
+ {
92
+ std::size_t index = 0 ;
93
+ for (auto jt = joint_models.begin (); jt != it; ++jt)
94
+ {
95
+ index += (*jt)->getVariableCount ();
96
+ }
97
+
98
+ EXPECT_TRUE (jacobian.block (0 , index , jacobian.rows (), jacobian.cols () - index ).isZero ())
99
+ << " Jacobian contains non-zero values for joints that are not used based on the reference link "
100
+ << reference_link->getName () << " . This is the faulty Jacobian: " << ' \n '
101
+ << jacobian << ' \n '
102
+ << " The columns " << index << " to " << jacobian.cols () << " should be zero. Instead the values are: " << ' \n '
103
+ << jacobian.block (0 , index , jacobian.rows (), jacobian.cols () - index );
104
+ }
105
+
106
+ // Compute the Cartesian velocity vector using the Jacobian.
79
107
const Eigen::VectorXd cartesian_velocity = jacobian * joint_velocities;
80
108
81
109
// Compute the instantaneous displacement that the end-effector would achieve if the given joint
@@ -84,8 +112,7 @@ void checkJacobian(moveit::core::RobotState& state, const moveit::core::JointMod
84
112
const Eigen::VectorXd delta_joint_angles = time_step * joint_velocities;
85
113
state.setJointGroupPositions (&joint_model_group, joint_values + delta_joint_angles);
86
114
state.updateLinkTransforms ();
87
- const Eigen::Isometry3d tip_pose_after_delta =
88
- root_pose_world * state.getGlobalLinkTransform (joint_model_group.getLinkModels ().back ());
115
+ const Eigen::Isometry3d tip_pose_after_delta = root_pose_world * state.getGlobalLinkTransform (reference_link);
89
116
const Eigen::Vector3d displacement = tip_pose_after_delta.translation () - tip_pose_initial.translation ();
90
117
91
118
// The Cartesian velocity vector obtained via the Jacobian should be aligned with the instantaneous robot motion, i.e.
@@ -843,6 +870,76 @@ TEST(getJacobian, RevoluteJoints)
843
870
checkJacobian (state, *jmg, makeVector ({ 0.1 , 0.2 , 0.3 , 0.4 }), makeVector ({ 0.5 , 0.3 , 0.2 , 0.1 }));
844
871
}
845
872
873
+ TEST (getJacobian, RevoluteJointsButDifferentLink)
874
+ {
875
+ // Robot URDF with four revolute joints.
876
+ constexpr char robot_urdf[] = R"(
877
+ <?xml version="1.0" ?>
878
+ <robot name="one_robot">
879
+ <link name="base_link"/>
880
+ <joint name="joint_a_revolute" type="revolute">
881
+ <axis xyz="0 0 1"/>
882
+ <parent link="base_link"/>
883
+ <child link="link_a"/>
884
+ <origin rpy="0 0 0" xyz="0 0 0"/>
885
+ <limit effort="100.0" lower="-3.14" upper="3.14" velocity="0.2"/>
886
+ </joint>
887
+ <link name="link_a"/>
888
+ <joint name="joint_b_revolute" type="revolute">
889
+ <axis xyz="0 0 1"/>
890
+ <parent link="link_a"/>
891
+ <child link="link_b"/>
892
+ <origin rpy="0 0 0" xyz="0.0 0.5 0"/>
893
+ <limit effort="100.0" lower="-3.14" upper="3.14" velocity="0.2"/>
894
+ </joint>
895
+ <link name="link_b"/>
896
+ <joint name="joint_c_revolute" type="revolute">
897
+ <axis xyz="0 1 0"/>
898
+ <parent link="link_b"/>
899
+ <child link="link_c"/>
900
+ <origin rpy="0 0 0" xyz="0.2 0.2 0"/>
901
+ <limit effort="100.0" lower="-3.14" upper="3.14" velocity="0.2"/>
902
+ </joint>
903
+ <link name="link_c"/>
904
+ <joint name="joint_d_revolute" type="revolute">
905
+ <axis xyz="1 0 0"/>
906
+ <parent link="link_c"/>
907
+ <child link="link_d"/>
908
+ <origin rpy="0 0 0" xyz="0.0 0.2 0.4"/>
909
+ <limit effort="100.0" lower="-3.14" upper="3.14" velocity="0.2"/>
910
+ </joint>
911
+ <link name="link_d"/>
912
+ </robot>
913
+ )" ;
914
+
915
+ constexpr char robot_srdf[] = R"xml(
916
+ <?xml version="1.0" ?>
917
+ <robot name="one_robot">
918
+ <group name="base_to_tip">
919
+ <joint name="joint_a_revolute"/>
920
+ <joint name="joint_b_revolute"/>
921
+ <joint name="joint_c_revolute"/>
922
+ <joint name="joint_d_revolute"/>
923
+ </group>
924
+ </robot>
925
+ )xml" ;
926
+
927
+ const urdf::ModelInterfaceSharedPtr urdf_model = urdf::parseURDF (robot_urdf);
928
+ ASSERT_TRUE (urdf_model);
929
+ const auto srdf_model = std::make_shared<srdf::Model>();
930
+ ASSERT_TRUE (srdf_model->initString (*urdf_model, robot_srdf));
931
+ const auto robot_model = std::make_shared<moveit::core::RobotModel>(urdf_model, srdf_model);
932
+
933
+ moveit::core::RobotState state (robot_model);
934
+ const moveit::core::JointModelGroup* jmg = state.getJointModelGroup (" base_to_tip" );
935
+
936
+ // Some made-up numbers, at zero and non-zero robot configurations.
937
+ checkJacobian (state, *jmg, makeVector ({ 0.0 , 0.0 , 0.0 , 0.0 }), makeVector ({ 0.1 , 0.2 , 0.3 , 0.4 }),
938
+ state.getLinkModel (" link_c" ));
939
+ checkJacobian (state, *jmg, makeVector ({ 0.1 , 0.2 , 0.3 , 0.4 }), makeVector ({ 0.5 , 0.3 , 0.2 , 0.1 }),
940
+ state.getLinkModel (" link_c" ));
941
+ }
942
+
846
943
TEST (getJacobian, RevoluteAndPrismaticJoints)
847
944
{
848
945
// Robot URDF with three revolute joints and one prismatic joint.
0 commit comments