ikfast_plugin.cpp
Go to the documentation of this file.
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         //ROS_ERROR("Stepper: %f %f %f %f, %d %d", *value, lower, upper, step, lower_, upper_);
00093     }
00094     void reset() {
00095         current_ = 0;
00096         *value = start_;
00097     }
00098     bool step() {
00099         int next;
00100         if (current_ <= 0) { // neg
00101             next = 1 - current_; // -> pos
00102             if (next > upper_) {
00103                 next = -next; // -> neg
00104                 if (next < lower_) return false;
00105             }
00106         } else { // pos
00107             next = -current_; // -> neg
00108             if (next < lower_) {
00109                 next = 1 - next; // -> pos
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) { // reverse!
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         //ROS_ERROR("Solution!");
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         // print_frame("FK:", p_out.p.data, p_out.M.data);
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         // Load and Read Models
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         // print_frame("IK:", frame.p.data, frame.M.data);
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             //ROS_ERROR("State: %f", jss.state[0]);
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; // is reachable but violates constraints
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         // get joint maxs and mins
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 


cob_kinematics
Author(s): Mathias Luedtke
autogenerated on Wed Aug 26 2015 11:01:11