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 
00032 
00033 
00034 
00035 
00036 
00037 
00038 #include <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 "goal_functions.h"
00047 
00048 using namespace std;
00049 using namespace costmap_2d;
00050 
00051 
00052 PLUGINLIB_DECLARE_CLASS(iri_ackermann_local_planner, TrajectoryPlannerROS, iri_ackermann_local_planner::TrajectoryPlannerROS, nav_core::BaseLocalPlanner)
00053 
00054 namespace iri_ackermann_local_planner {
00055 
00056   void TrajectoryPlannerROS::reconfigureCB(AckermannLocalPlannerConfig &config, uint32_t level) {
00057       if(setup_ && config.restore_defaults) {
00058         config = default_config_;
00059         
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   }
00074 
00075   TrajectoryPlannerROS::TrajectoryPlannerROS(std::string name, tf::TransformListener* tf, Costmap2DROS* costmap_ros) 
00076     : world_model_(NULL), tc_(NULL), costmap_ros_(NULL), tf_(NULL), initialized_(false), setup_(false) {
00077       
00078       initialize(name, tf, costmap_ros);
00079   }
00080 
00081   void TrajectoryPlannerROS::initialize(std::string name, tf::TransformListener* tf, Costmap2DROS* costmap_ros){
00082     if(!initialized_)
00083     {
00084       tf_ = tf;
00085       costmap_ros_ = costmap_ros;
00086       rot_stopped_velocity_ = 1e-2;
00087       trans_stopped_velocity_ = 1e-2;
00088       double sim_time, sim_granularity, angular_sim_granularity;
00089       int vx_samples, vtheta_samples;
00090       double pdist_scale, gdist_scale, occdist_scale, hdiff_scale;
00091       double ack_acc_max,ack_vel_max,ack_vel_min;
00092       double ack_steer_acc_max,ack_steer_vel_max,ack_steer_vel_min,ack_steer_angle_max,ack_steer_angle_min;
00093       double axis_distance;
00094       bool simple_attractor;
00095       int heading_points;
00096       string world_model_type;
00097       rotating_to_goal_ = false;
00098 
00099       
00100       costmap_ros_->getCostmapCopy(costmap_);
00101 
00102       ros::NodeHandle private_nh("~/" + name);
00103       
00104       g_plan_pub_ = private_nh.advertise<nav_msgs::Path>("global_plan", 1);
00105       l_plan_pub_ = private_nh.advertise<nav_msgs::Path>("local_plan", 1);
00106 
00107       global_frame_ = costmap_ros_->getGlobalFrameID();
00108       robot_base_frame_ = costmap_ros_->getBaseFrameID();
00109       private_nh.param("prune_plan", prune_plan_, true);
00110 
00111       private_nh.param("yaw_goal_tolerance", yaw_goal_tolerance_, 0.05);
00112       private_nh.param("xy_goal_tolerance", xy_goal_tolerance_, 0.10);
00113 
00114       
00115       inflation_radius_ = costmap_ros_->getInflationRadius();
00116 
00117       private_nh.param("ack_acc_max", ack_acc_max, 1.0);
00118       private_nh.param("ack_vel_max", ack_vel_max, 0.6);
00119       private_nh.param("ack_vel_min", ack_vel_min, -0.6);
00120       private_nh.param("ack_steer_acc_max", ack_steer_acc_max, 1.0);
00121       private_nh.param("ack_steer_speed_max", ack_steer_vel_max, 0.5);
00122       private_nh.param("ack_steer_speed_min", ack_steer_vel_min, -0.5);
00123       private_nh.param("ack_steer_angle_max", ack_steer_angle_max, 0.35);
00124       private_nh.param("ack_steer_angle_min", ack_steer_angle_min, -0.35);
00125       private_nh.param("ack_axis_distance", axis_distance, 1.65);
00126 
00127       private_nh.param("latch_xy_goal_tolerance", latch_xy_goal_tolerance_, false);
00128 
00129       
00130       
00131       
00132       std::string controller_frequency_param_name;
00133 
00134       private_nh.param("sim_time", sim_time, 10.0);
00135       private_nh.param("sim_granularity", sim_granularity, 0.025);
00136       private_nh.param("angular_sim_granularity", angular_sim_granularity, sim_granularity);
00137       private_nh.param("vx_samples", vx_samples, 10);
00138       private_nh.param("vtheta_samples", vtheta_samples, 20);
00139 
00140       private_nh.param("pdist_scale", pdist_scale, 0.6);
00141       private_nh.param("gdist_scale", gdist_scale, 0.8);
00142       private_nh.param("hdiff_scale", hdiff_scale, 1.0);
00143       private_nh.param("occdist_scale", occdist_scale, 0.01);
00144       private_nh.param("heading_points", heading_points, 8);
00145 
00146       private_nh.param("world_model", world_model_type, string("costmap")); 
00147 
00148       simple_attractor = false;
00149 
00150       
00151       double min_pt_separation, max_obstacle_height, grid_resolution;
00152       private_nh.param("point_grid/max_sensor_range", max_sensor_range_, 2.0);
00153       private_nh.param("point_grid/min_pt_separation", min_pt_separation, 0.01);
00154       private_nh.param("point_grid/max_obstacle_height", max_obstacle_height, 2.0);
00155       private_nh.param("point_grid/grid_resolution", grid_resolution, 0.2);
00156 
00157       ROS_ASSERT_MSG(world_model_type == "costmap", "At this time, only costmap world models are supported by this controller");
00158       world_model_ = new CostmapModel(costmap_);
00159 
00160       tc_ = new TrajectoryPlanner(*world_model_, costmap_, costmap_ros_->getRobotFootprint(),
00161           ack_acc_max, ack_vel_max, ack_vel_min, ack_steer_acc_max,ack_steer_vel_max,ack_steer_vel_min,ack_steer_angle_max,ack_steer_angle_min,axis_distance,
00162           sim_time, sim_granularity, vx_samples, vtheta_samples, pdist_scale,gdist_scale, occdist_scale, hdiff_scale,simple_attractor,angular_sim_granularity,
00163           heading_points,xy_goal_tolerance_);
00164 
00165       map_viz_.initialize(name, &costmap_, boost::bind(&TrajectoryPlanner::getCellCosts, tc_, _1, _2, _3, _4, _5, _6));
00166       initialized_ = true;
00167 
00168       dsrv_ = new dynamic_reconfigure::Server<AckermannLocalPlannerConfig>(private_nh);
00169       dynamic_reconfigure::Server<AckermannLocalPlannerConfig>::CallbackType cb = boost::bind(&TrajectoryPlannerROS::reconfigureCB, this, _1, _2);
00170       dsrv_->setCallback(cb);
00171 
00172       ros::NodeHandle global_node;
00173       odom_sub_ = global_node.subscribe<nav_msgs::Odometry>("odom", 1, boost::bind(&TrajectoryPlannerROS::odomCallback, this, _1));
00174     }
00175     else
00176       ROS_WARN("This planner has already been initialized, you can't call it twice, doing nothing");
00177   }
00178 
00179   TrajectoryPlannerROS::~TrajectoryPlannerROS(){
00180     
00181     delete dsrv_;
00182 
00183     if(tc_ != NULL)
00184       delete tc_;
00185 
00186     if(world_model_ != NULL)
00187       delete world_model_;
00188   }
00189 
00190   void TrajectoryPlannerROS::odomCallback(const nav_msgs::Odometry::ConstPtr& msg){
00191     
00192     boost::recursive_mutex::scoped_lock lock(odom_lock_);
00193     base_odom_.twist.twist.linear.x = msg->twist.twist.linear.x;
00194     base_odom_.twist.twist.linear.y = msg->twist.twist.linear.y;
00195     base_odom_.twist.twist.angular.z = msg->twist.twist.angular.z;
00196     ackermann_state_.linear.z=msg->twist.twist.linear.z;
00197     ackermann_state_.angular.x=msg->twist.twist.angular.x;
00198     ackermann_state_.angular.y=msg->twist.twist.angular.y;
00199     ROS_DEBUG("In the odometry callback with velocity values: (%.2f, %.2f, %.2f)",
00200         base_odom_.twist.twist.linear.x, base_odom_.twist.twist.linear.y, base_odom_.twist.twist.angular.z);
00201   }
00202 
00203   bool TrajectoryPlannerROS::setPlan(const std::vector<geometry_msgs::PoseStamped>& orig_global_plan)
00204   {
00205     if(!initialized_)
00206     {
00207       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00208       return false;
00209     }
00210 
00212     subPathList.clear();
00213     subPath.clear();
00214     subPathIndex      = 0;
00215     double pathLength = 0;
00216     for(unsigned int i = 0; i < orig_global_plan.size(); ++i)
00217     {
00218       if(i>1 && i<orig_global_plan.size())
00219       {
00220         double x0 = orig_global_plan[i  ].pose.position.x;
00221         double x1 = orig_global_plan[i-1].pose.position.x;
00222         double x2 = orig_global_plan[i-2].pose.position.x;
00223         double y0 = orig_global_plan[i  ].pose.position.y;
00224         double y1 = orig_global_plan[i-1].pose.position.y;
00225         double y2 = orig_global_plan[i-2].pose.position.y;
00226         double angle=std::acos(((x0-x1)*(x1-x2)+(y0-y1)*(y1-y2))/(std::sqrt(std::pow(x0-x1,2)+std::pow(y0-y1,2))*std::sqrt(std::pow(x1-x2,2)+std::pow(y1-y2,2))));
00227         pathLength+= std::sqrt(std::pow(x0-x1,2)+std::pow(y0-y1,2));
00228         if(fabs(angle)>1.57) 
00229         {
00230           if(pathLength>1.0)
00231           {
00232             ROS_INFO("TrajectoryPlannerROS::setPlan: subPath split at i=%d, angle=%f, length=%f", i, angle, pathLength);
00233             subPathList.push_back(subPath);
00234           }
00235           else 
00236           {
00237             ROS_INFO("TrajectoryPlannerROS::setPlan: subPath split at i=%d, angle=%f, Ignored by length=%f", i, angle, pathLength);
00238           }
00239           subPath.clear();
00240           pathLength=0.0;
00241         }
00242       }
00243       subPath.push_back(orig_global_plan[i]);
00244     }
00245     subPathList.push_back(subPath);
00246     ROS_INFO("TrajectoryPlannerROS::setPlan: subPath last length=%f", pathLength);
00247     ROS_INFO("TrajectoryPlannerROS::setPlan: Global plan (%lu points) split in %lu paths", orig_global_plan.size(), subPathList.size());
00248     global_plan_.clear();
00249     global_plan_ = subPathList[subPathIndex];
00251 
00252     
00255 
00256     
00257     xy_tolerance_latch_ = false;
00258 
00259     return true;
00260   }
00261 
00262   bool TrajectoryPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel){
00263     if(!initialized_){
00264       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00265       return false;
00266     }
00267     ROS_INFO("TrajectoryPlannerROS::computeVelocityCommands!");
00268 
00269     std::vector<geometry_msgs::PoseStamped> local_plan;
00270     tf::Stamped<tf::Pose> global_pose;
00271     if(!costmap_ros_->getRobotPose(global_pose))
00272       return false;
00273 
00274     std::vector<geometry_msgs::PoseStamped> transformed_plan;
00275     
00276     if(!transformGlobalPlan(*tf_, global_plan_, *costmap_ros_, global_frame_, transformed_plan)){
00277       ROS_WARN("Could not transform the global plan to the frame of the controller");
00278       return false;
00279     }
00280 
00281     
00282     if(prune_plan_)
00283       prunePlan(global_pose, transformed_plan, global_plan_);
00284 
00285 
00286     
00287     costmap_ros_->clearRobotFootprint();
00288 
00289     
00290     costmap_ros_->getCostmapCopy(costmap_);
00291 
00292     
00293     geometry_msgs::Twist global_vel;
00294 
00295     odom_lock_.lock();
00296     global_vel.linear.x = base_odom_.twist.twist.linear.x;
00297     global_vel.linear.y = base_odom_.twist.twist.linear.y;
00298     global_vel.angular.z = base_odom_.twist.twist.angular.z;
00299     odom_lock_.unlock();
00300 
00301     tf::Stamped<tf::Pose> drive_cmds;
00302     drive_cmds.frame_id_ = robot_base_frame_;
00303 
00304     tf::Stamped<tf::Pose> robot_vel;
00305     robot_vel.setData(tf::Transform(tf::createQuaternionFromYaw(global_vel.angular.z), tf::Vector3(global_vel.linear.x, global_vel.linear.y, 0)));
00306     robot_vel.frame_id_ = robot_base_frame_;
00307     robot_vel.stamp_ = ros::Time();
00308 
00309     
00310     if(transformed_plan.empty())
00311       return false;
00312 
00313     tf::Stamped<tf::Pose> goal_point;
00314     tf::poseStampedMsgToTF(transformed_plan.back(), goal_point);
00315     
00316     double goal_x = goal_point.getOrigin().getX();
00317     double goal_y = goal_point.getOrigin().getY();
00318 
00319     double yaw = tf::getYaw(goal_point.getRotation());
00320 
00321     double goal_th = yaw;
00322 
00323     
00324     if(goalPositionReached(global_pose, goal_x, goal_y, xy_goal_tolerance_) || xy_tolerance_latch_){
00325 
00327       if(subPathIndex < subPathList.size()-1)
00328       {
00329         subPathIndex++;
00330         global_plan_.clear();
00331         global_plan_ = subPathList[subPathIndex];
00332         return true;
00333       }
00335 
00336       
00337       
00338       if(latch_xy_goal_tolerance_)
00339         xy_tolerance_latch_ = true;
00340 
00341       
00342       if(goalOrientationReached(global_pose, goal_th, yaw_goal_tolerance_)){
00343         
00344         cmd_vel.linear.x = 0.0;
00345         cmd_vel.linear.y = 0.0;
00346         cmd_vel.angular.z = 0.0;
00347         rotating_to_goal_ = false;
00348         xy_tolerance_latch_ = false;
00349       }
00350 
00351       
00352       publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00353       publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00354 
00355       
00356       return true;
00357     }
00358 
00359     tc_->updatePlan(transformed_plan);
00360 
00361     
00362     Trajectory path = tc_->findBestPath(global_pose, robot_vel, drive_cmds,ackermann_state_);
00363 
00364     ROS_INFO("Speed command x,y,yaw: %f,%f,%f",drive_cmds.getOrigin().getX(),drive_cmds.getOrigin().getY(),tf::getYaw(drive_cmds.getRotation()));
00365 
00366     map_viz_.publishCostCloud();
00367 
00368     
00369     cmd_vel.linear.x = drive_cmds.getOrigin().getX();
00370     cmd_vel.linear.y = drive_cmds.getOrigin().getY();
00371     yaw = tf::getYaw(drive_cmds.getRotation());
00372 
00373     cmd_vel.angular.z = yaw;
00374 
00375     
00376     if(path.cost_ < 0){
00377       local_plan.clear();
00378       publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00379       publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00380       return false;
00381     }
00382 
00383     
00384     for(unsigned int i = 0; i < path.getPointsSize(); ++i){
00385       double p_x, p_y, p_th;
00386       path.getPoint(i, p_x, p_y, p_th);
00387 
00388       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_);
00389       geometry_msgs::PoseStamped pose;
00390       tf::poseStampedTFToMsg(p, pose);
00391       local_plan.push_back(pose);
00392     }
00393 
00394     
00395     publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00396     publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00397     return true;
00398   }
00399 
00400   bool TrajectoryPlannerROS::checkTrajectory(double vx_samp, double vy_samp, double vtheta_samp, bool update_map){
00401     tf::Stamped<tf::Pose> global_pose;
00402     if(costmap_ros_->getRobotPose(global_pose)){
00403       if(update_map){
00404         
00405         costmap_ros_->clearRobotFootprint();
00406 
00407         
00408         costmap_ros_->getCostmapCopy(costmap_);
00409 
00410         
00411         
00412         std::vector<geometry_msgs::PoseStamped> plan;
00413         geometry_msgs::PoseStamped pose_msg;
00414         tf::poseStampedTFToMsg(global_pose, pose_msg);
00415         plan.push_back(pose_msg);
00416         tc_->updatePlan(plan, true);
00417       }
00418 
00419       
00420       nav_msgs::Odometry base_odom;
00421       {
00422         boost::recursive_mutex::scoped_lock lock(odom_lock_);
00423         base_odom = base_odom_;
00424       }
00425 
00426       return tc_->checkTrajectory(global_pose.getOrigin().x(), global_pose.getOrigin().y(), tf::getYaw(global_pose.getRotation()),
00427           base_odom.twist.twist.linear.x,
00428           base_odom.twist.twist.linear.y,
00429           base_odom.twist.twist.angular.z, vx_samp, vy_samp, vtheta_samp);
00430 
00431     }
00432     ROS_WARN("Failed to get the pose of the robot. No trajectories will pass as legal in this case.");
00433     return false;
00434   }
00435 
00436 
00437   double TrajectoryPlannerROS::scoreTrajectory(double vx_samp, double vy_samp, double vtheta_samp, bool update_map){
00438     
00439     tf::Stamped<tf::Pose> global_pose;
00440     if(costmap_ros_->getRobotPose(global_pose)){
00441       if(update_map){
00442         
00443         costmap_ros_->clearRobotFootprint();
00444 
00445         
00446         costmap_ros_->getCostmapCopy(costmap_);
00447 
00448         
00449         
00450         std::vector<geometry_msgs::PoseStamped> plan;
00451         geometry_msgs::PoseStamped pose_msg;
00452         tf::poseStampedTFToMsg(global_pose, pose_msg);
00453         plan.push_back(pose_msg);
00454         tc_->updatePlan(plan, true);
00455       }
00456 
00457       
00458       nav_msgs::Odometry base_odom;
00459       {
00460         boost::recursive_mutex::scoped_lock lock(odom_lock_);
00461         base_odom = base_odom_;
00462       }
00463 
00464       return tc_->scoreTrajectory(global_pose.getOrigin().x(), global_pose.getOrigin().y(), tf::getYaw(global_pose.getRotation()),
00465           base_odom.twist.twist.linear.x,
00466           base_odom.twist.twist.linear.y,
00467           base_odom.twist.twist.angular.z, vx_samp, vy_samp, vtheta_samp);
00468 
00469     }
00470     ROS_WARN("Failed to get the pose of the robot. No trajectories will pass as legal in this case.");
00471     return -1.0;
00472   }
00473 
00474   bool TrajectoryPlannerROS::isGoalReached(){
00475     if(!initialized_){
00476       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00477       return false;
00478     }
00479 
00480     
00481     nav_msgs::Odometry base_odom;
00482     {
00483       boost::recursive_mutex::scoped_lock lock(odom_lock_);
00484       base_odom = base_odom_;
00485     }
00486 
00487     return iri_ackermann_local_planner::isGoalReached(*tf_, global_plan_, *costmap_ros_, global_frame_, base_odom, 
00488         rot_stopped_velocity_, trans_stopped_velocity_, xy_goal_tolerance_, yaw_goal_tolerance_);
00489   }
00490 };