abstract_planner_execution.cpp
Go to the documentation of this file.
00001 /*
00002  *  Copyright 2018, Magazino GmbH, Sebastian Pütz, Jorge Santos Simón
00003  *
00004  *  Redistribution and use in source and binary forms, with or without
00005  *  modification, are permitted provided that the following conditions
00006  *  are met:
00007  *
00008  *  1. Redistributions of source code must retain the above copyright
00009  *     notice, this list of conditions and the following disclaimer.
00010  *
00011  *  2. Redistributions in binary form must reproduce the above
00012  *     copyright notice, this list of conditions and the following
00013  *     disclaimer in the documentation and/or other materials provided
00014  *     with the distribution.
00015  *
00016  *  3. Neither the name of the copyright holder nor the names of its
00017  *     contributors may be used to endorse or promote products derived
00018  *     from this software without specific prior written permission.
00019  *
00020  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024  *  COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031  *  POSSIBILITY OF SUCH DAMAGE.
00032  *
00033  *  abstract_planner_execution.cpp
00034  *
00035  *  authors:
00036  *    Sebastian Pütz <spuetz@uni-osnabrueck.de>
00037  *    Jorge Santos Simón <santos@magazino.eu>
00038  *
00039  */
00040 
00041 #include "mbf_abstract_nav/abstract_planner_execution.h"
00042 
00043 namespace mbf_abstract_nav
00044 {
00045 
00046 
00047   AbstractPlannerExecution::AbstractPlannerExecution(const std::string name,
00048                                                      const mbf_abstract_core::AbstractPlanner::Ptr planner_ptr,
00049                                                      const MoveBaseFlexConfig &config,
00050                                                      boost::function<void()> setup_fn,
00051                                                      boost::function<void()> cleanup_fn) :
00052     AbstractExecutionBase(name, setup_fn, cleanup_fn),
00053       planner_(planner_ptr), state_(INITIALIZED), planning_(false),
00054       has_new_start_(false), has_new_goal_(false)
00055   {
00056     ros::NodeHandle private_nh("~");
00057 
00058     // non-dynamically reconfigurable parameters
00059     private_nh.param("robot_frame", robot_frame_, std::string("base_footprint"));
00060     private_nh.param("map_frame", global_frame_, std::string("map"));
00061 
00062     // dynamically reconfigurable parameters
00063     reconfigure(config);
00064   }
00065 
00066   AbstractPlannerExecution::~AbstractPlannerExecution()
00067   {
00068   }
00069 
00070 
00071   double AbstractPlannerExecution::getCost()
00072   {
00073     boost::lock_guard<boost::mutex> guard(plan_mtx_);
00074     // copy plan and costs to output
00075     // if the planner plugin do not compute costs compute costs by discrete path length
00076     if(cost_ == 0 && !plan_.empty())
00077     {
00078       ROS_DEBUG_STREAM("Compute costs by discrete path length!");
00079       double cost = 0;
00080 
00081       geometry_msgs::PoseStamped prev_pose = plan_.front();
00082       for(std::vector<geometry_msgs::PoseStamped>::iterator iter = plan_.begin() + 1; iter != plan_.end(); ++iter)
00083       {
00084         cost += mbf_utility::distance(prev_pose, *iter);
00085         prev_pose = *iter;
00086       }
00087       return cost;
00088     }
00089     return cost_;
00090   }
00091 
00092   void AbstractPlannerExecution::reconfigure(const MoveBaseFlexConfig &config)
00093   {
00094     boost::lock_guard<boost::mutex> guard(configuration_mutex_);
00095 
00096     max_retries_ = config.planner_max_retries;
00097     frequency_ = config.planner_frequency;
00098 
00099     // Timeout granted to the global planner. We keep calling it up to this time or up to max_retries times
00100     // If it doesn't return within time, the navigator will cancel it and abort the corresponding action
00101     patience_ = ros::Duration(config.planner_patience);
00102   }
00103 
00104 
00105   typename AbstractPlannerExecution::PlanningState AbstractPlannerExecution::getState()
00106   {
00107     boost::lock_guard<boost::mutex> guard(state_mtx_);
00108     return state_;
00109   }
00110 
00111   void AbstractPlannerExecution::setState(PlanningState state)
00112   {
00113     boost::lock_guard<boost::mutex> guard(state_mtx_);
00114     state_ = state;
00115   }
00116 
00117 
00118   ros::Time AbstractPlannerExecution::getLastValidPlanTime()
00119   {
00120     boost::lock_guard<boost::mutex> guard(plan_mtx_);
00121     return last_valid_plan_time_;
00122   }
00123 
00124 
00125   bool AbstractPlannerExecution::isPatienceExceeded()
00126   {
00127     return !patience_.isZero() && (ros::Time::now() - last_call_start_time_ > patience_);
00128   }
00129 
00130 
00131   std::vector<geometry_msgs::PoseStamped> AbstractPlannerExecution::getPlan()
00132   {
00133     boost::lock_guard<boost::mutex> guard(plan_mtx_);
00134     // copy plan and costs to output
00135     return plan_;
00136   }
00137 
00138 
00139   void AbstractPlannerExecution::setNewGoal(const geometry_msgs::PoseStamped &goal, double tolerance)
00140   {
00141     boost::lock_guard<boost::mutex> guard(goal_start_mtx_);
00142     goal_ = goal;
00143     tolerance_ = tolerance;
00144     has_new_goal_ = true;
00145   }
00146 
00147 
00148   void AbstractPlannerExecution::setNewStart(const geometry_msgs::PoseStamped &start)
00149   {
00150     boost::lock_guard<boost::mutex> guard(goal_start_mtx_);
00151     start_ = start;
00152     has_new_start_ = true;
00153   }
00154 
00155 
00156   void AbstractPlannerExecution::setNewStartAndGoal(const geometry_msgs::PoseStamped &start,
00157                                                     const geometry_msgs::PoseStamped &goal,
00158                                                     double tolerance)
00159   {
00160     boost::lock_guard<boost::mutex> guard(goal_start_mtx_);
00161     start_ = start;
00162     goal_ = goal;
00163     tolerance_ = tolerance;
00164     has_new_start_ = true;
00165     has_new_goal_ = true;
00166   }
00167 
00168 
00169   bool AbstractPlannerExecution::start(const geometry_msgs::PoseStamped &start,
00170                                        const geometry_msgs::PoseStamped &goal,
00171                                        double tolerance)
00172   {
00173     if (planning_)
00174     {
00175       return false;
00176     }
00177     boost::lock_guard<boost::mutex> guard(planning_mtx_);
00178     planning_ = true;
00179     start_ = start;
00180     goal_ = goal;
00181     tolerance_ = tolerance;
00182 
00183     geometry_msgs::Point s = start.pose.position;
00184     geometry_msgs::Point g = goal.pose.position;
00185 
00186     ROS_DEBUG_STREAM("Start planning from the start pose: (" << s.x << ", " << s.y << ", " << s.z << ")"
00187                                    << " to the goal pose: ("<< g.x << ", " << g.y << ", " << g.z << ")");
00188 
00189     return AbstractExecutionBase::start();
00190   }
00191 
00192 
00193   bool AbstractPlannerExecution::cancel()
00194   {
00195     cancel_ = true; // force cancel immediately, as the call to cancel in the planner can take a while
00196 
00197     // returns false if cancel is not implemented or rejected by the planner (will run until completion)
00198     if(!planner_->cancel())
00199     {
00200       ROS_WARN_STREAM("Cancel planning failed or is not supported by the plugin. "
00201           << "Wait until the current planning finished!");
00202 
00203       return false;
00204     }
00205     return true;
00206   }
00207 
00208   uint32_t AbstractPlannerExecution::makePlan(const geometry_msgs::PoseStamped &start,
00209                                               const geometry_msgs::PoseStamped &goal,
00210                                               double tolerance,
00211                                               std::vector<geometry_msgs::PoseStamped> &plan,
00212                                               double &cost,
00213                                               std::string &message)
00214   {
00215     return planner_->makePlan(start, goal, tolerance, plan, cost, message);
00216   }
00217 
00218   void AbstractPlannerExecution::run()
00219   {
00220     boost::lock_guard<boost::mutex> guard(planning_mtx_);
00221     int retries = 0;
00222     geometry_msgs::PoseStamped current_start = start_;
00223     geometry_msgs::PoseStamped current_goal = goal_;
00224     double current_tolerance = tolerance_;
00225 
00226     bool success = false;
00227     bool make_plan = false;
00228     bool exceeded = false;
00229 
00230     last_call_start_time_ = ros::Time::now();
00231     last_valid_plan_time_ = ros::Time::now();
00232 
00233     try
00234     {
00235       while (planning_ && ros::ok())
00236       {
00237         boost::chrono::thread_clock::time_point start_time = boost::chrono::thread_clock::now();
00238 
00239         // call the planner
00240         std::vector<geometry_msgs::PoseStamped> plan;
00241         double cost;
00242 
00243         // lock goal start mutex
00244         goal_start_mtx_.lock();
00245         if (has_new_start_)
00246         {
00247           has_new_start_ = false;
00248           current_start = start_;
00249           ROS_INFO_STREAM("A new start pose is available. Planning with the new start pose!");
00250           exceeded = false;
00251           geometry_msgs::Point s = start_.pose.position;
00252           ROS_INFO_STREAM("New planning start pose: (" << s.x << ", " << s.y << ", " << s.z << ")");
00253         }
00254         if (has_new_goal_)
00255         {
00256           has_new_goal_ = false;
00257           current_goal = goal_;
00258           current_tolerance = tolerance_;
00259           ROS_INFO_STREAM("A new goal pose is available. Planning with the new goal pose and the tolerance: "
00260                           << current_tolerance);
00261           exceeded = false;
00262           geometry_msgs::Point g = goal_.pose.position;
00263           ROS_INFO_STREAM("New goal pose: (" << g.x << ", " << g.y << ", " << g.z << ")");
00264         }
00265 
00266         make_plan = !(success || exceeded) || has_new_start_ || has_new_goal_;
00267 
00268         // unlock goal
00269         goal_start_mtx_.unlock();
00270         setState(PLANNING);
00271         if (make_plan)
00272         {
00273           outcome_ = makePlan(current_start, current_goal, current_tolerance, plan, cost, message_);
00274           success = outcome_ < 10;
00275 
00276           boost::lock_guard<boost::mutex> guard(configuration_mutex_);
00277 
00278           if (cancel_ && !isPatienceExceeded())
00279           {
00280             setState(CANCELED);
00281             ROS_INFO_STREAM("The global planner has been canceled!"); // but not due to patience exceeded
00282             planning_ = false;
00283             condition_.notify_all();
00284           }
00285           else if (success)
00286           {
00287             ROS_DEBUG_STREAM("Successfully found a plan.");
00288             exceeded = false;
00289             planning_ = false;
00290 
00291             plan_mtx_.lock();
00292             plan_ = plan;
00293             cost_ = cost;
00294             last_valid_plan_time_ = ros::Time::now();
00295             plan_mtx_.unlock();
00296             setState(FOUND_PLAN);
00297 
00298             condition_.notify_all(); // notify observer
00299           }
00300           else if (max_retries_ >= 0 && ++retries > max_retries_)
00301           {
00302             ROS_INFO_STREAM("Planning reached max retries! (" << max_retries_ << ")");
00303             setState(MAX_RETRIES);
00304             exceeded = true;
00305             planning_ = false;
00306             condition_.notify_all(); // notify observer
00307           }
00308           else if (isPatienceExceeded())
00309           {
00310             // Patience exceeded is handled at two levels: here to stop retrying planning when max_retries is
00311             // disabled, and on the navigation server when the planner doesn't return for more that patience seconds.
00312             // In the second case, the navigation server has tried to cancel planning (possibly without success, as
00313             // old nav_core-based planners do not support canceling), and we add here the fact to the log for info
00314             ROS_INFO_STREAM("Planning patience (" << patience_.toSec() << "s) has been exceeded"
00315                                                   << (cancel_ ? "; planner canceled!" : ""));
00316             setState(PAT_EXCEEDED);
00317             exceeded = true;
00318             planning_ = false;
00319             condition_.notify_all(); // notify observer
00320           }
00321           else if (max_retries_ == 0 && patience_.isZero())
00322           {
00323             ROS_INFO_STREAM("Planning could not find a plan!");
00324             exceeded = true;
00325             setState(NO_PLAN_FOUND);
00326             condition_.notify_all(); // notify observer
00327             planning_ = false;
00328           }
00329           else
00330           {
00331             exceeded = false;
00332             ROS_DEBUG_STREAM("Planning could not find a plan! Trying again...");
00333           }
00334         }
00335         else if (cancel_)
00336         {
00337           ROS_INFO_STREAM("The global planner has been canceled!");
00338           setState(CANCELED);
00339           planning_ = false;
00340           condition_.notify_all();
00341         }
00342       } // while (planning_ && ros::ok())
00343     }
00344     catch (const boost::thread_interrupted &ex)
00345     {
00346       // Planner thread interrupted; probably we have exceeded planner patience
00347       ROS_WARN_STREAM("Planner thread interrupted!");
00348       setState(STOPPED);
00349       condition_.notify_all(); // notify observer
00350       planning_ = false;
00351     }
00352     catch (...)
00353     {
00354       ROS_FATAL_STREAM("Unknown error occurred: " << boost::current_exception_diagnostic_information());
00355       setState(INTERNAL_ERROR);
00356     }
00357   }
00358 
00359 } /* namespace mbf_abstract_nav */
00360 


mbf_abstract_nav
Author(s): Sebastian Pütz
autogenerated on Mon Jun 17 2019 20:11:35