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 #include <dlux_global_planner/dlux_global_planner.h>
00036 #include <nav_grid/coordinate_conversion.h>
00037 #include <nav_core2/exceptions.h>
00038 #include <nav_2d_utils/tf_help.h>
00039 #include <nav_2d_utils/path_ops.h>
00040 #include <pluginlib/class_list_macros.h>
00041 #include <string>
00042 
00043 namespace dlux_global_planner
00044 {
00045 DluxGlobalPlanner::DluxGlobalPlanner() :
00046   calc_loader_("dlux_global_planner", "dlux_global_planner::PotentialCalculator"),
00047   traceback_loader_("dlux_global_planner", "dlux_global_planner::Traceback"),
00048   potential_grid_(HIGH_POTENTIAL), cached_goal_x_(-1), cached_goal_y_(-1), potential_pub_(potential_grid_)
00049 {
00050 }
00051 
00052 void DluxGlobalPlanner::initialize(const ros::NodeHandle& parent, const std::string& name,
00053                                    TFListenerPtr tf, nav_core2::Costmap::Ptr costmap)
00054 {
00055   ros::NodeHandle planner_nh(parent, name);
00056   costmap_ = costmap;
00057   potential_grid_.setInfo(costmap_->getInfo());
00058 
00059   cost_interpreter_ = std::make_shared<CostInterpreter>();
00060   cost_interpreter_->initialize(planner_nh, costmap_);
00061 
00062   std::string plugin_name;
00063   planner_nh.param("potential_calculator", plugin_name, std::string("dlux_plugins::AStar"));
00064   ROS_INFO_NAMED("DluxGlobalPlanner", "Using PotentialCalculator \"%s\"", plugin_name.c_str());
00065   calculator_ = calc_loader_.createInstance(plugin_name);
00066   calculator_->initialize(planner_nh, costmap, cost_interpreter_);
00067 
00068   planner_nh.param("traceback", plugin_name, std::string("dlux_plugins::GradientPath"));
00069   ROS_INFO_NAMED("DluxGlobalPlanner", "Using Traceback \"%s\"", plugin_name.c_str());
00070   traceback_ = traceback_loader_.createInstance(plugin_name);
00071   traceback_->initialize(planner_nh, cost_interpreter_);
00072 
00073   planner_nh.param("path_caching", path_caching_, false);
00074   planner_nh.param("improvement_threshold", improvement_threshold_, -1.0);
00075   cached_path_cost_ = -1.0;
00076 
00077   bool publish_potential;
00078   planner_nh.param("publish_potential", publish_potential, false);
00079   if (publish_potential)
00080     potential_pub_.init(planner_nh, "potential_grid", "potential");
00081 
00082   planner_nh.param("print_statistics", print_statistics_, false);
00083 }
00084 
00085 bool DluxGlobalPlanner::isPlanValid(const nav_2d_msgs::Path2D& path) const
00086 {
00087   
00088   unsigned int x, y;
00089   nav_core2::Costmap& costmap = *costmap_;
00090   const nav_grid::NavGridInfo& info = costmap.getInfo();
00091   for (geometry_msgs::Pose2D pose : path.poses)
00092   {
00093     if (!worldToGridBounded(info, pose.x, pose.y, x, y) || costmap(x, y) >= costmap.INSCRIBED_INFLATED_OBSTACLE)
00094     {
00095       return false;
00096     }
00097   }
00098   return true;
00099 }
00100 
00101 nav_2d_msgs::Path2D DluxGlobalPlanner::makePlan(const nav_2d_msgs::Pose2DStamped& start,
00102                                                 const nav_2d_msgs::Pose2DStamped& goal)
00103 {
00104   if (potential_grid_.getInfo() != costmap_->getInfo())
00105     potential_grid_.setInfo(costmap_->getInfo());
00106 
00107   geometry_msgs::Pose2D local_start = nav_2d_utils::transformStampedPose(tf_, start, potential_grid_.getFrameId());
00108   geometry_msgs::Pose2D local_goal = nav_2d_utils::transformStampedPose(tf_, goal, potential_grid_.getFrameId());
00109 
00110   nav_core2::Costmap& costmap = *costmap_;
00111   const nav_grid::NavGridInfo& info = costmap.getInfo();
00112 
00113   
00114   unsigned int x, y;
00115   if (!worldToGridBounded(info, local_start.x, local_start.y, x, y))
00116   {
00117     cached_path_cost_ = -1.0;
00118     throw nav_core2::StartBoundsException(start);
00119   }
00120   if (costmap(x, y) >= costmap.INSCRIBED_INFLATED_OBSTACLE)
00121   {
00122     cached_path_cost_ = -1.0;
00123     throw nav_core2::OccupiedStartException(start);
00124   }
00125   if (!worldToGridBounded(info, local_goal.x, local_goal.y, x, y))
00126   {
00127     cached_path_cost_ = -1.0;
00128     throw nav_core2::GoalBoundsException(goal);
00129   }
00130   if (costmap(x, y) >= costmap.INSCRIBED_INFLATED_OBSTACLE)
00131   {
00132     cached_path_cost_ = -1.0;
00133     throw nav_core2::OccupiedGoalException(goal);
00134   }
00135 
00136   bool cached_plan_available = false;
00137   if (path_caching_ && hasValidCachedPath(local_goal, x, y))
00138   {
00139     if (shouldReturnCachedPathImmediately())
00140     {
00141       return cached_path_;
00142     }
00143     cached_plan_available = true;
00144   }
00145 
00146   
00147   unsigned int n_updated = calculator_->updatePotentials(potential_grid_, local_start, local_goal);
00148   potential_pub_.publish();
00149   double path_cost = 0.0;  
00150   nav_2d_msgs::Path2D path = traceback_->getPath(potential_grid_, start.pose, goal.pose, path_cost);
00151   if (print_statistics_)
00152   {
00153     ROS_INFO_NAMED("DluxGlobalPlanner",
00154                    "Got plan! Cost: %.2f, %d updated potentials, path of length %.2f with %zu poses.",
00155                    path_cost, n_updated, nav_2d_utils::getPlanLength(path), path.poses.size());
00156   }
00157 
00158   
00159   if (cached_plan_available && !shouldReturnNewPath(path, path_cost))
00160   {
00161     return cached_path_;
00162   }
00163   cached_path_cost_ = path_cost;
00164   cached_path_ = path;
00165   return path;
00166 }
00167 
00168 
00169 bool DluxGlobalPlanner::hasValidCachedPath(const geometry_msgs::Pose2D& local_goal,
00170                                            unsigned int goal_x, unsigned int goal_y)
00171 {
00172   bool ret = cached_path_cost_ >= 0 && cached_goal_x_ == goal_x && cached_goal_y_ == goal_y &&
00173              isPlanValid(cached_path_);
00174   cached_goal_x_ = goal_x;
00175   cached_goal_y_ = goal_y;
00176   return ret;
00177 }
00178 
00179 bool DluxGlobalPlanner::shouldReturnCachedPathImmediately() const
00180 {
00181   
00182   return improvement_threshold_ < 0.0;
00183 }
00184 
00185 bool DluxGlobalPlanner::shouldReturnNewPath(const nav_2d_msgs::Path2D& new_path, const double new_path_cost) const
00186 {
00187   return new_path_cost + improvement_threshold_ <= cached_path_cost_;
00188 }
00189 
00190 PLUGINLIB_EXPORT_CLASS(dlux_global_planner::DluxGlobalPlanner, nav_core2::GlobalPlanner)
00191 
00192 }