|
|
|
startnode: SoundNode($,"barkhigh.wav") =T(5000)=> startnode |
startnode: StateNode =N=> {barker, buttonwatcher} barker: SoundNode($,"barkhigh.wav") =T(5000)=> barker buttonwatcher: StateNode =B(RobotInfo::GreenButOffset)[setSound("ping.wav")]=> buttonwatcher |
nodename: NodeClass<template_args>(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. State node constructors normally take a string as the initial argument, specifying the node name. In the shorthand notation, you can leave out the constructor arguments, in which case the argument list defaults to ($). The dollar sign is a special token that expands into a string that is the name of the node. So, for example:
buttonwatcher: StateNode
expands into
buttonwatcher: StateNode($)
which in turn expands into
buttonwatcher: StateNode("buttonwatcher")
When you specify arguments to the node constructor, the $ notation is
used so you don't have to explicitly repeat the name of the node.
This way, if you need to rename a node, you only have to change it in
one place. Example:
barker: SoundNode($, "barkhigh.wav")
expands into
barker: SoundNode("barker", "barkhigh.wav")
If you don't assign a name to a node, the stateparser will generate
one for you, e.g., SoundNode($,"barkhigh.wav")
expands
into SoundNode("soundnode1", "barkhigh.wav")
.
Initializers are used to call methods that set parameters of a node or
transition. The initializer expressions for a state node must be
methods of the node being initialized. For example, SoundNode has a
method called setAutoStop, so if you want to call this method as part
of your initialization of this node, you can write:
barker: SoundNode($, "barkhigh.wav") [setAutoStop(true);]
which expands into the following code:
A very common use of initializers is to set parameters for motion command nodes such as LedNode or WalkNode.
SoundNode *barker = new SoundNode("barker","barkhigh.wav"); addNode(barker); barker->setAutoStop(true);
sourcenodeAll components except the source node and transition class are optional, as are the spaces between them. A "source node" or "target node" can be either a node name, or an entire node declaration. Node and transition declarations can therefore be chained together, forming a sequence, like this:>==
transname: TransitionClass<template_args>(constructor_args) [initializers]==>
targetnode
bark: SoundNode($,"barkmed.wav") >== EventTrans($$,EventBase::buttonEGID) ==> howl: SoundNode($,"howl.wav")
Chaining node declarations and transitions together like this is
permitted but not required. Some people prefer to write all their
node declarations first, and then all their transition
declarations.
The special token $$ expands into the name of the destination node,
which is the first argument to the transition constructor.
Transitions also have a constructor that takes a string first argument
that is the name of the transition; the destination node is then the
second argument. If no constructor arguments are specified, defaults are
supplied. Thus,
howl >== CompletionTrans ==> wait: StateNode
expands into
howl >== CompletionTrans($,$$) ==> wait: StateNode($)
which in turn expands into
howl >== CompletionTrans("completiontrans1",wait) ==> wait: StateNode("wait")
Initializers can be used to set parameters of a transition, such as
telling it which sound file to play.
A list notation is used when a transition has multiple sources or
multiple destinations. In that case, each of the sources or
destinations must be referenced by name and declared elsewhere. For
multiple source nodes, use:
{srcname1, srcname2, ...} >==
transition ==>
Similarly, for multiple targets use:
>== transition ==>
{targname1, targname2, ...}
Here is an example of the bark/howl state machine from the previous
section written as simply as possible using the long form for
transitions. Notice the use of optional blank lines between
declarations since, in this version, we're not chaining nodes and
transition declarations together. Breaking up definitions by adding
blank lines can make it easier to find syntax errors.
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 |
Notice that we do not have to apply the EventBase:: qualifier to the arguments of the EventTrans transition when we write it in abbreviated form, e.g., we can write
NullTrans =N=> CompletionTrans =C=> CompletionTrans($, $$, n) =C(n)=> TextMsgTrans($, $$, str) =TM(str)=> EventTrans($, $$, EventBase::g, s, EventBase::t) =E(g,s,t)=> EventTrans($, $$, EventBase::buttonEGID, s, EventBase::activateETID) =B(s)=> EventTrans($, $$, EventBase::buttonEGID, s, EventBase::t) =B(s,t)=> TimeOutTrans($, $$, t) =T(t)=> RandomTrans =RND=>
=E(buttonEGID,ChiaraInfo::GreenButOffset,activateETID)=>.
For button press events there is an even more abbreviated form that assumes an event type of "activate"
by default: =B(ChiaraInfo::GreenButOffSet)=>
.
Here is an example of the full bark/howl/blink state machine defined
as compactly as possible, using chaining and transition abbreviations.
startnode: StateNode =N=> {noblink, bark} noblink: LedNode [setPriority(MotionManager::kBackgroundPriority); getMC()->set(RobotInfo::FaceLEDMask,0.0);] bark: SoundNode($,"barkmed.wav") =B(RobotInfo::GreenButOffset)[setSound("ping.wav");]=> wait: StateNode =T(15000)=> bark bark =T(5000)=> {howl, blink} howl: SoundNode($,"howl.wav") blink: LedNode [getMC()->cycle(RobotInfo::FaceLEDMask, 1500, 1.0);] {howl, blink} =C(1)=> wait |
$statemachine{
and terminated by a }
.
Alternatively, you can use $setupmachine{...}
which takes
care of defining setup() for you.
The Tekkotsu make file will read the fsm file and create xxx-fsm.h or
xxx-fsm.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:
#include "Behaviors/StateMachine.h" class BarkHowlBlinkBehavior : public StateNode { public: BarkHowlBlinkBehavior() : StateNode("BarkHowlBlinkBehavior") {}
|
If you supply a second argument of "-" the output will be written to the terminal instead of to a file.
Tekkotsu/tools/sbin/stateparser BarkHowlBlinkBehavior.cc.fsm -
startnode: StateNode =N=> startnode |
startnode
at the end of your setup() function.
You can assign names to transitions as well as to nodes. If you don't
do this, they will be assigned generated names like
nulltrans1
or eventtrans3
. Assigning your
own names can make the code more readable, and it can make traces
(either from the Event Logger or the Storyboard tool) more
understandable. Exanple:
{howl, blink} >== howldone: CompletionTrans($,$$,1) ==> wait |
{howl, blink} =howldone:C(1)=> wait |
=>
with no space before the left square bracket or
after the right square bracket. For example, you could use an
initializer to assign a sound to an EventTrans by calling its
setSound() method, which it inherits from Transition, as in the
example program above.
|
|
|