3 import roslib; roslib.load_manifest(
'flexbe_onboard')
15 import xml.etree.ElementTree
as ET
16 from ast
import literal_eval
as cast
18 from flexbe_core
import Logger, BehaviorLibrary
20 from flexbe_msgs.msg
import BehaviorSelection, BEStatus, ContainerStructure, CommandFeedback
23 from std_msgs.msg
import Int32, Empty
29 @author: Philipp Schillinger 34 Implements an idle state where the robot waits for a behavior to be started. 63 self.
_pub = ProxyPublisher()
64 self.
_sub = ProxySubscriberCached()
69 self._pub.createPublisher(self.
status_topic, BEStatus, _latch =
True)
75 self._sub.subscribe(
'flexbe/start_behavior', BehaviorSelection, self.
_behavior_callback)
78 self._pub.createPublisher(
'flexbe/heartbeat', Empty)
82 self._pub.publish(self.
status_topic, BEStatus(code=BEStatus.READY))
83 rospy.loginfo(
'\033[92m--- Behavior Engine ready! ---\033[0m')
93 Logger.loginfo(
'--> Initiating behavior switch...')
94 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'received']))
96 Logger.loginfo(
'--> Starting new behavior...')
100 Logger.logerr(
'Dropped behavior start request because preparation failed.')
102 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'failed']))
104 rospy.loginfo(
'\033[92m--- Behavior Engine ready! ---\033[0m')
109 Logger.logwarn(
'Already switching, dropped new start request.')
111 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'start']))
113 Logger.logerr(
'Dropped behavior start request because switching is not possible.')
114 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'not_switchable']))
117 active_state = self.be.get_current_state()
118 rospy.loginfo(
"Current state %s is kept active.", active_state.name)
120 be.prepare_for_switch(active_state)
121 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'prepared']))
122 except Exception
as e:
123 Logger.logerr(
'Failed to prepare behavior switch:\n%s' % str(e))
125 self._pub.publish(self.
feedback_topic, CommandFeedback(command=
"switch", args=[
'failed']))
127 rospy.loginfo(
'Preempting current behavior version...')
128 self.be.preempt_for_switch()
129 rate = rospy.Rate(10)
139 rospy.loginfo(
'Behavior ready, execution starts now.')
140 rospy.loginfo(
'[%s : %s]', be.name, msg.behavior_checksum)
142 args = [self.be.requested_state_path]
if self.be.requested_state_path
is not None else []
143 self._pub.publish(self.
status_topic, BEStatus(behavior_id=self.be.id, code=BEStatus.STARTED, args=args))
144 result = self.be.execute()
146 self._pub.publish(self.
status_topic, BEStatus(behavior_id=self.be.id, code=BEStatus.SWITCHING))
148 self._pub.publish(self.
status_topic, BEStatus(behavior_id=self.be.id, code=BEStatus.FINISHED, args=[str(result)]))
149 except Exception
as e:
150 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.FAILED))
151 Logger.logerr(
'Behavior execution failed!\n%s' % str(e))
153 Logger.loginfo(traceback.format_exc())
158 except Exception
as e:
159 rospy.logerr(
'Failed to clean up behavior:\n%s' % str(e))
163 rospy.loginfo(
'Behavior execution finished with result %s.', str(result))
164 rospy.loginfo(
'\033[92m--- Behavior Engine ready! ---\033[0m')
171 rp = rospkg.RosPack()
172 behavior = self._behavior_lib.get_behavior(msg.behavior_id)
174 raise ValueError(msg.behavior_id)
175 be_filepath = os.path.join(rp.get_path(behavior[
"package"]),
'src/' + behavior[
"package"] +
'/' + behavior[
"file"] +
'_tmp.py')
176 if os.path.isfile(be_filepath):
177 be_file = open(be_filepath,
"r") 178 rospy.logwarn("Found a tmp version of the referred behavior! Assuming local test run.")
180 be_filepath = os.path.join(rp.get_path(behavior[
"package"]),
'src/' + behavior[
"package"] +
'/' + behavior[
"file"] +
'.py')
181 be_file = open(be_filepath,
"r") 182 be_content = be_file.read() 184 except Exception
as e:
185 Logger.logerr(
'Failed to retrieve behavior from library:\n%s' % str(e))
186 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
193 for mod
in msg.modifications:
194 file_content += be_content[last_index:mod.index_begin] + mod.new_content
195 last_index = mod.index_end
196 file_content += be_content[last_index:]
197 if zlib.adler32(file_content) != msg.behavior_checksum:
198 mismatch_msg = (
"Checksum mismatch of behavior versions! \n" 199 "Attempted to load behavior: %s\n" 200 "Make sure that all computers are on the same version a.\n" 201 "Also try: rosrun flexbe_widget clear_cache" % str(be_filepath))
202 raise Exception(mismatch_msg)
204 rospy.loginfo(
"Successfully applied %d modifications." % len(msg.modifications))
205 except Exception
as e:
206 Logger.logerr(
'Failed to apply behavior modifications:\n%s' % str(e))
207 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
212 file_path = os.path.join(self.
_tmp_folder,
'tmp_%d.py' % msg.behavior_checksum)
213 sc_file = open(file_path,
"w")
214 sc_file.write(file_content)
216 except Exception
as e:
217 Logger.logerr(
'Failed to create temporary file for behavior class:\n%s' % str(e))
218 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
223 package = __import__(
"tmp_%d" % msg.behavior_checksum, fromlist=[
"tmp_%d" % msg.behavior_checksum])
224 clsmembers = inspect.getmembers(package,
lambda member: inspect.isclass(member)
and 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' % str(e))
230 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
237 except Exception
as e:
238 Logger.logerr(
'Failed to load contained behaviors:\n%s' % str(e))
242 if len(msg.arg_keys) > 0:
243 rospy.loginfo(
'The following parameters will be used:')
245 for i
in range(len(msg.arg_keys)):
246 if msg.arg_keys[i] ==
'':
249 key_splitted = msg.arg_keys[i].rsplit(
'/', 1)
250 if len(key_splitted) == 1:
252 key = key_splitted[0]
253 rospy.logwarn(
'Parameter key %s has no path specification, assuming: /%s' % (key, key))
255 behavior = key_splitted[0]
256 key = key_splitted[1]
259 if behavior ==
'' and hasattr(be, key):
262 for b
in contain_list:
263 if hasattr(contain_list[b], key):
267 for b
in contain_list:
268 if b == behavior
and hasattr(contain_list[b], key):
273 rospy.logwarn(
'Parameter ' + msg.arg_keys[i] +
' (set to ' + msg.arg_values[i] +
') not implemented')
275 except Exception
as e:
276 Logger.logerr(
'Failed to initialize parameters:\n%s' % str(e))
277 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
282 be.set_up(id=msg.behavior_checksum, autonomy_level=msg.autonomy_level, debug=
False)
284 rospy.loginfo(
'State machine built.')
285 except Exception
as e:
286 Logger.logerr(
'Behavior construction failed!\n%s' % str(e))
287 self._pub.publish(self.
status_topic, BEStatus(behavior_id=msg.behavior_checksum, code=BEStatus.ERROR))
294 if self.be.name != be.name:
295 Logger.logerr(
'Unable to switch behavior, names do not match:\ncurrent: %s <--> new: %s' % (self.be.name, be.name))
308 del(sys.modules[
"tmp_%d" % behavior_checksum])
309 file_path = os.path.join(self.
_tmp_folder,
'tmp_%d.pyc' % behavior_checksum)
315 os.remove(file_path +
'c')
321 attr = getattr(obj, name)
322 if type(attr)
is int:
324 elif type(attr)
is long:
326 elif type(attr)
is float:
328 elif type(attr)
is bool:
329 value = (value !=
"0")
330 elif type(attr)
is dict:
331 value = yaml.load(value)
332 setattr(obj, name, value)
333 suffix =
' (' + behavior +
')' if behavior !=
'' else '' 334 rospy.loginfo(name +
' = ' + str(value) + suffix)
340 for k, v
in zip(keys, values):
346 except SyntaxError
as se:
347 Logger.logdebug(
'Unable to parse input value for key "%s", assuming string:\n%s\n%s' % (k, str(v), str(se)))
354 contain_list = dict((path+
"/"+key,value)
for (key,value)
in getattr(obj,
'contains', {}).items())
356 for b_id, b_inst
in contain_list.items():
358 contain_list.update(add_to_list)
369 self._pub.publish(
'flexbe/heartbeat', Empty())
374 if isinstance(o, list):
376 elif isinstance(o, dict):
def _behavior_execution(self, msg)
def _convert_dict(self, o)
def _set_typed_attribute(self, obj, name, value, behavior='')
def _build_contains(self, obj, path)
def _execute_heartbeat(self)
def _behavior_callback(self, msg)
def _is_switchable(self, be)
def _cleanup_behavior(self, behavior_checksum)
def _convert_input_data(self, keys, values)
def _heartbeat_worker(self)
def _prepare_behavior(self, msg)