concurrency_container.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 from flexbe_core.logger import Logger
3 from flexbe_core.core.user_data import UserData
4 from flexbe_core.core.event_state import EventState
5 from flexbe_core.core.priority_container import PriorityContainer
6 
7 from flexbe_core.core.operatable_state_machine import OperatableStateMachine
8 
9 
11  """
12  A state machine that can be operated.
13  It synchronizes its current state with the mirror and supports some control mechanisms.
14  """
15 
16  def __init__(self, conditions=dict(), *args, **kwargs):
17  super(ConcurrencyContainer, self).__init__(*args, **kwargs)
18  self._conditions = conditions
19  self._returned_outcomes = dict()
20  self._sleep_dur = None
21 
22  def sleep(self):
23  if self._sleep_dur is not None:
24  self.wait(seconds=self._sleep_dur)
25  self._sleep_dur = None
26 
27  @property
28  def sleep_duration(self):
29  return self._sleep_dur or 0.
30 
32  # execute all states that are done with sleeping and determine next sleep duration
33  sleep_dur = None
34  for state in self._states:
35  if state.name in list(self._returned_outcomes.keys()) and self._returned_outcomes[state.name] is not None:
36  continue # already done with executing
37  if (PriorityContainer.active_container is not None
38  and not all(a == s for a, s in zip(PriorityContainer.active_container.split('/'),
39  state.path.split('/')))):
40  if isinstance(state, EventState):
41  state._notify_skipped()
42  elif state.get_deep_state() is not None:
43  state.get_deep_state()._notify_skipped()
44  continue # other state has priority
45  if state.sleep_duration <= 0: # ready to execute
46  self._returned_outcomes[state.name] = self._execute_single_state(state)
47  # check again in case the sleep has already been handled by the child
48  if state.sleep_duration <= 0:
49  # this sleep returns immediately since sleep duration is negative,
50  # but is required here to reset the sleep time after executing
51  state.sleep()
52  sleep_dur = state.sleep_duration if sleep_dur is None else min(sleep_dur, state.sleep_duration)
53  if sleep_dur > 0:
54  self._sleep_dur = sleep_dur
55 
56  # Determine outcome
57  outcome = None
58  if any(self._returned_outcomes[state.name] == state._preempted_name
59  for state in self._states if state.name in self._returned_outcomes):
60  return self._preempted_name # handle preemption if required
61  # check conditions
62  for item in self._conditions:
63  (oc, cond) = item
64  if all(sn in self._returned_outcomes and self._returned_outcomes[sn] == o for sn, o in cond):
65  outcome = oc
66  break
67 
68  if outcome is None:
69  return None
70 
71  # trigger on_exit for those states that are not done yet
72  self.on_exit(self.userdata,
73  states=[s for s in self._states if (s.name not in list(self._returned_outcomes.keys()) or
74  self._returned_outcomes[s.name] is None)])
75  self._returned_outcomes = dict()
76  # right now, going out of a cc may break sync
77  # thus, as a quick fix, explicitly sync again
78  self._parent._inner_sync_request = True
79  self._current_state = None
80  return outcome
81 
82  def _execute_single_state(self, state, force_exit=False):
83  result = None
84  try:
85  with UserData(reference=self._userdata, remap=self._remappings[state.name],
86  input_keys=state.input_keys, output_keys=state.output_keys) as userdata:
87  if force_exit:
88  state._entering = True
89  state.on_exit(userdata)
90  else:
91  result = state.execute(userdata)
92  except Exception as e:
93  result = None
94  self._last_exception = e
95  Logger.logerr('Failed to execute state %s:\n%s' % (self.current_state_label, str(e)))
96  return result
97 
99  state = self._states[0]
100  if isinstance(state, EventState):
101  state._enable_ros_control()
102  if isinstance(state, OperatableStateMachine):
103  state._enable_ros_control()
104 
106  state = self._states[0]
107  if isinstance(state, EventState):
108  state._disable_ros_control()
109  if isinstance(state, OperatableStateMachine):
110  state._disable_ros_control()
111 
112  def on_exit(self, userdata, states=None):
113  for state in self._states if states is None else states:
114  if state in self._returned_outcomes:
115  continue # skip states that already exited themselves
116  self._execute_single_state(state, force_exit=True)
def wait(self, seconds=None, condition=None)


flexbe_core
Author(s): Philipp Schillinger
autogenerated on Sun Dec 13 2020 04:01:39