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_ACTION_SERVER_IMP_H_
00038 #define ACTIONLIB_ACTION_SERVER_IMP_H_
00039 namespace actionlib {
00040 template <class ActionSpec>
00041 ActionServer<ActionSpec>::ActionServer(ros::NodeHandle n, std::string name,
00042 bool auto_start)
00043 : node_(n, name), goal_callback_(boost::function<void (GoalHandle)>()),
00044 cancel_callback_(boost::function<void (GoalHandle)>()), started_(auto_start), guard_(new DestructionGuard){
00045
00046 if(started_){
00047 ROS_WARN_NAMED("actionlib", "You've passed in true for auto_start for the C++ action server at [%s]. You should always pass in false to avoid race conditions.", node_.getNamespace().c_str());
00048 initialize();
00049 publishStatus();
00050 }
00051 }
00052
00053 template <class ActionSpec>
00054 ActionServer<ActionSpec>::ActionServer(ros::NodeHandle n, std::string name)
00055 : node_(n, name), goal_callback_(boost::function<void (GoalHandle)>()),
00056 cancel_callback_(boost::function<void (GoalHandle)>()), started_(true), guard_(new DestructionGuard){
00057
00058 if(started_){
00059 ROS_WARN_NAMED("actionlib", "You've passed in true for auto_start for the C++ action server at [%s]. You should always pass in false to avoid race conditions.", node_.getNamespace().c_str());
00060 initialize();
00061 publishStatus();
00062 }
00063 }
00064
00065 template <class ActionSpec>
00066 ActionServer<ActionSpec>::ActionServer(ros::NodeHandle n, std::string name,
00067 boost::function<void (GoalHandle)> goal_cb,
00068 boost::function<void (GoalHandle)> cancel_cb,
00069 bool auto_start)
00070 : node_(n, name), goal_callback_(goal_cb), cancel_callback_(cancel_cb), started_(auto_start), guard_(new DestructionGuard) {
00071
00072 if(started_){
00073 ROS_WARN_NAMED("actionlib", "You've passed in true for auto_start for the C++ action server at [%s]. You should always pass in false to avoid race conditions.", node_.getNamespace().c_str());
00074 initialize();
00075 publishStatus();
00076 }
00077 }
00078
00079 template <class ActionSpec>
00080 ActionServer<ActionSpec>::ActionServer(ros::NodeHandle n, std::string name,
00081 boost::function<void (GoalHandle)> goal_cb,
00082 boost::function<void (GoalHandle)> cancel_cb)
00083 : node_(n, name), goal_callback_(goal_cb), cancel_callback_(cancel_cb), started_(true), guard_(new DestructionGuard) {
00084
00085 if(started_){
00086 ROS_WARN_NAMED("actionlib", "You've passed in true for auto_start for the C++ action server at [%s]. You should always pass in false to avoid race conditions.", node_.getNamespace().c_str());
00087 initialize();
00088 publishStatus();
00089 }
00090 }
00091
00092 template <class ActionSpec>
00093 ActionServer<ActionSpec>::ActionServer(ros::NodeHandle n, std::string name,
00094 boost::function<void (GoalHandle)> goal_cb,
00095 bool auto_start)
00096 : node_(n, name), goal_callback_(goal_cb), cancel_callback_(boost::function<void (GoalHandle)>()), started_(auto_start), guard_(new DestructionGuard) {
00097
00098 if(started_){
00099 ROS_WARN_NAMED("actionlib", "You've passed in true for auto_start for the C++ action server at [%s]. You should always pass in false to avoid race conditions.", node_.getNamespace().c_str());
00100 initialize();
00101 publishStatus();
00102 }
00103 }
00104
00105 template <class ActionSpec>
00106 ActionServer<ActionSpec>::~ActionServer(){
00107
00108 guard_->destruct();
00109 }
00110
00111 template <class ActionSpec>
00112 void ActionServer<ActionSpec>::initialize(){
00113 result_pub_ = node_.advertise<ActionResult>("result", 50);
00114 feedback_pub_ = node_.advertise<ActionFeedback>("feedback", 50);
00115 status_pub_ = node_.advertise<actionlib_msgs::GoalStatusArray>("status", 50, true);
00116
00117
00118
00119 double status_frequency, status_list_timeout;
00120 if(!node_.getParam("status_frequency", status_frequency))
00121 {
00122 std::string status_frequency_param_name;
00123 if(!node_.searchParam("actionlib_status_frequency", status_frequency_param_name))
00124 status_frequency = 5.0;
00125 else
00126 node_.param(status_frequency_param_name, status_frequency, 5.0);
00127 }
00128 else
00129 ROS_WARN_NAMED("actionlib", "You're using the deprecated status_frequency parameter, please switch to actionlib_status_frequency.");
00130
00131 node_.param("status_list_timeout", status_list_timeout, 5.0);
00132
00133 status_list_timeout_ = ros::Duration(status_list_timeout);
00134
00135 if(status_frequency > 0){
00136 status_timer_ = node_.createTimer(ros::Duration(1.0 / status_frequency),
00137 boost::bind(&ActionServer::publishStatus, this, _1));
00138 }
00139
00140 goal_sub_ = node_.subscribe<ActionGoal>("goal", 50,
00141 boost::bind(&ActionServer::goalCallback, this, _1));
00142
00143 cancel_sub_ = node_.subscribe<actionlib_msgs::GoalID>("cancel", 50,
00144 boost::bind(&ActionServer::cancelCallback, this, _1));
00145
00146 }
00147
00148 template <class ActionSpec>
00149 void ActionServer<ActionSpec>::registerGoalCallback(boost::function<void (GoalHandle)> cb){
00150 goal_callback_ = cb;
00151 }
00152
00153 template <class ActionSpec>
00154 void ActionServer<ActionSpec>::registerCancelCallback(boost::function<void (GoalHandle)> cb){
00155 cancel_callback_ = cb;
00156 }
00157
00158 template <class ActionSpec>
00159 void ActionServer<ActionSpec>::publishResult(const actionlib_msgs::GoalStatus& status, const Result& result){
00160 boost::recursive_mutex::scoped_lock lock(lock_);
00161
00162 boost::shared_ptr<ActionResult> ar(new ActionResult);
00163 ar->header.stamp = ros::Time::now();
00164 ar->status = status;
00165 ar->result = result;
00166 ROS_DEBUG_NAMED("actionlib", "Publishing result for goal with id: %s and stamp: %.2f", status.goal_id.id.c_str(), status.goal_id.stamp.toSec());
00167 result_pub_.publish(ar);
00168 publishStatus();
00169 }
00170
00171 template <class ActionSpec>
00172 void ActionServer<ActionSpec>::publishFeedback(const actionlib_msgs::GoalStatus& status, const Feedback& feedback){
00173 boost::recursive_mutex::scoped_lock lock(lock_);
00174
00175 boost::shared_ptr<ActionFeedback> af(new ActionFeedback);
00176 af->header.stamp = ros::Time::now();
00177 af->status = status;
00178 af->feedback = feedback;
00179 ROS_DEBUG_NAMED("actionlib", "Publishing feedback for goal with id: %s and stamp: %.2f", status.goal_id.id.c_str(), status.goal_id.stamp.toSec());
00180 feedback_pub_.publish(af);
00181 }
00182
00183 template <class ActionSpec>
00184 void ActionServer<ActionSpec>::cancelCallback(const boost::shared_ptr<const actionlib_msgs::GoalID>& goal_id){
00185 boost::recursive_mutex::scoped_lock lock(lock_);
00186
00187
00188 if(!started_)
00189 return;
00190
00191
00192 ROS_DEBUG_NAMED("actionlib", "The action server has received a new cancel request");
00193 bool goal_id_found = false;
00194 for(typename std::list<StatusTracker<ActionSpec> >::iterator it = status_list_.begin(); it != status_list_.end(); ++it){
00195
00196
00197 if(
00198 (goal_id->id == "" && goal_id->stamp == ros::Time())
00199 || goal_id->id == (*it).status_.goal_id.id
00200 || (goal_id->stamp != ros::Time() && (*it).status_.goal_id.stamp <= goal_id->stamp)
00201 ){
00202
00203 if(goal_id->id == (*it).status_.goal_id.id)
00204 goal_id_found = true;
00205
00206
00207 boost::shared_ptr<void> handle_tracker = (*it).handle_tracker_.lock();
00208
00209 if((*it).handle_tracker_.expired()){
00210
00211 HandleTrackerDeleter<ActionSpec> d(this, it, guard_);
00212 handle_tracker = boost::shared_ptr<void>((void *)NULL, d);
00213 (*it).handle_tracker_ = handle_tracker;
00214
00215
00216 (*it).handle_destruction_time_ = ros::Time();
00217 }
00218
00219
00220
00221 GoalHandle gh(it, this, handle_tracker, guard_);
00222 if(gh.setCancelRequested()){
00223
00224 lock_.unlock();
00225
00226
00227 cancel_callback_(gh);
00228
00229
00230 lock_.lock();
00231 }
00232 }
00233 }
00234
00235
00236 if(goal_id->id != "" && !goal_id_found){
00237 typename std::list<StatusTracker<ActionSpec> >::iterator it = status_list_.insert(status_list_.end(),
00238 StatusTracker<ActionSpec> (*goal_id, actionlib_msgs::GoalStatus::RECALLING));
00239
00240 (*it).handle_destruction_time_ = ros::Time::now();
00241 }
00242
00243
00244 if(goal_id->stamp > last_cancel_)
00245 last_cancel_ = goal_id->stamp;
00246 }
00247
00248 template <class ActionSpec>
00249 void ActionServer<ActionSpec>::goalCallback(const boost::shared_ptr<const ActionGoal>& goal){
00250 boost::recursive_mutex::scoped_lock lock(lock_);
00251
00252
00253 if(!started_)
00254 return;
00255
00256 ROS_DEBUG_NAMED("actionlib", "The action server has received a new goal request");
00257
00258
00259 for(typename std::list<StatusTracker<ActionSpec> >::iterator it = status_list_.begin(); it != status_list_.end(); ++it){
00260 if(goal->goal_id.id == (*it).status_.goal_id.id){
00261
00262
00263 if ( (*it).status_.status == actionlib_msgs::GoalStatus::RECALLING ) {
00264 (*it).status_.status = actionlib_msgs::GoalStatus::RECALLED;
00265 publishResult((*it).status_, Result());
00266 }
00267
00268
00269
00270 if((*it).handle_tracker_.expired()){
00271 (*it).handle_destruction_time_ = ros::Time::now();
00272 }
00273
00274
00275 return;
00276 }
00277 }
00278
00279
00280 typename std::list<StatusTracker<ActionSpec> >::iterator it = status_list_.insert(status_list_.end(), StatusTracker<ActionSpec> (goal));
00281
00282
00283 HandleTrackerDeleter<ActionSpec> d(this, it, guard_);
00284 boost::shared_ptr<void> handle_tracker((void *)NULL, d);
00285 (*it).handle_tracker_ = handle_tracker;
00286
00287
00288 if(goal->goal_id.stamp != ros::Time() && goal->goal_id.stamp <= last_cancel_){
00289
00290 GoalHandle gh(it, this, handle_tracker, guard_);
00291 gh.setCanceled(Result(), "This goal handle was canceled by the action server because its timestamp is before the timestamp of the last cancel request");
00292 }
00293 else{
00294 GoalHandle gh = GoalHandle(it, this, handle_tracker, guard_);
00295
00296
00297 lock_.unlock();
00298
00299
00300 goal_callback_(gh);
00301
00302 lock_.lock();
00303 }
00304 }
00305
00306 template <class ActionSpec>
00307 void ActionServer<ActionSpec>::start(){
00308 initialize();
00309 started_ = true;
00310 publishStatus();
00311 }
00312
00313 template <class ActionSpec>
00314 void ActionServer<ActionSpec>::publishStatus(const ros::TimerEvent& e){
00315 boost::recursive_mutex::scoped_lock lock(lock_);
00316
00317 if(!started_)
00318 return;
00319
00320 publishStatus();
00321 }
00322
00323 template <class ActionSpec>
00324 void ActionServer<ActionSpec>::publishStatus(){
00325 boost::recursive_mutex::scoped_lock lock(lock_);
00326
00327 actionlib_msgs::GoalStatusArray status_array;
00328
00329 status_array.header.stamp = ros::Time::now();
00330
00331 status_array.status_list.resize(status_list_.size());
00332
00333 unsigned int i = 0;
00334 for(typename std::list<StatusTracker<ActionSpec> >::iterator it = status_list_.begin(); it != status_list_.end();){
00335 status_array.status_list[i] = (*it).status_;
00336
00337
00338 if((*it).handle_destruction_time_ != ros::Time()
00339 && (*it).handle_destruction_time_ + status_list_timeout_ < ros::Time::now()){
00340 it = status_list_.erase(it);
00341 }
00342 else
00343 ++it;
00344
00345 ++i;
00346 }
00347
00348 status_pub_.publish(status_array);
00349 }
00350 };
00351 #endif