hand_kinematics_utils.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 
35 /* Author: Sachin Chitta */
36 /* Modified by Guillaume Walck for Shadow Hands */
37 
39 #include <string>
40 #include <vector>
41 
42 namespace hand_kinematics
43 {
44  static const double IK_DEFAULT_TIMEOUT = 10.0;
45 
46  bool loadRobotModel(ros::NodeHandle node_handle, urdf::Model &robot_model, std::string &root_name,
47  std::string &tip_name, std::string &xml_string)
48  {
49  std::string urdf_xml, full_urdf_xml;
50  node_handle.param("urdf_xml", urdf_xml, std::string("robot_description"));
51  node_handle.searchParam(urdf_xml, full_urdf_xml);
52  TiXmlDocument xml;
53  ROS_DEBUG("Reading xml file from parameter server\n");
54  std::string result;
55  if (node_handle.getParam(full_urdf_xml, result))
56  {
57  xml.Parse(result.c_str());
58  }
59  else
60  {
61  ROS_FATAL("Could not load the xml from parameter server: %s\n", urdf_xml.c_str());
62  return false;
63  }
64  xml_string = result;
65  TiXmlElement *root_element = xml.RootElement();
66  TiXmlElement *root = xml.FirstChildElement("robot");
67  if (!root || !root_element)
68  {
69  ROS_FATAL("Could not parse the xml from %s\n", urdf_xml.c_str());
70  exit(1);
71  }
72  robot_model.initXml(root);
73 
74  if (root_name.find("palm") == std::string::npos)
75  {
76  ROS_FATAL("HANDIK: Current solver can only resolve to root frame = palm");
77  return false;
78  }
79 
80  if (tip_name.find("tip") == std::string::npos)
81  {
82  ROS_FATAL("Current solver can only resolve to one of the tip frames");
83  return false;
84  }
85  if (tip_name.find("fftip") == std::string::npos && tip_name.find("mftip") == std::string::npos &&
86  tip_name.find("rftip") == std::string::npos && tip_name.find("lftip") == std::string::npos &&
87  tip_name.find("thtip") == std::string::npos)
88  {
89  ROS_FATAL("Name of distal frame does not match any finger");
90  return false;
91  }
92 
93  return true;
94  }
95 
96  bool getKDLChain(const std::string &xml_string, const std::string &root_name, const std::string &tip_name,
97  KDL::Chain &kdl_chain)
98  {
99  // create robot chain from root to tip
100  KDL::Tree tree;
101  if (!kdl_parser::treeFromString(xml_string, tree))
102  {
103  ROS_ERROR("Could not initialize tree object");
104  return false;
105  }
106  if (!tree.getChain(root_name, tip_name, kdl_chain))
107  {
108  ROS_ERROR_STREAM("Could not initialize chain object for base " << root_name << " tip " << tip_name);
109  return false;
110  }
111  return true;
112  }
113 
114  bool getKDLTree(const std::string &xml_string, const std::string &root_name, const std::string &tip_name,
115  KDL::Tree &kdl_tree)
116  {
117  // create robot chain from root to tip
118  if (!kdl_parser::treeFromString(xml_string, kdl_tree))
119  {
120  ROS_ERROR("Could not initialize tree object");
121  return false;
122  }
123  return true;
124  }
125 
126 
127  void getKDLChainInfo(const KDL::Chain &chain,
128  moveit_msgs::KinematicSolverInfo &chain_info)
129  {
130  int i = 0; // segment number
131  while (i < static_cast<int>(chain.getNrOfSegments()))
132  {
133  chain_info.link_names.push_back(chain.getSegment(i).getName());
134  i++;
135  }
136  }
137 
138  int getKDLSegmentIndex(const KDL::Chain &chain,
139  const std::string &name)
140  {
141  int i = 0; // segment number
142  while (i < static_cast<int>(chain.getNrOfSegments()))
143  {
144  if (chain.getSegment(i).getName() == name)
145  {
146  return i + 1;
147  }
148  i++;
149  }
150  return -1;
151  }
152 
153 
154  bool checkJointNames(const std::vector<std::string> &joint_names,
155  const moveit_msgs::KinematicSolverInfo &chain_info)
156  {
157  for (unsigned int i = 0; i < chain_info.joint_names.size(); i++)
158  {
159  int index = -1;
160  for (unsigned int j = 0; j < joint_names.size(); j++)
161  {
162  if (chain_info.joint_names[i] == joint_names[j])
163  {
164  index = j;
165  break;
166  }
167  }
168  if (index < 0)
169  {
170  ROS_ERROR("Joint state does not contain joint state for %s.", chain_info.joint_names[i].c_str());
171  return false;
172  }
173  }
174  return true;
175  }
176 
177  bool checkLinkNames(const std::vector<std::string> &link_names,
178  const moveit_msgs::KinematicSolverInfo &chain_info)
179  {
180  if (link_names.empty())
181  {
182  return false;
183  }
184  for (unsigned int i = 0; i < link_names.size(); i++)
185  {
186  if (!checkLinkName(link_names[i], chain_info))
187  {
188  return false;
189  }
190  }
191  return true;
192  }
193 
194  bool checkLinkName(const std::string &link_name,
195  const moveit_msgs::KinematicSolverInfo &chain_info)
196  {
197  for (unsigned int i = 0; i < chain_info.link_names.size(); i++)
198  {
199  if (link_name == chain_info.link_names[i])
200  {
201  return true;
202  }
203  }
204  return false;
205  }
206 
207  bool checkRobotState(moveit_msgs::RobotState &robot_state,
208  const moveit_msgs::KinematicSolverInfo &chain_info)
209  {
210  if (robot_state.joint_state.position.size() != robot_state.joint_state.name.size())
211  {
212  ROS_ERROR(
213  "Number of joints in robot_state.joint_state does not match number of"
214  " positions in robot_state.joint_state");
215  return false;
216  }
217  if (!checkJointNames(robot_state.joint_state.name, chain_info))
218  {
219  ROS_ERROR("Robot state must contain joint state for every joint in the kinematic chain");
220  return false;
221  }
222  return true;
223  }
224 
225  bool checkFKService(moveit_msgs::GetPositionFK::Request &request,
226  moveit_msgs::GetPositionFK::Response &response,
227  const moveit_msgs::KinematicSolverInfo &chain_info)
228  {
229  if (!checkLinkNames(request.fk_link_names, chain_info))
230  {
231  ROS_ERROR("Link name in service request does not match links that kinematics can provide solutions for.");
232  response.error_code.val = response.error_code.INVALID_LINK_NAME;
233  return false;
234  }
235  if (!checkRobotState(request.robot_state, chain_info))
236  {
237  response.error_code.val = response.error_code.INVALID_ROBOT_STATE;
238  return false;
239  }
240  return true;
241  }
242 
243  bool checkIKService(moveit_msgs::GetPositionIK::Request &request,
244  moveit_msgs::GetPositionIK::Response &response,
245  const moveit_msgs::KinematicSolverInfo &chain_info)
246  {
247  if (!checkLinkName(request.ik_request.ik_link_name, chain_info))
248  {
249  ROS_ERROR("Link name in service request does not match links that kinematics can provide solutions for.");
250  response.error_code.val = response.error_code.INVALID_LINK_NAME;
251  return false;
252  }
253  if (!checkRobotState(request.ik_request.robot_state, chain_info))
254  {
255  response.error_code.val = response.error_code.INVALID_ROBOT_STATE;
256  return false;
257  }
258  if (request.ik_request.timeout <= ros::Duration(0.0))
259  {
260  response.error_code.val = response.error_code.TIMED_OUT;
261  return false;
262  }
263  return true;
264  }
265 
266  int getJointIndex(const std::string &name, const moveit_msgs::KinematicSolverInfo &chain_info)
267  {
268  for (unsigned int i = 0; i < chain_info.joint_names.size(); i++)
269  {
270  if (chain_info.joint_names[i] == name)
271  {
272  return i;
273  }
274  }
275  return -1;
276  }
277 
278  bool convertPoseToRootFrame(const geometry_msgs::PoseStamped &pose_msg,
279  KDL::Frame &pose_kdl,
280  const std::string &root_frame,
282  {
283  geometry_msgs::PoseStamped pose_stamped;
284  if (!convertPoseToRootFrame(pose_msg, pose_stamped, root_frame, tf))
285  {
286  return false;
287  }
288  tf::poseMsgToKDL(pose_stamped.pose, pose_kdl);
289  return true;
290  }
291 
292 
293  bool convertPoseToRootFrame(const geometry_msgs::PoseStamped &pose_msg,
294  geometry_msgs::PoseStamped &pose_msg_out,
295  const std::string &root_frame,
297  {
298  geometry_msgs::PoseStamped pose_msg_in = pose_msg;
299  ROS_DEBUG("Request:\nframe_id: %s\nPosition: %f %f %f\n:Orientation: %f %f %f %f\n",
300  pose_msg_in.header.frame_id.c_str(),
301  pose_msg_in.pose.position.x,
302  pose_msg_in.pose.position.y,
303  pose_msg_in.pose.position.z,
304  pose_msg_in.pose.orientation.x,
305  pose_msg_in.pose.orientation.y,
306  pose_msg_in.pose.orientation.z,
307  pose_msg_in.pose.orientation.w);
308  pose_msg_out = pose_msg;
309  tf::Stamped<tf::Pose> pose_stamped;
310  poseStampedMsgToTF(pose_msg_in, pose_stamped);
311 
312  if (!tf.canTransform(root_frame, pose_stamped.frame_id_, pose_stamped.stamp_))
313  {
314  std::string err;
315  if (tf.getLatestCommonTime(pose_stamped.frame_id_, root_frame, pose_stamped.stamp_, &err) != tf::NO_ERROR)
316  {
317  ROS_ERROR("hand_ik:: Cannot transform from '%s' to '%s'. TF said: %s", pose_stamped.frame_id_.c_str(),
318  root_frame.c_str(), err.c_str());
319  return false;
320  }
321  }
322  try
323  {
324  tf.transformPose(root_frame, pose_stamped, pose_stamped);
325  }
326  catch (...)
327  {
328  ROS_ERROR("hand_ik:: Cannot transform from '%s' to '%s'", pose_stamped.frame_id_.c_str(), root_frame.c_str());
329  return false;
330  }
331  tf::poseStampedTFToMsg(pose_stamped, pose_msg_out);
332  return true;
333  }
334 
335  Eigen::MatrixXd updateCouplingFF(const KDL::JntArray &q)
336  {
337  Eigen::MatrixXd cm(4, 3);
338  for (unsigned int i = 0; i < 4; i++)
339  {
340  for (unsigned int j = 0; j < 3; j++)
341  {
342  cm(i, j) = 0.0;
343  }
344  }
345 
346  cm(0, 0) = 1.0; // J4
347  cm(1, 1) = 1.0; // J3
348  cm(2, 2) = 1.0; // J2
349  cm(3, 2) = 1.0; // J1
350 
351  return cm;
352  }
353 
354  Eigen::MatrixXd updateCouplingMF(const KDL::JntArray &q)
355  {
356  Eigen::MatrixXd cm(4, 3);
357  for (unsigned int i = 0; i < 4; i++)
358  {
359  for (unsigned int j = 0; j < 3; j++)
360  {
361  cm(i, j) = 0.0;
362  }
363  }
364 
365  cm(0, 0) = 1.0; // J4
366  cm(1, 1) = 1.0; // J3
367  cm(2, 2) = 1.0; // J2
368  cm(3, 2) = 1.0; // J1
369 
370  return cm;
371  }
372 
373  Eigen::MatrixXd updateCouplingRF(const KDL::JntArray &q)
374  {
375  Eigen::MatrixXd cm(4, 3);
376  for (unsigned int i = 0; i < 4; i++)
377  {
378  for (unsigned int j = 0; j < 3; j++)
379  {
380  cm(i, j) = 0.0;
381  }
382  }
383 
384  cm(0, 0) = 1.0; // J4
385  cm(1, 1) = 1.0; // J3
386  cm(2, 2) = 1.0; // J2
387  cm(3, 2) = 1.0; // J1
388 
389  return cm;
390  }
391 
392  Eigen::MatrixXd updateCouplingLF(const KDL::JntArray &q)
393  {
394  Eigen::MatrixXd cm(5, 4);
395  for (unsigned int i = 0; i < 5; i++)
396  {
397  for (unsigned int j = 0; j < 4; j++)
398  {
399  cm(i, j) = 0.0;
400  }
401  }
402 
403  cm(0, 0) = 1.0; // J5
404  cm(1, 1) = 1.0; // J4
405  cm(2, 2) = 1.0; // J3
406  cm(3, 3) = 1.0; // J2
407  cm(4, 3) = 1.0; // J1
408 
409  return cm;
410  }
411 
412  Eigen::MatrixXd updateCouplingTH(const KDL::JntArray &q)
413  {
414  // There is no coupling in the thumb. So the coupling matrix is the identity matrix
415  return Eigen::MatrixXd::Identity(5, 5);
416  }
417 
418  bool init_ik(urdf::Model &robot_model, const std::string &root_name, const std::string &tip_name,
419  KDL::JntArray &joint_min, KDL::JntArray &joint_max, moveit_msgs::KinematicSolverInfo &info)
420  {
421  unsigned int num_joints = 0;
422  // get joint maxs and mins
423  boost::shared_ptr<const urdf::Link> link = robot_model.getLink(tip_name);
425 
426  urdf::Vector3 length;
427 
428  while (link && link->name != root_name)
429  {
430  joint = robot_model.getJoint(link->parent_joint->name);
431  if (!joint)
432  {
433  ROS_ERROR("Could not find joint: %s", link->parent_joint->name.c_str());
434  return false;
435  }
436  if (joint->type != urdf::Joint::UNKNOWN && joint->type != urdf::Joint::FIXED)
437  {
438  ROS_DEBUG("adding joint: [%s]", joint->name.c_str());
439  num_joints++;
440  }
441  link = robot_model.getLink(link->getParent()->name);
442  }
443 
444  joint_min.resize(num_joints);
445  joint_max.resize(num_joints);
446  info.joint_names.resize(num_joints);
447  info.link_names.resize(num_joints);
448  info.limits.resize(num_joints);
449 
450  link = robot_model.getLink(tip_name);
451  unsigned int i = 0;
452  while (link && i < num_joints)
453  {
454  joint = robot_model.getJoint(link->parent_joint->name);
455  if (joint->type != urdf::Joint::UNKNOWN && joint->type != urdf::Joint::FIXED)
456  {
457  ROS_DEBUG("getting bounds for joint: [%s]", joint->name.c_str());
458 
459  float lower, upper;
460  int hasLimits;
461  if (joint->type != urdf::Joint::CONTINUOUS)
462  {
463  lower = joint->limits->lower;
464  upper = joint->limits->upper;
465  hasLimits = 1;
466  }
467  else
468  {
469  lower = -M_PI;
470  upper = M_PI;
471  hasLimits = 0;
472  }
473  int index = num_joints - i - 1;
474  joint_min.data[index] = lower;
475  joint_max.data[index] = upper;
476  info.joint_names[index] = joint->name;
477  info.link_names[index] = link->name;
478  info.limits[index].joint_name = joint->name;
479  info.limits[index].has_position_limits = hasLimits;
480  info.limits[index].min_position = lower;
481  info.limits[index].max_position = upper;
482  i++;
483  }
484  link = robot_model.getLink(link->getParent()->name);
485  }
486  return true;
487  }
488 } // namespace hand_kinematics
#define ROS_FATAL(...)
const Segment & getSegment(unsigned int nr) const
bool checkRobotState(moveit_msgs::RobotState &robot_state, const moveit_msgs::KinematicSolverInfo &chain_info)
Eigen::MatrixXd updateCouplingRF(const KDL::JntArray &q)
static const double IK_DEFAULT_TIMEOUT
static void poseStampedTFToMsg(const Stamped< Pose > &bt, geometry_msgs::PoseStamped &msg)
bool convertPoseToRootFrame(const geometry_msgs::PoseStamped &pose_msg, KDL::Frame &pose_kdl, const std::string &root_frame, tf::TransformListener &tf)
URDF_EXPORT bool initXml(TiXmlElement *xml)
int getLatestCommonTime(const std::string &source_frame, const std::string &target_frame, ros::Time &time, std::string *error_string) const
unsigned int getNrOfSegments() const
bool checkIKService(moveit_msgs::GetPositionIK::Request &request, moveit_msgs::GetPositionIK::Response &response, const moveit_msgs::KinematicSolverInfo &chain_info)
#define M_PI
bool getKDLTree(const std::string &xml_string, const std::string &root_name, const std::string &tip_name, KDL::Tree &kdl_chain)
int getJointIndex(const std::string &name, const moveit_msgs::KinematicSolverInfo &chain_info)
bool canTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, std::string *error_msg=NULL) const
Eigen::MatrixXd updateCouplingMF(const KDL::JntArray &q)
const std::string & getName() const
unsigned int index
bool searchParam(const std::string &key, std::string &result) const
bool param(const std::string &param_name, T &param_val, const T &default_val) const
int getKDLSegmentIndex(const KDL::Chain &chain, const std::string &name)
Eigen::VectorXd data
void poseMsgToKDL(const geometry_msgs::Pose &m, KDL::Frame &k)
void getKDLChainInfo(const KDL::Chain &chain, moveit_msgs::KinematicSolverInfo &chain_info)
KDL_PARSER_PUBLIC bool treeFromString(const std::string &xml, KDL::Tree &tree)
Eigen::MatrixXd updateCouplingTH(const KDL::JntArray &q)
void resize(unsigned int newSize)
ros::Time stamp_
bool getChain(const std::string &chain_root, const std::string &chain_tip, Chain &chain) const
std::string frame_id_
void transformPose(const std::string &target_frame, const geometry_msgs::PoseStamped &stamped_in, geometry_msgs::PoseStamped &stamped_out) const
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 loadRobotModel(ros::NodeHandle node_handle, urdf::Model &robot_model, std::string &root_name, std::string &tip_name, std::string &xml_string)
bool checkJointNames(const std::vector< std::string > &joint_names, const moveit_msgs::KinematicSolverInfo &chain_info)
Eigen::MatrixXd updateCouplingLF(const KDL::JntArray &q)
#define ROS_ERROR_STREAM(args)
bool checkLinkName(const std::string &link_name, const moveit_msgs::KinematicSolverInfo &chain_info)
#define ROS_ERROR(...)
Eigen::MatrixXd updateCouplingFF(const KDL::JntArray &q)
bool checkLinkNames(const std::vector< std::string > &link_names, const moveit_msgs::KinematicSolverInfo &chain_info)
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)
NO_ERROR
bool checkFKService(moveit_msgs::GetPositionFK::Request &request, moveit_msgs::GetPositionFK::Response &response, const moveit_msgs::KinematicSolverInfo &chain_info)
#define ROS_DEBUG(...)


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