00001
00052 #include <ros/ros.h>
00053
00054 #include <moveit/kinematics_base/kinematics_base.h>
00055
00056 #include <tf_conversions/tf_kdl.h>
00057
00058 #define IKFAST_HAS_LIBRARY
00059 #define IKFAST_NO_MAIN
00060 #include "ikfast.h"
00061
00062 #include <moveit_msgs/GetKinematicSolverInfo.h>
00063 #include <moveit_msgs/MoveItErrorCodes.h>
00064 #include <urdf/model.h>
00065
00066 void print_frame(const char * str, const double* trans, const double* rot) {
00067 ROS_ERROR("%s %f %f %f, %f %f %f %f %f %f %f %f %f", str, trans[0], trans[1], trans[2], rot[0], rot[1], rot[2], rot[3], rot[4], rot[5], rot[6], rot[7], rot[8]);
00068 }
00069 void setConsistencyLimit(std::vector<std::pair<double, double> > &min_max,
00070 const std::vector<double> &seed, const std::vector<double> &consistency_limits) {
00071 if(min_max.size() != seed.size() || min_max.size() != consistency_limits.size()) return;
00072
00073 for(unsigned int i=0; i <min_max.size(); ++i){
00074 min_max[i].first = fmax(min_max[i].first, seed[i] - consistency_limits[i]);
00075 min_max[i].second = fmin(min_max[i].second, seed[i] + consistency_limits[i]);
00076 }
00077 }
00078
00079 struct Stepper {
00080 int upper_, lower_, current_;
00081 double *value;
00082 double start_, step_;
00083 Stepper(double *value, double lower, double upper, double step) :
00084 current_(0), value(value), start_(*value), step_(step) {
00085 double right_bound = fmax(lower, start_ - M_PI) + 2 * M_PI + step;
00086 double left_bound = fmin(upper, start_ + M_PI) - 2 * M_PI - step;
00087 right_bound = fmin(right_bound, upper);
00088 left_bound = fmax(left_bound, lower);
00089
00090 lower_ = -(int) (fabs(left_bound - start_) / step);
00091 upper_ = fabs(right_bound - start_) / step;
00092
00093 }
00094 void reset() {
00095 current_ = 0;
00096 *value = start_;
00097 }
00098 bool step() {
00099 int next;
00100 if (current_ <= 0) {
00101 next = 1 - current_;
00102 if (next > upper_) {
00103 next = -next;
00104 if (next < lower_) return false;
00105 }
00106 } else {
00107 next = -current_;
00108 if (next < lower_) {
00109 next = 1 - next;
00110 if (next > upper_) return false;
00111 }
00112
00113 }
00114 current_ = next;
00115 *value = start_ + current_ * step_;
00116 return true;
00117 }
00118 };
00119
00120 struct JointSpaceStepper {
00121 std::vector<Stepper> steppers;
00122 int current_;
00123 std::vector<double> state;
00124 JointSpaceStepper(double step, const std::vector<double> &ik_seed_state,
00125 const std::vector<std::pair<double, double> > &min_max,
00126 const std::vector<double> &indices) :
00127 current_(0), state(indices.size()) {
00128 int i = 0;
00129 for (std::vector<double>::const_reverse_iterator it = indices.rbegin(); it
00130 != indices.rend(); ++it) {
00131 steppers.push_back(Stepper(&state[i++], min_max[*it].first,
00132 min_max[*it].second, step));
00133 }
00134 }
00135 bool step() {
00136 bool overflow = false;
00137 while (current_ < steppers.size() && !steppers[current_].step()) {
00138 ++current_;
00139 overflow = true;
00140 }
00141 if (current_ >= steppers.size()) return false;
00142 if (overflow) {
00143 while (current_ > 0)
00144 steppers[current_--].reset();
00145 }
00146 return true;
00147
00148 }
00149 };
00150
00151 using namespace ikfast;
00152
00153 template<class A1, class A2>
00154 std::ostream& operator<<(std::ostream& s, std::vector<A1, A2> const& vec)
00155 {
00156 copy(vec.begin(), vec.end(), std::ostream_iterator<A1>(s, " "));
00157 return s;
00158 }
00159
00160 class IkSolutionListFiltered: public IkSolutionList<double> {
00161 protected:
00162 const std::vector<std::pair<double, double> > &min_max;
00163 const std::vector<double> &ik_seed_state;
00164 const kinematics::KinematicsBase::IKCallbackFn &solution_callback;
00165 const geometry_msgs::Pose &ik_pose;
00166 double min_dist;
00167 std::vector<double> min_solution;
00168
00169 virtual bool filterSolution(const std::vector<double> &values) {
00170 for (unsigned int i = 0; i < min_max.size(); ++i)
00171 if (values[i] < min_max[i].first || values[i] > min_max[i].second) {
00172 return false;
00173 }
00174
00175 moveit_msgs::MoveItErrorCodes error_code;
00176 error_code.val = error_code.SUCCESS;
00177 if (solution_callback) solution_callback(ik_pose, values, error_code);
00178 return error_code.val == error_code.SUCCESS;
00179 }
00180 double ik_values[12];
00181 public:
00182 IkSolutionListFiltered(
00183 const std::vector<std::pair<double, double> > &min_max,
00184 const std::vector<double> &ik_seed_state,
00185 const kinematics::KinematicsBase::IKCallbackFn &solution_callback,
00186 const geometry_msgs::Pose &ik_pose) :
00187 min_max(min_max), ik_seed_state(ik_seed_state), solution_callback(
00188 solution_callback), ik_pose(ik_pose) {
00189 KDL::Frame frame;
00190 tf::poseMsgToKDL(ik_pose, frame);
00191 ik_values[0] = frame.p[0]; ik_values[1] = frame.p[1]; ik_values[2] = frame.p[2];
00192 ik_values[3] = frame.M.data[0]; ik_values[4] = frame.M.data[1]; ik_values[5] = frame.M.data[2];
00193 ik_values[6] = frame.M.data[3]; ik_values[7] = frame.M.data[4]; ik_values[8] = frame.M.data[5];
00194 ik_values[9] = frame.M.data[6]; ik_values[10] = frame.M.data[7]; ik_values[11] = frame.M.data[8];
00195 }
00196
00197 virtual size_t AddSolution(const std::vector<
00198 IkSingleDOFSolutionBase<double> >& vinfos,
00199 const std::vector<int>& vfree) {
00200
00201
00202
00203 IkSolution<double> sol(vinfos, vfree);
00204 std::vector<double> vsolfree(sol.GetFree().size());
00205 std::vector<double> solvalues;
00206 sol.GetSolution(solvalues, vsolfree);
00207
00208
00209 double dist = harmonize(ik_seed_state, solvalues, min_max);
00210 if (filterSolution(solvalues)) {
00211 if (min_solution.empty() || dist < min_dist) min_solution
00212 = solvalues;
00213 }
00214
00215 return IkSolutionList<double>::AddSolution(vinfos, vfree);
00216 }
00217 static double harmonize(const std::vector<double> &ik_seed_state,
00218 std::vector<double> &solution, const std::vector<std::pair<double, double> > &min_max) {
00219 double dist_sqr = 0;
00220 for (size_t i = 0; i < solution.size(); ++i) {
00221 if (fabs(solution[i] - ik_seed_state[i]) > M_PI) {
00222 if (ik_seed_state[i] < solution[i]) {
00223 if (solution[i] > 0 && solution[i] - 2 * M_PI >= min_max[i].first) solution[i] -= 2 * M_PI;
00224 } else {
00225 if (solution[i] < 0 && solution[i] + 2 * M_PI <= min_max[i].second) solution[i] += 2 * M_PI;
00226 }
00227 }
00228
00229 dist_sqr += fabs(solution[i] - ik_seed_state[i]);
00230 }
00231 return dist_sqr;
00232 }
00233
00234 bool getMinSolution(std::vector<double> &dest) {
00235 if (min_solution.empty()) return false;
00236 dest = min_solution;
00237 return true;
00238 }
00239 };
00240 namespace IKFAST_NAMESPACE {
00241
00242 class IKFastPlugin: public kinematics::KinematicsBase {
00243 public:
00251 virtual bool getPositionIK(const geometry_msgs::Pose &ik_pose,
00252 const std::vector<double> &ik_seed_state,
00253 std::vector<double> &solution,
00254 moveit_msgs::MoveItErrorCodes &error_code,
00255 const kinematics::KinematicsQueryOptions &options) const {
00256
00257 return searchPositionIK(ik_pose, ik_seed_state, solution, min_max_,
00258 error_code);
00259 }
00260
00269 virtual bool searchPositionIK(const geometry_msgs::Pose &ik_pose,
00270 const std::vector<double> &ik_seed_state,
00271 double timeout,
00272 std::vector<double> &solution,
00273 moveit_msgs::MoveItErrorCodes &error_code,
00274 const kinematics::KinematicsQueryOptions &options) const {
00275
00276 return searchPositionIK(ik_pose, ik_seed_state, solution, min_max_,
00277 error_code, timeout);
00278 }
00279
00289 virtual bool searchPositionIK(const geometry_msgs::Pose &ik_pose,
00290 const std::vector<double> &ik_seed_state,
00291 double timeout,
00292 const std::vector<double> &consistency_limits,
00293 std::vector<double> &solution,
00294 moveit_msgs::MoveItErrorCodes &error_code,
00295 const kinematics::KinematicsQueryOptions &options) const {
00296
00297 std::vector<std::pair<double, double> > min_max = min_max_;
00298 setConsistencyLimit(min_max, ik_seed_state, consistency_limits);
00299 return searchPositionIK(ik_pose, ik_seed_state, solution, min_max,
00300 error_code, timeout);
00301 }
00302
00311 virtual bool searchPositionIK(const geometry_msgs::Pose &ik_pose,
00312 const std::vector<double> &ik_seed_state,
00313 double timeout,
00314 std::vector<double> &solution,
00315 const IKCallbackFn &solution_callback,
00316 moveit_msgs::MoveItErrorCodes &error_code,
00317 const kinematics::KinematicsQueryOptions &options) const {
00318
00319 return searchPositionIK(ik_pose, ik_seed_state, solution, min_max_,
00320 error_code, timeout, solution_callback);
00321 }
00322
00333 virtual bool searchPositionIK(const geometry_msgs::Pose &ik_pose,
00334 const std::vector<double> &ik_seed_state,
00335 double timeout,
00336 const std::vector<double> &consistency_limits,
00337 std::vector<double> &solution,
00338 const IKCallbackFn &solution_callback,
00339 moveit_msgs::MoveItErrorCodes &error_code,
00340 const kinematics::KinematicsQueryOptions &options) const {
00341
00342 std::vector<std::pair<double, double> > min_max = min_max_;
00343 setConsistencyLimit(min_max, ik_seed_state, consistency_limits);
00344 return searchPositionIK(ik_pose, ik_seed_state, solution, min_max,
00345 error_code, timeout, solution_callback);
00346 }
00347
00354 virtual bool getPositionFK(const std::vector<std::string> &link_names,
00355 const std::vector<double> &joint_angles,
00356 std::vector<geometry_msgs::Pose> &poses) const {
00357 KDL::Frame p_out;
00358
00359 if (joint_angles.size() != GetNumJoints()) {
00360 ROS_ERROR("%d joint angles are required", GetNumJoints());
00361 return false;
00362 }
00363
00364 if (link_names.size() != 1 || link_names[0] != tip_frame_) {
00365 ROS_ERROR("Can compute FK for %s only",tip_frame_.c_str());
00366 return false;
00367 }
00368
00369 ComputeFk(&joint_angles[0], p_out.p.data, p_out.M.data);
00370
00371 poses.resize(1);
00372 tf::poseKDLToMsg(p_out, poses[0]);
00373 return true;
00374 }
00375
00380 virtual bool initialize(const std::string& robot_description,
00381 const std::string& group_name,
00382 const std::string& base_frame,
00383 const std::string& tip_frame,
00384 double search_discretization){
00385 setValues(robot_description, group_name, base_frame, tip_frame, search_discretization);
00386
00387 links_.resize(1);
00388 links_[0] = tip_frame_;
00389
00390
00391 if (!loadModel(robot_description)) {
00392 ROS_FATAL("Could not load models!");
00393 return false;
00394 }
00395 indices_.clear();
00396 for (int i = 0; i < GetNumFreeParameters(); ++i)
00397 indices_.push_back(GetFreeParameters()[i]);
00398 return true;
00399 }
00400
00404 virtual const std::vector<std::string>& getJointNames() const {
00405 return joints_;
00406 }
00407
00411 virtual const std::vector<std::string>& getLinkNames() const {
00412 return links_;
00413 }
00414
00418 virtual ~IKFastPlugin() {
00419 }
00420 IKFastPlugin() :
00421 bounds_epsilon_(0.0) {
00422 }
00423 protected:
00424 std::vector<std::pair<double, double> > min_max_;
00425 double bounds_epsilon_;
00426 std::vector<double> indices_;
00427 std::vector<std::string> links_;
00428 std::vector<std::string> joints_;
00429 bool searchPositionIK(
00430 const geometry_msgs::Pose &ik_pose,
00431 const std::vector<double> &ik_seed_state,
00432 std::vector<double> &solution,
00433 const std::vector<std::pair<double, double> > &min_max,
00434 moveit_msgs::MoveItErrorCodes &error_code,
00435 const double timeout = -1,
00436 const IKCallbackFn &solution_callback = 0) const {
00437
00438 KDL::Frame frame;
00439 tf::poseMsgToKDL(ik_pose, frame);
00440 error_code.val = error_code.NO_IK_SOLUTION;
00441
00442 if(ik_seed_state.size() < GetNumJoints()){
00443 ROS_ERROR_STREAM("Needs " << GetNumJoints() << "joint values. but only " << ik_seed_state.size() << "were given.");
00444 return false;
00445 }
00446
00447
00448 JointSpaceStepper jss(search_discretization_, ik_seed_state, min_max,
00449 indices_);
00450
00451 IkSolutionListFiltered sollist(min_max, ik_seed_state,
00452 solution_callback, ik_pose);
00453
00454 ros::Time maxTime = ros::Time::now() + ros::Duration(timeout);
00455 do {
00456
00457 if (ComputeIk(frame.p.data, frame.M.data, indices_.empty()?0:&jss.state[0], sollist)) {
00458 error_code.val = error_code.START_STATE_IN_COLLISION;
00459 }
00460 if (sollist.getMinSolution(solution)) {
00461 error_code.val = error_code.SUCCESS;
00462 break;
00463 }
00464 if (timeout >= 0.0 && ros::Time::now() > maxTime) {
00465 error_code.val = error_code.TIMED_OUT;
00466 break;
00467 }
00468 } while (jss.step());
00469 return error_code.val == error_code.SUCCESS;
00470 }
00471 bool loadModel(const std::string param) {
00472 urdf::Model robot_model;
00473
00474 if (!robot_model.initParam(param)) {
00475 ROS_FATAL("Could not initialize robot model");
00476 return false;
00477 }
00478 if (!readJoints(robot_model)) {
00479 ROS_FATAL("Could not read information about the joints");
00480 return false;
00481 }
00482 return true;
00483 }
00484
00485 bool readJoints(urdf::Model &robot_model) {
00486 int dimension_ = 0;
00487
00488 boost::shared_ptr<const urdf::Link> link = robot_model.getLink(
00489 tip_frame_);
00490 boost::shared_ptr<const urdf::Joint> joint;
00491 while (link && link->name != base_frame_) {
00492 joint = robot_model.getJoint(link->parent_joint->name);
00493 if (!joint) {
00494 ROS_ERROR("Could not find joint: %s",link->parent_joint->name.c_str());
00495 return false;
00496 }
00497 if (joint->type != urdf::Joint::UNKNOWN && joint->type
00498 != urdf::Joint::FIXED) {
00499 ROS_INFO( "adding joint: [%s]", joint->name.c_str() );
00500 dimension_++;
00501 }
00502 link = robot_model.getLink(link->getParent()->name);
00503 }
00504
00505 if (dimension_ != GetNumJoints()) {
00506 ROS_ERROR("Solver needs %d joints, but %d were found.",GetNumJoints(), dimension_);
00507 return false;
00508 }
00509
00510 min_max_.resize(dimension_);
00511 joints_.resize(dimension_);
00512 link = robot_model.getLink(tip_frame_);
00513
00514 unsigned int i = 0;
00515 while (link && i < dimension_) {
00516 joint = robot_model.getJoint(link->parent_joint->name);
00517 if (joint->type != urdf::Joint::UNKNOWN && joint->type
00518 != urdf::Joint::FIXED) {
00519 ROS_INFO( "getting bounds for joint: [%s]", joint->name.c_str() );
00520
00521 float lower, upper;
00522 if (joint->type != urdf::Joint::CONTINUOUS) {
00523 if (joint->safety) {
00524 lower = joint->safety->soft_lower_limit
00525 + bounds_epsilon_;
00526 upper = joint->safety->soft_upper_limit
00527 - bounds_epsilon_;
00528 } else {
00529 lower = joint->limits->lower + bounds_epsilon_;
00530 upper = joint->limits->upper - bounds_epsilon_;
00531 }
00532 } else {
00533 lower = -M_PI;
00534 upper = M_PI;
00535 }
00536 min_max_[dimension_ - i - 1] = std::make_pair(lower, upper);
00537 joints_[dimension_ - i - 1] = joint->name;
00538 i++;
00539 }
00540 link = robot_model.getLink(link->getParent()->name);
00541 }
00542
00543 return true;
00544 }
00545 };
00546
00547 }
00548 #include <pluginlib/class_list_macros.h>
00549
00550 #define ADD_TYPED_PLUGIN(type,name) PLUGINLIB_DECLARE_CLASS(cob_kinematics, type##name, IKFAST_NAMESPACE::IKFastPlugin, kinematics::KinematicsBase)
00551 #define ADD_IKFAST_PLUGIN(name) ADD_TYPED_PLUGIN(IKFast_, name)
00552 ADD_IKFAST_PLUGIN(IKFAST_NAMESPACE)
00553 ;
00554