planner_action.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  *  planner_action.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 <sstream>
00042 
00043 #include "mbf_abstract_nav/planner_action.h"
00044 
00045 namespace mbf_abstract_nav{
00046 
00047 PlannerAction::PlannerAction(
00048     const std::string &name,
00049     const RobotInformation &robot_info)
00050   : AbstractAction(name, robot_info, boost::bind(&mbf_abstract_nav::PlannerAction::run, this, _1, _2)), path_seq_count_(0)
00051 {
00052   ros::NodeHandle private_nh("~");
00053   // informative topics: current navigation goal
00054   current_goal_pub_ = private_nh.advertise<geometry_msgs::PoseStamped>("current_goal", 1);
00055 }
00056 
00057 void PlannerAction::run(GoalHandle &goal_handle, AbstractPlannerExecution &execution)
00058 {
00059   const mbf_msgs::GetPathGoal& goal = *(goal_handle.getGoal().get());
00060 
00061   mbf_msgs::GetPathResult result;
00062   geometry_msgs::PoseStamped start_pose;
00063 
00064   result.path.header.seq = path_seq_count_++;
00065   result.path.header.frame_id = robot_info_.getGlobalFrame();
00066 
00067   double tolerance = goal.tolerance;
00068   bool use_start_pose = goal.use_start_pose;
00069   current_goal_pub_.publish(goal.target_pose);
00070 
00071   bool planner_active = true;
00072 
00073   if(use_start_pose)
00074   {
00075     start_pose = goal.start_pose;
00076     const geometry_msgs::Point& p = start_pose.pose.position;
00077     ROS_DEBUG_STREAM_NAMED(name_, "Use the given start pose (" << p.x << ", " << p.y << ", " << p.z << ").");
00078   }
00079   else
00080   {
00081     // get the current robot pose
00082     if (!robot_info_.getRobotPose(start_pose))
00083     {
00084       result.outcome = mbf_msgs::GetPathResult::TF_ERROR;
00085       result.message = "Could not get the current robot pose!";
00086       goal_handle.setAborted(result, result.message);
00087       ROS_ERROR_STREAM_NAMED(name_, result.message << " Canceling the action call.");
00088       return;
00089     }
00090     else
00091     {
00092       const geometry_msgs::Point& p = start_pose.pose.position;
00093       ROS_DEBUG_STREAM_NAMED(name_, "Got the current robot pose at ("
00094           << p.x << ", " << p.y << ", " << p.z << ").");
00095     }
00096   }
00097 
00098   AbstractPlannerExecution::PlanningState state_planning_input;
00099 
00100   std::vector<geometry_msgs::PoseStamped> plan, global_plan;
00101 
00102   while (planner_active && ros::ok())
00103   {
00104     // get the current state of the planning thread
00105     state_planning_input = execution.getState();
00106 
00107     switch (state_planning_input)
00108     {
00109       case AbstractPlannerExecution::INITIALIZED:
00110         ROS_DEBUG_STREAM_NAMED(name_, "planner state: initialized");
00111         if (!execution.start(start_pose, goal.target_pose, tolerance))
00112         {
00113           result.outcome = mbf_msgs::GetPathResult::INTERNAL_ERROR;
00114           result.message = "Another thread is still planning!";
00115           goal_handle.setAborted(result, result.message);
00116           ROS_ERROR_STREAM_NAMED(name_, result.message << " Canceling the action call.");
00117           planner_active = false;
00118         }
00119         break;
00120 
00121       case AbstractPlannerExecution::STARTED:
00122         ROS_DEBUG_STREAM_NAMED(name_, "planner state: started");
00123         break;
00124 
00125       case AbstractPlannerExecution::STOPPED:
00126         ROS_DEBUG_STREAM_NAMED(name_, "planner state: stopped");
00127         ROS_WARN_STREAM_NAMED(name_, "Planning has been stopped rigorously!");
00128         result.outcome = mbf_msgs::GetPathResult::STOPPED;
00129         result.message = "Global planner has been stopped!";
00130         goal_handle.setAborted(result, result.message);
00131         planner_active = false;
00132         break;
00133 
00134       case AbstractPlannerExecution::CANCELED:
00135         ROS_DEBUG_STREAM_NAMED(name_, "planner state: canceled");
00136         ROS_DEBUG_STREAM_NAMED(name_, "Global planner has been canceled successfully");
00137         result.path.header.stamp = ros::Time::now();
00138         result.outcome = mbf_msgs::GetPathResult::CANCELED;
00139         result.message = "Global planner has been canceled!";
00140         goal_handle.setCanceled(result, result.message);
00141         planner_active = false;
00142         break;
00143 
00144         // in progress
00145       case AbstractPlannerExecution::PLANNING:
00146         if (execution.isPatienceExceeded())
00147         {
00148           ROS_INFO_STREAM_NAMED(name_, "Global planner patience has been exceeded! "
00149               << "Cancel planning...");
00150           if (!execution.cancel())
00151           {
00152             ROS_WARN_STREAM_THROTTLE_NAMED(2.0, name_, "Cancel planning failed or is not supported; "
00153                 "must wait until current plan finish!");
00154             execution.stop(); // try to interrupt planning.
00155           }
00156         }
00157         else
00158         {
00159           ROS_DEBUG_THROTTLE_NAMED(2.0, name_, "planner state: planning");
00160         }
00161         break;
00162 
00163         // found a new plan
00164       case AbstractPlannerExecution::FOUND_PLAN:
00165         // set time stamp to now
00166         result.path.header.stamp = ros::Time::now();
00167         plan = execution.getPlan();
00168 
00169         ROS_DEBUG_STREAM_NAMED(name_, "planner state: found plan with cost: " << execution.getCost());
00170 
00171         if (!transformPlanToGlobalFrame(plan, global_plan))
00172         {
00173           result.outcome = mbf_msgs::GetPathResult::TF_ERROR;
00174           result.message = "Could not transform the plan to the global frame!";
00175 
00176           ROS_ERROR_STREAM_NAMED(name_, result.message << " Canceling the action call.");
00177           goal_handle.setAborted(result, result.message);
00178           planner_active = false;
00179           break;
00180         }
00181 
00182         if (global_plan.empty())
00183         {
00184           result.outcome = mbf_msgs::GetPathResult::EMPTY_PATH;
00185           result.message = "Global planner returned an empty path!";
00186 
00187           ROS_ERROR_STREAM_NAMED(name_, result.message);
00188           goal_handle.setAborted(result, result.message);
00189           planner_active = false;
00190           break;
00191         }
00192 
00193         result.path.poses = global_plan;
00194         result.cost = execution.getCost();
00195         result.outcome = execution.getOutcome();
00196         result.message = execution.getMessage();
00197         goal_handle.setSucceeded(result, result.message);
00198 
00199         planner_active = false;
00200         break;
00201 
00202         // no plan found
00203       case AbstractPlannerExecution::NO_PLAN_FOUND:
00204         ROS_DEBUG_STREAM_NAMED(name_, "planner state: no plan found");
00205         result.outcome = execution.getOutcome();
00206         result.message = execution.getMessage();
00207         goal_handle.setAborted(result, result.message);
00208         planner_active = false;
00209         break;
00210 
00211       case AbstractPlannerExecution::MAX_RETRIES:
00212         ROS_DEBUG_STREAM_NAMED(name_, "Global planner reached the maximum number of retries");
00213         result.outcome = execution.getOutcome();
00214         result.message = execution.getMessage();
00215         goal_handle.setAborted(result, result.message);
00216         planner_active = false;
00217         break;
00218 
00219       case AbstractPlannerExecution::PAT_EXCEEDED:
00220         ROS_DEBUG_STREAM_NAMED(name_, "Global planner exceeded the patience time");
00221         result.outcome = mbf_msgs::GetPathResult::PAT_EXCEEDED;
00222         result.message = "Global planner exceeded the patience time";
00223         goal_handle.setAborted(result, result.message);
00224         planner_active = false;
00225         break;
00226 
00227       case AbstractPlannerExecution::INTERNAL_ERROR:
00228         ROS_FATAL_STREAM_NAMED(name_, "Internal error: Unknown error thrown by the plugin!"); // TODO getMessage from planning
00229         planner_active = false;
00230         result.outcome = mbf_msgs::GetPathResult::INTERNAL_ERROR;
00231         result.message = "Internal error: Unknown error thrown by the plugin!";
00232         goal_handle.setAborted(result, result.message);
00233         break;
00234 
00235       default:
00236         result.outcome = mbf_msgs::GetPathResult::INTERNAL_ERROR;
00237         std::ostringstream ss;
00238         ss << "Internal error: Unknown state in a move base flex planner execution with the number: "
00239            << static_cast<int>(state_planning_input);
00240         result.message = ss.str();
00241         ROS_FATAL_STREAM_NAMED(name_, result.message);
00242         goal_handle.setAborted(result, result.message);
00243         planner_active = false;
00244     }
00245 
00246 
00247     if (planner_active)
00248     {
00249       // try to sleep a bit
00250       // normally this thread should be woken up from the planner execution thread
00251       // in order to transfer the results to the controller.
00252       boost::mutex mutex;
00253       boost::unique_lock<boost::mutex> lock(mutex);
00254       execution.waitForStateUpdate(boost::chrono::milliseconds(500));
00255     }
00256   }  // while (planner_active && ros::ok())
00257 
00258   if (!planner_active)
00259   {
00260     ROS_DEBUG_STREAM_NAMED(name_, "\"" << name_ << "\" action ended properly.");
00261   }
00262   else
00263   {
00264     ROS_ERROR_STREAM_NAMED(name_, "\"" << name_ << "\" action has been stopped!");
00265   }
00266 }
00267 
00268 bool PlannerAction::transformPlanToGlobalFrame(
00269     std::vector<geometry_msgs::PoseStamped> &plan, std::vector<geometry_msgs::PoseStamped> &global_plan)
00270 {
00271   global_plan.clear();
00272   std::vector<geometry_msgs::PoseStamped>::iterator iter;
00273   bool tf_success = false;
00274   for (iter = plan.begin(); iter != plan.end(); ++iter)
00275   {
00276     geometry_msgs::PoseStamped global_pose;
00277     tf_success = mbf_utility::transformPose(robot_info_.getTransformListener(), robot_info_.getGlobalFrame(), iter->header.stamp,
00278                                             robot_info_.getTfTimeout(), *iter, robot_info_.getGlobalFrame(), global_pose);
00279     if (!tf_success)
00280     {
00281       ROS_ERROR_STREAM("Can not transform pose from the \"" << iter->header.frame_id << "\" frame into the \""
00282                                                             << robot_info_.getGlobalFrame() << "\" frame !");
00283       return false;
00284     }
00285     global_plan.push_back(global_pose);
00286   }
00287   return true;
00288 }
00289 
00290 } /* namespace mbf_abstract_nav */
00291 


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