tree_kinematics.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (GNU Lesser General Public License)
00003  *
00004  * Copyright (c) 2011, PAL Robotics, S.L.
00005  * All rights reserved.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020  */
00027 #include <urdf/joint.h>
00028 #include <urdf/model.h>
00029 #include <tf_conversions/tf_kdl.h>
00030 #include "tree_kinematics/tree_kinematics.h"
00031 
00032 static const std::string FK_SERVICE = "get_position_fk";
00033 static const std::string IK_SERVICE = "get_position_ik";
00034 
00035 
00036 namespace tree_kinematics
00037 {
00038 
00039 bool TreeKinematics::init()
00040 {
00041   // get URDF XML
00042   std::string urdf_xml, full_urdf_xml;
00043   nh_.param("urdf_xml_model",urdf_xml,std::string("robot_description"));
00044   nh_.searchParam(urdf_xml,full_urdf_xml);
00045   ROS_DEBUG("Reading xml file from parameter server ...");
00046   std::string result;
00047   if (!nh_.getParam(full_urdf_xml, result))
00048   {
00049     ROS_FATAL("Could not load the xml from parameter server: %s!", urdf_xml.c_str());
00050     return false;
00051   }
00052 
00053   // data for the IK position solver obtained from the robot model
00054   KDL::JntArray     joint_min;             // Minimum joint positions
00055   KDL::JntArray     joint_max;             // Maximum joint positions
00056   KDL::JntArray     joint_vel_max;         // Maximum joint velocities
00057   // create robot model, KDL::Tree and load model parameters from the model
00058   if (!loadModel(result, kdl_tree_, tree_root_name_, nr_of_jnts_, joint_min, joint_max, joint_vel_max))
00059   {
00060     ROS_FATAL("Could not load model!");
00061     return false;
00062   }
00063 
00064   // data for the IK solvers obtained from the parameter server
00065   int nr_of_endpts = 0;
00066   std::vector<std::string> endpts;
00067   endpts.clear();
00068   if(nh_private_.getParam("nr_of_endpoints", nr_of_endpts) && nr_of_endpts >= 0)
00069   {
00070     for(int i = 0; i < nr_of_endpts; ++i)
00071     {
00072       std::string elementname;
00073       std::string endpt_name;
00074       std::stringstream ss;
00075       ss << "endpoint_" << i;
00076       ss >> elementname;
00077       if(nh_private_.getParam(elementname, endpt_name))
00078       {
00079         endpts.push_back(endpt_name);
00080         ROS_DEBUG("Added endpoint '%s'", endpts[i].c_str());
00081       }
00082       else
00083       {
00084         ROS_FATAL("Couldn't get the name of an endpoint!");
00085         return false;
00086       }
00087     }
00088   }
00089   nh_private_.param("srv_call_frequency", srv_call_frequency_, 10);
00090   double x_dot_trans_max, x_dot_rot_max, x_dot_trans_min, x_dot_rot_min;
00091   double q_dot_min_factor, q_dot_max_factor;
00092   double epsilon, low_pass_factor;
00093   int max_iterations;
00094   nh_private_.param("epsilon", epsilon, 1e-3);
00095   nh_private_.param("max_iterations", max_iterations, 10);
00096   nh_private_.param("low_pass_factor", low_pass_factor, 0.0);
00097   nh_private_.param("x_dot_trans_max", x_dot_trans_max, 1.0);
00098   nh_private_.param("x_dot_rot_max", x_dot_rot_max, 1.0);
00099   nh_private_.param("x_dot_trans_min", x_dot_trans_min, 0.0);
00100   nh_private_.param("x_dot_rot_min", x_dot_rot_min, 0.0);
00101   nh_private_.param("q_dot_max_factor", q_dot_max_factor, 1.0);
00102   nh_private_.param("q_dot_min_factor", q_dot_min_factor, 0.0);
00103   x_dot_trans_max = x_dot_trans_max / srv_call_frequency_;
00104   x_dot_rot_max = x_dot_rot_max / srv_call_frequency_;
00105   x_dot_trans_min = x_dot_trans_min / srv_call_frequency_;
00106   x_dot_rot_min = x_dot_rot_min / srv_call_frequency_;
00107   q_dot_max_factor = q_dot_max_factor / srv_call_frequency_;
00108   q_dot_min_factor = q_dot_min_factor / srv_call_frequency_;
00109   KDL::Multiply(joint_vel_max,  q_dot_max_factor, joint_vel_max);
00110   KDL::JntArray joint_vel_min(nr_of_jnts_); // Minimum joint velocities
00111   for (unsigned int i = 0; i < joint_vel_min.rows(); ++i)
00112   {
00113     joint_vel_min(i) = 1.0;
00114   }
00115   KDL::Multiply(joint_vel_min,  q_dot_min_factor, joint_vel_min);
00116 
00117   ROS_DEBUG("srv_call_frequency = %d", srv_call_frequency_);
00118   ROS_DEBUG("x_dot_trans_max = %f, x_dot_rot_max = %f", x_dot_trans_max, x_dot_rot_max);
00119   ROS_DEBUG("x_dot_trans_min = %f, x_dot_rot_min = %f", x_dot_trans_min, x_dot_rot_min);
00120   ROS_DEBUG("q_dot_max_factor = %f", q_dot_max_factor);
00121   ROS_DEBUG("q_dot_min_factor  = %f", q_dot_min_factor);
00122   ROS_DEBUG("maximum iterations = %d", max_iterations);
00123   ROS_DEBUG("precision = %f", epsilon);
00124   ROS_DEBUG("low_pass_factor  = %f", low_pass_factor);
00125 
00126   // Configure kdl's kinematic solvers
00127   fk_solver_.reset(new KDL::TreeFkSolverPos_recursive(kdl_tree_));
00128   ik_vel_solver_.reset(new KDL::TreeIkSolverVel_wdls(kdl_tree_, endpts));
00129   ik_pos_solver_.reset(new KDL::TreeIkSolverPos_Online(nr_of_jnts_,
00130                                                        endpts,
00131                                                        *fk_solver_,
00132                                                        *ik_vel_solver_,
00133                                                        joint_min,
00134                                                        joint_max,
00135                                                        joint_vel_min,
00136                                                        joint_vel_max,
00137                                                        x_dot_trans_max,
00138                                                        x_dot_rot_max,
00139                                                        x_dot_trans_min,
00140                                                        x_dot_rot_min,
00141                                                        low_pass_factor,
00142                                                        max_iterations,
00143                                                        epsilon));
00144 
00145   // Configuration of the IK velocity solver
00146   // Joint space weight matrix
00147   js_w_matr_ = KDL::MatrixXd::Identity(nr_of_jnts_, nr_of_jnts_);
00148   ROS_DEBUG("filling the joint space weight matrix:");
00149   for (unsigned int i = 0 ; i < nr_of_jnts_ ; ++i)
00150   {
00151     std::string elementname;
00152     std::stringstream ss;
00153     ss << "js_w_matr/j" << i;
00154     ss >> elementname;
00155     double elementvalue;
00156     nh_private_.param(elementname, elementvalue, 1.0);
00157     js_w_matr_( i, i ) = elementvalue;
00158     ROS_DEBUG("qs_w_matr_(%d,%d) = %f", i, i, js_w_matr_( i, i ));
00159   }
00160   ik_vel_solver_->setWeightJS(js_w_matr_);
00161 
00162   // Task space weight matrix
00163   ts_w_matr_ = KDL::MatrixXd::Identity( 6 * endpts.size(), 6 * endpts.size() );
00164   std::vector<std::string> ending;
00165   ending.clear();
00166   ending.push_back("px");
00167   ending.push_back("py");
00168   ending.push_back("pz");
00169   ending.push_back("rx");
00170   ending.push_back("ry");
00171   ending.push_back("rz");
00172   ROS_DEBUG("filling the task space weight matrix:");
00173   for (unsigned int i = 0 ; i < endpts.size() ; ++i)
00174   {
00175     for (unsigned int j = 0 ; j < 6; ++j)
00176     {
00177       std::string elementname;
00178       std::stringstream ss;
00179       ss << "ts_w_matr/endpt" << i << "/";
00180       ss << ending[j];
00181       ss >> elementname;
00182       double elementvalue;
00183       nh_private_.param(elementname, elementvalue, 0.0);
00184       ts_w_matr_( i * 6 + j, i * 6 + j ) = elementvalue;
00185       ROS_DEBUG("ts_w_matr_(%d,%d) = %f", i * 6 + j, i * 6 + j, ts_w_matr_( i * 6 + j, i * 6 + j ));
00186     }
00187   }
00188   ik_vel_solver_->setWeightTS(ts_w_matr_);
00189 
00190   // lambda
00191   nh_private_.param("lambda", lambda_, 0.01);
00192   ROS_DEBUG("lambda = %f", lambda_);
00193   ik_vel_solver_->setLambda(lambda_);
00194 
00195   fk_service_ = nh_private_.advertiseService(FK_SERVICE, &TreeKinematics::getPositionFk, this);
00196   ik_service_ = nh_private_.advertiseService(IK_SERVICE, &TreeKinematics::getPositionIk, this);
00197 
00198   return true;
00199 }
00200 
00201 
00202 bool TreeKinematics::loadModel(const std::string xml,
00203                                KDL::Tree &kdl_tree,
00204                                std::string &tree_root_name,
00205                                unsigned int &nr_of_jnts,
00206                                KDL::JntArray &joint_min,
00207                                KDL::JntArray &joint_max,
00208                                KDL::JntArray &joint_vel_max)
00209 {
00210   urdf::Model robot_model;
00211   if (!robot_model.initString(xml))
00212   {
00213       ROS_FATAL("Could not initialize robot model!");
00214       return false;
00215   }
00216   if (!kdl_parser::treeFromUrdfModel(robot_model, kdl_tree))
00217   {
00218       ROS_FATAL("Could not initialize tree object!");
00219       return false;
00220   }
00221   if (!readJoints(robot_model, kdl_tree, tree_root_name, nr_of_jnts, joint_min, joint_max, joint_vel_max))
00222   {
00223       ROS_FATAL("Could not read information about the joints!");
00224       return false;
00225   }
00226   return true;
00227 }
00228 
00229 
00230 bool TreeKinematics::readJoints(urdf::Model &robot_model,
00231                                 KDL::Tree &kdl_tree,
00232                                 std::string &tree_root_name,
00233                                 unsigned int &nr_of_jnts,
00234                                 KDL::JntArray &joint_min,
00235                                 KDL::JntArray &joint_max,
00236                                 KDL::JntArray &joint_vel_max)
00237 {
00238   KDL::SegmentMap segmentMap;
00239   segmentMap = kdl_tree.getSegments();
00240   tree_root_name = kdl_tree.getRootSegment()->second.segment.getName();
00241   nr_of_jnts = kdl_tree.getNrOfJoints();
00242   ROS_DEBUG( "the tree's number of joints: [%d]", nr_of_jnts );
00243   joint_min.resize(nr_of_jnts);
00244   joint_max.resize(nr_of_jnts);
00245   joint_vel_max.resize(nr_of_jnts);
00246   info_.joint_names.resize(nr_of_jnts);
00247   info_.limits.resize(nr_of_jnts);
00248 
00249   // The following walks through all tree segments, extracts their joints except joints of KDL::None and extracts
00250   // the information about min/max position and max velocity of the joints not of type urdf::Joint::UNKNOWN or
00251   // urdf::Joint::FIXED
00252   ROS_DEBUG("Extracting all joints from the tree, which are not of type KDL::Joint::None.");
00253   boost::shared_ptr<const urdf::Joint> joint;
00254   for (KDL::SegmentMap::const_iterator seg_it = segmentMap.begin(); seg_it != segmentMap.end(); ++seg_it)
00255   {
00256     if (seg_it->second.segment.getJoint().getType() != KDL::Joint::None)
00257     {
00258       // check, if joint can be found in the URDF model of the robot
00259       joint = robot_model.getJoint(seg_it->second.segment.getJoint().getName().c_str());
00260       if (!joint)
00261       {
00262         ROS_FATAL("Joint '%s' has not been found in the URDF robot model!", joint->name.c_str());
00263         return false;
00264       }
00265       // extract joint information
00266       if (joint->type != urdf::Joint::UNKNOWN && joint->type != urdf::Joint::FIXED)
00267       {
00268         ROS_DEBUG( "getting information about joint: [%s]", joint->name.c_str() );
00269         double lower = 0.0, upper = 0.0, vel_limit = 0.0;
00270         unsigned int has_pos_limits = 0, has_vel_limits = 0;
00271 
00272         if ( joint->type != urdf::Joint::CONTINUOUS )
00273         {
00274           ROS_DEBUG("joint is not continuous.");
00275           lower = joint->limits->lower;
00276           upper = joint->limits->upper;
00277           has_pos_limits = 1;
00278           if (joint->limits->velocity)
00279           {
00280             has_vel_limits = 1;
00281             vel_limit = joint->limits->velocity;
00282             ROS_DEBUG("joint has following velocity limit: %f", vel_limit);
00283           }
00284           else
00285           {
00286             has_vel_limits = 0;
00287             vel_limit = 0.0;
00288             ROS_DEBUG("joint has no velocity limit.");
00289           }
00290         }
00291         else
00292         {
00293           ROS_DEBUG("joint is continuous.");
00294           lower = -M_PI;
00295           upper = M_PI;
00296           has_pos_limits = 0;
00297           if(joint->limits && joint->limits->velocity)
00298           {
00299             has_vel_limits = 1;
00300             vel_limit = joint->limits->velocity;
00301             ROS_DEBUG("joint has following velocity limit: %f", vel_limit);
00302           }
00303           else
00304           {
00305             has_vel_limits = 0;
00306             vel_limit = 0.0;
00307             ROS_DEBUG("joint has no velocity limit.");
00308           }
00309         }
00310 
00311         joint_min(seg_it->second.q_nr) = lower;
00312         joint_max(seg_it->second.q_nr) = upper;
00313         joint_vel_max(seg_it->second.q_nr) = vel_limit;
00314         ROS_DEBUG("pos_min = %f, pos_max = %f, vel_max = %f", lower, upper, vel_limit);
00315 
00316         info_.joint_names[seg_it->second.q_nr] = joint->name;
00317         info_.limits[seg_it->second.q_nr].joint_name = joint->name;
00318         info_.limits[seg_it->second.q_nr].has_position_limits = has_pos_limits;
00319         info_.limits[seg_it->second.q_nr].min_position = lower;
00320         info_.limits[seg_it->second.q_nr].max_position = upper;
00321         info_.limits[seg_it->second.q_nr].has_velocity_limits = has_vel_limits;
00322         info_.limits[seg_it->second.q_nr].max_velocity = vel_limit;
00323       }
00324     }
00325   }
00326   return true;
00327 }
00328 
00329 
00330 int TreeKinematics::getJointIndex(const std::string &name)
00331 {
00332     for (unsigned int i=0; i < info_.joint_names.size(); ++i)
00333     {
00334       if (info_.joint_names[i] == name)
00335         return i;
00336     }
00337     return -1;
00338 }
00339 
00340 
00341 bool TreeKinematics::getPositionFk(kinematics_msgs::GetPositionFK::Request& request,
00342                                    kinematics_msgs::GetPositionFK::Response& response)
00343 {
00344   ROS_DEBUG("getPositionFK method invoked.");
00345   KDL::JntArray q_in;
00346   double nr_of_jnts = request.robot_state.joint_state.name.size();
00347   q_in.resize(nr_of_jnts);
00348 
00349   for (unsigned int i=0; i < nr_of_jnts; ++i)
00350   {
00351     int tmp_index = getJointIndex(request.robot_state.joint_state.name[i]);
00352     if (tmp_index >=0)
00353     {
00354       q_in(tmp_index) = request.robot_state.joint_state.position[i];
00355       ROS_DEBUG("joint '%s' is now number '%d'", request.robot_state.joint_state.name[i].c_str(), tmp_index);
00356     }
00357     else
00358     {
00359       ROS_FATAL("i: %d, No joint index for %s!", i, request.robot_state.joint_state.name[i].c_str());
00360       ROS_FATAL("Service call aborted.");
00361       return false;
00362     }
00363   }
00364 
00365   response.pose_stamped.resize(request.fk_link_names.size());
00366   response.fk_link_names.resize(request.fk_link_names.size());
00367   KDL::Frame p_out;
00368   geometry_msgs::PoseStamped pose;
00369   tf::Stamped<tf::Pose> tf_pose;
00370   for (unsigned int i=0; i < request.fk_link_names.size(); i++)
00371   {
00372     ROS_DEBUG("End effector name: %s",request.fk_link_names[i].c_str());
00373     int fk_ret = fk_solver_->JntToCart(q_in, p_out, request.fk_link_names[i]);
00374     if (fk_ret >= 0)
00375     {
00376       tf_pose.frame_id_ = tree_root_name_;
00377       tf_pose.stamp_ = ros::Time::now();
00378       tf::PoseKDLToTF(p_out, tf_pose);
00379       try
00380       {
00381         tf_listener_.transformPose(request.header.frame_id, tf_pose, tf_pose);
00382       }
00383       catch (tf::TransformException const &ex)
00384       {
00385         ROS_FATAL("Could not transform FK pose to frame: %s",request.header.frame_id.c_str());
00386         response.error_code.val = response.error_code.FRAME_TRANSFORM_FAILURE;
00387         return false;
00388       }
00389       tf::poseStampedTFToMsg(tf_pose, pose);
00390       response.pose_stamped[i] = pose;
00391       response.fk_link_names[i] = request.fk_link_names[i];
00392       response.error_code.val = response.error_code.SUCCESS;
00393     }
00394     else
00395     {
00396       ROS_WARN("A FK solution could not be found for %s (error code = %d)",
00397       request.fk_link_names[i].c_str(), fk_ret);
00398       response.error_code.val = response.error_code.NO_FK_SOLUTION;
00399     }
00400   }
00401 
00402   return true;
00403 }
00404 
00405 
00406 bool TreeKinematics::getPositionIk(tree_kinematics::get_tree_position_ik::Request &request,
00407                                    tree_kinematics::get_tree_position_ik::Response &response)
00408 {
00409   ik_srv_duration_ = ros::Time::now().toSec();
00410   ROS_DEBUG("getPositionIK method invoked.");
00411 
00412   // extract current joint positions from the request
00413   KDL::JntArray q, q_desi;
00414   double nr_of_jnts = request.pos_ik_request[0].ik_seed_state.joint_state.name.size();
00415   q.resize(nr_of_jnts);
00416   q_desi.resize(nr_of_jnts);
00417   for (unsigned int i=0; i < nr_of_jnts; ++i)
00418   {
00419     int tmp_index = getJointIndex(request.pos_ik_request[0].ik_seed_state.joint_state.name[i]);
00420     if (tmp_index >=0)
00421     {
00422       q(tmp_index) = request.pos_ik_request[0].ik_seed_state.joint_state.position[i];
00423       ROS_DEBUG("joint '%s' is now number '%d'", request.pos_ik_request[0].ik_seed_state.joint_state.name[i].c_str(),
00424                                                 tmp_index);
00425     }
00426     else
00427     {
00428       ROS_FATAL("i: %d, No joint index for %s!",i,request.pos_ik_request[0].ik_seed_state.joint_state.name[i].c_str());
00429       ROS_FATAL("Service call aborted.");
00430       return false;
00431     }
00432   }
00433 
00434   // convert pose messages into transforms from the root frame to the given poses and further into KDL::Frames
00435   geometry_msgs::PoseStamped pose_msg_in;
00436   geometry_msgs::PoseStamped pose_msg_transformed;
00437   tf::Stamped<tf::Pose> transform;
00438   tf::Stamped<tf::Pose> transform_root;
00439   KDL::Frames desired_poses;
00440   KDL::Frame desired_pose;
00441   for(unsigned int i = 0; i < request.pos_ik_request.size(); ++i)
00442   {
00443     pose_msg_in = request.pos_ik_request[i].pose_stamped;
00444     try
00445     {
00446       tf_listener_.waitForTransform(tree_root_name_, pose_msg_in.header.frame_id, pose_msg_in.header.stamp,
00447       ros::Duration(0.1));
00448       tf_listener_.transformPose(tree_root_name_, pose_msg_in, pose_msg_transformed);
00449     }
00450     catch (tf::TransformException const &ex)
00451     {
00452       ROS_FATAL("%s",ex.what());
00453       ROS_FATAL("Could not transform IK pose from '%s' to frame '%s'", tree_root_name_.c_str(),
00454       pose_msg_in.header.frame_id.c_str());
00455       response.error_code.val = response.error_code.FRAME_TRANSFORM_FAILURE;
00456       return false;
00457     }
00458     tf::PoseMsgToKDL(pose_msg_transformed.pose, desired_pose);
00459     desired_poses[request.pos_ik_request[i].ik_link_name] = desired_pose;
00460   }
00461 
00462   // use the solver to compute desired joint positions
00463   ik_duration_ = ros::Time::now().toSec();
00464   int ik_ret = ik_pos_solver_->CartToJnt_it(q, desired_poses, q_desi); // NOTE: Before it was CartToJnt (without the _it). What's the difference?
00465   ik_duration_ = ros::Time::now().toSec() - ik_duration_;
00466   ik_duration_median_ = ((ik_duration_median_ * (loop_count_ - 1)) + ik_duration_) / loop_count_;
00467 
00468   // insert the solver's result into the service response
00469   if (ik_ret >= 0 || ik_ret == -3)
00470   {
00471     response.solution.joint_state.name = info_.joint_names;
00472     response.solution.joint_state.position.resize(nr_of_jnts_);
00473     response.solution.joint_state.velocity.resize(nr_of_jnts_);
00474     for (unsigned int i=0; i < nr_of_jnts_; ++i)
00475     {
00476       response.solution.joint_state.position[i] = q_desi(i);
00477       response.solution.joint_state.velocity[i] = (q_desi(i) - q(i)) * srv_call_frequency_;
00478       ROS_DEBUG("IK Solution: %s %d: pos = %f, vel = %f",response.solution.joint_state.name[i].c_str(), i,
00479       response.solution.joint_state.position[i], response.solution.joint_state.velocity[i]);
00480     }
00481     response.error_code.val = response.error_code.SUCCESS;
00482 
00483     ik_srv_duration_ = ros::Time::now().toSec() - ik_srv_duration_;
00484     ik_srv_duration_median_ = ((ik_srv_duration_median_ * (loop_count_ - 1)) + ik_srv_duration_) / loop_count_;
00485     loop_count_++;
00486 
00487     ROS_INFO_THROTTLE(1.0, "tree_kinematics: ik_srv_duration %f and median %f", ik_srv_duration_,
00488     ik_srv_duration_median_);
00489     ROS_INFO_THROTTLE(1.0, "tree_kinematics: ik_duration %f and median %f", ik_duration_, ik_duration_median_);
00490 
00491     if (ik_ret == -3)
00492     {
00493       ROS_WARN_THROTTLE(1.0, "Maximum iterations reached! (error code = %d)", ik_ret);
00494     }
00495   }
00496   else
00497   {
00498     ROS_WARN("An IK solution could not be found (error code = %d)", ik_ret);
00499     response.error_code.val = response.error_code.NO_IK_SOLUTION;
00500 
00501     ik_srv_duration_ = ros::Time::now().toSec() - ik_srv_duration_;
00502     ik_srv_duration_median_ = ((ik_srv_duration_median_ * (loop_count_ - 1)) + ik_srv_duration_) / loop_count_;
00503     loop_count_++;
00504 
00505     ROS_INFO_THROTTLE(1.0, "tree_kinematics: ik_srv_duration %f and median %f", ik_srv_duration_,
00506     ik_srv_duration_median_);
00507     ROS_INFO_THROTTLE(1.0, "tree_kinematics: ik_duration %f and median %f", ik_duration_, ik_duration_median_);
00508   }
00509   return true;
00510 }
00511 
00512 } // namespace
00513 


tree_kinematics
Author(s): Marcus Liebhardt
autogenerated on Mon Jan 6 2014 11:40:04