trajectory_planner_ros.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 * Software License Agreement (BSD License)
00004 *
00005 *  Copyright (c) 2008, Willow Garage, Inc.
00006 *  All rights reserved.
00007 *
00008 *  Redistribution and use in source and binary forms, with or without
00009 *  modification, are permitted provided that the following conditions
00010 *  are met:
00011 *
00012 *   * Redistributions of source code must retain the above copyright
00013 *     notice, this list of conditions and the following disclaimer.
00014 *   * Redistributions in binary form must reproduce the above
00015 *     copyright notice, this list of conditions and the following
00016 *     disclaimer in the documentation and/or other materials provided
00017 *     with the distribution.
00018 *   * Neither the name of the Willow Garage nor the names of its
00019 *     contributors may be used to endorse or promote products derived
00020 *     from this software without specific prior written permission.
00021 *
00022 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 *  POSSIBILITY OF SUCH DAMAGE.
00034 *
00035 * Author: Eitan Marder-Eppstein
00036 *********************************************************************/
00037 
00038 #include <base_local_planner/trajectory_planner_ros.h>
00039 #include <ros/console.h>
00040 #include <sys/time.h>
00041 #include <pluginlib/class_list_macros.h>
00042 #include <boost/tokenizer.hpp>
00043 
00044 #include "geometry_msgs/PolygonStamped.h"
00045 #include "nav_msgs/Path.h"
00046 #include "base_local_planner/goal_functions.h"
00047 
00048 using namespace std;
00049 using namespace costmap_2d;
00050 
00051 //register this planner as a BaseLocalPlanner plugin
00052 PLUGINLIB_DECLARE_CLASS(base_local_planner, TrajectoryPlannerROS, base_local_planner::TrajectoryPlannerROS, nav_core::BaseLocalPlanner)
00053 
00054 namespace base_local_planner {
00055 
00056   void TrajectoryPlannerROS::reconfigureCB(BaseLocalPlannerConfig &config, uint32_t level) {
00057       if(setup_ && config.restore_defaults) {
00058         config = default_config_;
00059         //Avoid looping
00060         config.restore_defaults = false;
00061       }
00062       if(!setup_) {
00063         default_config_ = config;
00064         setup_ = true;
00065       }
00066       else if(setup_) {
00067         tc_->reconfigure(config);
00068       }
00069   }
00070 
00071   TrajectoryPlannerROS::TrajectoryPlannerROS() : world_model_(NULL), tc_(NULL), costmap_ros_(NULL), tf_(NULL), initialized_(false), setup_(false) {}
00072 
00073   TrajectoryPlannerROS::TrajectoryPlannerROS(std::string name, tf::TransformListener* tf, Costmap2DROS* costmap_ros) 
00074     : world_model_(NULL), tc_(NULL), costmap_ros_(NULL), tf_(NULL), initialized_(false), setup_(false) {
00075 
00076       //initialize the planner
00077       initialize(name, tf, costmap_ros);
00078   }
00079 
00080   void TrajectoryPlannerROS::initialize(std::string name, tf::TransformListener* tf, Costmap2DROS* costmap_ros){
00081     if(!initialized_){
00082       tf_ = tf;
00083       costmap_ros_ = costmap_ros;
00084       rot_stopped_velocity_ = 1e-2;
00085       trans_stopped_velocity_ = 1e-2;
00086       double sim_time, sim_granularity, angular_sim_granularity;
00087       int vx_samples, vtheta_samples;
00088       double pdist_scale, gdist_scale, occdist_scale, heading_lookahead, oscillation_reset_dist, escape_reset_dist, escape_reset_theta;
00089       bool holonomic_robot, dwa, simple_attractor, heading_scoring;
00090       double heading_scoring_timestep;
00091       double max_vel_x, min_vel_x;
00092       double backup_vel;
00093       double stop_time_buffer;
00094       string world_model_type;
00095       rotating_to_goal_ = false;
00096 
00097       //initialize the copy of the costmap the controller will use
00098       costmap_ros_->getCostmapCopy(costmap_);
00099 
00100       ros::NodeHandle private_nh("~/" + name);
00101       
00102       g_plan_pub_ = private_nh.advertise<nav_msgs::Path>("global_plan", 1);
00103       l_plan_pub_ = private_nh.advertise<nav_msgs::Path>("local_plan", 1);
00104 
00105       global_frame_ = costmap_ros_->getGlobalFrameID();
00106       robot_base_frame_ = costmap_ros_->getBaseFrameID();
00107       private_nh.param("prune_plan", prune_plan_, true);
00108 
00109       private_nh.param("yaw_goal_tolerance", yaw_goal_tolerance_, 0.05);
00110       private_nh.param("xy_goal_tolerance", xy_goal_tolerance_, 0.10);
00111 
00112       //to get odometery information, we need to get a handle to the topic in the global namespace of the node
00113       ros::NodeHandle global_node;
00114       odom_sub_ = global_node.subscribe<nav_msgs::Odometry>("odom", 1, boost::bind(&TrajectoryPlannerROS::odomCallback, this, _1));
00115 
00116       //we'll get the parameters for the robot radius from the costmap we're associated with
00117       inflation_radius_ = costmap_ros_->getInflationRadius();
00118 
00119       private_nh.param("acc_lim_x", acc_lim_x_, 2.5);
00120       private_nh.param("acc_lim_y", acc_lim_y_, 2.5);
00121       private_nh.param("acc_lim_th", acc_lim_theta_, 3.2);
00122 
00123       private_nh.param("stop_time_buffer", stop_time_buffer, 0.2);
00124 
00125       private_nh.param("latch_xy_goal_tolerance", latch_xy_goal_tolerance_, false);
00126 
00127       //Since I screwed up nicely in my documentation, I'm going to add errors
00128       //informing the user if they've set one of the wrong parameters
00129       if(private_nh.hasParam("acc_limit_x"))
00130         ROS_ERROR("You are using acc_limit_x where you should be using acc_lim_x. Please change your configuration files appropriately. The documentation used to be wrong on this, sorry for any confusion.");
00131 
00132       if(private_nh.hasParam("acc_limit_y"))
00133         ROS_ERROR("You are using acc_limit_y where you should be using acc_lim_y. Please change your configuration files appropriately. The documentation used to be wrong on this, sorry for any confusion.");
00134 
00135       if(private_nh.hasParam("acc_limit_th"))
00136         ROS_ERROR("You are using acc_limit_th where you should be using acc_lim_th. Please change your configuration files appropriately. The documentation used to be wrong on this, sorry for any confusion.");
00137 
00138       //Assuming this planner is being run within the navigation stack, we can
00139       //just do an upward search for the frequency at which its being run. This
00140       //also allows the frequency to be overwritten locally.
00141       std::string controller_frequency_param_name;
00142       if(!private_nh.searchParam("controller_frequency", controller_frequency_param_name))
00143         sim_period_ = 0.05;
00144       else
00145       {
00146         double controller_frequency = 0;
00147         private_nh.param(controller_frequency_param_name, controller_frequency, 20.0);
00148         if(controller_frequency > 0)
00149           sim_period_ = 1.0 / controller_frequency;
00150         else
00151         {
00152           ROS_WARN("A controller_frequency less than 0 has been set. Ignoring the parameter, assuming a rate of 20Hz");
00153           sim_period_ = 0.05;
00154         }
00155       }
00156       ROS_INFO("Sim period is set to %.2f", sim_period_);
00157 
00158       private_nh.param("sim_time", sim_time, 1.0);
00159       private_nh.param("sim_granularity", sim_granularity, 0.025);
00160       private_nh.param("angular_sim_granularity", angular_sim_granularity, sim_granularity);
00161       private_nh.param("vx_samples", vx_samples, 3);
00162       private_nh.param("vtheta_samples", vtheta_samples, 20);
00163 
00164       private_nh.param("path_distance_bias", pdist_scale, 0.6);
00165       private_nh.param("goal_distance_bias", gdist_scale, 0.8);
00166 
00167       bool meter_scoring;
00168       private_nh.param("meter_scoring", meter_scoring, false);
00169 
00170       if(meter_scoring)
00171       {
00172         //if we use meter scoring, then we want to multiply the biases by the resolution of the costmap
00173         double resolution = costmap_ros_->getResolution();
00174         gdist_scale *= resolution;
00175         pdist_scale *= resolution;
00176       }
00177 
00178       private_nh.param("occdist_scale", occdist_scale, 0.01);
00179       private_nh.param("heading_lookahead", heading_lookahead, 0.325);
00180       private_nh.param("oscillation_reset_dist", oscillation_reset_dist, 0.05);
00181       private_nh.param("escape_reset_dist", escape_reset_dist, 0.10);
00182       private_nh.param("escape_reset_theta", escape_reset_theta, M_PI_4);
00183       private_nh.param("holonomic_robot", holonomic_robot, true);
00184       private_nh.param("max_vel_x", max_vel_x, 0.5);
00185       private_nh.param("min_vel_x", min_vel_x, 0.1);
00186 
00187       double max_rotational_vel;
00188       private_nh.param("max_rotational_vel", max_rotational_vel, 1.0);
00189       max_vel_th_ = max_rotational_vel;
00190       min_vel_th_ = -1.0 * max_rotational_vel;
00191       private_nh.param("min_in_place_rotational_vel", min_in_place_vel_th_, 0.4);
00192 
00193       backup_vel = -0.1;
00194       if(private_nh.getParam("backup_vel", backup_vel))
00195         ROS_WARN("The backup_vel parameter has been deprecated in favor of the escape_vel parameter. To switch, just change the parameter name in your configuration files.");
00196 
00197       //if both backup_vel and escape_vel are set... we'll use escape_vel
00198       private_nh.getParam("escape_vel", backup_vel);
00199 
00200       if(backup_vel >= 0.0)
00201         ROS_WARN("You've specified a positive escape velocity. This is probably not what you want and will cause the robot to move forward instead of backward. You should probably change your escape_vel parameter to be negative");
00202 
00203       private_nh.param("world_model", world_model_type, string("costmap")); 
00204       private_nh.param("dwa", dwa, true);
00205       private_nh.param("heading_scoring", heading_scoring, false);
00206       private_nh.param("heading_scoring_timestep", heading_scoring_timestep, 0.8);
00207 
00208       simple_attractor = false;
00209 
00210       //parameters for using the freespace controller
00211       double min_pt_separation, max_obstacle_height, grid_resolution;
00212       private_nh.param("point_grid/max_sensor_range", max_sensor_range_, 2.0);
00213       private_nh.param("point_grid/min_pt_separation", min_pt_separation, 0.01);
00214       private_nh.param("point_grid/max_obstacle_height", max_obstacle_height, 2.0);
00215       private_nh.param("point_grid/grid_resolution", grid_resolution, 0.2);
00216 
00217       ROS_ASSERT_MSG(world_model_type == "costmap", "At this time, only costmap world models are supported by this controller");
00218       world_model_ = new CostmapModel(costmap_);
00219       std::vector<double> y_vels = loadYVels(private_nh);
00220 
00221       tc_ = new TrajectoryPlanner(*world_model_, costmap_, costmap_ros_->getRobotFootprint(),
00222           acc_lim_x_, acc_lim_y_, acc_lim_theta_, sim_time, sim_granularity, vx_samples, vtheta_samples, pdist_scale,
00223           gdist_scale, occdist_scale, heading_lookahead, oscillation_reset_dist, escape_reset_dist, escape_reset_theta, holonomic_robot,
00224           max_vel_x, min_vel_x, max_vel_th_, min_vel_th_, min_in_place_vel_th_, backup_vel,
00225           dwa, heading_scoring, heading_scoring_timestep, simple_attractor, y_vels, stop_time_buffer, sim_period_, angular_sim_granularity);
00226 
00227       map_viz_.initialize(name, &costmap_, boost::bind(&TrajectoryPlanner::getCellCosts, tc_, _1, _2, _3, _4, _5, _6));
00228       initialized_ = true;
00229 
00230       dsrv_ = new dynamic_reconfigure::Server<BaseLocalPlannerConfig>(private_nh);
00231       dynamic_reconfigure::Server<BaseLocalPlannerConfig>::CallbackType cb = boost::bind(&TrajectoryPlannerROS::reconfigureCB, this, _1, _2);
00232       dsrv_->setCallback(cb);
00233 
00234     }
00235     else
00236       ROS_WARN("This planner has already been initialized, you can't call it twice, doing nothing");
00237   }
00238 
00239   std::vector<double> TrajectoryPlannerROS::loadYVels(ros::NodeHandle node){
00240     std::vector<double> y_vels;
00241 
00242     std::string y_vel_list;
00243     if(node.getParam("y_vels", y_vel_list)){
00244       typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00245       boost::char_separator<char> sep("[], ");
00246       tokenizer tokens(y_vel_list, sep);
00247 
00248       for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); i++){
00249         y_vels.push_back(atof((*i).c_str()));
00250       }
00251     }
00252     else{
00253       //if no values are passed in, we'll provide defaults
00254       y_vels.push_back(-0.3);
00255       y_vels.push_back(-0.1);
00256       y_vels.push_back(0.1);
00257       y_vels.push_back(0.3);
00258     }
00259 
00260     return y_vels;
00261   }
00262 
00263   TrajectoryPlannerROS::~TrajectoryPlannerROS(){
00264     //make sure to clean things up
00265     delete dsrv_;
00266 
00267     if(tc_ != NULL)
00268       delete tc_;
00269 
00270     if(world_model_ != NULL)
00271       delete world_model_;
00272   }
00273 
00274   bool TrajectoryPlannerROS::stopWithAccLimits(const tf::Stamped<tf::Pose>& global_pose, const tf::Stamped<tf::Pose>& robot_vel, geometry_msgs::Twist& cmd_vel){
00275     //slow down with the maximum possible acceleration... we should really use the frequency that we're running at to determine what is feasible
00276     //but we'll use a tenth of a second to be consistent with the implementation of the local planner.
00277     double vx = sign(robot_vel.getOrigin().x()) * std::max(0.0, (fabs(robot_vel.getOrigin().x()) - acc_lim_x_ * sim_period_));
00278     double vy = sign(robot_vel.getOrigin().y()) * std::max(0.0, (fabs(robot_vel.getOrigin().y()) - acc_lim_y_ * sim_period_));
00279 
00280     double vel_yaw = tf::getYaw(robot_vel.getRotation());
00281     double vth = sign(vel_yaw) * std::max(0.0, (fabs(vel_yaw) - acc_lim_theta_ * sim_period_));
00282 
00283     //we do want to check whether or not the command is valid
00284     double yaw = tf::getYaw(global_pose.getRotation());
00285     bool valid_cmd = tc_->checkTrajectory(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), yaw, 
00286         robot_vel.getOrigin().getX(), robot_vel.getOrigin().getY(), vel_yaw, vx, vy, vth);
00287 
00288     //if we have a valid command, we'll pass it on, otherwise we'll command all zeros
00289     if(valid_cmd){
00290       ROS_DEBUG("Slowing down... using vx, vy, vth: %.2f, %.2f, %.2f", vx, vy, vth);
00291       cmd_vel.linear.x = vx;
00292       cmd_vel.linear.y = vy;
00293       cmd_vel.angular.z = vth;
00294       return true;
00295     }
00296 
00297     cmd_vel.linear.x = 0.0;
00298     cmd_vel.linear.y = 0.0;
00299     cmd_vel.angular.z = 0.0;
00300     return false;
00301   }
00302 
00303   bool TrajectoryPlannerROS::rotateToGoal(const tf::Stamped<tf::Pose>& global_pose, const tf::Stamped<tf::Pose>& robot_vel, double goal_th, geometry_msgs::Twist& cmd_vel){
00304     double yaw = tf::getYaw(global_pose.getRotation());
00305     double vel_yaw = tf::getYaw(robot_vel.getRotation());
00306     cmd_vel.linear.x = 0;
00307     cmd_vel.linear.y = 0;
00308     double ang_diff = angles::shortest_angular_distance(yaw, goal_th);
00309 
00310     double v_theta_samp = ang_diff > 0.0 ? std::min(max_vel_th_,
00311         std::max(min_in_place_vel_th_, ang_diff)) : std::max(min_vel_th_,
00312         std::min(-1.0 * min_in_place_vel_th_, ang_diff));
00313 
00314     //take the acceleration limits of the robot into account
00315     double max_acc_vel = fabs(vel_yaw) + acc_lim_theta_ * sim_period_;
00316     double min_acc_vel = fabs(vel_yaw) - acc_lim_theta_ * sim_period_;
00317 
00318     v_theta_samp = sign(v_theta_samp) * std::min(std::max(fabs(v_theta_samp), min_acc_vel), max_acc_vel);
00319 
00320     //we also want to make sure to send a velocity that allows us to stop when we reach the goal given our acceleration limits
00321     double max_speed_to_stop = sqrt(2 * acc_lim_theta_ * fabs(ang_diff)); 
00322 
00323     v_theta_samp = sign(v_theta_samp) * std::min(max_speed_to_stop, fabs(v_theta_samp));
00324 
00325     //we still want to lay down the footprint of the robot and check if the action is legal
00326     bool valid_cmd = tc_->checkTrajectory(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), yaw, 
00327         robot_vel.getOrigin().getX(), robot_vel.getOrigin().getY(), vel_yaw, 0.0, 0.0, v_theta_samp);
00328 
00329     ROS_DEBUG("Moving to desired goal orientation, th cmd: %.2f, valid_cmd: %d", v_theta_samp, valid_cmd);
00330 
00331     if(valid_cmd){
00332       cmd_vel.angular.z = v_theta_samp;
00333       return true;
00334     }
00335 
00336     cmd_vel.angular.z = 0.0;
00337     return false;
00338 
00339   }
00340 
00341   void TrajectoryPlannerROS::odomCallback(const nav_msgs::Odometry::ConstPtr& msg){
00342     //we assume that the odometry is published in the frame of the base
00343     boost::recursive_mutex::scoped_lock lock(odom_lock_);
00344     base_odom_.twist.twist.linear.x = msg->twist.twist.linear.x;
00345     base_odom_.twist.twist.linear.y = msg->twist.twist.linear.y;
00346     base_odom_.twist.twist.angular.z = msg->twist.twist.angular.z;
00347     ROS_DEBUG("In the odometry callback with velocity values: (%.2f, %.2f, %.2f)",
00348         base_odom_.twist.twist.linear.x, base_odom_.twist.twist.linear.y, base_odom_.twist.twist.angular.z);
00349   }
00350 
00351   bool TrajectoryPlannerROS::setPlan(const std::vector<geometry_msgs::PoseStamped>& orig_global_plan){
00352     if(!initialized_){
00353       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00354       return false;
00355     }
00356 
00357     //reset the global plan
00358     global_plan_.clear();
00359     global_plan_ = orig_global_plan;
00360 
00361     //when we get a new plan, we also want to clear any latch we may have on goal tolerances
00362     xy_tolerance_latch_ = false;
00363 
00364     return true;
00365   }
00366 
00367   bool TrajectoryPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel){
00368     if(!initialized_){
00369       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00370       return false;
00371     }
00372 
00373     std::vector<geometry_msgs::PoseStamped> local_plan;
00374     tf::Stamped<tf::Pose> global_pose;
00375     if(!costmap_ros_->getRobotPose(global_pose))
00376       return false;
00377 
00378     std::vector<geometry_msgs::PoseStamped> transformed_plan;
00379     //get the global plan in our frame
00380     if(!transformGlobalPlan(*tf_, global_plan_, *costmap_ros_, global_frame_, transformed_plan)){
00381       ROS_WARN("Could not transform the global plan to the frame of the controller");
00382       return false;
00383     }
00384 
00385     //now we'll prune the plan based on the position of the robot
00386     if(prune_plan_)
00387       prunePlan(global_pose, transformed_plan, global_plan_);
00388 
00389 
00390     //we also want to clear the robot footprint from the costmap we're using
00391     costmap_ros_->clearRobotFootprint();
00392 
00393     //make sure to update the costmap we'll use for this cycle
00394     costmap_ros_->getCostmapCopy(costmap_);
00395 
00396     // Set current velocities from odometry
00397     geometry_msgs::Twist global_vel;
00398 
00399     odom_lock_.lock();
00400     global_vel.linear.x = base_odom_.twist.twist.linear.x;
00401     global_vel.linear.y = base_odom_.twist.twist.linear.y;
00402     global_vel.angular.z = base_odom_.twist.twist.angular.z;
00403     odom_lock_.unlock();
00404 
00405     tf::Stamped<tf::Pose> drive_cmds;
00406     drive_cmds.frame_id_ = robot_base_frame_;
00407 
00408     tf::Stamped<tf::Pose> robot_vel;
00409     robot_vel.setData(tf::Transform(tf::createQuaternionFromYaw(global_vel.angular.z), tf::Vector3(global_vel.linear.x, global_vel.linear.y, 0)));
00410     robot_vel.frame_id_ = robot_base_frame_;
00411     robot_vel.stamp_ = ros::Time();
00412 
00413     /* For timing uncomment
00414     struct timeval start, end;
00415     double start_t, end_t, t_diff;
00416     gettimeofday(&start, NULL);
00417     */
00418 
00419     //if the global plan passed in is empty... we won't do anything
00420     if(transformed_plan.empty())
00421       return false;
00422 
00423     tf::Stamped<tf::Pose> goal_point;
00424     tf::poseStampedMsgToTF(transformed_plan.back(), goal_point);
00425     //we assume the global goal is the last point in the global plan
00426     double goal_x = goal_point.getOrigin().getX();
00427     double goal_y = goal_point.getOrigin().getY();
00428 
00429     double yaw = tf::getYaw(goal_point.getRotation());
00430 
00431     double goal_th = yaw;
00432 
00433     //check to see if we've reached the goal position
00434     if(goalPositionReached(global_pose, goal_x, goal_y, xy_goal_tolerance_) || xy_tolerance_latch_){
00435 
00436       //if the user wants to latch goal tolerance, if we ever reach the goal location, we'll
00437       //just rotate in place
00438       if(latch_xy_goal_tolerance_)
00439         xy_tolerance_latch_ = true;
00440 
00441       //check to see if the goal orientation has been reached
00442       if(goalOrientationReached(global_pose, goal_th, yaw_goal_tolerance_)){
00443         //set the velocity command to zero
00444         cmd_vel.linear.x = 0.0;
00445         cmd_vel.linear.y = 0.0;
00446         cmd_vel.angular.z = 0.0;
00447         rotating_to_goal_ = false;
00448         xy_tolerance_latch_ = false;
00449       }
00450       else {
00451         //we need to call the next two lines to make sure that the trajectory
00452         //planner updates its path distance and goal distance grids
00453         tc_->updatePlan(transformed_plan);
00454         Trajectory path = tc_->findBestPath(global_pose, robot_vel, drive_cmds);
00455         map_viz_.publishCostCloud();
00456 
00457         //copy over the odometry information
00458         nav_msgs::Odometry base_odom;
00459         {
00460           boost::recursive_mutex::scoped_lock lock(odom_lock_);
00461           base_odom = base_odom_;
00462         }
00463 
00464         //if we're not stopped yet... we want to stop... taking into account the acceleration limits of the robot
00465         if(!rotating_to_goal_ && !base_local_planner::stopped(base_odom, rot_stopped_velocity_, trans_stopped_velocity_)){
00466           if(!stopWithAccLimits(global_pose, robot_vel, cmd_vel))
00467             return false;
00468         }
00469         //if we're stopped... then we want to rotate to goal
00470         else{
00471           //set this so that we know its OK to be moving
00472           rotating_to_goal_ = true;
00473           if(!rotateToGoal(global_pose, robot_vel, goal_th, cmd_vel))
00474             return false;
00475         }
00476       }
00477 
00478       //publish an empty plan because we've reached our goal position
00479       publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00480       publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00481 
00482       //we don't actually want to run the controller when we're just rotating to goal
00483       return true;
00484     }
00485 
00486     tc_->updatePlan(transformed_plan);
00487 
00488     //compute what trajectory to drive along
00489     Trajectory path = tc_->findBestPath(global_pose, robot_vel, drive_cmds);
00490 
00491     map_viz_.publishCostCloud();
00492     /* For timing uncomment
00493     gettimeofday(&end, NULL);
00494     start_t = start.tv_sec + double(start.tv_usec) / 1e6;
00495     end_t = end.tv_sec + double(end.tv_usec) / 1e6;
00496     t_diff = end_t - start_t;
00497     ROS_INFO("Cycle time: %.9f", t_diff);
00498     */
00499 
00500     //pass along drive commands
00501     cmd_vel.linear.x = drive_cmds.getOrigin().getX();
00502     cmd_vel.linear.y = drive_cmds.getOrigin().getY();
00503     yaw = tf::getYaw(drive_cmds.getRotation());
00504 
00505     cmd_vel.angular.z = yaw;
00506 
00507     //if we cannot move... tell someone
00508     if(path.cost_ < 0){
00509       local_plan.clear();
00510       publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00511       publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00512       return false;
00513     }
00514 
00515     // Fill out the local plan
00516     for(unsigned int i = 0; i < path.getPointsSize(); ++i){
00517       double p_x, p_y, p_th;
00518       path.getPoint(i, p_x, p_y, p_th);
00519 
00520       tf::Stamped<tf::Pose> p = tf::Stamped<tf::Pose>(tf::Pose(tf::createQuaternionFromYaw(p_th), tf::Point(p_x, p_y, 0.0)), ros::Time::now(), global_frame_);
00521       geometry_msgs::PoseStamped pose;
00522       tf::poseStampedTFToMsg(p, pose);
00523       local_plan.push_back(pose);
00524     }
00525 
00526     //publish information to the visualizer
00527     publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00528     publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00529     return true;
00530   }
00531 
00532   bool TrajectoryPlannerROS::checkTrajectory(double vx_samp, double vy_samp, double vtheta_samp, bool update_map){
00533     tf::Stamped<tf::Pose> global_pose;
00534     if(costmap_ros_->getRobotPose(global_pose)){
00535       if(update_map){
00536         //we also want to clear the robot footprint from the costmap we're using
00537         costmap_ros_->clearRobotFootprint();
00538 
00539         //make sure to update the costmap we'll use for this cycle
00540         costmap_ros_->getCostmapCopy(costmap_);
00541 
00542         //we need to give the planne some sort of global plan, since we're only checking for legality
00543         //we'll just give the robots current position
00544         std::vector<geometry_msgs::PoseStamped> plan;
00545         geometry_msgs::PoseStamped pose_msg;
00546         tf::poseStampedTFToMsg(global_pose, pose_msg);
00547         plan.push_back(pose_msg);
00548         tc_->updatePlan(plan, true);
00549       }
00550 
00551       //copy over the odometry information
00552       nav_msgs::Odometry base_odom;
00553       {
00554         boost::recursive_mutex::scoped_lock lock(odom_lock_);
00555         base_odom = base_odom_;
00556       }
00557 
00558       return tc_->checkTrajectory(global_pose.getOrigin().x(), global_pose.getOrigin().y(), tf::getYaw(global_pose.getRotation()),
00559           base_odom.twist.twist.linear.x,
00560           base_odom.twist.twist.linear.y,
00561           base_odom.twist.twist.angular.z, vx_samp, vy_samp, vtheta_samp);
00562 
00563     }
00564     ROS_WARN("Failed to get the pose of the robot. No trajectories will pass as legal in this case.");
00565     return false;
00566   }
00567 
00568 
00569   double TrajectoryPlannerROS::scoreTrajectory(double vx_samp, double vy_samp, double vtheta_samp, bool update_map){
00570     // Copy of checkTrajectory that returns a score instead of True / False
00571     tf::Stamped<tf::Pose> global_pose;
00572     if(costmap_ros_->getRobotPose(global_pose)){
00573       if(update_map){
00574         //we also want to clear the robot footprint from the costmap we're using
00575         costmap_ros_->clearRobotFootprint();
00576 
00577         //make sure to update the costmap we'll use for this cycle
00578         costmap_ros_->getCostmapCopy(costmap_);
00579 
00580         //we need to give the planne some sort of global plan, since we're only checking for legality
00581         //we'll just give the robots current position
00582         std::vector<geometry_msgs::PoseStamped> plan;
00583         geometry_msgs::PoseStamped pose_msg;
00584         tf::poseStampedTFToMsg(global_pose, pose_msg);
00585         plan.push_back(pose_msg);
00586         tc_->updatePlan(plan, true);
00587       }
00588 
00589       //copy over the odometry information
00590       nav_msgs::Odometry base_odom;
00591       {
00592         boost::recursive_mutex::scoped_lock lock(odom_lock_);
00593         base_odom = base_odom_;
00594       }
00595 
00596       return tc_->scoreTrajectory(global_pose.getOrigin().x(), global_pose.getOrigin().y(), tf::getYaw(global_pose.getRotation()),
00597           base_odom.twist.twist.linear.x,
00598           base_odom.twist.twist.linear.y,
00599           base_odom.twist.twist.angular.z, vx_samp, vy_samp, vtheta_samp);
00600 
00601     }
00602     ROS_WARN("Failed to get the pose of the robot. No trajectories will pass as legal in this case.");
00603     return -1.0;
00604   }
00605 
00606   bool TrajectoryPlannerROS::isGoalReached(){
00607     if(!initialized_){
00608       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00609       return false;
00610     }
00611 
00612     //copy over the odometry information
00613     nav_msgs::Odometry base_odom;
00614     {
00615       boost::recursive_mutex::scoped_lock lock(odom_lock_);
00616       base_odom = base_odom_;
00617     }
00618 
00619     return base_local_planner::isGoalReached(*tf_, global_plan_, *costmap_ros_, global_frame_, base_odom, 
00620         rot_stopped_velocity_, trans_stopped_velocity_, xy_goal_tolerance_, yaw_goal_tolerance_);
00621   }
00622 };


base_local_planner
Author(s): Eitan Marder-Eppstein, Eric Perko
autogenerated on Sat Dec 28 2013 17:13:50