Exploring Tekkotsu Programming on Mobile Robots:

State Machine Shorthand Notation

Prev: Nodes and transitions
Up: Contents
Next: Defining new types

Contents: Shorthand notation, Creating an FSM file, Running the tool directly

Shorthand Notation

From inspecting the examples in the previous scetion you may conclude that constructing state machines by hand can be tedious, especially when there are many nodes and transitions. Fortunately, Tekkotsu provides a tool to translate state machine descriptions in shorthand form into executable code that goes inside your setup function.

The shorthand for a node definition looks like this:

nodename: NodeClass(constructor_args) [initializers]
All the elements except the NodeClass are optional. Node classes must begin with a capital letter; node names should begin with a lowercase letter.

The shorthand for a transition definition looks like this:

sourcenode == transname: TransitionClass(constructor_args) [initializers] ==> targetnode
All components except the source node and transition class are optional, as are the spaces between them. A source node can be either a node definition or the name of a previously-defined node. If the target node is omitted, the next defined node is used as the target. Thus, node and transition definitions can be conveniently interleaved, forming a chain.

Initializers are used to set parameters of a node or transition, such as modifying a motion command contained inside a motion command node. (LedNode is an example of a motion command node; it is actually an alias for MCNode<LedMC>.) Special notation is used to add additional source or target nodes to a previously-defined transition. To add a source node, use:

sourcenode == transname
To add a destination node, use:
transname ==> targetnode
To prevent these or any other expressions from inappropriately chaining with others, put blank lines around them.

Finally, if you leave off the constructor arguments to a node, the first argument, which is a string specifying the node name, will be supplied automatically. If you do specify constructor args you can write "$" in quotes (because the first argument is supposed to be a string), and the translator will replace this with the name assigned to the node. This could be either the name you assigned, in which case it simply keeps you from having to write the name twice, or it can be an automatically generated name if you did not assign one yourself. So writing foo:StateNode is equivalent to writing foo:StateNode("$"), which would expand to foo:StaetNode("foo").

The first argument to a transition constructor is always the destination node. If you leave off the constructor arguments, the first argument, will be supplied automatically based on what appears after the ==>. If you need to specify transition constructor arguments, you can use a $ (without quotes) for the first argument, and the translater will replaced it with the name of the destination node.

Here is an example of the bark/howl state machine written as simply as possible in the shorthand notation. Notice the use of blank lines between declarations since we're not chaining them together.

bark: SoundNode("$","barkmed.wav")

wait: StateNode

bark == EventTrans($,
		EventBase::buttonEGID,
		RobotInfo::HeadFrButOffset,
		EventBase::activateETID) [setSound("ping.wav");] ==> wait

wait ==TimeOutTrans($,15000)==> bark

howl: SoundNode("$","howl.wav") 

bark ==TimeOutTrans($,500)==> howl

howl ==CompletionTrans==> wait

Here is an example of the full bark/howl/blink state machine defined as compactly as possible, using chaining:

launch:StateNode ==n:NullTrans==> bark

n ==> LedNode [setPriority(MotionManager::kBackgroundPriority);
		 getMC()->set(RobotInfo::FaceLEDMask,0.0);]

bark: SoundNode("$","barkmed.wav")
  == EventTrans($,
		EventBase::buttonEGID,
		RobotInfo::HeadFrButOffset,
		EventBase::activateETID) [setSound("ping.wav");] ==>
    wait: StateNode == TimeOutTrans($,15000) ==> bark

bark ==tooLate: TimeOutTrans($,5000)==> SoundNode("$","howl.wav")
      ==howlDone: CompletionTrans($,1)==> wait

tooLate ==> LedNode [getMC()->cycle(RobotInfo::FaceLEDMask,1500,1.0);]  == howlDone

Creating an FSM File

To create a state machine using shorthand notation, you must name your file xxx.h.fsm or xxx.cc.fsm, as appropriate. The state machine definition goes inside your definition for setup(), and must be preceded by #statemachine and terminated by #endstatemachine. The Tekkotsu make file will read the fsm file and create xxx.h or xxx.cc for you, but this derived file will be hidden away in the build directory so that you don't accidentally edit it instead of the fsm file.

Here is an example of the full implementation of the bark/howl/blink state machine:

//-*-c++-*-
#ifndef INCLUDED_DstBehavior_h_
#define INCLUDED_DstBehavior_h_
 
#include "Behaviors/StateNode.h"
#include "Behaviors/Nodes/SoundNode.h"
#include "Behaviors/Nodes/LedNode.h"
#include "Behaviors/Transitions/CompletionTrans.h"
#include "Behaviors/Transitions/EventTrans.h"
#include "Behaviors/Transitions/NullTrans.h"
#include "Behaviors/Transitions/TimeOutTrans.h"
#include "Events/EventRouter.h"

class DstBehavior : public StateNode {

public:
  DstBehavior() : StateNode("DstBehavior") {}
 
  virtual void setup() {
    StateNode::setup();

#statemachine
launch:StateNode ==n:NullTrans==> bark

n ==> LedNode [setPriority(MotionManager::kBackgroundPriority);
		 getMC()->set(RobotInfo::FaceLEDMask,0.0);]

bark: SoundNode("$","barkmed.wav")
  == EventTrans($,
		EventBase::buttonEGID,
		RobotInfo::HeadFrButOffset,
		EventBase::activateETID) [setSound("ping.wav");] ==>
    wait: StateNode == TimeOutTrans($,15000) ==> bark

bark ==tooLate: TimeOutTrans($,5000)==> SoundNode("$","howl.wav")
      ==howlDone: CompletionTrans($,1)==> wait

tooLate ==> LedNode [getMC()->cycle(RobotInfo::FaceLEDMask,1500,1.0);]  == howlDone
#endstatemachine startnode = launch; } // end of setup() }; #endif

Running the State Parser Tool Directly

Normally the state parser tool is invoked automatically by the Makefile when you compile your project, if your directory contains FSM files. However, you can also run the tool directly if you want to see whether your state machine description is valid, or look at the generated code. Simply run the script tools/stateparser, and give it an input filename as the first command line argument. You can specify an output filename as the second argument; if omitted, a default filename will be used. If you supply a second argument of "-" the output will be written to the terminal instead of to a file.
Prev: Nodes and transitions
Up: Contents
Next: Defining new types


Last modified: Fri Feb 15 04:44:56 EST 2008