(!) 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.

Creating Editors for SMACH States That Has Inputs and Outputs

Description: Illustrates how to create editors for SMACH states that has defined inputs and outputs.

Tutorial Level: INTERMEDIATE


Until now we have only focused on the creation of editors that has simple SMACH states that does not make use of data passing. In this tutorial we will discuss the more sophisticated case where this needs to happen in RCommander.

Setting Up Data Passing via userdata

Before we begin, all the code in this tutorial can be found in the package rcommander_plain so there isn't a need to reproduce it. First, we will discuss saving data to userdata in RCommander. Start by opening up the file (LINK) output_tool.py. This new tool is similar to the sleep tool that we created in the previous tutorials with differences in two important areas. In our class that inherits from StateBase we now declare that we have one output with the name name that is of class float:

   1     def __init__(self, name, output_number):
   2         tu.StateBase.__init__(self, name, outputs={name: float})

Next, for the class that inherits from smach.State, we declare our input variable as being the node's name:

   1     def __init__(self, output_variable_name, output_number):
   2         smach.State.__init__(self, outcomes=['done'], input_keys=[], output_keys=[output_variable_name])

Then in the execute method, we copy output_number into userdata:

   1     def execute(self, userdata):
   2         exec("userdata.%s = self.output_number" % self.output_variable_name)
   3         return 'done'

Aside from a few more bookkeeping details in the example file, that's all we will need to do to output data in RCommander. Next we'll discuss how to use this in another node. Start this by opening the file input_tool.py (LINK) in the package rcommander_plain. We'll start first in the user interface class, creating the UI widgets that will allow users to pick which other node's output our node should use.

   1         self.source_box = QComboBox(pbox)
   2         self.source_box.addItem(' ')
   3         node_names = self.rcommander.outputs_of_type(float)
   4         for n in node_names:
   5             self.source_box.addItem(n)

The new RCommander API call here is outputs_of_type which returns a list of strings where each is the name of a node that outputs data of the type float.

   1     def __init__(self, name, source_input):
   2         tu.StateBase.__init__(self, name)
   3         self.set_remapping_for('myinput', source_input) 

Next in the class that inherits from StateBase, we call on set_remapping_for (defined in StateBase) to declare that the input variable named myinput should obtain its value from the variable whose name is defined in source_input.

   1     def execute(self, userdata):
   2         rospy.loginfo('got ' + str(userdata.myinput))
   3         return 'done'

In the execute method our new class that inherits from smach.State, we demonstrate the use of this new input variable userdata.myinput. After defining these two tools, we'll need to declare them in the export section of our manifext.xml file:

      <rcommander plugin="rcommander_plain.input_tool" robot="myrobot" tab="My Robot Actions"/>
      <rcommander plugin="rcommander_plain.output_tool" robot="myrobot" tab="My Robot Actions"/>

Now run rcommander_plain.launch:

roslaunch rcommander_plain rcommander_plain.launch

This will create a new RCommander window similar to the one below. First, create an output node with our My Output tool:


Next, create a node that takes that output node as an input with the My Input tool:


Finally, if everything goes right, clicking Actions then Run should output the following on our console:

[INFO] [WallTime: 1334274447.013887] ThreadRunSM started untitled0
[INFO] [WallTime: 1334274447.014395] State machine starting in initial state 'my_output0' with userdata: 
[INFO] [WallTime: 1334274447.014789] State machine transitioning 'my_output0':'done'-->'node_with_input0'
[INFO] [WallTime: 1334274447.015131] got 3.0
[INFO] [WallTime: 1334274447.015419] State machine terminating 'node_with_input0':'done':'done1'
[INFO] [WallTime: 1334274447.015702] ThreadRunSM.run: execution finished outcome done1
[INFO] [WallTime: 1334274447.015965] ThreadRunSM.run: exiting

Notice that our call to rosloginfo printed got 3.0 indicating that the system is working passing userdata as needed.

Wiki: rcommander_core/tutorials/Creating Editors for SMACH States That Has Inputs and Outputs (last edited 2012-04-13 14:54:14 by HaiDNguyen)