Go to the documentation of this file.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 import rospy
00033
00034 import threading
00035 import traceback
00036
00037 from actionlib_msgs.msg import *
00038
00039 from actionlib import ActionServer
00040 from actionlib.server_goal_handle import ServerGoalHandle;
00041
00042 def nop_cb(goal_handle):
00043 pass
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 class SimpleActionServer:
00057
00058
00059
00060
00061
00062
00063 def __init__(self, name, ActionSpec, execute_cb = None, auto_start = True):
00064
00065 self.new_goal = False
00066 self.preempt_request = False
00067 self.new_goal_preempt_request = False
00068
00069 self.execute_callback = execute_cb;
00070 self.goal_callback = None;
00071 self.preempt_callback = None;
00072
00073 self.need_to_terminate = False
00074 self.terminate_mutex = threading.RLock();
00075 self.lock = threading.RLock();
00076
00077 self.execute_condition = threading.Condition(self.lock);
00078
00079 self.current_goal = ServerGoalHandle();
00080 self.next_goal = ServerGoalHandle();
00081
00082 if self.execute_callback:
00083 self.execute_thread = threading.Thread(None, self.executeLoop);
00084 self.execute_thread.start();
00085 else:
00086 self.execute_thread = None
00087
00088
00089 self.action_server = ActionServer(name, ActionSpec, self.internal_goal_callback,self.internal_preempt_callback,auto_start);
00090
00091
00092 def __del__(self):
00093 if hasattr(self, 'execute_callback') and self.execute_callback:
00094 with self.terminate_mutex:
00095 self.need_to_terminate = True;
00096
00097 assert(self.execute_thread);
00098 self.execute_thread.join();
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110 def accept_new_goal(self):
00111 with self.lock:
00112 if not self.new_goal or not self.next_goal.get_goal():
00113 rospy.logerr("Attempting to accept the next goal when a new goal is not available");
00114 return None;
00115
00116
00117 if self.is_active() and self.current_goal.get_goal() and self.current_goal != self.next_goal:
00118 self.current_goal.set_canceled(None, "This goal was canceled because another goal was received by the simple action server");
00119
00120 rospy.logdebug("Accepting a new goal");
00121
00122
00123 self.current_goal = self.next_goal;
00124 self.new_goal = False;
00125
00126
00127 self.preempt_request = self.new_goal_preempt_request;
00128 self.new_goal_preempt_request = False;
00129
00130
00131 self.current_goal.set_accepted("This goal has been accepted by the simple action server");
00132
00133 return self.current_goal.get_goal();
00134
00135
00136
00137
00138 def is_new_goal_available(self):
00139 return self.new_goal;
00140
00141
00142
00143
00144 def is_preempt_requested(self):
00145 return self.preempt_request;
00146
00147
00148
00149 def is_active(self):
00150 if not self.current_goal.get_goal():
00151 return False;
00152
00153 status = self.current_goal.get_goal_status().status;
00154 return status == actionlib_msgs.msg.GoalStatus.ACTIVE or status == actionlib_msgs.msg.GoalStatus.PREEMPTING;
00155
00156
00157
00158 def set_succeeded(self,result=None, text=""):
00159 with self.lock:
00160 if not result:
00161 result=self.get_default_result();
00162 self.current_goal.set_succeeded(result, text);
00163
00164
00165
00166 def set_aborted(self, result = None, text=""):
00167 with self.lock:
00168 if not result:
00169 result=self.get_default_result();
00170 self.current_goal.set_aborted(result, text);
00171
00172
00173
00174 def publish_feedback(self,feedback):
00175 self.current_goal.publish_feedback(feedback);
00176
00177
00178 def get_default_result(self):
00179 return self.action_server.ActionResultType();
00180
00181
00182
00183 def set_preempted(self,result=None, text=""):
00184 if not result:
00185 result=self.get_default_result();
00186 with self.lock:
00187 rospy.logdebug("Setting the current goal as canceled");
00188 self.current_goal.set_canceled(result, text);
00189
00190
00191
00192 def register_goal_callback(self,cb):
00193 if self.execute_callback:
00194 rospy.logwarn("Cannot call SimpleActionServer.register_goal_callback() because an executeCallback exists. Not going to register it.");
00195 else:
00196 self.goal_callback = cb;
00197
00198
00199
00200 def register_preempt_callback(self, cb):
00201 self.preempt_callback = cb;
00202
00203
00204
00205 def start(self):
00206 self.action_server.start();
00207
00208
00209
00210 def internal_goal_callback(self, goal):
00211 self.execute_condition.acquire();
00212
00213 try:
00214 rospy.logdebug("A new goal %shas been recieved by the single goal action server",goal.get_goal_id().id);
00215
00216
00217 if((not self.current_goal.get_goal() or goal.get_goal_id().stamp >= self.current_goal.get_goal_id().stamp)
00218 and (not self.next_goal.get_goal() or goal.get_goal_id().stamp >= self.next_goal.get_goal_id().stamp)):
00219
00220 if(self.next_goal.get_goal() and (not self.current_goal.get_goal() or self.next_goal != self.current_goal)):
00221 self.next_goal.set_canceled(None, "This goal was canceled because another goal was received by the simple action server");
00222
00223 self.next_goal = goal;
00224 self.new_goal = True;
00225 self.new_goal_preempt_request = False;
00226
00227
00228 if(self.is_active()):
00229 self.preempt_request = True;
00230
00231 if(self.preempt_callback):
00232 self.preempt_callback();
00233
00234
00235 if self.goal_callback:
00236 self.goal_callback();
00237
00238
00239 self.execute_condition.notify();
00240 self.execute_condition.release();
00241 else:
00242
00243 goal.set_canceled(None, "This goal was canceled because another goal was received by the simple action server");
00244 self.execute_condition.release();
00245 except Exception, e:
00246 rospy.logerr("SimpleActionServer.internal_goal_callback - exception %s",str(e))
00247 self.execute_condition.release();
00248
00249
00250 def internal_preempt_callback(self,preempt):
00251 with self.lock:
00252 rospy.logdebug("A preempt has been received by the SimpleActionServer");
00253
00254
00255 if(preempt == self.current_goal):
00256 rospy.logdebug("Setting preempt_request bit for the current goal to TRUE and invoking callback");
00257 self.preempt_request = True;
00258
00259
00260 if(self.preempt_callback):
00261 self.preempt_callback();
00262
00263 elif(preempt == self.next_goal):
00264 rospy.logdebug("Setting preempt request bit for the next goal to TRUE");
00265 self.new_goal_preempt_request = True;
00266
00267
00268 def executeLoop(self):
00269 loop_duration = rospy.Duration.from_sec(.1);
00270
00271 while (not rospy.is_shutdown()):
00272 rospy.logdebug("SAS: execute");
00273
00274 with self.terminate_mutex:
00275 if (self.need_to_terminate):
00276 break;
00277
00278 shall_run=False;
00279 with self.lock:
00280 if (self.is_active()):
00281 rospy.logerr("Should never reach this code with an active goal");
00282 return
00283 elif (self.is_new_goal_available()):
00284 goal = self.accept_new_goal();
00285 if not self.execute_callback:
00286 rospy.logerr("execute_callback_ must exist. This is a bug in SimpleActionServer");
00287 return
00288 shall_run=True
00289
00290 if shall_run:
00291 try:
00292 self.execute_callback(goal)
00293
00294 if self.is_active():
00295 rospy.logwarn("Your executeCallback did not set the goal to a terminal status. " +
00296 "This is a bug in your ActionServer implementation. Fix your code! "+
00297 "For now, the ActionServer will set this goal to aborted");
00298 self.set_aborted(None, "No terminal state was set.");
00299 except Exception, ex:
00300 rospy.logerr("Exception in your execute callback: %s\n%s", str(ex),
00301 traceback.format_exc())
00302 self.set_aborted(None, "Exception in execute callback: %s" % str(ex))
00303
00304 with self.execute_condition:
00305 self.execute_condition.wait(loop_duration.to_sec());
00306
00307
00308