planner_action.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2018, Magazino GmbH, Sebastian Pütz, Jorge Santos Simón
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following
13  * disclaimer in the documentation and/or other materials provided
14  * with the distribution.
15  *
16  * 3. Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * planner_action.cpp
34  *
35  * authors:
36  * Sebastian Pütz <spuetz@uni-osnabrueck.de>
37  * Jorge Santos Simón <santos@magazino.eu>
38  *
39  */
40 
41 #include <sstream>
42 
44 
45 namespace mbf_abstract_nav{
46 
48  const std::string &name,
49  const RobotInformation &robot_info)
50  : AbstractAction(name, robot_info, boost::bind(&mbf_abstract_nav::PlannerAction::run, this, _1, _2)), path_seq_count_(0)
51 {
52  ros::NodeHandle private_nh("~");
53  // informative topics: current navigation goal
54  current_goal_pub_ = private_nh.advertise<geometry_msgs::PoseStamped>("current_goal", 1);
55 }
56 
58 {
59  const mbf_msgs::GetPathGoal& goal = *(goal_handle.getGoal().get());
60 
61  mbf_msgs::GetPathResult result;
62  geometry_msgs::PoseStamped start_pose;
63 
64  result.path.header.seq = path_seq_count_++;
65  result.path.header.frame_id = robot_info_.getGlobalFrame();
66 
67  double tolerance = goal.tolerance;
68  bool use_start_pose = goal.use_start_pose;
69  current_goal_pub_.publish(goal.target_pose);
70 
71  bool planner_active = true;
72 
73  if(use_start_pose)
74  {
75  start_pose = goal.start_pose;
76  const geometry_msgs::Point& p = start_pose.pose.position;
77  ROS_DEBUG_STREAM_NAMED(name_, "Use the given start pose (" << p.x << ", " << p.y << ", " << p.z << ").");
78  }
79  else
80  {
81  // get the current robot pose
82  if (!robot_info_.getRobotPose(start_pose))
83  {
84  result.outcome = mbf_msgs::GetPathResult::TF_ERROR;
85  result.message = "Could not get the current robot pose!";
86  goal_handle.setAborted(result, result.message);
87  ROS_ERROR_STREAM_NAMED(name_, result.message << " Canceling the action call.");
88  return;
89  }
90  else
91  {
92  const geometry_msgs::Point& p = start_pose.pose.position;
93  ROS_DEBUG_STREAM_NAMED(name_, "Got the current robot pose at ("
94  << p.x << ", " << p.y << ", " << p.z << ").");
95  }
96  }
97 
98  AbstractPlannerExecution::PlanningState state_planning_input;
99 
100  std::vector<geometry_msgs::PoseStamped> plan, global_plan;
101 
102  while (planner_active && ros::ok())
103  {
104  // get the current state of the planning thread
105  state_planning_input = execution.getState();
106 
107  switch (state_planning_input)
108  {
110  ROS_DEBUG_STREAM_NAMED(name_, "planner state: initialized");
111  if (!execution.start(start_pose, goal.target_pose, tolerance))
112  {
113  result.outcome = mbf_msgs::GetPathResult::INTERNAL_ERROR;
114  result.message = "Another thread is still planning!";
115  goal_handle.setAborted(result, result.message);
116  ROS_ERROR_STREAM_NAMED(name_, result.message << " Canceling the action call.");
117  planner_active = false;
118  }
119  break;
120 
122  ROS_DEBUG_STREAM_NAMED(name_, "planner state: started");
123  break;
124 
126  ROS_DEBUG_STREAM_NAMED(name_, "planner state: stopped");
127  ROS_WARN_STREAM_NAMED(name_, "Planning has been stopped rigorously!");
128  result.outcome = mbf_msgs::GetPathResult::STOPPED;
129  result.message = "Global planner has been stopped!";
130  goal_handle.setAborted(result, result.message);
131  planner_active = false;
132  break;
133 
135  ROS_DEBUG_STREAM_NAMED(name_, "planner state: canceled");
136  ROS_DEBUG_STREAM_NAMED(name_, "Global planner has been canceled successfully");
137  result.path.header.stamp = ros::Time::now();
138  result.outcome = mbf_msgs::GetPathResult::CANCELED;
139  result.message = "Global planner has been canceled!";
140  goal_handle.setCanceled(result, result.message);
141  planner_active = false;
142  break;
143 
144  // in progress
146  if (execution.isPatienceExceeded())
147  {
148  ROS_INFO_STREAM_NAMED(name_, "Global planner patience has been exceeded! "
149  << "Cancel planning...");
150  if (!execution.cancel())
151  {
152  ROS_WARN_STREAM_THROTTLE_NAMED(2.0, name_, "Cancel planning failed or is not supported; "
153  "must wait until current plan finish!");
154  execution.stop(); // try to interrupt planning.
155  }
156  }
157  else
158  {
159  ROS_DEBUG_THROTTLE_NAMED(2.0, name_, "planner state: planning");
160  }
161  break;
162 
163  // found a new plan
165  // set time stamp to now
166  result.path.header.stamp = ros::Time::now();
167  plan = execution.getPlan();
168 
169  ROS_DEBUG_STREAM_NAMED(name_, "planner state: found plan with cost: " << execution.getCost());
170 
171  if (!transformPlanToGlobalFrame(plan, global_plan))
172  {
173  result.outcome = mbf_msgs::GetPathResult::TF_ERROR;
174  result.message = "Could not transform the plan to the global frame!";
175 
176  ROS_ERROR_STREAM_NAMED(name_, result.message << " Canceling the action call.");
177  goal_handle.setAborted(result, result.message);
178  planner_active = false;
179  break;
180  }
181 
182  if (global_plan.empty())
183  {
184  result.outcome = mbf_msgs::GetPathResult::EMPTY_PATH;
185  result.message = "Global planner returned an empty path!";
186 
187  ROS_ERROR_STREAM_NAMED(name_, result.message);
188  goal_handle.setAborted(result, result.message);
189  planner_active = false;
190  break;
191  }
192 
193  result.path.poses = global_plan;
194  result.cost = execution.getCost();
195  result.outcome = execution.getOutcome();
196  result.message = execution.getMessage();
197  goal_handle.setSucceeded(result, result.message);
198 
199  planner_active = false;
200  break;
201 
202  // no plan found
204  ROS_DEBUG_STREAM_NAMED(name_, "planner state: no plan found");
205  result.outcome = execution.getOutcome();
206  result.message = execution.getMessage();
207  goal_handle.setAborted(result, result.message);
208  planner_active = false;
209  break;
210 
212  ROS_DEBUG_STREAM_NAMED(name_, "Global planner reached the maximum number of retries");
213  result.outcome = execution.getOutcome();
214  result.message = execution.getMessage();
215  goal_handle.setAborted(result, result.message);
216  planner_active = false;
217  break;
218 
220  ROS_DEBUG_STREAM_NAMED(name_, "Global planner exceeded the patience time");
221  result.outcome = mbf_msgs::GetPathResult::PAT_EXCEEDED;
222  result.message = "Global planner exceeded the patience time";
223  goal_handle.setAborted(result, result.message);
224  planner_active = false;
225  break;
226 
228  ROS_FATAL_STREAM_NAMED(name_, "Internal error: Unknown error thrown by the plugin!"); // TODO getMessage from planning
229  planner_active = false;
230  result.outcome = mbf_msgs::GetPathResult::INTERNAL_ERROR;
231  result.message = "Internal error: Unknown error thrown by the plugin!";
232  goal_handle.setAborted(result, result.message);
233  break;
234 
235  default:
236  result.outcome = mbf_msgs::GetPathResult::INTERNAL_ERROR;
237  std::ostringstream ss;
238  ss << "Internal error: Unknown state in a move base flex planner execution with the number: "
239  << static_cast<int>(state_planning_input);
240  result.message = ss.str();
241  ROS_FATAL_STREAM_NAMED(name_, result.message);
242  goal_handle.setAborted(result, result.message);
243  planner_active = false;
244  }
245 
246 
247  if (planner_active)
248  {
249  // try to sleep a bit
250  // normally this thread should be woken up from the planner execution thread
251  // in order to transfer the results to the controller.
252  boost::mutex mutex;
253  boost::unique_lock<boost::mutex> lock(mutex);
254  execution.waitForStateUpdate(boost::chrono::milliseconds(500));
255  }
256  } // while (planner_active && ros::ok())
257 
258  if (!planner_active)
259  {
260  ROS_DEBUG_STREAM_NAMED(name_, "\"" << name_ << "\" action ended properly.");
261  }
262  else
263  {
264  ROS_ERROR_STREAM_NAMED(name_, "\"" << name_ << "\" action has been stopped!");
265  }
266 }
267 
269  std::vector<geometry_msgs::PoseStamped> &plan, std::vector<geometry_msgs::PoseStamped> &global_plan)
270 {
271  global_plan.clear();
272  std::vector<geometry_msgs::PoseStamped>::iterator iter;
273  bool tf_success = false;
274  for (iter = plan.begin(); iter != plan.end(); ++iter)
275  {
276  geometry_msgs::PoseStamped global_pose;
278  robot_info_.getTfTimeout(), *iter, robot_info_.getGlobalFrame(), global_pose);
279  if (!tf_success)
280  {
281  ROS_ERROR_STREAM("Can not transform pose from the \"" << iter->header.frame_id << "\" frame into the \""
282  << robot_info_.getGlobalFrame() << "\" frame !");
283  return false;
284  }
285  global_plan.push_back(global_pose);
286  }
287  return true;
288 }
289 
290 } /* namespace mbf_abstract_nav */
291 
PlanningState getState()
Returns the current internal state.
#define ROS_DEBUG_STREAM_NAMED(name, args)
void publish(const boost::shared_ptr< M > &message) const
#define ROS_ERROR_STREAM_NAMED(name, args)
ros::Publisher current_goal_pub_
Publisher to publish the current goal pose, which is used for path planning.
bool isPatienceExceeded()
Checks whether the patience was exceeded.
unsigned int path_seq_count_
Path sequence counter.
No plan has been found (MAX_RETRIES and PAT_EXCEEDED are 0).
boost::shared_ptr< const Goal > getGoal() const
#define ROS_INFO_STREAM_NAMED(name, args)
bool getRobotPose(geometry_msgs::PoseStamped &robot_pose) const
std::string getMessage()
Gets the current plugin execution message.
void setCanceled(const Result &result=Result(), const std::string &text=std::string(""))
const std::string & getGlobalFrame() const
Exceeded the maximum number of retries without a valid command.
void waitForStateUpdate(boost::chrono::microseconds const &duration)
void setSucceeded(const Result &result=Result(), const std::string &text=std::string(""))
#define ROS_WARN_STREAM_THROTTLE_NAMED(period, name, args)
#define ROS_FATAL_STREAM_NAMED(name, args)
ROSCPP_DECL bool ok()
const ros::Duration & getTfTimeout() const
virtual bool cancel()
Cancel the planner execution. This calls the cancel method of the planner plugin. This could be usefu...
Exceeded the patience time without a valid command.
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
std::vector< geometry_msgs::PoseStamped > getPlan()
Returns a new plan, if one is available.
PlannerAction(const std::string &name, const RobotInformation &robot_info)
void setAborted(const Result &result=Result(), const std::string &text=std::string(""))
bool transformPlanToGlobalFrame(std::vector< geometry_msgs::PoseStamped > &plan, std::vector< geometry_msgs::PoseStamped > &global_plan)
Transforms a plan to the global frame (global_frame_) coord system.
#define ROS_DEBUG_THROTTLE_NAMED(period, name,...)
static Time now()
#define ROS_ERROR_STREAM(args)
bool start(const geometry_msgs::PoseStamped &start, const geometry_msgs::PoseStamped &goal, double tolerance)
Starts the planner execution thread with the given parameters.
bool transformPose(const TF &tf, const std::string &target_frame, const ros::Time &target_time, const ros::Duration &timeout, const geometry_msgs::PoseStamped &in, const std::string &fixed_frame, geometry_msgs::PoseStamped &out)
uint32_t getOutcome()
Gets the current plugin execution outcome.
void run(GoalHandle &goal_handle, AbstractPlannerExecution &execution)
The AbstractPlannerExecution class loads and binds the global planner plugin. It contains a thread ru...
#define ROS_WARN_STREAM_NAMED(name, args)


mbf_abstract_nav
Author(s): Sebastian Pütz
autogenerated on Tue Jun 18 2019 19:34:34