behavior_action_server.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 import rospy
3 import actionlib
4 
5 from flexbe_msgs.msg import *
6 from rospkg import RosPack
7 from flexbe_core import BehaviorLibrary
8 
9 from std_msgs.msg import String, Empty
10 
11 import zlib
12 import difflib
13 import os
14 import xml.etree.ElementTree as ET
15 
16 
17 class BehaviorActionServer(object):
18 
19  def __init__(self):
20  self._behavior_started = False
21  self._current_state = None
22  self._engine_status = None
23 
24  self._pub = rospy.Publisher('flexbe/start_behavior', BehaviorSelection, queue_size=100)
25  self._preempt_pub = rospy.Publisher('flexbe/command/preempt', Empty, queue_size=100)
26  self._status_sub = rospy.Subscriber('flexbe/status', BEStatus, self._status_cb)
27  self._state_sub = rospy.Subscriber('flexbe/behavior_update', String, self._state_cb)
28 
29  self._as = actionlib.SimpleActionServer('flexbe/execute_behavior', BehaviorExecutionAction, self._execute_cb, False)
30 
31  self._rp = RosPack()
32  self._behavior_lib = BehaviorLibrary()
33 
34  # start action server after all member variables have been initialized
35  self._as.start()
36 
37  rospy.loginfo("%d behaviors available, ready for start request." % self._behavior_lib.count_behaviors())
38 
39 
40  def _execute_cb(self, goal):
41  rospy.loginfo('Received a new request to start behavior: %s' % goal.behavior_name)
42  be_id, behavior = self._behavior_lib.find_behavior(goal.behavior_name)
43  if be_id is None:
44  Logger.logerr("Did not find behavior with requested name: %s" % goal.behavior_name)
45  self._as.set_preempted()
46  return
47 
48  be_selection = BehaviorSelection()
49  be_selection.behavior_id = be_id
50  be_selection.autonomy_level = 255
51  be_selection.arg_keys = goal.arg_keys
52  be_selection.arg_values = goal.arg_values
53  be_selection.input_keys = goal.input_keys
54  be_selection.input_values = goal.input_values
55 
56  # check for local modifications of the behavior to send them to the onboard behavior
57  be_filepath_new = os.path.join(self._rp.get_path(behavior["package"]), 'src/' + behavior["package"] + '/' + behavior["file"] + '.py')
58  with open(be_filepath_new, "r") as f:
59  be_content_new = f.read()
60 
61  be_filepath_old = os.path.join(self._rp.get_path(behavior["package"]), 'src/' + behavior["package"] + '/' + behavior["file"] + '_tmp.py')
62  if not os.path.isfile(be_filepath_old):
63  be_selection.behavior_checksum = zlib.adler32(be_content_new)
64  else:
65  with open(be_filepath_old, "r") as f:
66  be_content_old = f.read()
67 
68  sqm = difflib.SequenceMatcher(a=be_content_old, b=be_content_new)
69  diffs = [x[1] for x in sqm.get_grouped_opcodes(0)]
70  for opcode, a0, a1, b0, b1 in diffs:
71  content = be_content_new[b0:b1]
72  be_selection.modifications.append(BehaviorModification(a0, a1, content))
73 
74  be_selection.behavior_checksum = zlib.adler32(be_content_new)
75 
76  # reset state before starting new behavior
77  self._engine_status = None
78  self._current_state = None
79  self._behavior_started = False
80 
81  # start new behavior
82  self._pub.publish(be_selection)
83 
84  try:
85  rate = rospy.Rate(10)
86  while not rospy.is_shutdown():
87  if self._current_state is not None:
88  self._as.publish_feedback(BehaviorExecutionFeedback(self._current_state))
89  self._current_state = None
90 
91  # check if goal has been preempted first
92  if self._as.is_preempt_requested():
93  rospy.loginfo('Behavior execution preempt requested!')
94  self._preempt_pub.publish()
95  rate.sleep()
96  self._as.set_preempted('')
97  break
98 
99  if self._engine_status is None:
100  rospy.logdebug_throttle(1, 'No behavior engine status received yet. Waiting for it...')
101  rate.sleep()
102  continue
103 
104  if self._engine_status.code == BEStatus.ERROR:
105  rospy.logerr('Failed to run behavior! Check onboard terminal for further infos.')
106  rate.sleep()
107  self._as.set_aborted('')
108  break
109 
110  if not self._behavior_started:
111  rospy.logdebug_throttle(1, 'Behavior execution has not yet started. Waiting for it...')
112  rate.sleep()
113  continue
114 
115  if self._engine_status.code == BEStatus.FINISHED:
116  result = self._engine_status.args[0] \
117  if len(self._engine_status.args) >= 1 else ''
118  rospy.loginfo('Finished behavior execution with result "%s"!' % result)
119  self._as.set_succeeded(BehaviorExecutionResult(outcome=result))
120  break
121 
122  if self._engine_status.code == BEStatus.FAILED:
123  rospy.logerr('Behavior execution failed in state %s!' % str(self._current_state))
124  rate.sleep()
125  self._as.set_aborted('')
126  break
127 
128  rate.sleep()
129 
130  rospy.loginfo('Ready for next behavior start request.')
131 
132  except rospy.ROSInterruptException:
133  pass # allow clean exit on ROS shutdown
134 
135 
136  def _status_cb(self, msg):
137  self._engine_status = msg
138 
139  # check for behavior start here, to avoid race condition between execute_cb and status_cb threads
140  if not self._behavior_started and self._engine_status.code == BEStatus.STARTED:
141  self._behavior_started = True
142  rospy.loginfo('Behavior execution has started!')
143 
144 
145  def _state_cb(self, msg):
146  self._current_state = msg.data
147  rospy.loginfo('Current state: %s' % self._current_state)


flexbe_widget
Author(s): Philipp Schillinger
autogenerated on Wed Jun 5 2019 21:52:10