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 }