RTT 2.0 Data Flow Ports

RTT 2.0 has a more powerful, simple and flexible system to exchange data between components.

Renames

Every instance of ReadDataPort and ReadBufferPort must be renamed to 'InputPort' and every instance of WriteDataPort and WriteBufferPort must be renamed to OutputPort. 'DataPort' and 'BufferPort' must be renamed according to their function.

The rtt2-converter tool will do this renaming for you, or at least, make its best guess.

Usage

InputPort and OutputPort have a read() and a write() function respectively:

using namespace RTT;
double data;
 
InputPort<double> in("name");
FlowStatus fs = in.read( data ); // was: Get( data ) or Pull( data ) in 1.x
 
OutputPort<double> out("name");
out.write( data );               // was: Set( data ) or Push( data ) in 1.x

As you can see, Get() and Pull() are mapped to read(), Set() and Push() to write(). read() returns a FlowStatus object, which can be NoData, OldData, NewData. write() does not return a value (send and forget).

Writing to a not connected port is not an error. Reading from a not connected (or never written to) port returns NoData.

Your component can no longer see if a connection is buffered or not. It doesn't need to know. It can always inspect the return value of read() to see if a new data sample arrived or not. In case multiple data samples are ready to read in a buffer, read() will fetch each sample in order and each time return NewData, until the buffer is empty, in which case it returns the last data sample read with 'OldData'.

If data exchange is buffered or not is now fixed by 'Connection Policies', or 'RTT::ConnPolicy' objects. This allows you to be very flexible on how components are connected, since you only need to specify the policy at deployment time. It is possible to define a default policy for each input port, but it is not recommended to count on a certain default when building serious applications. See the 'RTT::ConnPolicy' API documentation for which policies are available and what the defaults are.

Deployment

The DeploymentComponent has been extended such that it can create new-style connections. You only need to add sections to your XML files, you don't need to change existing ones. The sections to add have the form:

  <!-- You can set per data flow connection policies -->
  <struct name="SensorValuesConnection" type="ConnPolicy">
    <!-- Type is 'shared data' or buffered: DATA: 0 , BUFFER: 1 -->
    <simple name="type" type="short"><value>1</value></simple>
    <!-- buffer size is 12 -->
    <simple name="size" type="short"><value>12</value></simple>
  </struct>
  <!-- You can repeat this struct for each connection below ... -->

Where 'SensorValuesConnection' is a connection between data flow ports, like in the traditional 1.x way.

Consult the deployment component manual for all allowed ConnPolicy XML options.

Real-time with Complex data

The data flow implementation tries to pass on your data as real-time as possible. This requires that your operator=() of your data type is hard real-time. In case your operator=() is only real-time if enough storage is allocated on beforehand, you can inform your output port of the amount of storage to pre-allocate. You can do this by using:

  std::vector<double> joints(10, 0.0);
  OutputPort<std::vector<double> > out("out");
 
  out.setDataSample( joints ); // initialises all current and future connections to hold a vector of size 10.
 
  // modify joint values... add connections etc.
 
  out.write( joints );  // always hard real-time if joints.size() <= 10

As the example shows, a single call to setDataSample() is enough. This is not the same as write() ! A write() will deliver data to each connected InputPort, a setDataSample() will only initialize the connections, but no actual writing is done. Be warned that setDataSample() may clear all data already in a connection, so it is better to call it before any data is written to the OutputPort.

In case your data type is always hard real-time copyable, there is no need to call setDataSample. For example:

  KDL::Frame f = ... ; // KDL::Frame never (de-)allocates memory during copy or construction.
 
  OutputPort< KDL::Frame > out("out");
 
  out.write( f );  // always hard real-time

Further reading

Please also consult the Component Builder's Manual and the Doxygen documentation for further reference.