at works a bit like if, expect that is it always running in the background:
at (distance < 50) echo "Obstacle appears";
The echo command in the above example will start at the time when the test becomes true, only once. To be more precise, at triggers the command when the test switches from false to true. It is very useful to start an action when a condition is met to react to this condition. If you run the above code, the message "Obstacle appear" will be displayed once when you move your hand in front of the Aibo.
onleave is a bit like else and is followed by an action that will be executed when the test switches from true to false:
at (distance < 50) echo "Obstacle appears" onleave echo "The obstacle is gone";
whenever works a bit like while, except that it never terminates and run in the background:
whenever (distance < 50) echo "There is an obstacle";
The echo command will be executed whenever the test is true. Then, it will be executed again if the test is still true, and so on, until the test becomes false. Whenever the test switches to true again, the loop restarts and the command is executed. Compared to the at example above, the difference is that the message "There is an obstacle" will be displayed several times, as long as you leave your hand near the head of the robot.
Alternatively, you also have an else construct available to specify something to do when the test is false:
whenever (distance < 50) echo "There is an obstacle" else echo "There is no obstacle";
whenever and at are the two fundamental constructs that you will use when doing reactive programming and event catching mechanisms on your robot.
The command wait (n) will wait for n milliseconds before ending. It is useful to have a temporal break in a series of commands, typically motor commands:
headPan = 0 | wait(1s) | headPan = 90;
The command waituntil(test) waits until the test becomes true and can be useful to synchronize different parallel programs on a given condition.
The command timeout (n) cmd will execute the command cmd and stop it after n milliseconds if it is not already finished.
timeout(10s) loop legRF2 = legLF2;
The command stopif (test) cmd will execute the command cmd and stops it when the test becomes true. Of course, if the command is already finished, nothing special happens.
stopif(distance<50) robot.walk();
The command freezeif (test) cmd will execute the command cmd and freeze it when the test becomes true. When the test is false again, cmd is unfreezed.
freezeif(!ball.visible) trackball();
This can be very useful to specify that certain portions of code should run only when certain conditions are met.
The tests used in event catching commands like at, whenever, waituntil, stopif or freezeif can be associated to time constraints, becoming "soft tests":
at (headSensor >0 ~ 2s)
echo "Head touched...";
This means that the test has to be true for 2 seconds before it becomes actually true for the at command. You can specify the time in s or ms by using the appropriate suffix and it should be separated from the test by a tilde ~
Soft tests are usable with any event catching command and they are very useful in robotics as a simple noise filter for sensor inputs.
Event programming is a very useful feature and a good way of doing robot programming. The basic idea of event programming is that some command emit an event and some other catches this event and do something.
To emit an event, the emit command is available in URBI, and you can use at or whenever to catch it:
at (boom()) echo "boom!"; emit boom; [139464:notag] *** boom!
Note that the boom event here is local to the connection. If you want to make the event visible from other connection, you should use a prefix, like myprefix.boom.
You can add parameters to events like this:
emit myevent(1,"hello");
The parameters can be retrieved when the event is catched:
at (myevent(x,y)) echo "catch two: " + x + " " + y; at (myevent(1,x)) echo "catch one: " + x;
The second at here is interesting as it is doing a filtering on the event parameters, accepting only events whose first parameter equals 1:
emit myevent(1,"hello"); [146711:notag] *** catch two: 1.000000 hello [146711:notag] *** catch one: hello emit myevent(2,15); [148991:notag] *** catch two: 2.000000 15.000000
Events usually have a virtually null duration, they are just spikes (Dirac functions of time). However, you can explicitly request that an event lasts for a certain duration by specifying this duration between parenthesis like this:
emit(10s) boom; emit(15h12m) myevent(1,"hello");
This will make a difference between at and whenever event catcher for example: whenever will loop during the whole event duration.
You can have any command repeated at specific time intervals in URBI, using the every command. The following example will say "hello" every 10 minutes:
every (10m) echo "hello";
One typical usage is to use the every command to pulse events at regular intervals:
every (100ms) emit pulse;
To stop the emission, just use stop on the every command with the appropriate tag :
mypulse:every (100ms) emit pulse; stop mypulse;