## For instruction on writing tutorials ## http://www.ros.org/wiki/WritingTutorials #################################### ##FILL ME IN #################################### ## for a custom note with links: ## note = ## for the canned note of "This tutorial assumes that you have completed the previous tutorials:" just add the links ## note.0= ## descriptive title for the tutorial ## title = Passing User Data between States ## multi-line description to be displayed in search ## description = This tutorial teaches you how to pass data from one state(machine) to the next state(machine). ## the next tutorial description (optional) ## next = ## links to next tutorial (optional) ## next.0.link=[[smach/Tutorials/Create a hierarchical state machine|Create a hierarchical state machine]] ## next.1.link= ## what level user is this tutorial for ## level= BeginnerCategory ## keywords = #################################### <> <> == Specifying User Data == A state could require some input data to do its work, and/or it could have some output data it wants to provide to other states. The input and output data of a state is called '''userdata''' of the state. When you construct a state, you can specify the names of the userdata fields it needs/provides. {{{#!python class Foo(smach.State): def __init__(self, outcomes=['outcome1', 'outcome2'], input_keys=['foo_input'], output_keys=['foo_output']) def execute(self, userdata): # Do something with userdata if userdata.foo_input == 1: return 'outcome1' else: userdata.foo_output = 3 return 'outcome2' }}} * The '''input_keys''' list enumerates all the inputs that a state needs to run. A state declares that it expect these fields to exist in the userdata. The execute method is provided a copy of the userdata struct. The state can read from all userdata fields that it enumerates in the input_keys list, but it can't write to any of these fields. * The '''output_keys''' list enumerates all the outputs that a state provides. The state can write to all fields in the userdata struct that are enumerated in the output_keys list. ''' /!\ Note: '''Objects obtained from userdata via input_keys are wrapped for immutability, thus a state cannot call methods on these objects. If you require a mutable input object, you must specify the same key in both input_keys and output_keys. If you are not passing objects, or you do not need to call methods on or modify them, you should use unique names in input_keys and output_keys, to avoid confusion and potential bugs. {{attachment:user_data_single.png||width="250"}} The interface to a state is defined by its outcomes, its input keys and its output keys. == Connecting User Data == When adding states to a state machine, you also need to connect the user data fields, to allow states to pass data to each other. For example, if state FOO produces 'foo_output', and state BAR needs 'bar_input', then you can attach these two user data ports together using name remapping: {{{#!python sm_top = smach.StateMachine(outcomes=['outcome4','outcome5'], input_keys=['sm_input'], output_keys=['sm_output']) with sm_top: smach.StateMachine.add('FOO', Foo(), transitions={'outcome1':'BAR', 'outcome2':'outcome4'}, remapping={'foo_input':'sm_input', 'foo_output':'sm_data'}) smach.StateMachine.add('BAR', Bar(), transitions={'outcome2':'FOO'}, remapping={'bar_input':'sm_data', 'bar_output1':'sm_output'}) }}} The remapping field maps the in/output_key of a state to a userdata field of the state machine. So when you remap 'x':'y': * x needs to be an input_key or an output_key of the state, and * y will automatically become part of the userdata of the state machine. /!\ Note that remapping is ''not required'' when the user data names used in your state are the same as the user data names used by the state machine. However, remapping makes the connections very explicit, so it is ''recommended'' to always specify remapping, even something like "remapping={'a':'a'}". === Passing data between states === We can use the remapping mechanism to pass data from state FOO to state BAR. To accomplish this, we need one remapping when adding FOO, and one remapping when adding BAR: * FOO: remapping={'foo_output':'sm_user_data'} * BAR: remapping={'bar_input':'sm_user_data'} === Passing data between state machines and states === We can also use the remapping mechanism to pass data from a state BAR to the state machine that contains BAR. If 'sm_output' is an output key of the state machine: * BAR: remapping={'bar_output':'sm_output'} Or, the opposite, we can pass data from the state machine to a state FOO. If 'sm_input' is an input key of the state machine: * FOO: remapping={'foo_input':'sm_input'} {{attachment:user_data.png||width="650"}} == Example == This is a complete runnable example you can find in the [[executive_smach_tutorials]] package. {{{#!wiki <> }}} Running the example: {{{ $ roscd smach_tutorials $ ./examples/user_data2.py }}} The [[smach/Tutorials/Create a hierarchical state machine|next tutorial]] teaches you how to nest different state machines, creating a hierarchical state machine. ## AUTOGENERATED DO NOT DELETE ## TutorialCategory ## FILL IN THE STACK TUTORIAL CATEGORY HERE ## LearningSMACHCategory