00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00040 #include <reem_kinematics_constraint_aware/reem_arm_kinematics_plugin.h>
00041 #include <pluginlib/class_list_macros.h>
00042 
00043 using namespace KDL;
00044 using namespace tf;
00045 using namespace std;
00046 using namespace ros;
00047  
00048 const double BOUNDS_EPSILON = .00001;
00049  
00050 
00051 PLUGINLIB_DECLARE_CLASS(reem_kinematics_constraint_aware,ReemKinematicsPlugin, reem_kinematics_constraint_aware::ReemKinematicsPlugin, kinematics::KinematicsBase)
00052 
00053 namespace reem_kinematics_constraint_aware {
00054 
00055 ReemKinematicsPlugin::ReemKinematicsPlugin():active_(false)
00056 {
00057   srand ( time(NULL) );
00058 }
00059 
00060 bool ReemKinematicsPlugin::isActive()
00061 {
00062   if(active_)
00063     return true;
00064   return false;
00065 }
00066 
00067 double ReemKinematicsPlugin::genRandomNumber(const double &min, const double &max)
00068 {
00069   int rand_num = rand()%100+1;
00070   double result = min + (double)((max-min)*rand_num)/101.0;
00071   return result;
00072 }
00073 
00074 KDL::JntArray ReemKinematicsPlugin::getRandomConfiguration()
00075 {
00076   KDL::JntArray jnt_array;
00077   jnt_array.resize(dimension_);
00078   for(unsigned int i=0; i < dimension_; ++i)
00079     jnt_array(i) = genRandomNumber(joint_min_(i),joint_max_(i));
00080   return jnt_array;
00081 }
00082 
00083 KDL::JntArray ReemKinematicsPlugin::getRandomConfiguration(const KDL::JntArray& seed_state,
00084                                                            const unsigned int& redundancy,
00085                                                            const double& consistency_limit)
00086 {
00087   KDL::JntArray jnt_array;
00088   jnt_array.resize(dimension_);
00089   for(unsigned int i=0; i < dimension_; i++) {
00090     if(i != redundancy) {
00091       jnt_array(i) = genRandomNumber(joint_min_(i),joint_max_(i));
00092     } else {
00093       double jmin = fmin(joint_min_(i), seed_state(i)-consistency_limit);
00094       double jmax = fmax(joint_max_(i), seed_state(i)+consistency_limit);
00095       jnt_array(i) = genRandomNumber(jmin, jmax);
00096     }
00097   }
00098   return jnt_array;
00099 }
00100 
00101 bool ReemKinematicsPlugin::checkConsistency(const KDL::JntArray& seed_state,
00102                                             const unsigned int& redundancy,
00103                                             const double& consistency_limit,
00104                                             const KDL::JntArray& solution) const
00105 {
00106   KDL::JntArray jnt_array;
00107   jnt_array.resize(dimension_);
00108   for(unsigned int i=0; i < dimension_; i++) {
00109     if(i == redundancy) {
00110       double jmin = fmin(joint_min_(i), seed_state(i)-consistency_limit);
00111       double jmax = fmax(joint_max_(i), seed_state(i)+consistency_limit);
00112       if(solution(i) < jmin || solution(i) > jmax) {
00113         return false;
00114       }
00115     }
00116   }
00117   return true;
00118 }
00119 
00120 bool ReemKinematicsPlugin::initialize(const std::string& group_name,
00121                                       const std::string& base_name,
00122                                       const std::string& tip_name,
00123                                       const double& search_discretization)
00124 {
00125   setValues(group_name, base_name, tip_name, search_discretization);
00126   
00127   std::string urdf_xml, full_urdf_xml;
00128   ros::NodeHandle node_handle;
00129   ros::NodeHandle private_handle("~"+group_name);
00130   ROS_INFO_STREAM("Private handle registered under " << private_handle.getNamespace());
00131   node_handle.param("urdf_xml",urdf_xml,std::string("robot_description"));
00132   node_handle.searchParam(urdf_xml,full_urdf_xml);
00133   ROS_DEBUG("Reading xml file from parameter server");
00134   std::string result;
00135   if (!node_handle.getParam(full_urdf_xml, result)) {
00136     ROS_FATAL("Could not load the xml from parameter server: %s", urdf_xml.c_str());
00137     return false;
00138   }
00139 
00140   
00141   if (!loadModel(result)) {
00142     ROS_FATAL("Could not load models!");
00143     return false;
00144   }
00145 
00146   
00147   std::map<std::string, int> joint_name_to_idx;
00148   for (size_t i = 0; i < kdl_chain_.getNrOfSegments(); ++i)
00149   {
00150     const KDL::Joint& joint = kdl_chain_.getSegment(i).getJoint();
00151     if (joint.getType() != KDL::Joint::None)
00152     {
00153       joint_name_to_idx[joint.getName()] = i;
00154     }
00155   }
00156 
00157   
00158   const int q_dim = kdl_chain_.getNrOfJoints();
00159   const int x_dim = 6;
00160 
00161   
00162   int max_iterations;
00163   double epsilon;
00164   double max_delta_x;
00165   double max_delta_q;
00166   double velik_gain;
00167 
00168   private_handle.param("max_solver_iterations", max_iterations, 500);
00169   private_handle.param("max_search_iterations", max_search_iterations_, 3);
00170   private_handle.param("epsilon", epsilon, 1e-5);
00171   private_handle.param("max_delta_x", max_delta_x, 0.006);
00172   private_handle.param("max_delta_q", max_delta_q, 0.03);
00173   private_handle.param("velik_gain", velik_gain,   1.0);
00174 
00175   
00176   Eigen::VectorXd Wqinv = Eigen::VectorXd::Ones(q_dim);
00177   default_posture_.resize(q_dim);
00178   for (size_t i = 0; i < kdl_chain_.getNrOfSegments(); ++i)
00179   {
00180     const KDL::Joint& joint = kdl_chain_.getSegment(i).getJoint();
00181     if (joint.getType() != KDL::Joint::None)
00182     {
00183       private_handle.param("joint_weights/"   + joint.getName(), Wqinv(joint_name_to_idx[joint.getName()]),            1.0);
00184       private_handle.param("default_posture/" + joint.getName(), default_posture_[joint_name_to_idx[joint.getName()]], 0.0);
00185     }
00186   }
00187 
00188   
00189   Eigen::VectorXd Wxinv = Eigen::VectorXd::Ones(x_dim);
00190   private_handle.param("task_weights/position/x", Wxinv(0), 1.0);
00191   private_handle.param("task_weights/position/y", Wxinv(1), 1.0);
00192   private_handle.param("task_weights/position/z", Wxinv(2), 1.0);
00193   private_handle.param("task_weights/orientation/x", Wxinv(3), 1.0);
00194   private_handle.param("task_weights/orientation/y", Wxinv(4), 1.0);
00195   private_handle.param("task_weights/orientation/z", Wxinv(5), 1.0);
00196 
00197   
00198   fk_solver_.reset(new KDL::ChainFkSolverPos_recursive(kdl_chain_));
00199   ik_solver_.reset(new IkSolver(kdl_chain_));
00200   ik_solver_->setJointPositionLimits(joint_min_.data, joint_max_.data);
00201   ik_solver_->setEpsilon(epsilon);
00202   ik_solver_->setMaxIterations(max_iterations);
00203   ik_solver_->setMaxDeltaPosTask(max_delta_x);
00204   ik_solver_->setMaxDeltaPosJoint(max_delta_q);
00205   ik_solver_->setVelocityIkGain(velik_gain);
00206   ik_solver_->setJointSpaceWeights(Wqinv);
00207   ik_solver_->setTaskSpaceWeights(Wxinv);
00208   active_ = true;
00209   return true;
00210 }
00211 
00212 bool ReemKinematicsPlugin::loadModel(const std::string xml)
00213 {
00214   urdf::Model robot_model;
00215   KDL::Tree tree;
00216 
00217   if (!robot_model.initString(xml)) {
00218     ROS_FATAL("Could not initialize robot model");
00219     return -1;
00220   }
00221   if (!kdl_parser::treeFromString(xml, tree)) {
00222     ROS_ERROR("Could not initialize tree object");
00223     return false;
00224   }
00225   if (!tree.getChain(base_name_, tip_name_, kdl_chain_)) {
00226     ROS_ERROR("Could not initialize chain object");
00227     return false;
00228   }
00229   if (!readJoints(robot_model)) {
00230     ROS_FATAL("Could not read information about the joints");
00231     return false;
00232   }
00233   return true;
00234 }
00235 
00236 bool ReemKinematicsPlugin::readJoints(urdf::Model &robot_model)
00237 {
00238   dimension_ = 0;
00239   
00240   boost::shared_ptr<const urdf::Link> link = robot_model.getLink(tip_name_);
00241   boost::shared_ptr<const urdf::Joint> joint;
00242   while (link && link->name != base_name_) {
00243     joint = robot_model.getJoint(link->parent_joint->name);
00244     if (!joint) {
00245       ROS_ERROR("Could not find joint: %s",link->parent_joint->name.c_str());
00246       return false;
00247     }
00248     if (joint->type != urdf::Joint::UNKNOWN && joint->type != urdf::Joint::FIXED) {
00249       ROS_INFO( "adding joint: [%s]", joint->name.c_str() );
00250       dimension_++;
00251     }
00252     link = robot_model.getLink(link->getParent()->name);
00253   }
00254   joint_min_.resize(dimension_);
00255   joint_max_.resize(dimension_);
00256   chain_info_.joint_names.resize(dimension_);
00257   chain_info_.limits.resize(dimension_);
00258   link = robot_model.getLink(tip_name_);
00259   if(link)
00260     chain_info_.link_names.push_back(tip_name_);
00261 
00262   unsigned int i = 0;
00263   while (link && i < dimension_) {
00264     joint = robot_model.getJoint(link->parent_joint->name);
00265     if (joint->type != urdf::Joint::UNKNOWN && joint->type != urdf::Joint::FIXED) {
00266       ROS_INFO( "getting bounds for joint: [%s]", joint->name.c_str() );
00267 
00268       float lower, upper;
00269       int hasLimits;
00270       if ( joint->type != urdf::Joint::CONTINUOUS ) {
00271         if(joint->safety) {
00272           lower = joint->safety->soft_lower_limit+BOUNDS_EPSILON; 
00273           upper = joint->safety->soft_upper_limit-BOUNDS_EPSILON;
00274         } else {
00275           lower = joint->limits->lower+BOUNDS_EPSILON;
00276           upper = joint->limits->upper-BOUNDS_EPSILON;
00277         }
00278         hasLimits = 1;
00279       } else {
00280         lower = -M_PI;
00281         upper = M_PI;
00282         hasLimits = 0;
00283       }
00284       int index = dimension_ - i -1;
00285 
00286       joint_min_.data[index] = lower;
00287       joint_max_.data[index] = upper;
00288       chain_info_.joint_names[index] = joint->name;
00289       chain_info_.limits[index].joint_name = joint->name;
00290       chain_info_.limits[index].has_position_limits = hasLimits;
00291       chain_info_.limits[index].min_position = lower;
00292       chain_info_.limits[index].max_position = upper;
00293       ++i;
00294     }
00295     link = robot_model.getLink(link->getParent()->name);
00296   }
00297   return true;
00298 }
00299 
00300 int ReemKinematicsPlugin::getJointIndex(const std::string &name)
00301 {
00302   for (unsigned int i=0; i < chain_info_.joint_names.size(); ++i) {
00303     if (chain_info_.joint_names[i] == name)
00304       return i;
00305   }
00306   return -1;
00307 }
00308 
00309 int ReemKinematicsPlugin::getKDLSegmentIndex(const std::string &name)
00310 {
00311   int i=0; 
00312   while (i < (int)kdl_chain_.getNrOfSegments()) {
00313     if (kdl_chain_.getSegment(i).getName() == name) {
00314       return i+1;
00315     }
00316     ++i;
00317   }
00318   return -1;
00319 }
00320 
00321 bool ReemKinematicsPlugin::getPositionIK(const geometry_msgs::Pose &ik_pose,
00322                                          const std::vector<double> &ik_seed_state,
00323                                          const std::vector<double> &posture,
00324                                          std::vector<double> &solution,
00325                                          int &error_code)
00326 {
00327   ros::WallTime n1 = ros::WallTime::now();
00328   if(!active_)
00329   {
00330     ROS_ERROR("kinematics not active");
00331     return false;
00332   }
00333 
00334   ROS_DEBUG_STREAM("getPositionIK1:Position request pose is " <<
00335                    ik_pose.position.x << " " <<
00336                    ik_pose.position.y << " " <<
00337                    ik_pose.position.z << " " <<
00338                    ik_pose.orientation.x << " " <<
00339                    ik_pose.orientation.y << " " <<
00340                    ik_pose.orientation.z << " " <<
00341                    ik_pose.orientation.w);
00342 
00343   KDL::Frame pose_desired;
00344   tf::PoseMsgToKDL(ik_pose, pose_desired);
00345   
00346   KDL::JntArray jnt_pos_in(dimension_);
00347   KDL::JntArray jnt_pos_out(dimension_);
00348   KDL::JntArray jnt_posture(dimension_);
00349   for(unsigned int i=0; i < dimension_; ++i)
00350   {
00351     jnt_pos_in(i)  = ik_seed_state[i];
00352     jnt_posture(i) = posture[i];
00353   }
00354   ik_solver_->setPosture(jnt_posture);
00355   bool ik_valid = ik_solver_->solve(jnt_pos_in, pose_desired, jnt_pos_out);
00356   ROS_DEBUG_STREAM("IK success " << ik_valid << " time " << (ros::WallTime::now()-n1).toSec());
00357   solution.resize(dimension_);
00358   
00359   for(unsigned int i=0; i < dimension_; ++i)
00360   {
00361     solution[i] = jnt_pos_out(i);
00362   }
00363   if(ik_valid)
00364   {
00365     error_code = kinematics::SUCCESS;
00366     return true;
00367   }
00368   else
00369   {
00370     ROS_DEBUG("An IK solution could not be found");
00371     error_code = kinematics::NO_IK_SOLUTION;
00372     return false;
00373   }
00374 }
00375 
00376 bool ReemKinematicsPlugin::getPositionIK(const geometry_msgs::Pose &ik_pose,
00377                                          const std::vector<double> &ik_seed_state,
00378                                          std::vector<double> &solution,
00379                                          int &error_code)
00380 {
00381   return getPositionIK(ik_pose,
00382                        ik_seed_state,
00383                        default_posture_,
00384                        solution,
00385                        error_code);
00386 }
00387 
00388 bool ReemKinematicsPlugin::searchPositionIK(const geometry_msgs::Pose &ik_pose,
00389                                               const std::vector<double> &ik_seed_state,
00390                                               const double &timeout,
00391                                               std::vector<double> &solution,
00392                                               int &error_code)
00393 {
00394   ros::WallTime n1 = ros::WallTime::now();
00395   if(!active_)
00396   {
00397     ROS_ERROR("kinematics not active");
00398     error_code = kinematics::INACTIVE;
00399     return false;
00400   }
00401   KDL::Frame pose_desired;
00402   tf::PoseMsgToKDL(ik_pose, pose_desired);
00403 
00404   ROS_DEBUG_STREAM("searchPositionIK1:Position request pose is " <<
00405                    ik_pose.position.x << " " <<
00406                    ik_pose.position.y << " " <<
00407                    ik_pose.position.z << " " <<
00408                    ik_pose.orientation.x << " " << 
00409                    ik_pose.orientation.y << " " << 
00410                    ik_pose.orientation.z << " " << 
00411                    ik_pose.orientation.w);
00412 
00413   
00414   KDL::JntArray jnt_pos_in;
00415   KDL::JntArray jnt_pos_out;
00416   jnt_pos_in.resize(dimension_);
00417   KDL::JntArray posture(dimension_);
00418   for(unsigned int i=0; i < dimension_; ++i)
00419   {
00420     jnt_pos_in(i) = ik_seed_state[i];
00421     posture(i)    = default_posture_[i];
00422   }
00423   for(int i=0; i < max_search_iterations_; ++i)
00424   {
00425     for(unsigned int j=0; j < dimension_; ++j)
00426     { 
00427       ROS_DEBUG_STREAM("seed state " << j << " " << jnt_pos_in(j));
00428     }
00429     ik_solver_->setPosture(posture);
00430     bool ik_valid = ik_solver_->solve(jnt_pos_in, pose_desired, jnt_pos_out);
00431     ROS_DEBUG_STREAM("IK success " << ik_valid << " time " << (ros::WallTime::now()-n1).toSec());
00432     if(ik_valid) {
00433       solution.resize(dimension_);
00434       for(unsigned int j=0; j < dimension_; ++j) {
00435         solution[j] = jnt_pos_out(j);
00436       }
00437       error_code = kinematics::SUCCESS;
00438       ROS_DEBUG_STREAM("Solved after " << i+1 << " iterations");
00439       return true;
00440     }      
00441     jnt_pos_in = getRandomConfiguration();
00442   }
00443   ROS_DEBUG("An IK solution could not be found");   
00444   error_code = kinematics::NO_IK_SOLUTION;
00445   return false;
00446 }
00447 
00448 bool ReemKinematicsPlugin::searchPositionIK(const geometry_msgs::Pose &ik_pose,
00449                                             const std::vector<double> &ik_seed_state,
00450                                             const double &timeout,
00451                                             const unsigned int& redundancy,
00452                                             const double &consistency_limit,
00453                                             std::vector<double> &solution,
00454                                             int &error_code)
00455 {
00456   ros::WallTime n1 = ros::WallTime::now();
00457   if(!active_)
00458   {
00459     ROS_ERROR("kinematics not active");
00460     error_code = kinematics::INACTIVE;
00461     return false;
00462   }
00463   KDL::Frame pose_desired;
00464   tf::PoseMsgToKDL(ik_pose, pose_desired);
00465 
00466   ROS_DEBUG_STREAM("searchPositionIK1:Position request pose is " <<
00467                    ik_pose.position.x << " " <<
00468                    ik_pose.position.y << " " <<
00469                    ik_pose.position.z << " " <<
00470                    ik_pose.orientation.x << " " <<
00471                    ik_pose.orientation.y << " " <<
00472                    ik_pose.orientation.z << " " <<
00473                    ik_pose.orientation.w);
00474 
00475   
00476   KDL::JntArray jnt_pos_in;
00477   KDL::JntArray jnt_pos_out;
00478   KDL::JntArray jnt_seed_state;
00479   jnt_pos_in.resize(dimension_);
00480   KDL::JntArray posture(dimension_);
00481   for(unsigned int i=0; i < dimension_; ++i)
00482   {
00483     jnt_seed_state(i) = ik_seed_state[i];
00484     posture(i)        = default_posture_[i];
00485   }
00486   jnt_pos_in = jnt_seed_state;
00487   for(int i=0; i < max_search_iterations_; ++i)
00488   {
00489     for(unsigned int j=0; j < dimension_; ++j)
00490     {
00491       ROS_DEBUG_STREAM("seed state " << j << " " << jnt_pos_in(j));
00492     }
00493     ik_solver_->setPosture(posture);
00494     int ik_valid = ik_solver_->solve(jnt_pos_in, pose_desired, jnt_pos_out);
00495     ROS_DEBUG_STREAM("IK success " << ik_valid << " time " << (ros::WallTime::now()-n1).toSec());
00496     if(ik_valid >= 0 && checkConsistency(jnt_seed_state, redundancy, consistency_limit, jnt_pos_out)) {
00497       solution.resize(dimension_);
00498       for(unsigned int j=0; j < dimension_; j++) {
00499         solution[j] = jnt_pos_out(j);
00500       }
00501       error_code = kinematics::SUCCESS;
00502       ROS_DEBUG_STREAM("Solved after " << i+1 << " iterations");
00503       return true;
00504     }
00505     jnt_pos_in = getRandomConfiguration(jnt_seed_state, redundancy, consistency_limit);
00506   }
00507   ROS_DEBUG("An IK solution could not be found");
00508   error_code = kinematics::NO_IK_SOLUTION;
00509   return false;
00510 }
00511 
00512 bool ReemKinematicsPlugin::searchPositionIK(const geometry_msgs::Pose &ik_pose,
00513                                               const std::vector<double> &ik_seed_state,
00514                                               const double &timeout,
00515                                               std::vector<double> &solution,
00516                                               const boost::function<void(const geometry_msgs::Pose &ik_pose,const std::vector<double> &ik_solution,int &error_code)> &desired_pose_callback,
00517                                               const boost::function<void(const geometry_msgs::Pose &ik_pose,const std::vector<double> &ik_solution,int &error_code)> &solution_callback,
00518                                               int &error_code)  
00519 {
00520   if(!active_)
00521   {
00522     ROS_ERROR("kinematics not active");
00523     error_code = kinematics::INACTIVE;
00524     return false;
00525   }
00526   KDL::Frame pose_desired;
00527   tf::PoseMsgToKDL(ik_pose, pose_desired);
00528 
00529   ROS_DEBUG_STREAM("searchPositionIK2: Position request pose is " <<
00530                    ik_pose.position.x << " " <<
00531                    ik_pose.position.y << " " <<
00532                    ik_pose.position.z << " " <<
00533                    ik_pose.orientation.x << " " << 
00534                    ik_pose.orientation.y << " " << 
00535                    ik_pose.orientation.z << " " << 
00536                    ik_pose.orientation.w);
00537 
00538   
00539   KDL::JntArray jnt_pos_in;
00540   KDL::JntArray jnt_pos_out;
00541   jnt_pos_in.resize(dimension_);
00542   KDL::JntArray posture(dimension_);
00543   for(unsigned int i=0; i < dimension_; ++i)
00544   {
00545     jnt_pos_in(i) = ik_seed_state[i];
00546     posture(i)    = default_posture_[i];
00547   }
00548 
00549   if(!desired_pose_callback.empty())
00550     desired_pose_callback(ik_pose,ik_seed_state,error_code);
00551 
00552   if(error_code < 0)
00553   {
00554     ROS_DEBUG("Could not find inverse kinematics for desired end-effector pose since the pose may be in collision");
00555     return false;
00556   }
00557   for(int i=0; i < max_search_iterations_; ++i)
00558   {
00559     ik_solver_->setPosture(posture);
00560     bool ik_valid = ik_solver_->solve(jnt_pos_in, pose_desired, jnt_pos_out);
00561     jnt_pos_in = getRandomConfiguration();
00562     if(!ik_valid)
00563       continue;
00564     std::vector<double> solution_local;
00565     solution_local.resize(dimension_);
00566     for(unsigned int j=0; j < dimension_; ++j)
00567       solution_local[j] = jnt_pos_out(j);
00568     solution_callback(ik_pose,solution_local,error_code);
00569     if(error_code == kinematics::SUCCESS)
00570     {
00571       solution = solution_local;
00572       ROS_DEBUG_STREAM("Solved after " << i+1 << " iterations");
00573       return true;
00574     }
00575   }
00576   ROS_DEBUG("An IK that satisifes the constraints and is collision free could not be found");   
00577   error_code = kinematics::NO_IK_SOLUTION;
00578   return false;
00579 }
00580 
00581 bool ReemKinematicsPlugin::searchPositionIK(const geometry_msgs::Pose &ik_pose,
00582                                             const std::vector<double> &ik_seed_state,
00583                                             const double &timeout,
00584                                             const unsigned int& redundancy,
00585                                             const double& consistency_limit,
00586                                             std::vector<double> &solution,
00587                                             const boost::function<void(const geometry_msgs::Pose &ik_pose,const std::vector<double> &ik_solution,int &error_code)> &desired_pose_callback,
00588                                             const boost::function<void(const geometry_msgs::Pose &ik_pose,const std::vector<double> &ik_solution,int &error_code)> &solution_callback,
00589                                             int &error_code)
00590 {
00591   if(!active_)
00592   {
00593     ROS_ERROR("kinematics not active");
00594     error_code = kinematics::INACTIVE;
00595     return false;
00596   }
00597   KDL::Frame pose_desired;
00598   tf::PoseMsgToKDL(ik_pose, pose_desired);
00599 
00600   ROS_DEBUG_STREAM("searchPositionIK2: Position request pose is " <<
00601                    ik_pose.position.x << " " <<
00602                    ik_pose.position.y << " " <<
00603                    ik_pose.position.z << " " <<
00604                    ik_pose.orientation.x << " " <<
00605                    ik_pose.orientation.y << " " <<
00606                    ik_pose.orientation.z << " " <<
00607                    ik_pose.orientation.w);
00608 
00609   
00610   
00611   KDL::JntArray jnt_pos_in;
00612   KDL::JntArray jnt_pos_out;
00613   KDL::JntArray jnt_seed_state;
00614   jnt_pos_in.resize(dimension_);
00615   KDL::JntArray posture(dimension_);
00616   for(unsigned int i=0; i < dimension_; ++i)
00617   {
00618     jnt_seed_state(i) = ik_seed_state[i];
00619     posture(i)        = default_posture_[i];
00620   }
00621   jnt_pos_in = jnt_seed_state;
00622 
00623   if(!desired_pose_callback.empty())
00624     desired_pose_callback(ik_pose,ik_seed_state,error_code);
00625 
00626   if(error_code < 0)
00627   {
00628     ROS_DEBUG("Could not find inverse kinematics for desired end-effector pose since the pose may be in collision");
00629     return false;
00630   }
00631   for(int i=0; i < max_search_iterations_; ++i)
00632   {
00633     ik_solver_->setPosture(posture);
00634     int ik_valid = ik_solver_->solve(jnt_pos_in,pose_desired,jnt_pos_out);
00635     jnt_pos_in = getRandomConfiguration(jnt_seed_state, redundancy, consistency_limit);
00636     if(ik_valid < 0 || !checkConsistency(jnt_seed_state, redundancy, consistency_limit, jnt_pos_out))
00637       continue;
00638     std::vector<double> solution_local;
00639     solution_local.resize(dimension_);
00640     for(unsigned int j=0; j < dimension_; j++)
00641       solution_local[j] = jnt_pos_out(j);
00642     solution_callback(ik_pose,solution_local,error_code);
00643     if(error_code == kinematics::SUCCESS)
00644     {
00645       solution = solution_local;
00646       ROS_DEBUG_STREAM("Solved after " << i+1 << " iterations");
00647       return true;
00648     }
00649   }
00650   ROS_DEBUG("An IK that satisifes the constraints and is collision free could not be found");
00651   error_code = kinematics::NO_IK_SOLUTION;
00652   return false;
00653 }
00654 
00655 bool ReemKinematicsPlugin::getPositionFK(const std::vector<std::string> &link_names,
00656                                            const std::vector<double> &joint_angles,
00657                                            std::vector<geometry_msgs::Pose> &poses)
00658 {
00659   if(!active_)
00660   {
00661     ROS_ERROR("kinematics not active");
00662     return false;
00663   }
00664   
00665   KDL::Frame p_out;
00666   KDL::JntArray jnt_pos_in;
00667   geometry_msgs::PoseStamped pose;
00668   tf::Stamped<tf::Pose> tf_pose;
00669   
00670   jnt_pos_in.resize(dimension_);
00671   for(unsigned int i=0; i < dimension_; ++i)
00672   {
00673     jnt_pos_in(i) = joint_angles[i];
00674   }
00675   
00676   poses.resize(link_names.size());
00677   
00678   bool valid = true;
00679   for(unsigned int i=0; i < poses.size(); ++i)
00680   {
00681     if(fk_solver_->JntToCart(jnt_pos_in,p_out,getKDLSegmentIndex(link_names[i])) >=0)
00682     {
00683       tf::PoseKDLToMsg(p_out,poses[i]);
00684     }
00685     else
00686     {
00687       ROS_ERROR("Could not compute FK for %s",link_names[i].c_str());
00688       valid = false;
00689     }
00690   }
00691   return valid;
00692 }
00693 
00694 std::string ReemKinematicsPlugin::getBaseFrame()
00695 {
00696   if(!active_)
00697   {
00698     ROS_ERROR("kinematics not active");
00699     return std::string("");
00700   }
00701   return base_name_;
00702 }
00703 
00704 std::string ReemKinematicsPlugin::getToolFrame()
00705 {
00706   if(!active_ || chain_info_.link_names.empty())
00707   {
00708     ROS_ERROR("kinematics not active");
00709     return std::string("");
00710   }
00711   return chain_info_.link_names[0];
00712 }
00713 
00714 const std::vector<std::string>& ReemKinematicsPlugin::getJointNames() const
00715 {
00716   if(!active_)
00717   {
00718     ROS_ERROR("kinematics not active");
00719   }
00720   return chain_info_.joint_names;
00721 }
00722 
00723 const std::vector<std::string>& ReemKinematicsPlugin::getLinkNames() const
00724 {
00725   if(!active_)
00726   {
00727     ROS_ERROR("kinematics not active");
00728   }
00729   return chain_info_.link_names;
00730 }
00731 
00732 }