queued_action_server_imp.h
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2008, Willow Garage, Inc.
6  * Copyright (c) 2020, Ubiquity Robotics, Inc.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of Willow Garage, Inc. nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  *********************************************************************/
37 #ifndef QUEUED_ACTION_SERVER_IMP_H_
38 #define QUEUED_ACTION_SERVER_IMP_H_
39 
40 #include <ros/ros.h>
41 #include <chrono>
42 #include <string>
43 
44 namespace actionlib {
45 
46 template <class ActionSpec>
48  ExecuteCallback execute_callback)
49  : new_goal_(false),
50  preempt_request_(false),
51  new_goal_preempt_request_(false),
52  execute_callback(execute_callback),
53  execute_thread(NULL),
54  need_to_terminate(false) {
55  // create the action server
56  as = std::make_shared<ActionServer<ActionSpec>>(
57  n_, name, boost::bind(&QueuedActionServer::goalCallback, this, _1),
58  boost::bind(&QueuedActionServer::preemptCallback, this, _1), false);
59 
60  if (execute_callback != NULL) {
61  execute_thread = new std::thread(std::bind(&QueuedActionServer::executeLoop, this));
62  }
63 }
64 
65 template <class ActionSpec>
68  : n_(n),
69  new_goal_(false),
70  preempt_request_(false),
72  execute_callback(execute_callback),
73  execute_thread(NULL),
74  need_to_terminate(false) {
75  // create the action server
76  as = std::make_shared<ActionServer<ActionSpec>>(
77  n, name, boost::bind(&QueuedActionServer::goalCallback, this, _1),
78  boost::bind(&QueuedActionServer::preemptCallback, this, _1), false);
79 
80  if (execute_callback != NULL) {
81  execute_thread = new std::thread(std::bind(&QueuedActionServer::executeLoop, this));
82  }
83 }
84 
85 template <class ActionSpec>
87  if (execute_thread) {
88  shutdown();
89  }
90 }
91 
92 template <class ActionSpec>
94  if (execute_callback) {
95  need_to_terminate = true;
96 
97  assert(execute_thread);
98  if (execute_thread) {
99  execute_thread->join();
100  delete execute_thread;
101  execute_thread = NULL;
102  }
103  }
104 }
105 
106 template <class ActionSpec>
109  std::lock_guard<std::recursive_mutex> lk(lock);
110 
111  if (!new_goal_ || !next_goal.getGoal()) {
112  ROS_ERROR_NAMED("actionlib",
113  "Attempting to accept the next goal when a new goal is not available");
115  }
116 
117  ROS_DEBUG_NAMED("actionlib", "Accepting a new goal");
118 
119  // accept the next goal
121  new_goal_ = false;
122 
123  // set preempt to request to equal the preempt state of the new goal
126 
127  // set the status of the current goal to be active
128  current_goal.setAccepted("This goal has been accepted by the simple action server");
129 
130  return current_goal.getGoal();
131 }
132 
133 template <class ActionSpec>
135  return new_goal_;
136 }
137 
138 template <class ActionSpec>
140  return preempt_request_;
141 }
142 
143 template <class ActionSpec>
145  if (!current_goal.getGoal()) {
146  return false;
147  }
148  unsigned int status = current_goal.getGoalStatus().status;
149  return status == actionlib_msgs::GoalStatus::ACTIVE ||
150  status == actionlib_msgs::GoalStatus::PREEMPTING;
151 }
152 
153 template <class ActionSpec>
154 void QueuedActionServer<ActionSpec>::setSucceeded(const Result& result, const std::string& text) {
155  std::lock_guard<std::recursive_mutex> lk(lock);
156  ROS_DEBUG_NAMED("actionlib", "Setting the current goal as succeeded");
157  current_goal.setSucceeded(result, text);
158 }
159 
160 template <class ActionSpec>
161 void QueuedActionServer<ActionSpec>::setAborted(const Result& result, const std::string& text) {
162  std::lock_guard<std::recursive_mutex> lk(lock);
163  ROS_DEBUG_NAMED("actionlib", "Setting the current goal as aborted");
164  current_goal.setAborted(result, text);
165 }
166 
167 template <class ActionSpec>
168 void QueuedActionServer<ActionSpec>::setPreempted(const Result& result, const std::string& text) {
169  std::lock_guard<std::recursive_mutex> lk(lock);
170  ROS_DEBUG_NAMED("actionlib", "Setting the current goal as canceled");
171  current_goal.setCanceled(result, text);
172 }
173 
174 template <class ActionSpec>
176  std::lock_guard<std::recursive_mutex> lk(lock);
177  ROS_DEBUG_NAMED("actionlib", "A new goal has been recieved by the single goal action server");
178 
179  // check that the timestamp is past or equal to that of the current goal and the next goal
180  if ((!current_goal.getGoal() || goal.getGoalID().stamp >= current_goal.getGoalID().stamp) &&
181  (!next_goal.getGoal() || goal.getGoalID().stamp >= next_goal.getGoalID().stamp)) {
182 
183  // if next_goal has not been accepted already... its going to get bumped, but we need to let
184  // the client know we're preempting
186  next_goal.setCanceled(Result(),
187  "This goal was canceled because another goal was received"
188  "bumping this one out of the queue");
189  }
190 
191  next_goal = goal;
192  new_goal_ = true;
194 
195  // Trigger runLoop to call execute()
196  execute_condition.notify_all();
197  } else {
198  // This is an old goal, we are going to reject it
199  goal.setRejected(
200  Result(),
201  "This goal was rejected because another goal there are newer goals in the queue");
202  }
203 }
204 
205 template <class ActionSpec>
207  std::lock_guard<std::recursive_mutex> lk(lock);
208  ROS_DEBUG_NAMED("actionlib", "A preempt has been received by the QueuedActionServer");
209 
210  // if the preempt is for the current goal, then we'll set the preemptRequest flag and call the
211  // user's preempt callback
212  if (preempt == current_goal) {
214  "actionlib",
215  "Setting preempt_request bit for the current goal to TRUE");
216  preempt_request_ = true;
217 
218  } else if (preempt == next_goal) {
219  // if the preempt applies to the next goal, we'll set the preempt bit for that
220  ROS_DEBUG_NAMED("actionlib", "Setting preempt request bit for the next goal to TRUE");
222  }
223 }
224 
225 template <class ActionSpec>
227  ros::Duration loop_duration = ros::Duration().fromSec(.1);
228 
229  while (n_.ok()) {
230  if (need_to_terminate) {
231  break;
232  }
233 
234  std::unique_lock<std::recursive_mutex> lk(lock);
235  execute_condition.wait_for(lk, std::chrono::duration<double>(loop_duration.toSec()),
236  [this] { return this->new_goal_; });
237 
238  if (isActive()) {
239  ROS_ERROR_NAMED("actionlib", "Should never reach this code with an active goal");
240  } else if (isNewGoalAvailable()) {
241  GoalConstPtr goal = acceptNewGoal();
242 
244  "execute_callback must exist. This is a bug in QueuedActionServer");
245 
246  {
247  // Make sure we're not locked when we call execute, relock in exception safe way
248  lk.unlock();
249  try {
250  execute_callback(goal);
251  } catch (...) {
252  lk.lock();
253  throw;
254  }
255  lk.lock();
256  }
257 
258  if (isActive()) {
259  ROS_WARN_NAMED("actionlib",
260  "Your executeCallback did not set the goal to a terminal status.\n"
261  "This is a bug in your ActionServer implementation. Fix your code!\n"
262  "For now, the ActionServer will set this goal to aborted");
263  setAborted(Result(),
264  "This goal was aborted by the simple action server. The user should "
265  "have set a terminal status on this goal and did not");
266  }
267  }
268  }
269 }
270 
271 template <class ActionSpec>
273  as->start();
274 }
275 
276 } // namespace actionlib
277 
278 #endif
#define ROS_WARN_NAMED(name,...)
actionlib_msgs::GoalID getGoalID() const
void setPreempted(const Result &result=Result(), const std::string &text=std::string(""))
std::condition_variable_any execute_condition
void setRejected(const Result &result=Result(), const std::string &text=std::string(""))
boost::shared_ptr< const Goal > getGoal() const
std::atomic< bool > need_to_terminate
void goalCallback(GoalHandle preempt)
std::shared_ptr< ActionServer< ActionSpec > > as
#define ROS_FATAL_COND(cond,...)
QueuedActionServer(std::string name, ExecuteCallback execute_callback)
void setSucceeded(const Result &result=Result(), const std::string &text=std::string(""))
void setCanceled(const Result &result=Result(), const std::string &text=std::string(""))
void setAccepted(const std::string &text=std::string(""))
#define ROS_DEBUG_NAMED(name,...)
void setSucceeded(const Result &result=Result(), const std::string &text=std::string(""))
Duration & fromSec(double t)
void setAborted(const Result &result=Result(), const std::string &text=std::string(""))
boost::shared_ptr< const Goal > acceptNewGoal()
void setAborted(const Result &result=Result(), const std::string &text=std::string(""))
#define ROS_ERROR_NAMED(name,...)
void preemptCallback(GoalHandle preempt)
bool ok() const
boost::function< void(const GoalConstPtr &)> ExecuteCallback
actionlib_msgs::GoalStatus getGoalStatus() const


move_basic
Author(s): Jim Vaughan
autogenerated on Fri Mar 26 2021 02:46:58