00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #ifndef ACTIONLIB__SERVER__SIMPLE_ACTION_SERVER_IMP_H_
00038 #define ACTIONLIB__SERVER__SIMPLE_ACTION_SERVER_IMP_H_
00039
00040 #include <ros/ros.h>
00041 #include <string>
00042
00043 namespace actionlib
00044 {
00045
00046 template<class ActionSpec>
00047 SimpleActionServer<ActionSpec>::SimpleActionServer(std::string name,
00048 ExecuteCallback execute_callback,
00049 bool auto_start)
00050 : new_goal_(false), preempt_request_(false), new_goal_preempt_request_(false), execute_callback_(
00051 execute_callback), execute_thread_(NULL), need_to_terminate_(false)
00052 {
00053 if (execute_callback_ != NULL) {
00054 execute_thread_ = new boost::thread(boost::bind(&SimpleActionServer::executeLoop, this));
00055 }
00056
00057
00058 as_ = boost::shared_ptr<ActionServer<ActionSpec> >(new ActionServer<ActionSpec>(n_, name,
00059 boost::bind(&SimpleActionServer::goalCallback, this, _1),
00060 boost::bind(&SimpleActionServer::preemptCallback, this, _1),
00061 auto_start));
00062 }
00063
00064 template<class ActionSpec>
00065 SimpleActionServer<ActionSpec>::SimpleActionServer(std::string name, bool auto_start)
00066 : new_goal_(false), preempt_request_(false), new_goal_preempt_request_(false), execute_callback_(
00067 NULL), execute_thread_(NULL), need_to_terminate_(false)
00068 {
00069
00070 as_ = boost::shared_ptr<ActionServer<ActionSpec> >(new ActionServer<ActionSpec>(n_, name,
00071 boost::bind(&SimpleActionServer::goalCallback, this, _1),
00072 boost::bind(&SimpleActionServer::preemptCallback, this, _1),
00073 auto_start));
00074
00075 if (execute_callback_ != NULL) {
00076 execute_thread_ = new boost::thread(boost::bind(&SimpleActionServer::executeLoop, this));
00077 }
00078 }
00079
00080 template<class ActionSpec>
00081 SimpleActionServer<ActionSpec>::SimpleActionServer(std::string name,
00082 ExecuteCallback execute_callback)
00083 : new_goal_(false), preempt_request_(false), new_goal_preempt_request_(false), execute_callback_(
00084 execute_callback), execute_thread_(NULL), need_to_terminate_(false)
00085 {
00086
00087 as_ = boost::shared_ptr<ActionServer<ActionSpec> >(new ActionServer<ActionSpec>(n_, name,
00088 boost::bind(&SimpleActionServer::goalCallback, this, _1),
00089 boost::bind(&SimpleActionServer::preemptCallback, this, _1),
00090 true));
00091
00092 if (execute_callback_ != NULL) {
00093 execute_thread_ = new boost::thread(boost::bind(&SimpleActionServer::executeLoop, this));
00094 }
00095 }
00096
00097
00098 template<class ActionSpec>
00099 SimpleActionServer<ActionSpec>::SimpleActionServer(ros::NodeHandle n, std::string name,
00100 ExecuteCallback execute_callback,
00101 bool auto_start)
00102 : n_(n), new_goal_(false), preempt_request_(false), new_goal_preempt_request_(false),
00103 execute_callback_(execute_callback), execute_thread_(NULL), need_to_terminate_(false)
00104 {
00105
00106 as_ = boost::shared_ptr<ActionServer<ActionSpec> >(new ActionServer<ActionSpec>(n, name,
00107 boost::bind(&SimpleActionServer::goalCallback, this, _1),
00108 boost::bind(&SimpleActionServer::preemptCallback, this, _1),
00109 auto_start));
00110
00111 if (execute_callback_ != NULL) {
00112 execute_thread_ = new boost::thread(boost::bind(&SimpleActionServer::executeLoop, this));
00113 }
00114 }
00115
00116 template<class ActionSpec>
00117 SimpleActionServer<ActionSpec>::SimpleActionServer(ros::NodeHandle n, std::string name,
00118 bool auto_start)
00119 : n_(n), new_goal_(false), preempt_request_(false), new_goal_preempt_request_(false),
00120 execute_callback_(NULL), execute_thread_(NULL), need_to_terminate_(false)
00121 {
00122
00123 as_ = boost::shared_ptr<ActionServer<ActionSpec> >(new ActionServer<ActionSpec>(n, name,
00124 boost::bind(&SimpleActionServer::goalCallback, this, _1),
00125 boost::bind(&SimpleActionServer::preemptCallback, this, _1),
00126 auto_start));
00127
00128 if (execute_callback_ != NULL) {
00129 execute_thread_ = new boost::thread(boost::bind(&SimpleActionServer::executeLoop, this));
00130 }
00131 }
00132
00133 template<class ActionSpec>
00134 SimpleActionServer<ActionSpec>::SimpleActionServer(ros::NodeHandle n, std::string name,
00135 ExecuteCallback execute_callback)
00136 : n_(n), new_goal_(false), preempt_request_(false), new_goal_preempt_request_(false),
00137 execute_callback_(execute_callback), execute_thread_(NULL), need_to_terminate_(false)
00138 {
00139
00140 as_ = boost::shared_ptr<ActionServer<ActionSpec> >(new ActionServer<ActionSpec>(n, name,
00141 boost::bind(&SimpleActionServer::goalCallback, this, _1),
00142 boost::bind(&SimpleActionServer::preemptCallback, this, _1),
00143 true));
00144
00145 if (execute_callback_ != NULL) {
00146 execute_thread_ = new boost::thread(boost::bind(&SimpleActionServer::executeLoop, this));
00147 }
00148 }
00149
00150 template<class ActionSpec>
00151 SimpleActionServer<ActionSpec>::~SimpleActionServer()
00152 {
00153 if (execute_thread_) {
00154 shutdown();
00155 }
00156 }
00157
00158 template<class ActionSpec>
00159 void SimpleActionServer<ActionSpec>::shutdown()
00160 {
00161 if (execute_callback_) {
00162 {
00163 boost::mutex::scoped_lock terminate_lock(terminate_mutex_);
00164 need_to_terminate_ = true;
00165 }
00166
00167 assert(execute_thread_);
00168 if (execute_thread_) {
00169 execute_thread_->join();
00170 delete execute_thread_;
00171 execute_thread_ = NULL;
00172 }
00173 }
00174 }
00175
00176 template<class ActionSpec>
00177 boost::shared_ptr<const typename SimpleActionServer<ActionSpec>::Goal> SimpleActionServer<ActionSpec>
00178 ::acceptNewGoal()
00179 {
00180 boost::recursive_mutex::scoped_lock lock(lock_);
00181
00182 if (!new_goal_ || !next_goal_.getGoal()) {
00183 ROS_ERROR_NAMED("actionlib",
00184 "Attempting to accept the next goal when a new goal is not available");
00185 return boost::shared_ptr<const Goal>();
00186 }
00187
00188
00189 if (isActive() &&
00190 current_goal_.getGoal() &&
00191 current_goal_ != next_goal_)
00192 {
00193 current_goal_.setCanceled(
00194 Result(),
00195 "This goal was canceled because another goal was recieved by the simple action server");
00196 }
00197
00198 ROS_DEBUG_NAMED("actionlib", "Accepting a new goal");
00199
00200
00201 current_goal_ = next_goal_;
00202 new_goal_ = false;
00203
00204
00205 preempt_request_ = new_goal_preempt_request_;
00206 new_goal_preempt_request_ = false;
00207
00208
00209 current_goal_.setAccepted("This goal has been accepted by the simple action server");
00210
00211 return current_goal_.getGoal();
00212 }
00213
00214 template<class ActionSpec>
00215 bool SimpleActionServer<ActionSpec>::isNewGoalAvailable()
00216 {
00217 return new_goal_;
00218 }
00219
00220
00221 template<class ActionSpec>
00222 bool SimpleActionServer<ActionSpec>::isPreemptRequested()
00223 {
00224 return preempt_request_;
00225 }
00226
00227 template<class ActionSpec>
00228 bool SimpleActionServer<ActionSpec>::isActive()
00229 {
00230 if (!current_goal_.getGoal()) {
00231 return false;
00232 }
00233 unsigned int status = current_goal_.getGoalStatus().status;
00234 return status == actionlib_msgs::GoalStatus::ACTIVE ||
00235 status == actionlib_msgs::GoalStatus::PREEMPTING;
00236 }
00237
00238 template<class ActionSpec>
00239 void SimpleActionServer<ActionSpec>::setSucceeded(const Result & result, const std::string & text)
00240 {
00241 boost::recursive_mutex::scoped_lock lock(lock_);
00242 ROS_DEBUG_NAMED("actionlib", "Setting the current goal as succeeded");
00243 current_goal_.setSucceeded(result, text);
00244 }
00245
00246 template<class ActionSpec>
00247 void SimpleActionServer<ActionSpec>::setAborted(const Result & result, const std::string & text)
00248 {
00249 boost::recursive_mutex::scoped_lock lock(lock_);
00250 ROS_DEBUG_NAMED("actionlib", "Setting the current goal as aborted");
00251 current_goal_.setAborted(result, text);
00252 }
00253
00254 template<class ActionSpec>
00255 void SimpleActionServer<ActionSpec>::setPreempted(const Result & result, const std::string & text)
00256 {
00257 boost::recursive_mutex::scoped_lock lock(lock_);
00258 ROS_DEBUG_NAMED("actionlib", "Setting the current goal as canceled");
00259 current_goal_.setCanceled(result, text);
00260 }
00261
00262 template<class ActionSpec>
00263 void SimpleActionServer<ActionSpec>::registerGoalCallback(boost::function<void()> cb)
00264 {
00265
00266 if (execute_callback_) {
00267 ROS_WARN_NAMED("actionlib",
00268 "Cannot call SimpleActionServer::registerGoalCallback() because an executeCallback exists. Not going to register it.");
00269 } else {
00270 goal_callback_ = cb;
00271 }
00272 }
00273
00274 template<class ActionSpec>
00275 void SimpleActionServer<ActionSpec>::registerPreemptCallback(boost::function<void()> cb)
00276 {
00277 preempt_callback_ = cb;
00278 }
00279
00280 template<class ActionSpec>
00281 void SimpleActionServer<ActionSpec>::publishFeedback(const FeedbackConstPtr & feedback)
00282 {
00283 current_goal_.publishFeedback(*feedback);
00284 }
00285
00286 template<class ActionSpec>
00287 void SimpleActionServer<ActionSpec>::publishFeedback(const Feedback & feedback)
00288 {
00289 current_goal_.publishFeedback(feedback);
00290 }
00291
00292 template<class ActionSpec>
00293 void SimpleActionServer<ActionSpec>::goalCallback(GoalHandle goal)
00294 {
00295 boost::recursive_mutex::scoped_lock lock(lock_);
00296 ROS_DEBUG_NAMED("actionlib", "A new goal has been recieved by the single goal action server");
00297
00298
00299 if ((!current_goal_.getGoal() || goal.getGoalID().stamp >= current_goal_.getGoalID().stamp) &&
00300 (!next_goal_.getGoal() || goal.getGoalID().stamp >= next_goal_.getGoalID().stamp))
00301 {
00302
00303 if (next_goal_.getGoal() && (!current_goal_.getGoal() || next_goal_ != current_goal_)) {
00304 next_goal_.setCanceled(
00305 Result(),
00306 "This goal was canceled because another goal was recieved by the simple action server");
00307 }
00308
00309 next_goal_ = goal;
00310 new_goal_ = true;
00311 new_goal_preempt_request_ = false;
00312
00313
00314 if (isActive()) {
00315 preempt_request_ = true;
00316
00317 if (preempt_callback_) {
00318 preempt_callback_();
00319 }
00320 }
00321
00322
00323 if (goal_callback_) {
00324 goal_callback_();
00325 }
00326
00327
00328 execute_condition_.notify_all();
00329 } else {
00330
00331 goal.setCanceled(
00332 Result(),
00333 "This goal was canceled because another goal was recieved by the simple action server");
00334 }
00335 }
00336
00337 template<class ActionSpec>
00338 void SimpleActionServer<ActionSpec>::preemptCallback(GoalHandle preempt)
00339 {
00340 boost::recursive_mutex::scoped_lock lock(lock_);
00341 ROS_DEBUG_NAMED("actionlib", "A preempt has been received by the SimpleActionServer");
00342
00343
00344 if (preempt == current_goal_) {
00345 ROS_DEBUG_NAMED("actionlib",
00346 "Setting preempt_request bit for the current goal to TRUE and invoking callback");
00347 preempt_request_ = true;
00348
00349
00350 if (preempt_callback_) {
00351 preempt_callback_();
00352 }
00353 } else if (preempt == next_goal_) {
00354
00355 ROS_DEBUG_NAMED("actionlib", "Setting preempt request bit for the next goal to TRUE");
00356 new_goal_preempt_request_ = true;
00357 }
00358 }
00359
00360 template<class ActionSpec>
00361 void SimpleActionServer<ActionSpec>::executeLoop()
00362 {
00363 ros::Duration loop_duration = ros::Duration().fromSec(.1);
00364
00365 while (n_.ok()) {
00366 {
00367 boost::mutex::scoped_lock terminate_lock(terminate_mutex_);
00368 if (need_to_terminate_) {
00369 break;
00370 }
00371 }
00372
00373 boost::recursive_mutex::scoped_lock lock(lock_);
00374 if (isActive()) {
00375 ROS_ERROR_NAMED("actionlib", "Should never reach this code with an active goal");
00376 } else if (isNewGoalAvailable()) {
00377 GoalConstPtr goal = acceptNewGoal();
00378
00379 ROS_FATAL_COND(!execute_callback_,
00380 "execute_callback_ must exist. This is a bug in SimpleActionServer");
00381
00382 {
00383
00384 boost::reverse_lock<boost::recursive_mutex::scoped_lock> unlocker(lock);
00385 execute_callback_(goal);
00386 }
00387
00388 if (isActive()) {
00389 ROS_WARN_NAMED("actionlib", "Your executeCallback did not set the goal to a terminal status.\n"
00390 "This is a bug in your ActionServer implementation. Fix your code!\n"
00391 "For now, the ActionServer will set this goal to aborted");
00392 setAborted(
00393 Result(),
00394 "This goal was aborted by the simple action server. The user should have set a terminal status on this goal and did not");
00395 }
00396 } else {
00397 execute_condition_.timed_wait(lock,
00398 boost::posix_time::milliseconds(static_cast<int64_t>(loop_duration.toSec() * 1000.0f)));
00399 }
00400 }
00401 }
00402
00403 template<class ActionSpec>
00404 void SimpleActionServer<ActionSpec>::start()
00405 {
00406 as_->start();
00407 }
00408
00409 }
00410
00411 #endif // ACTIONLIB__SERVER__SIMPLE_ACTION_SERVER_IMP_H_