test_jacobian_derivative.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2019, PickNik LLC.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the PickNik nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Ivo Vatavuk */
36 
41 #include <kdl/chainjnttojacsolver.hpp>
42 #include <kdl/chainjnttojacdotsolver.hpp>
43 #include <kdl/tree.hpp>
46 
47 using namespace moveit::core;
48 
49 namespace
50 {
51 KDL::Chain setupKdlChain(const RobotModel& robot_model, const std::string& tip_link)
52 {
53  KDL::Chain kdl_chain;
54  KDL::Tree tree;
55  if (!kdl_parser::treeFromUrdfModel(*(robot_model.getURDF()), tree))
56  {
57  ROS_ERROR("Could not initialize tree object");
58  }
59  auto link_models = robot_model.getLinkModels();
60  auto root_model = link_models[0]->getName();
61 
62  if (!tree.getChain(root_model, tip_link, kdl_chain))
63  {
64  ROS_ERROR_STREAM("Could not establish chain from base " << root_model << " to tip " << tip_link);
65  }
66  return kdl_chain;
67 }
68 
69 KDL::JntArrayVel setupKdlJntArrayVel(const std::vector<double>& q, const std::vector<double>& q_dot)
70 {
71  KDL::JntArray kdl_jnt_array(q.size());
72  kdl_jnt_array.data = Eigen::VectorXd::Map(q.data(), q.size());
73 
74  KDL::JntArray kdl_jnt_array_qdot(q_dot.size());
75  kdl_jnt_array_qdot.data = Eigen::VectorXd::Map(q_dot.data(), q_dot.size());
76 
77  KDL::JntArrayVel kdl_jnt_array_vel;
78  kdl_jnt_array_vel.q = kdl_jnt_array;
79  kdl_jnt_array_vel.qdot = kdl_jnt_array_qdot;
80  return kdl_jnt_array_vel;
81 }
82 
83 Eigen::MatrixXd calculateJacobianDerivativeKDL(const std::vector<double>& q, const std::vector<double>& q_dot,
84  const RobotModel& robot_model, const std::string& tip_link)
85 {
86  KDL::Chain kdl_chain = setupKdlChain(robot_model, tip_link);
87 
88  KDL::JntArrayVel kdl_jnt_array_vel = setupKdlJntArrayVel(q, q_dot);
89 
90  KDL::ChainJntToJacDotSolver kdl_jacobian_dot_solver(kdl_chain);
91  KDL::Jacobian kdl_jacobian_dot(kdl_chain.getNrOfJoints());
92 
93  kdl_jacobian_dot_solver.JntToJacDot(kdl_jnt_array_vel, kdl_jacobian_dot);
94 
95  return kdl_jacobian_dot.data;
96 }
97 
98 Eigen::MatrixXd calculateNumericalJDot(const RobotStatePtr& robot_state, const LinkModel* link_model,
99  const JointModelGroup* jmg, const Eigen::Vector3d& reference_point_position,
100  const std::vector<double>& q, const std::vector<double>& qdot,
101  double dt = 0.00001)
102 {
103  // Calculate numerical JDot = (J(q + qdot*dt) - J(q)) / dq;
104  Eigen::MatrixXd jac, jac_plus_dt;
105 
106  robot_state->setJointGroupPositions(jmg, q);
107  robot_state->setJointGroupVelocities(jmg, qdot);
108  robot_state->updateLinkTransforms();
109 
110  robot_state->getJacobian(jmg, link_model, reference_point_position, jac);
111 
112  auto q_plus_dt = q;
113  for (unsigned int i = 0; i < q.size(); i++)
114  q_plus_dt[i] += dt * qdot[i];
115 
116  robot_state->setJointGroupPositions(jmg, q_plus_dt);
117  robot_state->updateLinkTransforms();
118 
119  robot_state->getJacobian(jmg, link_model, reference_point_position, jac_plus_dt);
120  return (jac_plus_dt - jac) / dt;
121 }
122 } // namespace
123 
124 class SimpleRobot : public testing::Test
125 {
126 protected:
127  void SetUp() override
128  {
129  RobotModelBuilder builder("simple", "a");
130  builder.addChain("a->b", "revolute", {}, urdf::Vector3(0, 0, 1)); // Rotates around the z-axis
131  builder.addChain("b->c", "prismatic", {}, urdf::Vector3(1, 0, 0)); // Translates along the x-axis
132  builder.addChain("c->d", "revolute", {}, urdf::Vector3(0, 0, 1)); // Rotates around the z-axis
133  builder.addChain("d->e", "prismatic", {}, urdf::Vector3(1, 0, 0)); // Translates along the x-axis
134  builder.addGroupChain("a", "e", "group");
135  robot_model_ = builder.build();
136  robot_state_ = std::make_shared<RobotState>(robot_model_);
137  }
138 
139  void TearDown() override
140  {
141  }
142 
143 protected:
144  RobotModelPtr robot_model_;
145  RobotStatePtr robot_state_;
146 };
147 
148 TEST_F(SimpleRobot, testSimpleRobotJacobianDerivative)
149 {
150  std::cout << "Testing SimpleRobotJacobianDerivative\n";
151 
152  Eigen::Vector3d reference_point_position(0.0, 0.0, 0.0);
153  Eigen::MatrixXd moveit_jacobian, moveit_jacobian_derivative;
154  auto joint_model_group = robot_model_->getJointModelGroup("group");
155 
156  //-----------------------Test state-----------------------
157  std::vector<double> test_q{ 0.72552, 0.11599, 0.99237, 0.24576 };
158  std::vector<double> test_qdot{ 0.31079, 0.56458, 0.60189, 0.12969 };
159 
160  //-----------------------Set robot state-----------------------
161  robot_state_->setJointGroupPositions(joint_model_group, test_q);
162  robot_state_->setJointGroupVelocities(joint_model_group, test_qdot);
163  robot_state_->updateLinkTransforms();
164 
165  //-----------------------Calculate Jacobian Derivative in MoveIt-----------------------
166  robot_state_->getJacobianDerivative(joint_model_group, robot_state_->getLinkModel("e"), reference_point_position,
167  moveit_jacobian, moveit_jacobian_derivative);
168 
169  //-----------------------Calculate Jacobian Derivative with KDL-----------------------
170  Eigen::MatrixXd kdl_jacobian_derivative = calculateJacobianDerivativeKDL(test_q, test_qdot, *robot_model_, "e");
171 
172  //-----------------------Compare Jacobian Derivatives-----------------------
173  std::cout << "MoveIt Jacobian Derivative\n" << moveit_jacobian_derivative << "\n\n";
174  std::cout << "KDL Jacobian Derivative\n" << kdl_jacobian_derivative << "\n\n";
175 
176  EXPECT_EIGEN_NEAR(moveit_jacobian_derivative, kdl_jacobian_derivative, 1e-5);
177 }
178 
179 // Gracefully handle gtest 1.8 (Melodic)
180 #ifndef INSTANTIATE_TEST_SUITE_P
181 #define _STATIC
182 #define _OLD_GTEST
183 #else
184 #define _STATIC static
185 #endif
186 
187 class PandaRobot : public testing::Test
188 {
189 protected:
190  _STATIC void SetUpTestSuite() // setup resources shared between tests
191  {
192  robot_model_ = loadTestingRobotModel("panda");
193  jmg_ = robot_model_->getJointModelGroup("panda_arm");
194  }
195 
197  {
198  robot_model_.reset();
199  }
200 
201  void SetUp() override
202  {
203 #ifdef _OLD_GTEST
204  SetUpTestSuite();
205 #endif
206  robot_state_ = std::make_shared<RobotState>(robot_model_);
207  }
208 #ifdef _OLD_GTEST
209  void TearDown() override
210  {
211  TearDownTestSuite();
212  }
213 #endif
214 protected:
215  _STATIC RobotModelPtr robot_model_;
217 
218  double prec_ = 1e-8;
219  RobotStatePtr robot_state_;
220 };
221 #ifndef _OLD_GTEST
222 RobotModelPtr PandaRobot::robot_model_;
224 #endif
225 
226 TEST_F(PandaRobot, testPandaRobotJacobianDerivative)
227 {
228  ROS_WARN("Testing PandaRobotJacobianDerivative");
229  Eigen::Vector3d reference_point_position(0.0, 0.0, 0.0);
230  Eigen::MatrixXd moveit_jacobian, moveit_jacobian_derivative;
231 
232  //-----------------------Test state-----------------------
233  std::vector<double> test_q{ 0.32640, 0.82863, 0.99677, 0.54311, 0.76774, 0.82150, 0.06884 };
234  std::vector<double> test_qdot{ 0.29751, 0.76376, 0.70464, 0.38797, 0.63743, 0.20855, 0.72211 };
235 
236  //-----------------------Set robot state-----------------------
237  robot_state_->setJointGroupPositions(jmg_, test_q);
238  robot_state_->setJointGroupVelocities(jmg_, test_qdot);
239  robot_state_->updateLinkTransforms();
240 
241  //-----------------------Calculate Jacobian Derivative in MoveIt-----------------------
242  robot_state_->getJacobianDerivative(jmg_, robot_model_->getLinkModel("panda_link8"), reference_point_position,
243  moveit_jacobian, moveit_jacobian_derivative);
244  //-----------------------Calculate Jacobian Derivative with KDL-----------------------
245  Eigen::MatrixXd kdl_jacobian_derivative =
246  calculateJacobianDerivativeKDL(test_q, test_qdot, *robot_model_, "panda_link8");
247 
248  //-----------------------Compare Jacobian Derivatives-----------------------
249  std::cout << "MoveIt Jacobian Derivative\n" << moveit_jacobian_derivative << "\n\n";
250  std::cout << "KDL Jacobian Derivative\n" << kdl_jacobian_derivative << "\n\n";
251 
252  EXPECT_EIGEN_NEAR(moveit_jacobian_derivative, kdl_jacobian_derivative, 1e-3);
253 }
254 
255 TEST_F(PandaRobot, testPandaRobotMidLinkJacobianDerivative)
256 {
257  ROS_WARN("Testing testPandaRobotMidLinkJacobianDerivative");
258  Eigen::Vector3d reference_point_position(0.0, 0.0, 0.0);
259  Eigen::MatrixXd moveit_jacobian, moveit_jacobian_derivative;
260  std::string link = "panda_link5";
261  //-----------------------Test state-----------------------
262  std::vector<double> test_q{ 0.32640, 0.82863, 0.99677, 0.54311, 0.76774, 0.82150, 0.06884 };
263  std::vector<double> test_qdot{ 0.29751, 0.76376, 0.70464, 0.38797, 0.63743, 0.20855, 0.72211 };
264 
265  //-----------------------Set robot state-----------------------
266  robot_state_->setJointGroupPositions(jmg_, test_q);
267  robot_state_->setJointGroupVelocities(jmg_, test_qdot);
268  robot_state_->updateLinkTransforms();
269 
270  //-----------------------Calculate Jacobian Derivative in MoveIt-----------------------
271  robot_state_->getJacobianDerivative(jmg_, robot_model_->getLinkModel(link), reference_point_position, moveit_jacobian,
272  moveit_jacobian_derivative);
273 
274  //-----------------------Calculate Numerical Jacobian Derivative-----------------------
275  Eigen::MatrixXd numerical_jdot = calculateNumericalJDot(robot_state_, robot_model_->getLinkModel(link), jmg_,
276  reference_point_position, test_q, test_qdot);
277 
278  //-----------------------Compare Jacobian Derivatives-----------------------
279  std::cout << "MoveIt Jacobian Derivative\n" << moveit_jacobian_derivative << "\n\n";
280  std::cout << "Numerical Jacobian Derivative\n" << numerical_jdot << "\n\n";
281 
282  EXPECT_EIGEN_NEAR(moveit_jacobian_derivative, numerical_jdot, 1e-5);
283 }
284 
285 TEST_F(PandaRobot, testPandaRobotRefPointJacobianDerivative)
286 {
287  ROS_WARN("Testing testPandaRobotRefPointJacobianDerivative");
288  Eigen::Vector3d reference_point_position(2.0, 4.0, 5.0);
289  Eigen::MatrixXd moveit_jacobian, moveit_jacobian_derivative;
290  std::string link = "panda_link8";
291  //-----------------------Test state-----------------------
292  std::vector<double> test_q{ 0.32640, 0.82863, 0.99677, 0.54311, 0.76774, 0.82150, 0.06884 };
293  std::vector<double> test_qdot{ 0.29751, 0.76376, 0.70464, 0.38797, 0.63743, 0.20855, 0.72211 };
294 
295  //-----------------------Set robot state-----------------------
296  robot_state_->setJointGroupPositions(jmg_, test_q);
297  robot_state_->setJointGroupVelocities(jmg_, test_qdot);
298  robot_state_->updateLinkTransforms();
299 
300  //-----------------------Calculate Jacobian Derivative in MoveIt-----------------------
301  robot_state_->getJacobianDerivative(jmg_, robot_model_->getLinkModel(link), reference_point_position, moveit_jacobian,
302  moveit_jacobian_derivative);
303 
304  //-----------------------Calculate Numerical Jacobian Derivative-----------------------
305  Eigen::MatrixXd numerical_jdot = calculateNumericalJDot(robot_state_, robot_model_->getLinkModel(link), jmg_,
306  reference_point_position, test_q, test_qdot);
307 
308  //-----------------------Compare Jacobian Derivatives-----------------------
309  std::cout << "MoveIt Jacobian Derivative\n" << moveit_jacobian_derivative << "\n\n";
310  std::cout << "Numerical Jacobian Derivative\n" << numerical_jdot << "\n\n";
311 
312  EXPECT_EIGEN_NEAR(moveit_jacobian_derivative, numerical_jdot, 1e-3);
313 }
314 
315 int main(int argc, char** argv)
316 {
317  testing::InitGoogleTest(&argc, argv);
318  ros::init(argc, argv, "test_jacobian_derivative");
319  return RUN_ALL_TESTS();
320 }
moveit::core::LinkModel
A link from the robot. Contains the constant transform applied to the link and its geometry.
Definition: link_model.h:71
moveit::core
Core components of MoveIt.
Definition: kinematics_base.h:83
PandaRobot
Definition: test_cartesian_interpolator.cpp:203
PandaRobot::SetUp
void SetUp() override
Definition: test_jacobian_derivative.cpp:201
moveit::core::RobotModelBuilder::addGroupChain
RobotModelBuilder & addGroupChain(const std::string &base_link, const std::string &tip_link, const std::string &name="")
Adds a new group using a chain of links. The group is the parent joint of each link in the chain.
Definition: robot_model_test_utils.cpp:436
SimpleRobot::SetUp
void SetUp() override
Definition: test_jacobian_derivative.cpp:127
ROS_ERROR_STREAM
#define ROS_ERROR_STREAM(args)
moveit::core::JointModelGroup
Definition: joint_model_group.h:134
ros::init
ROSCPP_DECL void init(const M_string &remappings, const std::string &name, uint32_t options=0)
PandaRobot::robot_model_
static RobotModelPtr robot_model_
Definition: test_cartesian_interpolator.cpp:245
moveit::core::RobotModel
Definition of a kinematic model. This class is not thread safe, however multiple instances can be cre...
Definition: robot_model.h:143
PandaRobot::TearDown
void TearDown() override
Definition: test_jacobian_derivative.cpp:209
TEST_F
TEST_F(SimpleRobot, testSimpleRobotJacobianDerivative)
Definition: test_jacobian_derivative.cpp:148
kdl_parser::treeFromUrdfModel
KDL_PARSER_PUBLIC bool treeFromUrdfModel(const urdf::ModelInterface &robot_model, KDL::Tree &tree)
robot_model.h
profiler.h
PandaRobot::SetUpTestSuite
_STATIC void SetUpTestSuite()
Definition: test_jacobian_derivative.cpp:190
PandaRobot::robot_state_
RobotStatePtr robot_state_
Definition: test_jacobian_derivative.cpp:219
ROS_ERROR
#define ROS_ERROR(...)
moveit::core::RobotModelBuilder::build
moveit::core::RobotModelPtr build()
Builds and returns the robot model added to the builder.
Definition: robot_model_test_utils.cpp:484
ROS_WARN
#define ROS_WARN(...)
PandaRobot::jmg_
static JointModelGroup * jmg_
Definition: test_cartesian_interpolator.cpp:246
SimpleRobot
Definition: test_cartesian_interpolator.cpp:45
PandaRobot::robot_model_
_STATIC RobotModelPtr robot_model_
Definition: test_jacobian_derivative.cpp:215
kdl_parser.hpp
main
int main(int argc, char **argv)
Definition: test_jacobian_derivative.cpp:315
robot_model_test_utils.h
EXPECT_EIGEN_NEAR
#define EXPECT_EIGEN_NEAR(val1, val2, prec_)
Definition: eigen_test_utils.h:76
SimpleRobot::robot_model_
RobotModelPtr robot_model_
Definition: test_jacobian_derivative.cpp:144
moveit::core::RobotModelBuilder
Easily build different robot models for testing. Essentially a programmer-friendly light wrapper arou...
Definition: robot_model_test_utils.h:158
moveit::core::RobotModelBuilder::addChain
RobotModelBuilder & addChain(const std::string &section, const std::string &type, const std::vector< geometry_msgs::Pose > &joint_origins={}, urdf::Vector3 joint_axis=urdf::Vector3(1.0, 0.0, 0.0))
Adds a chain of links and joints to the builder. The joint names are generated automatically as "<par...
Definition: robot_model_test_utils.cpp:204
SimpleRobot::TearDown
void TearDown() override
Definition: test_jacobian_derivative.cpp:139
PandaRobot::TearDownTestSuite
_STATIC void TearDownTestSuite()
Definition: test_jacobian_derivative.cpp:196
_STATIC
#define _STATIC
Definition: test_jacobian_derivative.cpp:181
eigen_test_utils.h
SimpleRobot::robot_state_
RobotStatePtr robot_state_
Definition: test_jacobian_derivative.cpp:145
robot_state.h
PandaRobot::jmg_
_STATIC JointModelGroup * jmg_
Definition: test_jacobian_derivative.cpp:216
fcl::Vector3d
Vec3fX< details::Vec3Data< double > > Vector3d
Definition: fcl_compat.h:89
moveit::core::loadTestingRobotModel
moveit::core::RobotModelPtr loadTestingRobotModel(const std::string &robot_name)
Loads a robot from moveit_resources.
Definition: robot_model_test_utils.cpp:117


moveit_core
Author(s): Ioan Sucan , Sachin Chitta , Acorn Pooley
autogenerated on Thu Feb 27 2025 03:26:58