From 74a0d2470393f338bb930c7fd9f729ab71596987 Mon Sep 17 00:00:00 2001 From: Carlos Costa Date: Mon, 9 Sep 2019 17:14:19 +0100 Subject: [PATCH 1/2] Changed the outcome_map structure in Concurrence class from {outcome:{state1:outcome1, state2:outcome2}} to {outcome:[{state1:outcome1}, {state2:outcome2}]} for allowing the specification of several outcomes for a single state (the previous implementation would not allow state1:outcome1a and state1:outcome1b, since dictionaries do not allow repeated keys). --- smach/src/smach/concurrence.py | 37 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/smach/src/smach/concurrence.py b/smach/src/smach/concurrence.py index e40b23c..dd1a923 100644 --- a/smach/src/smach/concurrence.py +++ b/smach/src/smach/concurrence.py @@ -66,13 +66,13 @@ def __init__(self, @type outcome_map: list @param outcome_map: This is an outcome map for determining the outcome of this container. Each outcome of the container is mapped - to a dictionary mapping child labels onto outcomes. If none of the + to a list containing dictionaries mapping child labels onto outcomes. If none of the child-outcome maps is satisfied, the concurrence will terminate - with thhe default outcome. + with the default outcome. For example, if the and_outcome_map is: - {'succeeded' : {'FOO':'succeeded', 'BAR':'done'}, - 'aborted' : {'FOO':'aborted'}} + {'succeeded' : [{'FOO':'succeeded'}, {'BAR':'done'}], + 'aborted' : [{'FOO':'aborted'}]} Then the concurrence will terimate with outcome 'succeeded' only if BOTH states 'FOO' and 'BAR' have terminated with outcomes 'succeeded' and 'done', respectively. The outcome @@ -281,10 +281,11 @@ def execute(self, parent_ud = smach.UserData()): # Determine the outcome from the outcome map smach.logdebug("SMACH Concurrence determining contained state outcomes.") - for (container_outcome, outcomes) in ((k,self._outcome_map[k]) for k in self._outcome_map): - if all([self._child_outcomes[label] == outcomes[label] for label in outcomes]): - smach.logdebug("Terminating concurrent split with mapped outcome.") - outcome = container_outcome + for (container_outcome, outcomes_list) in ((k,self._outcome_map[k]) for k in self._outcome_map): + for outcomes in outcomes_list: + if all([self._child_outcomes[label] == outcomes[label] for label in outcomes]): + smach.logdebug("Terminating concurrent split with mapped outcome.") + outcome = container_outcome # Check outcome callback if self._outcome_cb: @@ -391,16 +392,18 @@ def get_active_states(self): def get_internal_edges(self): int_edges = [] - for (container_outcome, outcomes) in ((k,self._outcome_map[k]) for k in self._outcome_map): - for state_key in outcomes: - int_edges.append((outcomes[state_key], state_key, container_outcome)) + for (container_outcome, outcomes_list) in ((k,self._outcome_map[k]) for k in self._outcome_map): + for outcomes in outcomes_list: + for state_key in outcomes: + int_edges.append((outcomes[state_key], state_key, container_outcome)) return int_edges def check_consistency(self): - for (co,cso) in ((k,self._outcome_map[k]) for k in self._outcome_map): - for state_label,outcome in ((k,cso[k]) for k in cso): - if outcome not in self._states[state_label].get_registered_outcomes(): - raise smach.InvalidTransitionError( - 'Outcome map in SMACH Concurrence references a state outcome that does not exist. Requested state outcome: \'%s\', but state \'%s\' only has outcomes %s' % - (outcome, state_label, str(self._states[state_label].get_registered_outcomes()))) + for (co,outcomes_list) in ((k,self._outcome_map[k]) for k in self._outcome_map): + for cso in outcomes_list: + for state_label,outcome in ((k,cso[k]) for k in cso): + if outcome not in self._states[state_label].get_registered_outcomes(): + raise smach.InvalidTransitionError( + 'Outcome map in SMACH Concurrence references a state outcome that does not exist. Requested state outcome: \'%s\', but state \'%s\' only has outcomes %s' % + (outcome, state_label, str(self._states[state_label].get_registered_outcomes()))) From 1f9a14f5190009f11dc2ad58c0348364b0313961 Mon Sep 17 00:00:00 2001 From: Carlos Miguel Correia da Costa Date: Tue, 11 Aug 2020 13:15:59 +0100 Subject: [PATCH 2/2] Added backwards compatibility. --- smach/src/smach/concurrence.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/smach/src/smach/concurrence.py b/smach/src/smach/concurrence.py index dd1a923..77a3565 100644 --- a/smach/src/smach/concurrence.py +++ b/smach/src/smach/concurrence.py @@ -282,6 +282,8 @@ def execute(self, parent_ud = smach.UserData()): # Determine the outcome from the outcome map smach.logdebug("SMACH Concurrence determining contained state outcomes.") for (container_outcome, outcomes_list) in ((k,self._outcome_map[k]) for k in self._outcome_map): + if not isinstance(outcomes_list, list): + outcomes_list = [outcomes_list] for outcomes in outcomes_list: if all([self._child_outcomes[label] == outcomes[label] for label in outcomes]): smach.logdebug("Terminating concurrent split with mapped outcome.") @@ -393,6 +395,8 @@ def get_active_states(self): def get_internal_edges(self): int_edges = [] for (container_outcome, outcomes_list) in ((k,self._outcome_map[k]) for k in self._outcome_map): + if not isinstance(outcomes_list, list): + outcomes_list = [outcomes_list] for outcomes in outcomes_list: for state_key in outcomes: int_edges.append((outcomes[state_key], state_key, container_outcome)) @@ -400,6 +404,8 @@ def get_internal_edges(self): def check_consistency(self): for (co,outcomes_list) in ((k,self._outcome_map[k]) for k in self._outcome_map): + if not isinstance(outcomes_list, list): + outcomes_list = [outcomes_list] for cso in outcomes_list: for state_label,outcome in ((k,cso[k]) for k in cso): if outcome not in self._states[state_label].get_registered_outcomes():