Userdata

Note

Before reading the following documentation, it is highly recommended that you consult the “Passing User Data between States” SMACH tutorial first!

Userdata is a special type of data structure that is inherited from SMACH and is used to pass data between states as either input_keys or output_keys.

Certain functionalities have been developed for SMACHA templates to make it easy to manipulate userdata within scripts.

Userdata Hello World Example

Here is the print_userdata.yml script from the test/smacha_scripts/smacha_test_examples folder in the smacha package that develops a simple “Hello World” example for userdata manipulation:

--- # SMACHA print userdata example
name: sm
template: Base
outcomes: [final_outcome]
userdata: {foo: 'Hello World!'}
states:
  - FOO_0:
      template: PrintUserdataState
      input_keys: [foo]
      transitions: {succeeded: FOO_1}
  - FOO_1:
      template: CallbacksState
      userdata: {bar: 'Goodbye World!'}
      transitions: {succeeded: FOO_2}
  - FOO_2:
      template: PrintUserdataState
      input_keys: [foobar]
      remapping: {foobar: bar}
      transitions: {succeeded: final_outcome}

In this example a variable foo with the value ‘Hello World!’ is added to the userdata at the beginning of the script and is passed as an input_key to the FOO_0 state which uses a PrintUserdataState template which looks like this:

{% block meta %}
name: PrintUserdataState
description: SMACH state that prints the values of userdata input_keys to standard output.
language: Python
framework: SMACH
type: State
tags: [core]
includes: []
extends:
  - State
variables:
- input_keys:
    description:
      The names of the userdata input keys to be printed.
    type: list of str
- - output_keys:
      description:
        The names of the userdata output keys corresponding to each
        optionally specified callback function.
      type: list of str
- - callbacks:
      description:
        Either callback function names or backtick-wrapped lambda functions
        for possible modifications to the printing procedure.
      type: dict of str
- - outcomes:
      description: The possible outcomes.
      type: list of str
input_keys: []
output_keys: []
outcomes:
- succeeded
{% endblock meta %}

{% from "Utils.tpl.py" import import_module %}

{% extends "State.tpl.py" %}

{% block imports %}
{{ super() }}
{% endblock imports %}

{% block class_defs %}
{{ super() }}
{% if 'class_PrintUserdataState' not in defined_headers %}
class PrintUserdataState(smach.State):
    def __init__(self, input_keys = [], output_keys = [], callbacks = [], outcomes=['succeeded']):
        smach.State.__init__(self, input_keys=input_keys, output_keys=output_keys, outcomes=outcomes)

    def execute(self, userdata):

        # Print input keys to terminal
        for input_key in self._input_keys:
            smach.loginfo('userdata.{}: {}'.format(input_key, userdata[input_key]))

        return 'succeeded'
{% do defined_headers.append('class_PrintUserdataState') %}{% endif %}
{% endblock class_defs %}

This template defines a small class that simply prints out any input_keys that it is passed to standard output.

Userdata Definitions

In the subsequent FOO_1 state, which uses a CallbacksState template, another variable called bar is entered into the userdata with the value Goodbye World!’. The :doc:`CallbacksState template <../API/Templates/CallbacksState.tpl.py> is interesting in its own right and can be quite powerful in other circumstances, but it is only used in this example as an intermediary state for illustrative purposes.

Note

All userdata that is defined within a script is entered into the userdata structure at the beginning of run-time when the state machine is first run. This is a carryover from the way in which SMACH state machines are designed. However, it can still be useful for a script designer to be able to define userdata at arbitrary points within a script, e.g. within a the state that is going to make use of it, as in the above example for the FOO_1 state:

- FOO_1:
    template: CallbacksState
    userdata: {bar: 'Goodbye World!'}
    transitions: {succeeded: FOO_2}

Wherever the userdata definitions are located within the script, be that within the main script, or in a container state or sub-script, SMACHA will try to place them at the appropriate locations in the rendered SMACH Python code. This “smart” rendering of userdata will be more apparent in later examples.

Userdata Remappings

After FOO_1 in the above example, the state machine transitions to FOO_2, but according to its definition within the script (admittedly contrived for illustrative purposes!), FOO_2 expects an input_key named foobar, yet the userdata only contains the foo and bar variables.

This is easily solved with a remapping (another carryover from SMACH), which allows for the bar variable to be mapped onto the foobar input_key:

- FOO_2:
    template: PrintUserdataState
    input_keys: [foobar]
    remapping: {foobar: bar}