Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags. |
Concurrence container
Description: This tutorial teaches you how to use the Concurrence container.Tutorial Level: BEGINNER
Next Tutorial: Sequence container
1 from smach import Concurrence
Specify concurrence outcomes
Concurrence Outcome Map
The outcome map of a SMACH concurrence specifies the policy for determining the outcome of the concurrence based on the outcomes of its children. Specifically, the map is a dictionary where the keys are potential outcomes of the concurrence, and the values are dictionaries mapping child labels onto child outcomes. Once all the states in the concurrence have terminated, if one of these child-outcome mappings is satisfied, the concurrence will return its associated outcome. If none of the mappings are satisfied, the concurrence will return its default outcome.
1 cc = Concurrence(outcomes = ['outcome1', 'outcome2'],
2 default_outcome = 'outcome1',
3 input_keys = ['sm_input'],
4 output_keys = ['sm_output'],
5 outcome_map = {'succeeded':{'FOO':'succeeded',
6 'BAR':'outcome2'},
7 'outcome3':{'FOO':'outcome2'}})
8 with cc:
9 Concurrence.add('FOO', Foo())
10 Concurrence.add('BAR', Bar())
The example above specifies the following policy:
- When 'FOO' has outcome 'succeeded' and 'BAR' has outcome 'outcome2', the state machine will exit with outcome 'succeeded'.
- When 'FOO' has outcome 'outcome2', the state machine will exit with outcome 'outcome3', independent of the outcome of state BAR.
Callbacks
If you want full control over a concurrence state machine, you can use the callbacks it provides, the child_termination_cb and the outcome_cb:
1 # gets called when ANY child state terminates
2 def child_term_cb(outcome_map):
3
4 # terminate all running states if FOO finished with outcome 'outcome3'
5 if outcome_map['FOO'] == 'outcome3':
6 return True
7
8 # terminate all running states if BAR finished
9 if outcome_map['BAR']:
10 return True
11
12 # in all other case, just keep running, don't terminate anything
13 return False
14
15
16 # gets called when ALL child states are terminated
17 def out_cb(outcome_map):
18 if outcome_map['FOO'] == 'succeeded':
19 return 'outcome1'
20 else:
21 return 'outcome2'
22
23
24 # creating the concurrence state machine
25 sm = Concurrence(outcomes=['outcome1', 'outcome2'],
26 default_outcome='outcome1',
27 input_keys=['sm_input'],
28 output_keys=['sm_output'],
29 child_termination_cb = child_term_cb,
30 outcome_cb = out_cb)
31
32 with sm:
33 Concurrence.add('FOO', Foo(),
34 remapping={'foo_in':'input'})
35
36 Concurrence.add('BAR', Bar(),
37 remapping={'bar_out':'bar_out'})
- The child_termination_cb is called every time one of the child states terminates. In the callback function you can decide if the state machine should keep running (return False), or if it should preempt all remaining running states (return True).
- The outcome_cb is called once when the last child state terminates. This callback returns the outcome of the concurrence state machine.