11 from ast
import literal_eval
as cast
13 from flexbe_core
import Logger, BehaviorLibrary
16 from flexbe_msgs.msg
import BehaviorSelection, BEStatus, CommandFeedback
17 from std_msgs.msg
import Empty
22 Controls the execution of robot behaviors. 40 self.
_pub = ProxyPublisher({
42 'flexbe/heartbeat': Empty
44 self._pub.createPublisher(self.
status_topic, BEStatus, _latch=
True)
53 self.
_sub = ProxySubscriberCached()
54 self._sub.subscribe(
'flexbe/start_behavior', BehaviorSelection, self.
_behavior_callback)
57 self._pub.publish(self.
status_topic, BEStatus(code=BEStatus.READY))
58 rospy.loginfo(
'\033[92m--- Behavior Engine ready! ---\033[0m')
72 Logger.loginfo(
'--> Initiating behavior switch...')
73 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'received']))
75 Logger.loginfo(
'--> Starting new behavior...')
80 Logger.logerr(
'Dropped behavior start request because preparation failed.')
82 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'failed']))
84 rospy.loginfo(
'\033[92m--- Behavior Engine ready! ---\033[0m')
91 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'start']))
94 Logger.logerr(
'Dropped behavior start request because switching is not possible.')
95 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'not_switchable']))
98 rate = rospy.Rate(100)
99 while not rospy.is_shutdown():
100 active_state = self.be.get_current_state()
101 if active_state
is not None or not self.
_running:
105 if active_state
is not None:
106 rospy.loginfo(
"Current state %s is kept active.", active_state.name)
108 be.prepare_for_switch(active_state)
109 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'prepared']))
110 except Exception
as e:
111 Logger.logerr(
'Failed to prepare behavior switch:\n%s' % str(e))
112 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'failed']))
115 rospy.loginfo(
'Preempting current behavior version...')
126 rospy.loginfo(
'Behavior ready, execution starts now.')
127 rospy.loginfo(
'[%s : %s]', be.name, msg.behavior_checksum)
129 args = [self.be.requested_state_path]
if self.be.requested_state_path
is not None else []
131 BEStatus(behavior_id=self.be.id, code=BEStatus.STARTED, args=args))
132 result = self.be.execute()
135 BEStatus(behavior_id=self.be.id, code=BEStatus.SWITCHING))
138 BEStatus(behavior_id=self.be.id, code=BEStatus.FINISHED, args=[str(result)]))
139 except Exception
as e:
140 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.FAILED))
141 Logger.logerr(
'Behavior execution failed!\n%s' % str(e))
143 Logger.loginfo(traceback.format_exc())
144 result = result
or "exception" 153 except Exception
as e:
154 rospy.logerr(
'Failed to clean up behavior:\n%s' % str(e))
157 Logger.loginfo(
'Behavior execution finished with result %s.', str(result))
158 rospy.loginfo(
'\033[92m--- Behavior Engine ready! ---\033[0m')
169 behavior = self._behavior_lib.get_behavior(msg.behavior_id)
171 raise ValueError(msg.behavior_id)
172 be_filepath = self._behavior_lib.get_sourcecode_filepath(msg.behavior_id, add_tmp=
True)
173 if os.path.isfile(be_filepath):
174 be_file = open(be_filepath,
"r") 175 rospy.logwarn("Found a tmp version of the referred behavior! Assuming local test run.")
177 be_filepath = self._behavior_lib.get_sourcecode_filepath(msg.behavior_id)
178 be_file = open(be_filepath,
"r") 180 be_content = be_file.read()
183 except Exception
as e:
184 Logger.logerr(
'Failed to retrieve behavior from library:\n%s' % str(e))
185 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
192 for mod
in msg.modifications:
193 file_content += be_content[last_index:mod.index_begin] + mod.new_content
194 last_index = mod.index_end
195 file_content += be_content[last_index:]
196 if zlib.adler32(file_content.encode()) & 0x7fffffff != msg.behavior_checksum:
197 mismatch_msg = (
"Checksum mismatch of behavior versions! \n" 198 "Attempted to load behavior: %s\n" 199 "Make sure that all computers are on the same version a.\n" 200 "Also try: rosrun flexbe_widget clear_cache" % str(be_filepath))
201 raise Exception(mismatch_msg)
203 rospy.loginfo(
"Successfully applied %d modifications." % len(msg.modifications))
204 except Exception
as e:
205 Logger.logerr(
'Failed to apply behavior modifications:\n%s' % str(e))
206 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
211 file_path = os.path.join(self.
_tmp_folder,
'tmp_%d.py' % msg.behavior_checksum)
212 with open(file_path,
"w")
as sc_file:
213 sc_file.write(file_content)
214 except Exception
as e:
215 Logger.logerr(
'Failed to create temporary file for behavior class:\n%s' % str(e))
216 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
222 package = __import__(
"tmp_%d" % msg.behavior_checksum, fromlist=[
"tmp_%d" % msg.behavior_checksum])
223 clsmembers = inspect.getmembers(package,
lambda member: (inspect.isclass(member)
and 224 member.__module__ == package.__name__))
225 beclass = clsmembers[0][1]
227 rospy.loginfo(
'Behavior ' + be.name +
' created.')
228 except Exception
as e:
229 Logger.logerr(
'Exception caught in behavior definition:\n%s\n' 230 'See onboard terminal for more information.' % str(e))
232 traceback.print_exc()
233 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
239 if len(msg.arg_keys) > 0:
240 rospy.loginfo(
'The following parameters will be used:')
242 for i
in range(len(msg.arg_keys)):
244 if msg.arg_keys[i] ==
'':
246 found = be.set_parameter(msg.arg_keys[i], msg.arg_values[i])
248 name_split = msg.arg_keys[i].rsplit(
'/', 1)
249 behavior = name_split[0]
if len(name_split) == 2
else '' 251 suffix =
' (' + behavior +
')' if behavior !=
'' else '' 252 rospy.loginfo(key +
' = ' + msg.arg_values[i] + suffix)
254 rospy.logwarn(
'Parameter ' + msg.arg_keys[i] +
' (set to ' + msg.arg_values[i] +
') not defined')
255 except Exception
as e:
256 Logger.logerr(
'Failed to initialize parameters:\n%s' % str(e))
257 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
262 be.set_up(id=msg.behavior_checksum, autonomy_level=msg.autonomy_level, debug=
False)
264 rospy.loginfo(
'State machine built.')
265 except Exception
as e:
266 Logger.logerr(
'Behavior construction failed!\n%s\n' 267 'See onboard terminal for more information.' % str(e))
269 traceback.print_exc()
270 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
282 if self.be.name != be.name:
283 Logger.logerr(
'Unable to switch behavior, names do not match:\ncurrent: %s <--> new: %s' %
284 (self.be.name, be.name))
292 file_path = os.path.join(self.
_tmp_folder,
'tmp_%d.pyc' % behavior_checksum)
298 os.remove(file_path +
'c')
304 if module
in sys.modules:
305 del sys.modules[module]
316 for k, v
in zip(keys, values):
325 except SyntaxError
as se:
326 Logger.loginfo(
'Unable to parse input value for key "%s", assuming string:\n%s\n%s' %
327 (k, str(v), str(se)))
338 self._pub.publish(
'flexbe/heartbeat', Empty())
342 if isinstance(o, list):
344 elif isinstance(o, dict):
350 __getattr__ = dict.__getitem__
352 @contextlib.contextmanager
354 previous_modules = set(sys.modules.keys())
358 self._tracked_imports.extend(set(sys.modules.keys()) - previous_modules)
def _behavior_execution(self, msg)
def _prepare_behavior(self, msg)
def _convert_input_data(self, keys, values)
def _convert_dict(self, o)
def _cleanup_behavior(self, behavior_checksum)
def _is_switchable(self, be)
def _behavior_callback(self, msg)
def _execute_heartbeat(self)
def _cleanup_tempdir(self)
def _heartbeat_worker(self)