collvoid_local_planner.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2012, Daniel Claes, Maastricht University
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Maastricht University nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
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 //register this planner as a BaseLocalPlanner plugin
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     //initialize the planner
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       //base local planner params
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       //set my id
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       //init ros agent
00115       me_.reset(new ROSAgent());
00116 
00117       //acceleration limits
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       //holo_robot
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       //min max speeds
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       //set radius
00150       getParam(private_nh,"footprint_radius",&radius_);
00151       me_->setFootprintRadius(radius_);
00152 
00153       //set frames
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       //sim period
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       //other params agent
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); //HRVO
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       //set Footprint
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       //ROS_ERROR("%s name of node", thisname.c_str());
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     //end if init
00280   } // end init
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     //The first time we're called, we just want to make sure we have the
00287     //original configuration
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       //if someone sets restore defaults on the parameter server, prevent looping
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     //take the acceleration limits of the robot into account
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     //we also want to make sure to send a velocity that allows us to stop when we reach the goal given our acceleration limits
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     //we still want to lay down the footprint of the robot and check if the action is legal
00398     bool valid_cmd = true;//collision_planner_.checkTrajectory(0.0, 0.0, v_th_samp,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     //slow down with the maximum possible acceleration... we should really use the frequency that we're running at to determine what is feasible
00413     //but we'll use a tenth of a second to be consistent with the implementation of the local planner.
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     //we do want to check whether or not the command is valid
00421     //    double yaw = tf::getYaw(global_pose.getRotation());
00422     bool valid_cmd = true; //collision_planner_.checkTrajectory(vx, vy, vth, true);
00423 
00424     //if we have a valid command, we'll pass it on, otherwise we'll command all zeros
00425     if(valid_cmd){
00426       //ROS_DEBUG("Slowing down... using vx, vy, vth: %.2f, %.2f, %.2f", vx, vy, vth);
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   // void CollvoidLocalPlanner::odomCallback(const nav_msgs::Odometry::ConstPtr& msg){
00441   //   //we assume that the odometry is published in the frame of the base
00442   //   boost::mutex::scoped_lock(me_->me_lock_);
00443   //   me_->base_odom_.twist.twist.linear.x = msg->twist.twist.linear.x;
00444   //   me_->base_odom_.twist.twist.linear.y = msg->twist.twist.linear.y;
00445   //   me_->base_odom_.twist.twist.angular.z = msg->twist.twist.angular.z;
00446   //   ROS_DEBUG("In the odometry callback with velocity values: (%.2f, %.2f, %.2f)",
00447   //          me_->base_odom_.twist.twist.linear.x, me_->base_odom_.twist.twist.linear.y, me_->base_odom_.twist.twist.angular.z);
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     //reset the global plan
00457     global_plan_.clear();
00458     global_plan_ = orig_global_plan;
00459     current_waypoint_ = 0;
00460     xy_tolerance_latch_ = false;
00461     //transformed_plan = global_plan;
00462     //get the global plan in our frame
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     //copy over the odometry information
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     //let's get the pose of the robot in the frame of the plan
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     // Set current velocities from odometry
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     //we assume the global goal is the last point in the global plan
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     //check to see if we've reached the goal position
00526     if(base_local_planner::goalPositionReached(global_pose, goal_x, goal_y, xy_goal_tolerance_) || xy_tolerance_latch_){
00527 
00528       //if the user wants to latch goal tolerance, if we ever reach the goal location, we'll
00529       //just rotate in place
00530       if(latch_xy_goal_tolerance_)
00531         xy_tolerance_latch_ = true;
00532 
00533       //check to see if the goal orientation has been reached
00534       if(base_local_planner::goalOrientationReached(global_pose, goal_th, yaw_goal_tolerance_)){
00535         //set the velocity command to zero
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         //copy over the odometry information
00544         nav_msgs::Odometry base_odom;
00545         {
00546           boost::mutex::scoped_lock(me_->me_lock_);
00547           base_odom = me_->base_odom_;
00548         }
00549 
00550         //if we're not stopped yet... we want to stop... taking into account the acceleration limits of the robot
00551         if(!rotating_to_goal_ && !base_local_planner::stopped(base_odom, rot_stopped_velocity_, trans_stopped_velocity_)){
00552           //ROS_DEBUG("Not stopped yet. base_odom: x=%6.4f,y=%6.4f,z=%6.4f", base_odom.twist.twist.linear.x,base_odom.twist.twist.linear.y,base_odom.twist.twist.angular.z); 
00553           if(!stopWithAccLimits(global_pose, robot_vel, cmd_vel))
00554             return false;
00555         }
00556         //if we're stopped... then we want to rotate to goal
00557         else{
00558           //set this so that we know its OK to be moving
00559           rotating_to_goal_ = true;
00560           if(!rotateToGoal(global_pose, robot_vel, goal_th, cmd_vel))
00561             return false;
00562         }
00563       }
00564 
00565       //publish an empty plan because we've reached our goal position
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       //we don't actually want to run the controller when we're just rotating to goal
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     // collvoid::Vector2 goal_dir = collvoid::Vector2(goal_x,goal_y);
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     //TODO collvoid added
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; //collision_planner_.checkTrajectory(cmd_vel.linear.x, cmd_vel.linear.y, cmd_vel.angular.z,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     //  if (!skip_next_ && current_waypoint_ < transformed_plan_.size()-1)
00647     //transformed_plan_.erase(transformed_plan_.begin()+current_waypoint_,transformed_plan_.end());
00648     //ROS_DEBUG("%s cmd_vel.x %6.4f, cmd_vel.y %6.4f, cmd_vel_z %6.4f", me_->getId().c_str(), cmd_vel.linear.x, cmd_vel.linear.y, cmd_vel.angular.z); 
00649     std::vector<geometry_msgs::PoseStamped> local_plan;
00650     geometry_msgs::PoseStamped pos;
00651     //pos.header.frame_id = robot_base_frame_;
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     //me_->publishOrcaLines();
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     //ROS_DEBUG("waypoint = %d, of %d", current_waypoint_, transformed_plan_.size());
00678 
00679     //if (min_dist > pt_agg_->getRadius() && transformed_plan_.size()>2) //lets first get to the begin pose of the plan
00680     //  return;
00681     
00682     if (current_waypoint_ == transformed_plan_.size()-1) //I am at the end of the plan
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     //ROS_DEBUG("dif = %f,%f of %f",dif_x,dif_y, dif_ang );
00693     
00694     //size_t look_ahead_ind = 0;
00695     //bool look_ahead = false;
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       //target_pose = transformed_plan_[current_waypoint_];
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         //ROS_DEBUG("waypoint = %d, of %d", current_waypoint_, transformed_plan_.size());
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       //let's get the pose of the robot in the frame of the plan
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       //we'll keep points on the plan that are within the window that we're looking at
00745       //double dist_threshold = std::max(costmap.getSizeInCellsX() * costmap.getResolution() / 2.0, costmap.getSizeInCellsY() * costmap.getResolution() / 2.0);
00746 
00747       //      double sq_dist_threshold = dist_threshold * dist_threshold;
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       //now we'll transform until points are outside of our distance threshold
00769       while(i < (unsigned int)global_plan.size()) {// && sq_dist < sq_dist_threshold){
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       //ROS_DEBUG("obstacle at %f %f",msg->cells[i].x,msg->cells[i].y);
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 }; //end namespace
00832 
00833 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


collvoid_local_planner
Author(s): Daniel Claes
autogenerated on Sun Aug 25 2013 10:10:23