hand_kinematics_coupling_plugin.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2008, Willow Garage, Inc.
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 Willow Garage 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 // majority of this code comes from package urdf_tool/arm_kinematics
35 // written by David Lu!!
36 // Copyright David Lu <David Lu>
37 //
38 // Modified by Juan A. Corrales, ISIR, UPMC
39 // -Added support for coupled joints of Shadow Hand. Now, the coupling is a fixed 1:1 value
40 // but the updateCoupling functions can be modified in order to implement dynamic coupling
41 // (which can be modified depending on the values of the joint values of the finger).
42 // -Use of WDLS velocity IK method in order to solve IK only for 3D position.
43 // -IK is solved at the fingertip frame, which should be defined in the URDF/Xacro file of the
44 // Shadow Hand.
45 
46 // Modified by Guillaume WALCK (UPMC) 2012
47 // - Turned it into a kinematics_plugin
48 
49 #include <cstring>
50 #include <string>
51 #include <vector>
54 
55 #include <ros/ros.h>
56 
57 #include <tf_conversions/tf_kdl.h>
59 #include <moveit_msgs/MoveItErrorCodes.h>
60 #include <sr_utilities/sr_math_utils.hpp>
61 
62 
63 using std::string;
64 
65 static const std::string IK_WITH_COLLISION_SERVICE = "get_constraint_aware_ik";
66 static const std::string IK_SERVICE = "get_ik";
67 static const std::string FK_SERVICE = "get_fk";
68 
69 #define IK_EPS 1e-5
70 
71 
72 namespace hand_kinematics
73 {
74  static const double IK_DEFAULT_TIMEOUT = 10.0;
75 
76  // register the plugin
78 
80  {
81  }
82 
84  {
85  if (active_)
86  {
87  return true;
88  }
89  return false;
90  }
91 
92  bool HandKinematicsPlugin::initialize(const std::string &robot_description,
93  const std::string &group_name,
94  const std::string &base_frame,
95  const std::string &tip_frame,
96  double search_discretization)
97  {
98  setValues(robot_description, group_name, base_frame, tip_frame, search_discretization);
99  urdf::Model robot_model;
100  std::string xml_string;
101  ros::NodeHandle private_handle("~/" + group_name);
102  ROS_INFO("Started IK for %s", tip_frame_.c_str());
103  while (!loadRobotModel(private_handle, robot_model, base_frame_, tip_frame_, xml_string) && private_handle.ok())
104  {
105  ROS_ERROR("Could not load robot model. Are you sure the robot model is on the parameter server?");
106  ros::Duration(0.5).sleep();
107  }
108 
109  ROS_DEBUG("Loading KDL Tree");
110  if (!getKDLChain(xml_string, base_frame_, tip_frame_, kdl_chain_))
111  {
112  active_ = false;
113  ROS_ERROR("Could not load kdl tree");
114  }
115 
116  // Define coupling matrix for fingers ff, mf, rf: their first two joints (J1 and J2)
117  // are coupled while J3 and J4 are independent.
118  // The rows of coupling matrix correspond to all joints (unlocked ones) while the columns
119  // correspond to independent joints (not coupled).
120  if (tip_frame_.find("fftip") != string::npos)
121  {
122  // Assign update function for dynamic coupling
124  dimension_ = 4;
125  }
126  if (tip_frame_.find("mftip") != string::npos)
127  {
128  // Assign update function for dynamic coupling
130  dimension_ = 4;
131  }
132  if (tip_frame_.find("rftip") != string::npos)
133  {
134  // Assign update function for dynamic coupling
136  dimension_ = 4;
137  }
138  if (tip_frame_.find("lftip") != string::npos)
139  {
140  // Assign update function for dynamic coupling
142  dimension_ = 5;
143  }
144  if (tip_frame_.find("thtip") != string::npos)
145  {
146  // Assign update function for thumb: identity matrix is used since there is no coupling
148  dimension_ = 5;
149  }
150 
151  Eigen::MatrixXd Mx(6, 6); // Task space weighting matrix: We will only consider translation components.
152  for (unsigned int i = 0; i < 6; i++)
153  {
154  for (unsigned int j = 0; j < 6; j++)
155  {
156  Mx(i, j) = 0.0;
157  }
158  }
159  // Control only position of the fingertip. Discard error in orientation
160  Mx(0, 0) = 1.0; // coordinate X
161  Mx(1, 1) = 1.0; // coordinate Y
162  Mx(2, 2) = 1.0; // coordinate Z
163  Mx(3, 3) = 0.0; // rotation X
164  Mx(4, 4) = 0.0; // rotation Y
165  Mx(5, 5) = 0.0; // rotation Z
166 
167  ROS_DEBUG("CHAIN--> Joints:%d, Ind. Joints:%d, Segments:%d", kdl_chain_.getNrOfJoints(),
169  // Get Solver Parameters
170  int maxIterations;
171  double epsilon, lambda;
172 
173  if (!private_handle.getParam("maxIterations", maxIterations))
174  {
175  maxIterations = 1000;
176  ROS_WARN("No maxIterations on param server, using %d as default", maxIterations);
177  }
178 
179  if (!private_handle.getParam("epsilon", epsilon))
180  {
181  epsilon = 1e-2;
182  ROS_WARN("No epsilon on param server, using %f as default", epsilon);
183  }
184 
185  if (!private_handle.getParam("lambda", lambda))
186  {
187  lambda = 0.01;
188  ROS_WARN("No lambda on param server, using %f as default", lambda);
189  }
190 
191  ROS_DEBUG("IK Solver, maxIterations: %d, epsilon: %f, lambda: %f", maxIterations, epsilon, lambda);
192 
194  // Build Solvers
195  ROS_DEBUG("Advertising services");
197  ik_solver_vel = new KDL::ChainIkSolverVel_wdls_coupling(kdl_chain_, epsilon, maxIterations);
198  ik_solver_vel->setLambda(lambda);
201  *ik_solver_vel, maxIterations, epsilon);
202 
203  active_ = true;
204  return active_;
205  }
206 
207 
208  bool HandKinematicsPlugin::getPositionIK(const geometry_msgs::Pose &ik_pose,
209  const std::vector<double> &ik_seed_state,
210  std::vector<double> &solution,
211  moveit_msgs::MoveItErrorCodes &error_code,
212  const kinematics::KinematicsQueryOptions &options) const
213  {
214  if (!active_)
215  {
216  ROS_ERROR("kinematics not active");
217  error_code.val = error_code.NO_IK_SOLUTION;
218  return false;
219  }
220 
221  KDL::Frame pose_desired;
222  tf::poseMsgToKDL(ik_pose, pose_desired);
223 
224  // Do the IK
225  KDL::JntArray jnt_pos_in;
226  KDL::JntArray jnt_pos_out;
227  jnt_pos_in.resize(dimension_);
228  for (int i = 0; i < dimension_; i++)
229  {
230  jnt_pos_in(i) = ik_seed_state[i];
231  }
232 
233  int ik_valid = -1;
234  // restart 10 times with different rand
235  for (int i = 0; i < 10 && ik_valid < 0; i++)
236  {
237  if (tip_frame_.find("thtip") != std::string::npos || tip_frame_.find("lftip") != std::string::npos)
238  ROS_DEBUG("IK Seed: %f, %f, %f, %f, %f", jnt_pos_in(0), jnt_pos_in(1), jnt_pos_in(2), jnt_pos_in(3),
239  jnt_pos_in(4));
240  else
241  ROS_DEBUG("IK Seed: %f, %f, %f, %f", jnt_pos_in(0), jnt_pos_in(1), jnt_pos_in(2), jnt_pos_in(3));
242  ik_valid = ik_solver_pos->CartToJnt(jnt_pos_in, pose_desired, jnt_pos_out);
243  generateRandomJntSeed(jnt_pos_in);
244  // maintain 1:1 coupling
245  if (tip_frame_.find("thtip") == std::string::npos && tip_frame_.find("lftip") == std::string::npos)
246  {
247  jnt_pos_in(3) = jnt_pos_in(2);
248  }
249  else if (tip_frame_.find("lftip") != std::string::npos)
250  {
251  jnt_pos_in(4) = jnt_pos_in(3);
252  }
253  if (i > 0)
254  ROS_DEBUG("IK Recalculation step: %d", i);
255  }
256 
257  if (ik_valid >= 0)
258  {
259  solution.resize(dimension_);
260  for (int i = 0; i < dimension_; i++)
261  {
262  solution[i] = jnt_pos_out(i);
263  }
264  error_code.val = moveit_msgs::MoveItErrorCodes::SUCCESS;
265  ROS_DEBUG("IK Success");
266  return true;
267  }
268  else
269  {
270  ROS_DEBUG("An IK solution could not be found");
271  error_code.val = moveit_msgs::MoveItErrorCodes::NO_IK_SOLUTION;
272  return false;
273  }
274  }
275 
276  bool HandKinematicsPlugin::searchPositionIK(const geometry_msgs::Pose &ik_pose,
277  const std::vector<double> &ik_seed_state,
278  double timeout,
279  std::vector<double> &solution,
280  moveit_msgs::MoveItErrorCodes &error_code,
281  const kinematics::KinematicsQueryOptions &options) const
282  {
283  static IKCallbackFn solution_callback = 0;
284  static std::vector<double> consistency_limits;
285  return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, solution_callback,
286  error_code);
287  }
288 
289  bool HandKinematicsPlugin::searchPositionIK(const geometry_msgs::Pose &ik_pose,
290  const std::vector<double> &ik_seed_state,
291  double timeout,
292  const std::vector<double> &consistency_limits,
293  std::vector<double> &solution,
294  moveit_msgs::MoveItErrorCodes &error_code,
295  const kinematics::KinematicsQueryOptions &options) const
296  {
297  static IKCallbackFn solution_callback = 0;
298  return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, solution_callback,
299  error_code);
300  }
301 
302  bool HandKinematicsPlugin::searchPositionIK(const geometry_msgs::Pose &ik_pose,
303  const std::vector<double> &ik_seed_state,
304  double timeout,
305  std::vector<double> &solution,
306  const IKCallbackFn &solution_callback,
307  moveit_msgs::MoveItErrorCodes &error_code,
308  const kinematics::KinematicsQueryOptions &options) const
309  {
310  static std::vector<double> consistency_limits;
311  return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, solution_callback,
312  error_code);
313  }
314 
315 
316  bool HandKinematicsPlugin::searchPositionIK(const geometry_msgs::Pose &ik_pose,
317  const std::vector<double> &ik_seed_state,
318  double timeout,
319  const std::vector<double> &consistency_limits,
320  std::vector<double> &solution,
321  const IKCallbackFn &solution_callback,
322  moveit_msgs::MoveItErrorCodes &error_code,
323  const kinematics::KinematicsQueryOptions &options) const
324  {
325  if (!active_)
326  {
327  ROS_ERROR("kinematics not active");
328  error_code.val = error_code.FAILURE;
329  return false;
330  }
331  if (!consistency_limits.empty() && consistency_limits.size() != (size_t) dimension_)
332  {
333  ROS_ERROR("Consistency limits should be of size: %d", dimension_);
334  error_code.val = error_code.FAILURE;
335  return false;
336  }
337 
338  KDL::Frame pose_desired;
339  tf::poseMsgToKDL(ik_pose, pose_desired);
340 
341  // Do the IK
342  KDL::JntArray jnt_pos_in;
343  KDL::JntArray jnt_pos_out;
344  jnt_pos_in.resize(dimension_);
345  for (int i = 0; i < dimension_; i++)
346  {
347  jnt_pos_in(i) = ik_seed_state[i];
348  }
349 
350  int ik_valid = -1;
351  // restart 10 times with different rand
352  for (int i = 0; i < 10 && ik_valid < 0; i++)
353  {
354  if (tip_frame_.find("thtip") != std::string::npos || tip_frame_.find("lftip") != std::string::npos)
355  ROS_DEBUG("IK Seed: %f, %f, %f, %f, %f", jnt_pos_in(0), jnt_pos_in(1), jnt_pos_in(2), jnt_pos_in(3),
356  jnt_pos_in(4));
357  else
358  ROS_DEBUG("IK Seed: %f, %f, %f, %f", jnt_pos_in(0), jnt_pos_in(1), jnt_pos_in(2), jnt_pos_in(3));
359  ik_valid = ik_solver_pos->CartToJnt(jnt_pos_in, pose_desired, jnt_pos_out);
360  generateRandomJntSeed(jnt_pos_in);
361  // maintain 1:1 coupling
362  if (tip_frame_.find("thtip") == std::string::npos && tip_frame_.find("lftip") == std::string::npos)
363  {
364  jnt_pos_in(3) = jnt_pos_in(2);
365  }
366  else if (tip_frame_.find("lftip") != std::string::npos)
367  {
368  jnt_pos_in(4) = jnt_pos_in(3);
369  }
370  if (i > 0)
371  ROS_DEBUG("IK Recalculation step: %d", i);
372  }
373 
374  if (ik_valid >= 0)
375  {
376  solution.resize(dimension_);
377  for (int i = 0; i < dimension_; i++)
378  {
379  solution[i] = jnt_pos_out(i);
380  }
381  error_code.val = moveit_msgs::MoveItErrorCodes::SUCCESS;
382  ROS_DEBUG("IK Success");
383  return true;
384  }
385  else
386  {
387  ROS_DEBUG("An IK solution could not be found");
388  error_code.val = moveit_msgs::MoveItErrorCodes::NO_IK_SOLUTION;
389  return false;
390  }
391  }
392 
393  bool HandKinematicsPlugin::getPositionFK(const std::vector<std::string> &link_names,
394  const std::vector<double> &joint_angles,
395  std::vector<geometry_msgs::Pose> &poses) const
396  {
397  if (!active_)
398  {
399  ROS_ERROR("kinematics not active");
400  return false;
401  }
402 
403  KDL::Frame p_out;
404  KDL::JntArray jnt_pos_in;
405  geometry_msgs::PoseStamped pose;
406  tf::Stamped<tf::Pose> tf_pose;
407 
408  jnt_pos_in.resize(dimension_);
409  for (int i = 0; i < dimension_; i++)
410  {
411  jnt_pos_in(i) = joint_angles[i];
412  // ROS_DEBUG("Joint angle: %d %f",i,joint_angles[i]);
413  }
414 
415  poses.resize(link_names.size());
416 
417  bool valid = true;
418 
419  for (unsigned int i = 0; i < poses.size(); i++)
420  {
421  ROS_DEBUG("End effector index: %d", hand_kinematics::getKDLSegmentIndex(kdl_chain_, link_names[i]));
422  if (fk_solver->JntToCart(jnt_pos_in, p_out, hand_kinematics::getKDLSegmentIndex(kdl_chain_, link_names[i])) >= 0)
423  {
424  tf::poseKDLToMsg(p_out, poses[i]);
425  /*
426  tf_pose.frame_id_ = root_name;
427  tf_pose.stamp_ = ros::Time();
428  tf::PoseKDLToTF(p_out,tf_pose);
429  try {
430  tf_listener.transformPose(request.header.frame_id,tf_pose,tf_pose);
431  } catch (...) {
432  ROS_ERROR("Could not transform FK pose to frame: %s",request.header.frame_id.c_str());
433  response.error_code.val = response.error_code.FRAME_TRANSFORM_FAILURE;
434  return false;
435  }
436  tf::poseStampedTFToMsg(tf_pose,pose);
437  response.pose_stamped[i] = pose;
438  */
439  }
440  else
441  {
442  ROS_ERROR("Could not compute FK for %s", link_names[i].c_str());
443  valid = false;
444  }
445  }
446  return valid;
447  }
448 
449  const std::vector<std::string> &HandKinematicsPlugin::getJointNames() const
450  {
451  if (!active_)
452  {
453  ROS_ERROR("kinematics not active");
454  }
455  return ik_solver_info_.joint_names;
456  }
457 
458  const std::vector<std::string> &HandKinematicsPlugin::getLinkNames() const
459  {
460  if (!active_)
461  {
462  ROS_ERROR("kinematics not active");
463  }
464  return fk_solver_info_.link_names;
465  }
466 
468  {
469  for (int i = 0; i < dimension_; i++)
470  {
471  double min = ik_solver_info_.limits[i].min_position;
472  double max = ik_solver_info_.limits[i].max_position;
473  double r = sr_math_utils::Random::instance().generate<double>(min, max);
474  jnt_pos_in(i) = r;
475  }
476  }
477 } // namespace hand_kinematics
478 
479 
const std::vector< std::string > & getLinkNames() const
Return all the link names in the order they are represented internally.
moveit_msgs::KinematicSolverInfo ik_solver_info_
virtual int JntToCart(const JntArray &q_in, Frame &p_out, int segmentNr=-1)
static const std::string FK_SERVICE
Eigen::MatrixXd updateCouplingRF(const KDL::JntArray &q)
static const double IK_DEFAULT_TIMEOUT
const std::vector< std::string > & getJointNames() const
Return all the joint names in the order they are used internally.
virtual bool getPositionIK(const geometry_msgs::Pose &ik_pose, const std::vector< double > &ik_seed_state, std::vector< double > &solution, moveit_msgs::MoveItErrorCodes &error_code, const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions()) const
Given a desired pose of the end-effector, compute the joint angles to reach it.
bool sleep() const
unsigned int getNrOfSegments() const
virtual bool initialize(const std::string &robot_description, const std::string &group_name, const std::string &base_frame, const std::string &tip_frame, double search_discretization)
Initialization function for the kinematics.
KDL::ChainIkSolverPos_NR_JL_coupling * ik_solver_pos
void generateRandomJntSeed(KDL::JntArray &jnt_pos_in) const
This method generates a random joint array vector between the joint limits so that local minima in IK...
#define ROS_WARN(...)
bool setUpdateCouplingFunction(updateFuncPtr updateFunc)
static const std::string IK_SERVICE
PLUGINLIB_EXPORT_CLASS(test_moveit_controller_manager::TestMoveItControllerManager, moveit_controller_manager::MoveItControllerManager)
Eigen::MatrixXd updateCouplingMF(const KDL::JntArray &q)
KDL::ChainFkSolverPos_recursive * fk_solver
virtual bool getPositionFK(const std::vector< std::string > &link_names, const std::vector< double > &joint_angles, std::vector< geometry_msgs::Pose > &poses) const
Given a set of joint angles and a set of links, compute their pose.
unsigned int getNrOfIndJoints() const
#define ROS_INFO(...)
void setWeightTS(const Eigen::MatrixXd &Mx)
int getKDLSegmentIndex(const KDL::Chain &chain, const std::string &name)
void poseMsgToKDL(const geometry_msgs::Pose &m, KDL::Frame &k)
unsigned int getNrOfJoints() const
virtual void setValues(const std::string &robot_description, const std::string &group_name, const std::string &base_frame, const std::string &tip_frame, double search_discretization)
def xml_string(rootXml, addHeader=True)
boost::function< void(const geometry_msgs::Pose &ik_pose, const std::vector< double > &ik_solution, moveit_msgs::MoveItErrorCodes &error_code)> IKCallbackFn
Eigen::MatrixXd updateCouplingTH(const KDL::JntArray &q)
void resize(unsigned int newSize)
moveit_msgs::KinematicSolverInfo fk_solver_info_
void poseKDLToMsg(const KDL::Frame &k, geometry_msgs::Pose &m)
bool getParam(const std::string &key, std::string &s) const
bool getKDLChain(const std::string &xml_string, const std::string &root_name, const std::string &tip_name, KDL::Chain &kdl_chain)
bool isActive()
Specifies if the node is active or not.
bool loadRobotModel(ros::NodeHandle node_handle, urdf::Model &robot_model, std::string &root_name, std::string &tip_name, std::string &xml_string)
bool ok() const
Eigen::MatrixXd updateCouplingLF(const KDL::JntArray &q)
KDL::ChainIkSolverVel_wdls_coupling * ik_solver_vel
virtual bool searchPositionIK(const geometry_msgs::Pose &ik_pose, const std::vector< double > &ik_seed_state, double timeout, std::vector< double > &solution, moveit_msgs::MoveItErrorCodes &error_code, const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions()) const
virtual int CartToJnt(const JntArray &q_init, const Frame &p_in, JntArray &q_out)
r
#define ROS_ERROR(...)
Eigen::MatrixXd updateCouplingFF(const KDL::JntArray &q)
bool init_ik(urdf::Model &robot_model, const std::string &root_name, const std::string &tip_name, KDL::JntArray &joint_min, KDL::JntArray &joint_max, moveit_msgs::KinematicSolverInfo &info)
void setLambda(const double &lambda)
static const std::string IK_WITH_COLLISION_SERVICE
#define ROS_DEBUG(...)


hand_kinematics
Author(s): Juan Antonio Corrales Ramon (UPMC),, Guillaume Walck (CITEC)
autogenerated on Wed Oct 14 2020 04:05:07