Reactive RTT state machines

Hi,
I try to set up a reactive RTT state machine. Unfortunately the state machine does not react to any events. I followed the instructions in the Orocos component manual. I thought, I need a (probably infinite) run function in reactive mode, so the state can react to events. But it doesn't make any difference if a implement a run function or not. The state machine stays in Init even though events are sent from the Hello-component. Could anyone please tell me, what I'm doing wrong? I'm using Orocos 2.7rc9.

Thanks a lot.
Sandra

Here is a simple example:

State Machine:
StateMachine States
{
var int count;

initial state Init
{
/* run */
/* { */
/* while(true) */
/* { */
/* yield; */
/* } */
/* } */

entry
{
msg("Init entry");
}

exit
{
msg("Init exit");
}

transition input(count)
{
msg("count: " + count);
} select sub;
}

state sub
{
entry
{
msg("sub entry");
}

/* run */
/* { */
/* while(true) */
/* { */
/* yield; */
/* } */
/* } */
exit
{
msg("sub exit");
}

transition input(count)
{
msg("count: " + count);
}

}

final state Final
{
}
}

RootMachine States StateI

Classes:
class Hello : public RTT::TaskContext
{
private:
OutputPort<int> output;
int count;

public:
Hello(std::string name) : RTT::TaskContext(name, PreOperational)
{
count = 0;
addPort( "output", output );
}
virtual void updateHook()
{
count++;
output.write(count);
}
};

class World : public RTT::TaskContext
{
private:
InputPort<int> input;

public:
World(std::string name) : RTT::TaskContext(name, PreOperational)
{
addEventPort("input", input);
addOperation("msg", &World::msg, this, RTT::OwnThread);
}

void msg(std::string msg)
{
std::cerr << msg <<std::endl;
}

virtual bool configureHook()
{
if(getProvider<Scripting>("scripting")->loadStateMachines("testFSM.osd"))
{
if (getProvider<Scripting>("scripting")->activateStateMachine("StateI"))
{
boost::dynamic_pointer_cast<scripting::ScriptingService>(provides("scripting"))->getStateMachine("StateI")->trace(true);
boost::dynamic_pointer_cast < RTT::scripting::ScriptingService > (provides("scripting"))->getStateMachine("StateI")->step();
// getProvider<Scripting>("scripting")->startStateMachine("StateI"); // don't start so it's in reactive mode
return true;
}
}
return false;
}
};

int ORO_main(int argc, char** argv)
{
Logger::In in("main()");

Hello hello("Hello");
hello.setActivity( new Activity(ORO_SCHED_OTHER, RTT::os::LowestPriority, 0.5 ) );

World world("World");
world.setActivity( new Activity(ORO_SCHED_OTHER, RTT::os::LowestPriority, 0 ) );

connectPeers(&world, &hello );

//connect Ports
hello.ports()->getPort("output")->connectTo(world.ports()->getPort("input"));

// Start the component:
if (world.configure())
{
world.start();
}
if (hello.configure())
{
hello.start();
}

getchar();

world.stop();
hello.stop();

world.disconnect();
hello.disconnect();

return 0;
}

Reactive RTT state machines

Hi Sandra,

The documentation clearly needs some updating here.

First of all, the reactive behavior only works 'out of the box' for
operations. They will wake up the state machine and process the event. For
ports, you need to wake up the state machine yourself by attaching a
callback.

I got your case working by adding this code:

In World's constructor :

addEventPort("input", input, boost::bind(&World::gotint, this,_1));

+ in the class body:

void gotint(base::PortInterface* pi)
{
std::cerr << "got int" <<std::endl;

boost::dynamic_pointer_cast<scripting::ScriptingService>(provides("scripting"))->getStateMachine("StateI")->step();
}

This 'step' will request a new state in reactive mode, each time new data
arrives on the input port. Because you don't read that port in 'gotint',
the state machine gets the new value instead and processes it. If you would
read the port in gotint, the SM would not see the new data, since it would
see OldData.

You should store the result of getStateMachine in a StateMachinePtr shared
ptr for efficiency reasons.

A 'run' state is not required for reactive behavior.

Dev Note : The RTT StateMachine code could easily install this step handler
for you to have identical bahavior for operations and ports.... but ports
take only one callback, so the user or the SM could cancel out each other's
callback if both need one.

Peter

On Tue, Jul 15, 2014 at 9:52 AM, Sandra Beyer <sandra [dot] beyer [..] ...>
wrote:

> Hi,
>
> I try to set up a reactive RTT state machine. Unfortunately the state
> machine does not react to any events. I followed the instructions in the
> Orocos component manual. I thought, I need a (probably infinite) run
> function in reactive mode, so the state can react to events. But it doesn’t
> make any difference if a implement a run function or not. The state machine
> stays in Init even though events are sent from the Hello-component. Could
> anyone please tell me, what I’m doing wrong? I’m using Orocos 2.7rc9.
>
>
>
> Thanks a lot.
>
> Sandra
>
>
>
> Here is a simple example:
>
>
>
> State Machine:
>
> StateMachine States
>
> {
>
> var int count;
>
>
>
> initial state Init
>
> {
>
> /* run */
>
> /* { */
>
> /* while(true) */
>
> /* { */
>
> /* yield; */
>
> /* } */
>
> /* } */
>
>
>
> entry
>
> {
>
> msg("Init entry");
>
> }
>
>
>
> exit
>
> {
>
> msg("Init exit");
>
> }
>
>
>
> transition input(count)
>
> {
>
> msg("count: " + count);
>
> } select sub;
>
> }
>
>
>
> state sub
>
> {
>
> entry
>
> {
>
> msg("sub entry");
>
> }
>
>
>
> /* run */
>
> /* { */
>
> /* while(true) */
>
> /* { */
>
> /* yield; */
>
> /* } */
>
> /* } */
>
> exit
>
> {
>
> msg("sub exit");
>
> }
>
>
>
> transition input(count)
>
> {
>
> msg("count: " + count);
>
> }
>
>
>
>
>
> }
>
>
>
> final state Final
>
> {
>
> }
>
> }
>
>
>
> RootMachine States StateI
>
>
>
>
>
>
>
> Classes:
>
> class Hello : public RTT::TaskContext
>
> {
>
> private:
>
> OutputPort<int> output;
>
> int count;
>
>
>
> public:
>
> Hello(std::string name) : RTT::TaskContext(name,
> PreOperational)
>
> {
>
> count = 0;
>
> addPort( "output", output );
>
> }
>
> virtual void updateHook()
>
> {
>
> count++;
>
> output.write(count);
>
> }
>
> };
>
>
>
> class World : public RTT::TaskContext
>
> {
>
> private:
>
> InputPort<int> input;
>
>
>
> public:
>
> World(std::string name) : RTT::TaskContext(name,
> PreOperational)
>
> {
>
> addEventPort("input", input);
>
> addOperation("msg", &World::msg, this, RTT::OwnThread);
>
> }
>
>
>
> void msg(std::string msg)
>
> {
>
> std::cerr << msg <<std::endl;
>
> }
>
>
>
> virtual bool configureHook()
>
> {
>
>
> if(getProvider<Scripting>("scripting")->loadStateMachines("testFSM.osd"))
>
> {
>
> if
> (getProvider<Scripting>("scripting")->activateStateMachine("StateI"))
>
> {
>
>
> boost::dynamic_pointer_cast<scripting::ScriptingService>(provides("scripting"))->getStateMachine("StateI")->trace(true);
>
> boost::dynamic_pointer_cast <
> RTT::scripting::ScriptingService >
> (provides("scripting"))->getStateMachine("StateI")->step();
>
> //
> getProvider<Scripting>("scripting")->startStateMachine("StateI"); // don’t
> start so it’s in reactive mode
>
> return true;
>
> }
>
> }
>
> return false;
>
> }
>
> };
>
>
>
> int ORO_main(int argc, char** argv)
>
> {
>
> Logger::In in("main()");
>
>
>
> Hello hello("Hello");
>
> hello.setActivity( new Activity(ORO_SCHED_OTHER,
> RTT::os::LowestPriority, 0.5 ) );
>
>
>
> World world("World");
>
> world.setActivity( new Activity(ORO_SCHED_OTHER,
> RTT::os::LowestPriority, 0 ) );
>
>
>
> connectPeers(&world, &hello );
>
>
>
> //connect Ports
>
>
> hello.ports()->getPort("output")->connectTo(world.ports()->getPort("input"));
>
>
>
> // Start the component:
>
> if (world.configure())
>
> {
>
> world.start();
>
> }
>
> if (hello.configure())
>
> {
>
> hello.start();
>
> }
>
>
>
> getchar();
>
>
>
> world.stop();
>
> hello.stop();
>
>
>
> world.disconnect();
>
> hello.disconnect();
>
>
>
>
>
> return 0;
>
> }
>
> --
> Orocos-Dev mailing list
> Orocos-Dev [..] ...
> http://lists.mech.kuleuven.be/mailman/listinfo/orocos-dev
>
>

Reactive RTT state machines

Hi Sandra,

The documentation clearly needs some updating here.

First of all, the reactive behavior only works 'out of the box' for
operations. They will wake up the state machine and process the event. For
ports, you need to wake up the state machine yourself by attaching a
callback.

I got your case working by adding this code:

In World's constructor :

addEventPort("input", input, boost::bind(&World::gotint, this,_1));

+ in the class body:

void gotint(base::PortInterface* pi)
{
std::cerr << "got int" <<std::endl;

boost::dynamic_pointer_cast<scripting::ScriptingService>(provides("scripting"))->getStateMachine("StateI")->step();
}

This 'step' will request a new state in reactive mode, each time new data
arrives on the input port. Because you don't read that port in 'gotint',
the state machine gets the new value instead and processes it. If you would
read the port in gotint, the SM would not see the new data, since it would
see OldData.

You should store the result of getStateMachine in a StateMachinePtr shared
ptr for efficiency reasons.

A 'run' state is not required for reactive behavior.

Dev Note : The RTT StateMachine code could easily install this step handler
for you to have identical bahavior for operations and ports.... but ports
take only one callback, so the user or the SM could cancel out each other's
callback if both need one.

Peter

On Tue, Jul 15, 2014 at 9:52 AM, Sandra Beyer <sandra [dot] beyer [..] ...>
wrote:

> Hi,
>
> I try to set up a reactive RTT state machine. Unfortunately the state
> machine does not react to any events. I followed the instructions in the
> Orocos component manual. I thought, I need a (probably infinite) run
> function in reactive mode, so the state can react to events. But it doesn’t
> make any difference if a implement a run function or not. The state machine
> stays in Init even though events are sent from the Hello-component. Could
> anyone please tell me, what I’m doing wrong? I’m using Orocos 2.7rc9.
>
>
>
> Thanks a lot.
>
> Sandra
>
>
>
> Here is a simple example:
>
>
>
> State Machine:
>
> StateMachine States
>
> {
>
> var int count;
>
>
>
> initial state Init
>
> {
>
> /* run */
>
> /* { */
>
> /* while(true) */
>
> /* { */
>
> /* yield; */
>
> /* } */
>
> /* } */
>
>
>
> entry
>
> {
>
> msg("Init entry");
>
> }
>
>
>
> exit
>
> {
>
> msg("Init exit");
>
> }
>
>
>
> transition input(count)
>
> {
>
> msg("count: " + count);
>
> } select sub;
>
> }
>
>
>
> state sub
>
> {
>
> entry
>
> {
>
> msg("sub entry");
>
> }
>
>
>
> /* run */
>
> /* { */
>
> /* while(true) */
>
> /* { */
>
> /* yield; */
>
> /* } */
>
> /* } */
>
> exit
>
> {
>
> msg("sub exit");
>
> }
>
>
>
> transition input(count)
>
> {
>
> msg("count: " + count);
>
> }
>
>
>
>
>
> }
>
>
>
> final state Final
>
> {
>
> }
>
> }
>
>
>
> RootMachine States StateI
>
>
>
>
>
>
>
> Classes:
>
> class Hello : public RTT::TaskContext
>
> {
>
> private:
>
> OutputPort<int> output;
>
> int count;
>
>
>
> public:
>
> Hello(std::string name) : RTT::TaskContext(name,
> PreOperational)
>
> {
>
> count = 0;
>
> addPort( "output", output );
>
> }
>
> virtual void updateHook()
>
> {
>
> count++;
>
> output.write(count);
>
> }
>
> };
>
>
>
> class World : public RTT::TaskContext
>
> {
>
> private:
>
> InputPort<int> input;
>
>
>
> public:
>
> World(std::string name) : RTT::TaskContext(name,
> PreOperational)
>
> {
>
> addEventPort("input", input);
>
> addOperation("msg", &World::msg, this, RTT::OwnThread);
>
> }
>
>
>
> void msg(std::string msg)
>
> {
>
> std::cerr << msg <<std::endl;
>
> }
>
>
>
> virtual bool configureHook()
>
> {
>
>
> if(getProvider<Scripting>("scripting")->loadStateMachines("testFSM.osd"))
>
> {
>
> if
> (getProvider<Scripting>("scripting")->activateStateMachine("StateI"))
>
> {
>
>
> boost::dynamic_pointer_cast<scripting::ScriptingService>(provides("scripting"))->getStateMachine("StateI")->trace(true);
>
> boost::dynamic_pointer_cast <
> RTT::scripting::ScriptingService >
> (provides("scripting"))->getStateMachine("StateI")->step();
>
> //
> getProvider<Scripting>("scripting")->startStateMachine("StateI"); // don’t
> start so it’s in reactive mode
>
> return true;
>
> }
>
> }
>
> return false;
>
> }
>
> };
>
>
>
> int ORO_main(int argc, char** argv)
>
> {
>
> Logger::In in("main()");
>
>
>
> Hello hello("Hello");
>
> hello.setActivity( new Activity(ORO_SCHED_OTHER,
> RTT::os::LowestPriority, 0.5 ) );
>
>
>
> World world("World");
>
> world.setActivity( new Activity(ORO_SCHED_OTHER,
> RTT::os::LowestPriority, 0 ) );
>
>
>
> connectPeers(&world, &hello );
>
>
>
> //connect Ports
>
>
> hello.ports()->getPort("output")->connectTo(world.ports()->getPort("input"));
>
>
>
> // Start the component:
>
> if (world.configure())
>
> {
>
> world.start();
>
> }
>
> if (hello.configure())
>
> {
>
> hello.start();
>
> }
>
>
>
> getchar();
>
>
>
> world.stop();
>
> hello.stop();
>
>
>
> world.disconnect();
>
> hello.disconnect();
>
>
>
>
>
> return 0;
>
> }
>
> --
> Orocos-Dev mailing list
> Orocos-Dev [..] ...
> http://lists.mech.kuleuven.be/mailman/listinfo/orocos-dev
>
>