Go to the documentation of this file.00001
00002 import rospy
00003 import actionlib
00004
00005 from flexbe_msgs.msg import *
00006 from rospkg import RosPack
00007 from flexbe_core import BehaviorLibrary
00008
00009 from std_msgs.msg import String, Empty
00010
00011 import zlib
00012 import difflib
00013 import os
00014 import xml.etree.ElementTree as ET
00015
00016
00017 class BehaviorActionServer(object):
00018
00019 def __init__(self):
00020 self._behavior_started = False
00021 self._current_state = None
00022 self._engine_status = None
00023
00024 self._pub = rospy.Publisher('flexbe/start_behavior', BehaviorSelection, queue_size=100)
00025 self._preempt_pub = rospy.Publisher('flexbe/command/preempt', Empty, queue_size=100)
00026 self._status_sub = rospy.Subscriber('flexbe/status', BEStatus, self._status_cb)
00027 self._state_sub = rospy.Subscriber('flexbe/behavior_update', String, self._state_cb)
00028
00029 self._as = actionlib.SimpleActionServer('flexbe/execute_behavior', BehaviorExecutionAction, self._execute_cb, False)
00030
00031 self._rp = RosPack()
00032 self._behavior_lib = BehaviorLibrary()
00033
00034
00035 self._as.start()
00036
00037 rospy.loginfo("%d behaviors available, ready for start request." % self._behavior_lib.count_behaviors())
00038
00039
00040 def _execute_cb(self, goal):
00041 rospy.loginfo('Received a new request to start behavior: %s' % goal.behavior_name)
00042 be_id, behavior = self._behavior_lib.find_behavior(goal.behavior_name)
00043 if be_id is None:
00044 Logger.logerr("Did not find behavior with requested name: %s" % goal.behavior_name)
00045 self._as.set_preempted()
00046 return
00047
00048 be_selection = BehaviorSelection()
00049 be_selection.behavior_id = be_id
00050 be_selection.autonomy_level = 255
00051 be_selection.arg_keys = goal.arg_keys
00052 be_selection.arg_values = goal.arg_values
00053 be_selection.input_keys = goal.input_keys
00054 be_selection.input_values = goal.input_values
00055
00056
00057 be_filepath_new = os.path.join(self._rp.get_path(behavior["package"]), 'src/' + behavior["package"] + '/' + behavior["file"] + '.py')
00058 with open(be_filepath_new, "r") as f:
00059 be_content_new = f.read()
00060
00061 be_filepath_old = os.path.join(self._rp.get_path(behavior["package"]), 'src/' + behavior["package"] + '/' + behavior["file"] + '_tmp.py')
00062 if not os.path.isfile(be_filepath_old):
00063 be_selection.behavior_checksum = zlib.adler32(be_content_new)
00064 else:
00065 with open(be_filepath_old, "r") as f:
00066 be_content_old = f.read()
00067
00068 sqm = difflib.SequenceMatcher(a=be_content_old, b=be_content_new)
00069 diffs = [x[1] for x in sqm.get_grouped_opcodes(0)]
00070 for opcode, a0, a1, b0, b1 in diffs:
00071 content = be_content_new[b0:b1]
00072 be_selection.modifications.append(BehaviorModification(a0, a1, content))
00073
00074 be_selection.behavior_checksum = zlib.adler32(be_content_new)
00075
00076
00077 self._engine_status = None
00078 self._current_state = None
00079 self._behavior_started = False
00080
00081
00082 self._pub.publish(be_selection)
00083
00084 try:
00085 rate = rospy.Rate(10)
00086 while not rospy.is_shutdown():
00087 if self._current_state is not None:
00088 self._as.publish_feedback(BehaviorExecutionFeedback(self._current_state))
00089 self._current_state = None
00090
00091
00092 if self._as.is_preempt_requested():
00093 rospy.loginfo('Behavior execution preempt requested!')
00094 self._preempt_pub.publish()
00095 rate.sleep()
00096 self._as.set_preempted('')
00097 break
00098
00099 if self._engine_status is None:
00100 rospy.logdebug_throttle(1, 'No behavior engine status received yet. Waiting for it...')
00101 rate.sleep()
00102 continue
00103
00104 if self._engine_status.code == BEStatus.ERROR:
00105 rospy.logerr('Failed to run behavior! Check onboard terminal for further infos.')
00106 rate.sleep()
00107 self._as.set_aborted('')
00108 break
00109
00110 if not self._behavior_started:
00111 rospy.logdebug_throttle(1, 'Behavior execution has not yet started. Waiting for it...')
00112 rate.sleep()
00113 continue
00114
00115 if self._engine_status.code == BEStatus.FINISHED:
00116 result = self._engine_status.args[0] \
00117 if len(self._engine_status.args) >= 1 else ''
00118 rospy.loginfo('Finished behavior execution with result "%s"!' % result)
00119 self._as.set_succeeded(BehaviorExecutionResult(outcome=result))
00120 break
00121
00122 if self._engine_status.code == BEStatus.FAILED:
00123 rospy.logerr('Behavior execution failed in state %s!' % str(self._current_state))
00124 rate.sleep()
00125 self._as.set_aborted('')
00126 break
00127
00128 rate.sleep()
00129
00130 rospy.loginfo('Ready for next behavior start request.')
00131
00132 except rospy.ROSInterruptException:
00133 pass
00134
00135
00136 def _status_cb(self, msg):
00137 self._engine_status = msg
00138
00139
00140 if not self._behavior_started and self._engine_status.code == BEStatus.STARTED:
00141 self._behavior_started = True
00142 rospy.loginfo('Behavior execution has started!')
00143
00144
00145 def _state_cb(self, msg):
00146 self._current_state = msg.data
00147 rospy.loginfo('Current state: %s' % self._current_state)