behavior.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 import rospy
3 import smach_ros
4 import smach
5 import importlib
6 import sys
7 import string
8 
9 from flexbe_core import OperatableStateMachine, LockableStateMachine
10 from flexbe_core.core import PreemptableState
11 
12 '''
13 Created on 20.05.2013
14 
15 @author: Philipp Schillinger
16 '''
17 
18 class Behavior(object):
19  '''
20  This is the superclass for all implemented behaviors.
21  '''
22 
23  def __init__(self):
24  '''
25  Please call this superclass constructor first when overriding it with your behavior.
26  '''
27  self._state_machine = None
28  self.name = "unnamed behavior"
29  self.id = 0
30 
31  self.contains = {}
32  self._behaviors = {}
33 
34  self._autonomy_level = 3
35  self._debug = False
36 
38 
39 
40  # Please implement those:
41 
42  def create(self):
43  """
44  Should create the state machine for this behavior and return it.
45  It is called immediately before executing the behavior, so used parameters will have their final value when called.
46 
47  @return The complete state machine for this behavior.
48  """
49  pass
50 
51 
52  # Use those if you need them:
53 
54  def add_parameter(self, name, default):
55  """
56  Adds a parameter to this behavior.
57  The parameter should be declared in the behavior manifest.
58 
59  @type name: string
60  @param name: The name of the parameter.
61 
62  @type default: object
63  @param default: The default value of this parameter. Be sure to set it to the right type.
64  """
65  setattr(self, name, default)
66 
67  def add_behavior(self, behavior_class, behavior_id):
68  """
69  Adds another behavior as part of this behavior.
70  This other behavior should be declared as contained in the behavior manifest.
71 
72  @type behavior_class: class
73  @param behavior_class: The class implementing the other behavior.
74 
75  @type behavior_id: string
76  @param behavior_id: Unique identifier for this behavior instance.
77  """
78  if not hasattr(self, 'contains'):
79  rospy.logerr('Behavior was not initialized! Please call superclass constructor.')
80 
81  instance = behavior_class()
82  self.contains[behavior_id] = instance
83 
84  def use_behavior(self, behavior_class, behavior_id, default_keys=None, parameters=None):
85  """
86  Creates a state machine implementing the given behavior to use it in the behavior state machine.
87  Behavior has to be added first.
88 
89  @type behavior_class: class
90  @param behavior_class: The class implementing the other behavior.
91 
92  @type behavior_id: string
93  @param behavior_id: Same identifier as used for adding.
94 
95  @type default_keys: list
96  @param default_keys: List of input keys of the behavior which should be ignored and instead use the default values as given by the behavior.
97 
98  @type parameters: dict
99  @param parameters: Optional assignment of values to behavior parameters. Any assigned parameter will be ignored for runtime customization, i.e., cannot be overwritten by a user who runs the behavior.
100  """
101  if not self.contains.has_key(behavior_id):
102  rospy.logerr('Tried to use not added behavior!')
103  return None
104 
105  if parameters is not None:
106  for parameter, value in parameters.items():
107  setattr(self.contains[behavior_id], parameter, value)
108 
109  state_machine = self.contains[behavior_id]._get_state_machine()
110 
111  if default_keys is not None:
112  state_machine._input_keys = list(set(state_machine._input_keys) - set(default_keys))
113 
114  return state_machine
115 
116 
117  # Lifecycle
118 
119  def prepare_for_execution(self, input_data = {}):
120  """
121  Prepares this behavior for execution by building its state machine.
122  """
123  OperatableStateMachine.autonomy_level = self._autonomy_level
124 
125  self._state_machine = self.create()
126  self._state_machine._input_keys = {}
127  self._state_machine._output_keys = {}
128 
129  for k, v in input_data.items():
130  if k in self._state_machine.userdata:
131  self._state_machine.userdata[k] = v
132 
133 
134  def confirm(self):
135  """
136  Confirms that this behavior is ready for execution.
137  """
138  LockableStateMachine.path_for_switch = self.requested_state_path
139 
140  self._state_machine.confirm(self.name, self.id)
141 
142 
143  def execute(self):
144  """
145  Called when the behavior is executed.
146  Need to call self.execute_behavior when ready to start the state machine and return its result.
147 
148  @return: A string containing the execution result such as finished or failed.
149  """
150  PreemptableState.switching = False
151  result = self._state_machine.execute()
152 
153  self._state_machine.destroy()
154 
155  return result
156 
157 
158  def prepare_for_switch(self, state):
159  """
160  Prepares the behavior for being executed after a behavior switch.
161 
162  @type name: string
163  @param name: The name of this behavior.
164  """
165  states = self._get_states_of_path(state._get_path(), self._state_machine)
166  if states is None:
167  raise smach.InvalidConstructionError("Did not find locked state in new behavior!")
168  state_container = state._parent
169  for sm in states[1:]:
170  sm.set_initial_state([sm._initial_state_label], state_container.userdata)
171  #rospy.loginfo("Set userdata for %s from %s; (keys: %d): %s", str(sm.name), str(state_container.name), len(state_container.userdata._data), str(state_container.userdata._data))
172  state_container = state_container._parent
173  states[1].replace(state)
174 
175  self.requested_state_path = state._get_path()
176 
177 
178  def get_current_state(self):
179  return self._state_machine._get_deep_state()
180 
181  def get_locked_state(self):
182  state = self._state_machine._get_deep_state()
183  while not state is None:
184  if state.is_locked():
185  return state
186  else:
187  state = state._parent
188  return None
189 
190  def preempt(self):
191  PreemptableState.preempt = True
192 
194  PreemptableState.switching = True
195  PreemptableState.preempt = True
196 
197 
198  # For internal use only
199 
201  if self._state_machine is None:
202  self._state_machine = self.create()
203  return self._state_machine
204 
206  if self._state_machine is None:
207  self._state_machine = self.create()
209  return self._state_machine
210 
211  def _mute_state_machine(self, sm):
212  for state in sm._ordered_states:
213  if isinstance(state, OperatableStateMachine):
214  self._mute_state_machine(state)
215  else:
216  state._is_controlled = False
217 
218 
219  def set_up(self, id, autonomy_level, debug):
220  self.id = id
221  self._autonomy_level = autonomy_level
222  self._debug = debug
223 
224  def _get_states_of_path(self, path, container):
225  path_elements = path.split('/')
226  if len(path_elements) < 2:
227  return [container]
228  state_label = path_elements[1]
229  new_path = "/".join(path_elements[1:])
230 
231  if container.get_children().has_key(state_label):
232  childlist = self._get_states_of_path(new_path, container.get_children()[state_label])
233  if childlist is None:
234  return None
235  childlist.append(container)
236  return childlist
237  else:
238  return None
239 
240 
241 
242 
243 
244 
245 
246 
247 
248 
249 
250 
251 
252 
253 
254 
255 
256 
257 
258 
259 
260 
261 
262 
263 
264 
265 
266 
267 
def use_behavior(self, behavior_class, behavior_id, default_keys=None, parameters=None)
Definition: behavior.py:84
def set_up(self, id, autonomy_level, debug)
Definition: behavior.py:219
def add_behavior(self, behavior_class, behavior_id)
Definition: behavior.py:67
def _mute_state_machine(self, sm)
Definition: behavior.py:211
def _get_muted_state_machine(self)
Definition: behavior.py:205
def prepare_for_execution(self, input_data={})
Definition: behavior.py:119
def _get_states_of_path(self, path, container)
Definition: behavior.py:224
def add_parameter(self, name, default)
Definition: behavior.py:54
def prepare_for_switch(self, state)
Definition: behavior.py:158


flexbe_core
Author(s): Philipp Schillinger
autogenerated on Wed Jun 5 2019 21:51:59