simple_action_server_imp.h
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 * Software License Agreement (BSD License)
00004 *
00005 *  Copyright (c) 2008, Willow Garage, Inc.
00006 *  All rights reserved.
00007 *
00008 *  Redistribution and use in source and binary forms, with or without
00009 *  modification, are permitted provided that the following conditions
00010 *  are met:
00011 *
00012 *   * Redistributions of source code must retain the above copyright
00013 *     notice, this list of conditions and the following disclaimer.
00014 *   * Redistributions in binary form must reproduce the above
00015 *     copyright notice, this list of conditions and the following
00016 *     disclaimer in the documentation and/or other materials provided
00017 *     with the distribution.
00018 *   * Neither the name of Willow Garage, Inc. nor the names of its
00019 *     contributors may be used to endorse or promote products derived
00020 *     from this software without specific prior written permission.
00021 *
00022 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 *  POSSIBILITY OF SUCH DAMAGE.
00034 *
00035 * Author: Eitan Marder-Eppstein
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   // create the action server
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   // create the action server
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   // create the action server
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   // create the action server
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   // create the action server
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   // create the action server
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   // check if we need to send a preempted message for the goal that we're currently pursuing
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   // accept the next goal
00201   current_goal_ = next_goal_;
00202   new_goal_ = false;
00203 
00204   // set preempt to request to equal the preempt state of the new goal
00205   preempt_request_ = new_goal_preempt_request_;
00206   new_goal_preempt_request_ = false;
00207 
00208   // set the status of the current goal to be active
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   // Cannot register a goal callback if an execute callback exists
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   // check that the timestamp is past or equal to that of the current goal and the next goal
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     // if next_goal has not been accepted already... its going to get bumped, but we need to let the client know we're preempting
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     // if the server is active, we'll want to call the preempt callback for the current goal
00314     if (isActive()) {
00315       preempt_request_ = true;
00316       // if the user has registered a preempt callback, we'll call it now
00317       if (preempt_callback_) {
00318         preempt_callback_();
00319       }
00320     }
00321 
00322     // if the user has defined a goal callback, we'll call it now
00323     if (goal_callback_) {
00324       goal_callback_();
00325     }
00326 
00327     // Trigger runLoop to call execute()
00328     execute_condition_.notify_all();
00329   } else {
00330     // the goal requested has already been preempted by a different goal, so we're not going to execute it
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   // if the preempt is for the current goal, then we'll set the preemptRequest flag and call the user's preempt callback
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     // if the user has registered a preempt callback, we'll call it now
00350     if (preempt_callback_) {
00351       preempt_callback_();
00352     }
00353   } else if (preempt == next_goal_) {
00354     // if the preempt applies to the next goal, we'll set the preempt bit for that
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         // Make sure we're not locked when we call execute
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 }  // namespace actionlib
00410 
00411 #endif  // ACTIONLIB__SERVER__SIMPLE_ACTION_SERVER_IMP_H_


actionlib
Author(s): Eitan Marder-Eppstein, Vijay Pradeep, Mikael Arguedas
autogenerated on Sat Feb 16 2019 03:21:28