dlux_global_planner.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2018, Locus Robotics
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the copyright holder nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
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   // NB: Only checks for obstacles at each pose
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   // Check Start / Goal Quality
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   // Commence path planning.
00147   unsigned int n_updated = calculator_->updatePotentials(potential_grid_, local_start, local_goal);
00148   potential_pub_.publish();
00149   double path_cost = 0.0;  // right now we don't do anything with the cost
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   // If there is a cached path available and the new path cost has not sufficiently improved
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   // If we don't care if the plan improves, return immediately.
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 }  // namespace dlux_global_planner


dlux_global_planner
Author(s):
autogenerated on Wed Jun 26 2019 20:09:53