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 #include <pluginlib/class_list_macros.h>
00032 #include <base_local_planner/goal_functions.h>
00033 
00034 #include "collvoid_local_planner/collvoid_local_planner.h"
00035 
00036 using namespace std;
00037 using namespace costmap_2d;
00038 
00039 
00040 PLUGINLIB_DECLARE_CLASS(collvoid_local_planner, CollvoidLocalPlanner, collvoid_local_planner::CollvoidLocalPlanner, nav_core::BaseLocalPlanner)
00041 
00042 
00043 template <typename T>
00044 void getParam (const ros::NodeHandle nh, const string& name, T* place)
00045 {
00046   bool found = nh.getParam(name, *place);
00047   ROS_ASSERT_MSG (found, "Could not find parameter %s", name.c_str());
00048   ROS_DEBUG_STREAM_NAMED ("init", "Initialized " << name << " to " << *place);
00049 }
00050 
00051 
00052 template <class T>
00053 T getParamDef (const ros::NodeHandle nh, const string& name, const T& default_val)
00054 {
00055   T val;
00056   nh.param(name, val, default_val);
00057   ROS_DEBUG_STREAM_NAMED ("init", "Initialized " << name << " to " << val <<
00058                           "(default was " << default_val << ")");
00059   return val;
00060 }
00061 
00062 namespace collvoid_local_planner {
00063   
00064   CollvoidLocalPlanner::CollvoidLocalPlanner():
00065     costmap_ros_(NULL), tf_(NULL), initialized_(false){
00066   }
00067 
00068   CollvoidLocalPlanner::CollvoidLocalPlanner(std::string name, tf::TransformListener* tf, Costmap2DROS* costmap_ros): 
00069     costmap_ros_(NULL), tf_(NULL), initialized_(false){
00070 
00071     
00072     initialize(name, tf, costmap_ros);
00073   }
00074 
00075   CollvoidLocalPlanner::~CollvoidLocalPlanner() {
00076   }
00077 
00078   
00079   void CollvoidLocalPlanner::initialize(std::string name, tf::TransformListener* tf, costmap_2d::Costmap2DROS* costmap_ros){
00080     if (!initialized_){
00081       tf_ = tf;
00082       costmap_ros_ = costmap_ros;
00083       
00084       rot_stopped_velocity_ = 1e-2;
00085       trans_stopped_velocity_ = 1e-2;
00086   
00087       current_waypoint_ = 0;
00088 
00089       ros::NodeHandle private_nh("~/" + name);
00090 
00091 
00092       
00093       yaw_goal_tolerance_ = getParamDef(private_nh,"yaw_goal_tolerance", 0.05);
00094       xy_goal_tolerance_  = getParamDef(private_nh,"xy_goal_tolerance", 0.10);
00095       latch_xy_goal_tolerance_ = getParamDef(private_nh,"latch_xy_goal_tolerance", false);
00096       ignore_goal_yaw_ = getParamDef(private_nh, "ignore_goal_jaw", false);
00097 
00098 
00099       ros::NodeHandle nh;
00100 
00101 
00102       
00103       std::string my_id = nh.getNamespace();
00104       if (strcmp(my_id.c_str(), "/") == 0) {
00105         char hostname[1024];
00106         hostname[1023] = '\0';
00107         gethostname(hostname,1023); 
00108         my_id = std::string(hostname);
00109       }
00110       my_id = getParamDef<std::string>(private_nh,"name",my_id);
00111       ROS_INFO("My name is: %s",my_id.c_str());
00112 
00113 
00114       
00115       me_.reset(new ROSAgent());
00116 
00117       
00118       getParam(private_nh,"acc_lim_x", &acc_lim_x_ );
00119       getParam(private_nh,"acc_lim_y", &acc_lim_y_ );
00120       getParam(private_nh,"acc_lim_th", &acc_lim_th_ );
00121 
00122       me_->setAccelerationConstraints(acc_lim_x_, acc_lim_y_, acc_lim_th_);
00123 
00124       
00125       getParam(private_nh, "holo_robot",&holo_robot_);
00126       me_->setIsHoloRobot(holo_robot_);
00127       
00128       if (!holo_robot_) 
00129         getParam(private_nh,"wheel_base", &wheel_base_);
00130       else
00131         wheel_base_ = 0.0;
00132       me_->setWheelBase(wheel_base_);
00133      
00134 
00135       
00136       getParam(private_nh,"max_vel_with_obstacles", &max_vel_with_obstacles_);
00137       me_->setMaxVelWithObstacles(max_vel_with_obstacles_);
00138 
00139       getParam(private_nh,"max_vel_x", &max_vel_x_);
00140       getParam(private_nh,"min_vel_x", &min_vel_x_);
00141       getParam(private_nh,"max_vel_y", &max_vel_y_);
00142       getParam(private_nh,"min_vel_y", &min_vel_y_);
00143       getParam(private_nh,"max_vel_th", &max_vel_th_);
00144       getParam(private_nh,"min_vel_th", &min_vel_th_);
00145       getParam(private_nh,"min_vel_th_inplace", &min_vel_th_inplace_);
00146 
00147       me_->setMinMaxSpeeds(min_vel_x_, max_vel_x_, min_vel_y_, max_vel_y_, min_vel_th_, max_vel_th_, min_vel_th_inplace_);
00148 
00149       
00150       getParam(private_nh,"footprint_radius",&radius_);
00151       me_->setFootprintRadius(radius_);
00152 
00153       
00154       robot_base_frame_ = costmap_ros_->getBaseFrameID();
00155       global_frame_ = getParamDef<std::string>(private_nh,"global_frame", "/map");
00156       me_->setGlobalFrame(global_frame_);
00157       me_->setRobotBaseFrame(robot_base_frame_);
00158 
00159       
00160       std::string controller_frequency_param_name;
00161       if(!private_nh.searchParam("controller_frequency", controller_frequency_param_name))
00162         sim_period_ = 0.05;
00163       else
00164         {
00165           double controller_frequency = 0;
00166           private_nh.param(controller_frequency_param_name, controller_frequency, 20.0);
00167           if(controller_frequency > 0)
00168             sim_period_ = 1.0 / controller_frequency;
00169           else
00170             {
00171               ROS_WARN("A controller_frequency less than 0 has been set. Ignoring the parameter, assuming a rate of 20Hz");
00172               sim_period_ = 0.05;
00173             }
00174         }
00175       ROS_INFO("Sim period is set to %.2f", sim_period_);
00176       me_->setSimPeriod(sim_period_);
00177 
00178 
00179 
00180       
00181       time_horizon_obst_ = getParamDef(private_nh,"time_horizon_obst",10.0);
00182       time_to_holo_ = getParamDef(private_nh,"time_to_holo", 0.4);
00183       min_error_holo_ = getParamDef(private_nh,"min_error_holo", 0.01);
00184       max_error_holo_ = getParamDef(private_nh, "max_error_holo", 0.15);
00185       delete_observations_ = getParamDef(private_nh, "delete_observations", true);
00186       threshold_last_seen_ = getParamDef(private_nh,"threshold_last_seen",1.0);
00187       eps_= getParamDef(private_nh, "eps", 0.1);
00188 
00189       bool orca, convex, clearpath, use_truncation;
00190       int num_samples, type_vo;
00191       getParam(private_nh, "orca", &orca);
00192       getParam(private_nh, "convex", &convex);
00193       getParam(private_nh, "clearpath", &clearpath);
00194       getParam(private_nh, "use_truncation", &use_truncation);
00195 
00196       num_samples = getParamDef(private_nh, "num_samples", 400);
00197       type_vo = getParamDef(private_nh, "type_vo", 0); 
00198       
00199             
00200       me_->setTimeHorizonObst(time_horizon_obst_);
00201       me_->setTimeToHolo(time_to_holo_);
00202       me_->setMinMaxErrorHolo(min_error_holo_, max_error_holo_);
00203       me_->setDeleteObservations(delete_observations_);
00204       me_->setThresholdLastSeen(threshold_last_seen_);
00205       me_->setLocalizationEps(eps_);
00206 
00207       me_->setOrca(orca);
00208       me_->setClearpath(clearpath);
00209       me_->setTypeVO(type_vo);
00210       me_->setConvex(convex);
00211       me_->setUseTruncation(use_truncation);
00212       me_->setNumSamples(num_samples);
00213      
00214       
00215       trunc_time_ = getParamDef(private_nh,"trunc_time",5.0);
00216       left_pref_ = getParamDef(private_nh,"left_pref",0.1);
00217 
00218       publish_positions_period_ = getParamDef(private_nh,"publish_positions_frequency",10.0);
00219       publish_positions_period_ = 1.0 / publish_positions_period_;
00220       
00221       publish_me_period_ = getParamDef(private_nh,"publish_me_frequency",10.0);
00222       publish_me_period_ = 1.0/publish_me_period_;
00223       
00224       me_->setTruncTime(trunc_time_);
00225       me_->setLeftPref(left_pref_);
00226       me_->setPublishPositionsPeriod(publish_positions_period_);
00227       me_->setPublishMePeriod(publish_me_period_);
00228 
00229       
00230 
00231       
00232       
00233       std::vector<geometry_msgs::Point> footprint_points;
00234       footprint_points = costmap_ros_->getRobotFootprint();
00235 
00236       geometry_msgs::PolygonStamped footprint;
00237       geometry_msgs::Point32 p;
00238       for (int i = 0; i<(int)footprint_points.size(); i++) {
00239         p.x = footprint_points[i].x;
00240         p.y = footprint_points[i].y;
00241         footprint.polygon.points.push_back(p);
00242       }
00243       if (footprint.polygon.points.size()>2)
00244         me_->setFootprint(footprint);
00245       else {
00246         double angle = 0;
00247         double step = 2 * M_PI / 72;
00248         while(angle < 2 * M_PI){
00249           geometry_msgs::Point32 pt;
00250           pt.x = radius_ * cos(angle);
00251           pt.y = radius_ * sin(angle);
00252           pt.z = 0.0;
00253           footprint.polygon.points.push_back(pt);
00254           angle += step;
00255         }
00256         me_->setFootprint(footprint);
00257       }
00258 
00259       me_->initAsMe(tf_);
00260       me_->setId(my_id);
00261 
00262 
00263       
00264       skip_next_ = false;
00265       g_plan_pub_ = private_nh.advertise<nav_msgs::Path>("global_plan", 1);
00266       l_plan_pub_ = private_nh.advertise<nav_msgs::Path>("local_plan", 1);
00267       std::string move_base_name = ros::this_node::getName();
00268       
00269       obstacles_sub_ = nh.subscribe(move_base_name + "/local_costmap/obstacles",1,&CollvoidLocalPlanner::obstaclesCallback,this);
00270 
00271       setup_= false;
00272       dsrv_ = new dynamic_reconfigure::Server<collvoid_local_planner::CollvoidConfig>(private_nh);
00273       dynamic_reconfigure::Server<collvoid_local_planner::CollvoidConfig>::CallbackType cb = boost::bind(&CollvoidLocalPlanner::reconfigureCB, this, _1, _2);
00274       dsrv_->setCallback(cb);
00275       initialized_ = true;
00276     }
00277     else
00278       ROS_WARN("This planner has already been initialized, you can't call it twice, doing nothing");
00279     
00280   } 
00281 
00282   
00283   void CollvoidLocalPlanner::reconfigureCB(collvoid_local_planner::CollvoidConfig &config, uint32_t level){
00284     boost::recursive_mutex::scoped_lock l(configuration_mutex_);
00285 
00286     
00287     
00288     if(!setup_)
00289       {
00290         last_config_ = config;
00291         default_config_ = config;
00292         setup_ = true;
00293         return;
00294       }
00295     if(config.restore_defaults) {
00296       config = default_config_;
00297       
00298       config.restore_defaults = false;
00299     }
00300 
00301     acc_lim_x_ = config.acc_lim_x;
00302     acc_lim_y_ = config.acc_lim_y;
00303     acc_lim_th_ = config.acc_lim_th;
00304 
00305     max_vel_with_obstacles_ = config.max_vel_with_obstacles;
00306     max_vel_x_ = config.max_vel_x;
00307     min_vel_x_ = config.min_vel_x;
00308     max_vel_y_ = config.max_vel_y;
00309     min_vel_y_ = config.min_vel_y;
00310     max_vel_th_ = config.max_vel_th;
00311     min_vel_th_ = config.min_vel_th;
00312     min_vel_th_inplace_ = config.min_vel_th_inplace;
00313 
00314     radius_ = config.footprint_radius;
00315 
00316     time_horizon_obst_ = config.time_horizon_obst;
00317     time_to_holo_ = config.time_to_holo;
00318     min_error_holo_ = config.min_error_holo;
00319     max_error_holo_ = config.max_error_holo;
00320     delete_observations_ = config.delete_observations;
00321     threshold_last_seen_ = config.threshold_last_seen;
00322 
00323     eps_ = config.eps;
00324 
00325     
00326     trunc_time_ = config.trunc_time;
00327     left_pref_ = config.left_pref;
00328     publish_positions_period_ = config.publish_positions_frequency;
00329     publish_positions_period_ = 1.0 / publish_positions_period_;
00330     publish_me_period_ = config.publish_me_frequency;
00331     publish_me_period_ = 1.0 / publish_me_period_;
00332 
00333 
00334     me_->setAccelerationConstraints(acc_lim_x_, acc_lim_y_, acc_lim_th_);
00335    
00336     me_->setMaxVelWithObstacles(max_vel_with_obstacles_);
00337       
00338     me_->setMinMaxSpeeds(min_vel_x_, max_vel_x_, min_vel_y_, max_vel_y_, min_vel_th_, max_vel_th_, min_vel_th_inplace_);
00339     
00340     me_->setFootprintRadius(radius_);
00341         
00342     me_->setTimeHorizonObst(time_horizon_obst_);
00343     me_->setTimeToHolo(time_to_holo_);
00344     me_->setMinMaxErrorHolo(min_error_holo_, max_error_holo_);
00345 
00346     me_->setDeleteObservations(delete_observations_);
00347     me_->setThresholdLastSeen(threshold_last_seen_);
00348     me_->setLocalizationEps(eps_);
00349     
00350     me_->setTruncTime(trunc_time_);
00351     me_->setLeftPref(left_pref_);
00352     me_->setPublishPositionsPeriod(publish_positions_period_);
00353     me_->setPublishMePeriod(publish_me_period_);
00354 
00355 
00356     me_->setOrca(config.orca);
00357     me_->setClearpath(config.clearpath);
00358     me_->setTypeVO(config.type_vo);
00359     me_->setConvex(config.convex);
00360     me_->setUseTruncation(config.use_truncation);
00361     me_->setNumSamples(config.num_samples);
00362 
00363     
00364     last_config_ = config;
00365   }
00366 
00367 
00368   bool CollvoidLocalPlanner::rotateToGoal(const tf::Stamped<tf::Pose>& global_pose, const tf::Stamped<tf::Pose>& robot_vel, double goal_th, geometry_msgs::Twist& cmd_vel){
00369     if (ignore_goal_yaw_) {
00370       cmd_vel.angular.z = 0.0;
00371       return true;
00372     }
00373     double yaw = tf::getYaw(global_pose.getRotation());
00374     double vel_yaw = tf::getYaw(robot_vel.getRotation());
00375     cmd_vel.linear.x = 0;
00376     cmd_vel.linear.y = 0;
00377     double ang_diff = angles::shortest_angular_distance(yaw, goal_th);
00378 
00379     double v_th_samp = ang_diff > 0.0 ? std::min(max_vel_th_,
00380                                                     std::max(min_vel_th_inplace_, ang_diff)) : std::max(-1.0 * max_vel_th_,
00381                                                                                                            std::min(-1.0 * min_vel_th_inplace_, ang_diff));
00382 
00383     
00384     double max_acc_vel = fabs(vel_yaw) + acc_lim_th_ * sim_period_;
00385     double min_acc_vel = fabs(vel_yaw) - acc_lim_th_ * sim_period_;
00386 
00387     v_th_samp = sign(v_th_samp) * std::min(std::max(fabs(v_th_samp), min_acc_vel), max_acc_vel);
00388 
00389     
00390     double max_speed_to_stop = sqrt(2 * acc_lim_th_ * fabs(ang_diff)); 
00391 
00392     v_th_samp = sign(v_th_samp) * std::min(max_speed_to_stop, fabs(v_th_samp));
00393     if (fabs(v_th_samp) <= 0.0 * min_vel_th_inplace_)
00394       v_th_samp  = 0.0;
00395     else if (fabs(v_th_samp) < min_vel_th_inplace_)
00396       v_th_samp = sign(v_th_samp) * max(min_vel_th_inplace_,fabs(v_th_samp));
00397     
00398     bool valid_cmd = true;
00399 
00400     ROS_DEBUG("Moving to desired goal orientation, th cmd: %.2f", v_th_samp);
00401 
00402     if(valid_cmd){
00403       cmd_vel.angular.z = v_th_samp;
00404       return true;
00405     }
00406 
00407     cmd_vel.angular.z = 0.0;
00408     return false;
00409   }
00410 
00411   bool CollvoidLocalPlanner::stopWithAccLimits(const tf::Stamped<tf::Pose>& global_pose, const tf::Stamped<tf::Pose>& robot_vel, geometry_msgs::Twist& cmd_vel){
00412     
00413     
00414     double vx = sign(robot_vel.getOrigin().x()) * std::max(0.0, (fabs(robot_vel.getOrigin().x()) - acc_lim_x_ * sim_period_));
00415     double vy = sign(robot_vel.getOrigin().y()) * std::max(0.0, (fabs(robot_vel.getOrigin().y()) - acc_lim_y_ * sim_period_));
00416 
00417     double vel_yaw = tf::getYaw(robot_vel.getRotation());
00418     double vth = sign(vel_yaw) * std::max(0.0, (fabs(vel_yaw) - acc_lim_th_ * sim_period_));
00419 
00420     
00421     
00422     bool valid_cmd = true; 
00423 
00424     
00425     if(valid_cmd){
00426       
00427       cmd_vel.linear.x = vx;
00428       cmd_vel.linear.y = vy;
00429       cmd_vel.angular.z = vth;
00430       return true;
00431     }
00432 
00433     cmd_vel.linear.x = 0.0;
00434     cmd_vel.linear.y = 0.0;
00435     cmd_vel.angular.z = 0.0;
00436     return false;
00437   }
00438 
00439 
00440   
00441   
00442   
00443   
00444   
00445   
00446   
00447   
00448   
00449 
00450   bool CollvoidLocalPlanner::setPlan(const std::vector<geometry_msgs::PoseStamped>& orig_global_plan){
00451     if(!initialized_){
00452       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00453       return false;
00454     }
00455     
00456     
00457     global_plan_.clear();
00458     global_plan_ = orig_global_plan;
00459     current_waypoint_ = 0;
00460     xy_tolerance_latch_ = false;
00461     
00462     
00463     if(!transformGlobalPlan(*tf_, global_plan_, *costmap_ros_, global_frame_, transformed_plan_)){
00464       ROS_WARN("Could not transform the global plan to the frame of the controller");
00465       return false;
00466     }
00467      
00468     return true;
00469   }
00470 
00471   bool CollvoidLocalPlanner::isGoalReached(){
00472     if(!initialized_){
00473       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00474       return false;
00475     }
00476 
00477     
00478     nav_msgs::Odometry base_odom;
00479     {
00480       boost::mutex::scoped_lock(me_->me_lock_);
00481       base_odom = me_->base_odom_;
00482     }
00483 
00484     return base_local_planner::isGoalReached(*tf_, global_plan_, *costmap_ros_, global_frame_, base_odom, 
00485                                              rot_stopped_velocity_, trans_stopped_velocity_, xy_goal_tolerance_, yaw_goal_tolerance_);
00486   }
00487 
00488 
00489 
00490   bool CollvoidLocalPlanner::computeVelocityCommands(geometry_msgs::Twist& cmd_vel){
00491     if(!initialized_){
00492       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00493       return false;
00494     }
00495 
00496     tf::Stamped<tf::Pose> global_pose;
00497     
00498     global_pose.setIdentity();
00499     global_pose.frame_id_ = robot_base_frame_;
00500     global_pose.stamp_ = ros::Time();
00501     tf_->transformPose(global_frame_, global_pose, global_pose);
00502 
00503     
00504     geometry_msgs::Twist global_vel;
00505     me_->me_lock_.lock();
00506     global_vel.linear.x = me_->base_odom_.twist.twist.linear.x;
00507     global_vel.linear.y = me_->base_odom_.twist.twist.linear.y;
00508     global_vel.angular.z = me_->base_odom_.twist.twist.angular.z;
00509     me_->me_lock_.unlock();
00510 
00511     tf::Stamped<tf::Pose> robot_vel;
00512     robot_vel.setData(tf::Transform(tf::createQuaternionFromYaw(global_vel.angular.z), tf::Vector3(global_vel.linear.x, global_vel.linear.y, 0)));
00513     robot_vel.frame_id_ = robot_base_frame_;
00514     robot_vel.stamp_ = ros::Time();
00515 
00516     tf::Stamped<tf::Pose> goal_point;
00517     tf::poseStampedMsgToTF(global_plan_.back(), goal_point);
00518 
00519     
00520     double goal_x = goal_point.getOrigin().getX();
00521     double goal_y = goal_point.getOrigin().getY();
00522     double yaw = tf::getYaw(goal_point.getRotation());
00523     double goal_th = yaw;
00524 
00525     
00526     if(base_local_planner::goalPositionReached(global_pose, goal_x, goal_y, xy_goal_tolerance_) || xy_tolerance_latch_){
00527 
00528       
00529       
00530       if(latch_xy_goal_tolerance_)
00531         xy_tolerance_latch_ = true;
00532 
00533       
00534       if(base_local_planner::goalOrientationReached(global_pose, goal_th, yaw_goal_tolerance_)){
00535         
00536         cmd_vel.linear.x = 0.0;
00537         cmd_vel.linear.y = 0.0;
00538         cmd_vel.angular.z = 0.0;
00539         rotating_to_goal_ = false;
00540         xy_tolerance_latch_ = false;
00541       }
00542       else {
00543         
00544         nav_msgs::Odometry base_odom;
00545         {
00546           boost::mutex::scoped_lock(me_->me_lock_);
00547           base_odom = me_->base_odom_;
00548         }
00549 
00550         
00551         if(!rotating_to_goal_ && !base_local_planner::stopped(base_odom, rot_stopped_velocity_, trans_stopped_velocity_)){
00552           
00553           if(!stopWithAccLimits(global_pose, robot_vel, cmd_vel))
00554             return false;
00555         }
00556         
00557         else{
00558           
00559           rotating_to_goal_ = true;
00560           if(!rotateToGoal(global_pose, robot_vel, goal_th, cmd_vel))
00561             return false;
00562         }
00563       }
00564 
00565       
00566       transformed_plan_.clear();
00567       base_local_planner::publishPlan(transformed_plan_, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00568       base_local_planner::publishPlan(transformed_plan_, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00569       
00570       return true;
00571     } 
00572 
00573     tf::Stamped<tf::Pose> target_pose;
00574     target_pose.setIdentity();
00575     target_pose.frame_id_ = robot_base_frame_;
00576     
00577     if (!skip_next_){
00578       if(!transformGlobalPlan(*tf_, global_plan_, *costmap_ros_, global_frame_, transformed_plan_)){
00579         ROS_WARN("Could not transform the global plan to the frame of the controller");
00580         return false;
00581       }
00582       geometry_msgs::PoseStamped target_pose_msg;
00583       findBestWaypoint(target_pose_msg, global_pose);
00584     }    
00585     tf::poseStampedMsgToTF(transformed_plan_[current_waypoint_], target_pose);
00586    
00587     
00588     geometry_msgs::Twist res;
00589 
00590     res.linear.x = target_pose.getOrigin().x() - global_pose.getOrigin().x();
00591     res.linear.y = target_pose.getOrigin().y() - global_pose.getOrigin().y();
00592     res.angular.z = angles::shortest_angular_distance(tf::getYaw(global_pose.getRotation()),atan2(res.linear.y, res.linear.x));
00593 
00594     
00595     collvoid::Vector2 goal_dir = collvoid::Vector2(res.linear.x,res.linear.y);
00596     
00597     if (collvoid::abs(goal_dir) > max_vel_x_) {
00598       goal_dir = max_vel_x_ * collvoid::normalize(goal_dir);
00599     }
00600     else if (collvoid::abs(goal_dir) < min_vel_x_) {
00601       goal_dir = min_vel_x_ * 1.2* collvoid::normalize(goal_dir);
00602     }
00603   
00604 
00605     collvoid::Vector2 pref_vel = collvoid::Vector2(goal_dir.x(),goal_dir.y());
00606    
00607     
00608 
00609     me_->computeNewVelocity(pref_vel, cmd_vel);
00610     
00611 
00612     if(std::abs(cmd_vel.angular.z)<min_vel_th_)
00613       cmd_vel.angular.z = 0.0;
00614     if(std::abs(cmd_vel.linear.x)<min_vel_x_)
00615       cmd_vel.linear.x = 0.0;
00616     if(std::abs(cmd_vel.linear.y)<min_vel_y_)
00617       cmd_vel.linear.y = 0.0;
00618 
00619     bool valid_cmd = true; 
00620 
00621     if (!valid_cmd){
00622       cmd_vel.angular.z = 0.0;
00623       cmd_vel.linear.x = 0.0;
00624       cmd_vel.linear.y = 0.0;
00625     }
00626 
00627     if (cmd_vel.linear.x == 0.0 && cmd_vel.angular.z == 0.0 && cmd_vel.linear.y == 0.0) {
00628       
00629       ROS_DEBUG("Did not find a good vel, calculated best holonomic velocity was: %f, %f, cur wp %d of %d trying next waypoint", me_->velocity_.x(),me_->velocity_.y(), current_waypoint_, (int)transformed_plan_.size());
00630       if (current_waypoint_ < transformed_plan_.size()-1){
00631         current_waypoint_++;
00632         skip_next_= true;
00633       }
00634       else {
00635         transformed_plan_.clear();
00636         base_local_planner::publishPlan(transformed_plan_, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00637         base_local_planner::publishPlan(transformed_plan_, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00638  
00639         return false;
00640       }
00641     }
00642     else {
00643       skip_next_ = false;
00644     }
00645 
00646     
00647     
00648     
00649     std::vector<geometry_msgs::PoseStamped> local_plan;
00650     geometry_msgs::PoseStamped pos;
00651     
00652 
00653     tf::poseStampedTFToMsg(global_pose,pos);
00654     local_plan.push_back(pos);
00655     local_plan.push_back(transformed_plan_[current_waypoint_]);
00656     base_local_planner::publishPlan(transformed_plan_, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00657     base_local_planner::publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00658     
00659     return true;
00660   }
00661   
00662   void CollvoidLocalPlanner::findBestWaypoint(geometry_msgs::PoseStamped& target_pose, const tf::Stamped<tf::Pose>& global_pose){
00663     current_waypoint_ = 0;
00664     double min_dist = DBL_MAX;
00665     for (size_t i=current_waypoint_; i < transformed_plan_.size(); i++) 
00666       {
00667         double y = global_pose.getOrigin().y();
00668         double x = global_pose.getOrigin().x();
00669         double dist = base_local_planner::distance(x, y, transformed_plan_[i].pose.position.x, transformed_plan_[i].pose.position.y);
00670         if (dist < me_->getRadius() || dist < min_dist) {
00671           min_dist = dist;
00672           target_pose = transformed_plan_[i];
00673           current_waypoint_ = i;
00674 
00675         }
00676       }
00677     
00678 
00679     
00680     
00681     
00682     if (current_waypoint_ == transformed_plan_.size()-1) 
00683       return;
00684 
00685     double dif_x = transformed_plan_[current_waypoint_+1].pose.position.x - target_pose.pose.position.x;
00686     double dif_y = transformed_plan_[current_waypoint_+1].pose.position.y - target_pose.pose.position.y;
00687     
00688     double plan_dir = atan2(dif_y, dif_x);
00689 
00690     double dif_ang = plan_dir;
00691 
00692     
00693     
00694     
00695     
00696 
00697     for (size_t i=current_waypoint_+1; i<transformed_plan_.size(); i++) {
00698       dif_x = transformed_plan_[i].pose.position.x - target_pose.pose.position.x;
00699       dif_y = transformed_plan_[i].pose.position.y - target_pose.pose.position.y;
00700     
00701       dif_ang = atan2(dif_y, dif_x);
00702       
00703 
00704       if(fabs(plan_dir - dif_ang) > 1.0* yaw_goal_tolerance_) {
00705         target_pose = transformed_plan_[i-1];
00706         current_waypoint_ = i-1;
00707         
00708 
00709         return;
00710       }
00711     }
00712     target_pose = transformed_plan_.back();
00713     current_waypoint_ = transformed_plan_.size()-1;
00714     
00715     
00716   }
00717 
00718   bool CollvoidLocalPlanner::transformGlobalPlan(const tf::TransformListener& tf, const std::vector<geometry_msgs::PoseStamped>& global_plan, 
00719                                                  const costmap_2d::Costmap2DROS& costmap, const std::string& global_frame, 
00720                                                  std::vector<geometry_msgs::PoseStamped>& transformed_plan){
00721     const geometry_msgs::PoseStamped& plan_pose = global_plan[0];
00722 
00723     transformed_plan.clear();
00724 
00725     try{
00726       if (!global_plan.size() > 0)
00727         {
00728           ROS_ERROR("Recieved plan with zero length");
00729           return false;
00730         }
00731 
00732       tf::StampedTransform transform;
00733       tf.lookupTransform(global_frame, ros::Time(), 
00734                          plan_pose.header.frame_id, plan_pose.header.stamp, 
00735                          plan_pose.header.frame_id, transform);
00736 
00737       
00738       tf::Stamped<tf::Pose> robot_pose;
00739       robot_pose.setIdentity();
00740       robot_pose.frame_id_ = costmap.getBaseFrameID();
00741       robot_pose.stamp_ = ros::Time();
00742       tf.transformPose(plan_pose.header.frame_id, robot_pose, robot_pose);
00743 
00744       
00745       
00746 
00747       
00748       double sq_dist = DBL_MAX;
00749 
00750       unsigned int cur_waypoint = 0;
00751       for (size_t i=0; i < global_plan_.size(); i++) 
00752         {
00753           double y = robot_pose.getOrigin().y();
00754           double x = robot_pose.getOrigin().x();
00755           double dist = base_local_planner::distance(x, y, global_plan_[i].pose.position.x, global_plan_[i].pose.position.y);
00756           if (dist < sqrt(sq_dist)) {
00757             sq_dist = dist * dist;
00758             cur_waypoint = i;
00759           
00760           }
00761         }
00762 
00763       unsigned int i = cur_waypoint;
00764 
00765       tf::Stamped<tf::Pose> tf_pose;
00766       geometry_msgs::PoseStamped newer_pose;
00767 
00768       
00769       while(i < (unsigned int)global_plan.size()) {
00770         double x_diff = robot_pose.getOrigin().x() - global_plan[i].pose.position.x;
00771         double y_diff = robot_pose.getOrigin().y() - global_plan[i].pose.position.y;
00772         sq_dist = x_diff * x_diff + y_diff * y_diff;
00773 
00774         const geometry_msgs::PoseStamped& pose = global_plan[i];
00775         poseStampedMsgToTF(pose, tf_pose);
00776         tf_pose.setData(transform * tf_pose);
00777         tf_pose.stamp_ = transform.stamp_;
00778         tf_pose.frame_id_ = global_frame;
00779         poseStampedTFToMsg(tf_pose, newer_pose);
00780 
00781         transformed_plan.push_back(newer_pose);
00782 
00783         ++i;
00784       }
00785     }
00786     catch(tf::LookupException& ex) {
00787       ROS_ERROR("No Transform available Error: %s\n", ex.what());
00788       return false;
00789     }
00790     catch(tf::ConnectivityException& ex) {
00791       ROS_ERROR("Connectivity Error: %s\n", ex.what());
00792       return false;
00793     }
00794     catch(tf::ExtrapolationException& ex) {
00795       ROS_ERROR("Extrapolation Error: %s\n", ex.what());
00796       if (global_plan.size() > 0)
00797         ROS_ERROR("Global Frame: %s Plan Frame size %d: %s\n", global_frame.c_str(), (unsigned int)global_plan.size(), global_plan[0].header.frame_id.c_str());
00798 
00799       return false;
00800     }
00801 
00802     return true;
00803   }
00804 
00805   void CollvoidLocalPlanner::obstaclesCallback(const nav_msgs::GridCells::ConstPtr& msg){
00806     size_t num_obst = msg->cells.size();
00807     boost::mutex::scoped_lock lock(me_->obstacle_lock_);
00808     me_->obstacle_points_.clear();
00809     
00810     for (size_t i = 0; i < num_obst; i++) {
00811       geometry_msgs::PointStamped in, result;
00812       in.header = msg->header;
00813       in.point = msg->cells[i];
00814       
00815       try {
00816         tf_->waitForTransform(global_frame_, robot_base_frame_, msg->header.stamp, ros::Duration(0.2));
00817 
00818         tf_->transformPoint(global_frame_, in, result);
00819       }
00820       catch (tf::TransformException ex){
00821         ROS_ERROR("%s",ex.what());
00822         return;
00823       };
00824 
00825       me_->obstacle_points_.push_back(collvoid::Vector2(result.point.x,result.point.y));
00826     }
00827   }
00828 
00829 
00830 
00831 }; 
00832 
00833