Logic of Actions and Observations

In this section the logic of the time series used for communication between front and back end and for synchronization between actions and observations is explained. For more details, please see our paper on the open-source version of the TriFinger robot.

On Time Series and Time Relation of Actions and Observations

All data transfer between the front end (= user code) and the back end (= robot hardware) goes through so called time series. When calling append_desired_action(action), the action is not applied immediately but is appended to the time series of desired actions which serves as a queue.

At each time step, identified by a time index t, the backend takes the action at position t from the “desired actions” time series and sends it to the robot driver. At the same time an observation is acquired from the robot and added to the “observation” time series. This means that the effect of the desired action a_t is not yet visible in the observation y_t as is illustrated below (a'_t corresponds to the applied action, see Desired vs Applied Action).

Time relation of actions and observations

append_desired_action() returns the time index t at which the appended action will be executed. Methods like get_observation() expect a time index as input. If the specified time step has already passed, they immediately return the value from the corresponding step. If it lies in the future, the method will block and wait until the specified time step is reached and then return.

Note that the buffer size of the time series is limited (see the history_length argument of SingleProcessRobotData and MultiProcessRobotData). If the buffer is full, the oldest element is discarded. Trying to access an time index that is not in the buffer anymore results in an exception.

This design allows for simple code that is automatically executed at the control rate of the robot:

# send zero-torque action to get first observation, see explanation below
zero_torque_action = robot_interfaces.trifinger.Action()
t = frontend.append_desired_action(zero_torque_action)
observation = frontend.get_observation(t)

while True:
    action = smart_algorithm_to_compute_next_action(observation)

    t = frontend.append_desired_action(action)
    # The t given above refers to the moment the given action will be
    # executed.  Right now, this is in the future, so the following call
    # will automatically wait until the action is actually applied to the
    # platform
    observation = frontend.get_observation(t)

Send Action to Start Backend

In the beginning of the program execution, the back end is idle and waiting for the first action. Only after the first action is received, the loop is started that applies actions and writes observations to the time series.

This means you first have to send an action before you can read the first observation!

There are applications where an observation is needed before sending the first real action (e.g. when the action depends on the current position). In this case you need to send a “neutral” action first. How this action may look is robot dependent. The TriFinger robot, for example, can safely be started with a zero-torque action:

Python:

# an action without arguments defaults to zero torque
zero_torque_action = robot_interfaces.trifinger.Action()
t = frontend.append_desired_action(zero_torque_action)
first_observation = frontend.get_observation(t)

C++:

Action zero_torque_action = Action::Zero();
auto t = frontend.append_desired_action(zero_torque_action);
auto first_observation = frontend.get_observation(t);

Note that the creation of the zero torque action in the above example is specific to the _TriFinger_ robot. For other robots, the creation of the action would need to be adjusted to the action type of that specific robot.

When Next Action Is Not Provided In Time

If the back end reaches a time step t but the user did not yet provide an action for this time step (e.g. because the user code is running slower than 1 kHz), the back end automatically sets the desired action for step t to the same as the one of t - 1.

This is indicated to the user through the action_repetitions field in the status message which contains the number of times the current action has been repeated.