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