Motion editor/Dynamics simulator
Integrated Development Platform
AIST RTC collection
RT-Components collection by AIST
Tokyo Opensource Robotics Association
Middleware for DAQ (Data Aquisition) by KEK
(GA) In the Data Port (Basic), the basic usage of the data port was explained. In the advanced section, I will explain how to use it a little more.
Use of original data type
In addition to the predefined data types (eg TimedLong, TimedDouble, etc.), you can also use your own defined data types in the data port. However, before creating a new data type yourself, make sure that a similar data type is not already defined, and define a new data type only if the required data type is not found in it. Is recommended.
In OpenRTM-aist, the data type used for the data port is defined in the following IDL file.
Create a folder for the component. Here, we will create a folder called “UserDefType” directly under the C drive. (C: \UserDefType)
Create IDL file
Create an IDL file that defines the data type. The data type is defined by the struct keyword. The following basic types, string types, and sequence types are available.
In this example, MyDataType.idl defines a data type called MyData.
// @file MyDataType.idl
On the second line #include "BasicDataType.idl" Is necessary to use the first field tm of MyData type (RTC::Time type). Unless you have a specific reason, declare the first field as RTC::Time tm; to store the time stamp, even for custom data types.
Create a project with RTC Builder
Create a project with RTCBuilder.
Click the "RTC Builder Project" icon, enter the project name in the displayed window, and click "Finish" to display the generated project file in the left window.
Since there is an idl folder where you can place your own data type, please place the IDL file (MyDataType.idl) of your own data type by dragging and dropping or [Right click]> [Paste].
The project folder is located under the [c: \ Users \ username \ workspase] folder if you proceed by default with "Select directory as workspace" to be displayed immediately after starting RTC Builder.
Creating a data port
Create a component using idl of the original data type in RTCBuilder.
Open the Data Port Settings tab and define the data port (InPort / OutPort).
If you want to use your own data type in the created data port, click [Reload] to load MyDataType.idl in the idl folder, and you can select the newly defined MyData from the * data type pull-down.
After setting the other items required for component creation, return to the basic tab and click the [Code Generation] button to generate the code.
Using data port and connector callbacks
We have already mentioned that InPort checks for data arrival with isNew() and reads it with read(), or OutPort sends out data with write().
For example, InPort cannot obtain data until it is called by read function after calling isNew() in a function such as onExecute(). Even if the onExecute() cycle is very fast, the timing at which data arrives at InPort and the timing at which the actual processing is performed are asynchronous.
What if you want to process data as soon as it arrives, that is, synchronously? As a way to achieve this, OpenRTM-aist defines callbacks that are called at various data port and connector processing timings.
There are four types of callbacks: 1) InPort, 2) OutPort, 3) connector, and 4) port.
InPort provides two types of callbacks: These are defined in rtm / PortCallback.h.
The OnRead callback is a callback used to return data with some conversion to the caller when read() is called and OnReadConvert is called when read() is called.
Each callback is implemented by inheriting the base class of each functor defined in rtm/PortCallback.h.
Each implementation example is shown below.
In MyOnRead functor that inherits OnRead, output stream std :: ostream is passed in the constructor. It is intended to pass a file output stream std :: ofstream etc. opened somewhere. The functor entity operator()() outputs a character string to the output stream and standard output. In this way, functors can also call other objects by passing state variables in advance in the constructor.
On the other hand, MyOnReadConvert which inherits OnReadConvert<T> implements only operator()(const T&). The argument of this function is passed the data before being read into the InPort variable when read() is called. Some processing is performed in this function, and the data returned by return is written to the InPort variable. In this example, the square is calculated and returned assuming that the data type has a member called data and the multiplication operator is defined. If you use a variable type that does not have an appropriate member, you will get a compilation error.
Now, let's actually incorporate this functor into the component. As a sample using InPort, ConsoleOut, which is a sample included in OpenRTM-aist, is used here. When ConsoleOut expands the OpenRTM-aist source,
If you install from a package etc.
Below is the source code.
First, write the above class definition in ConsoleOut.h. It is better to describe the class definition in a separate source, but the functor class is only used in this component and its content is short. In such cases, define it including the implementation in the header. It does n’t matter.
First, declare the callback functors MyOnRead and MyOnReadConvert before declaring the ConsoleOut class. In order to have pointer variables of these classes as members, declare each pointer variable in the private part. At this time, please note that both MyOnRead / MyOnReadConvert give TimedLong, which is the same as the InPort type of this component, to the type argument of the class template.
OutPort provides the following two types of callbacks. These are defined in rtm / PortCallback.h.
The OnWrite callback is a callback used to send data with some sort of conversion when write () is called, and OnWriteConvert is called when write () is called.
Each callback is implemented by inheriting the base class of each functor defined in rtm / PortCallback.h like InPort.
Each implementation example is shown below.
The way to write a callback functor is almost the same as InPort OnRead / OnReadConvert. MyOnWrite functor that inherits OnWrite passes the output stream std :: ostream in the constructor. It is intended to pass a file output stream std :: ofstream etc. opened somewhere. The functor entity operator () outputs a character string to the output stream and standard output. In this way, functors can also call other objects by passing state variables in advance in the constructor.
On the other hand, MyOnReadConvert which inherits OnReadConvert <T> implements only operator () (constT &). The argument of this function is passed the data before being read into the InPort variable when read () is called. Some processing is performed in this function, and the data returned by return is written to the InPort variable. In this example, the square is calculated and returned assuming that the data type has a member called data and the multiplication operator is defined. If you use a variable type that does not have an appropriate member, you will get a compilation error.
Connector buffer callback
A connector is an object that abstracts buffers and communication paths. As shown in the figure, it exists between OutPort and InPort, data is written from OutPort by write () function, and data is read from InPort by read () function. The connector abstracts and hides how the data is transmitted from OutPort to InPort.OutPort is a buffer in the connector
OutPort can be connected to multiple InPorts, but one connector is created for each connection. (In fact, InPort can have multiple connections at the same time, but since there is no way to distinguish the data, it is not normally used.) In other words, if there are three connections, there are three connectors, each with a write status.
You can also see that for these functions, there must be one connector for each OutPort / InPort pair. Furthermore, when modeling the connector at the implementation level corresponding to the subscription type, we introduced an object for asynchronous communication called publisher.
A data port creates one connector object per connection when a connection is established. A connector is an abstract channel of data stream that connects OutPort and InPort.
The data port returns a status when data is sent and received. The status is defined in rtm/DataPortStatus.h.
PORT_OK, PORT_ERROR, SEND_FULL, SEND_TIMEOUT, CONNECTION_LOST, UNKNOWN_ERROR
PORT_OK, PORT_ERROR, BUFFER_ERROR, BUFFER_FULL, BUFFER_TIMEOUT, UNKNOWN_ERROR
PORT_OK, PORT_ERROR, RECV_EMPTY, RECV_TIMEOUT, CONNETION_LOST, UNKNOWN_ERROR
Creating your own data port interface
An example of creating a custom data port interface is shown below.
The following functions and classes must be defined.
Provider class (InPortTestProvider)
Provider class of data port interface (Push type). When the put function is called on the consumer side, it is necessary to transfer data to the provider side in some way. In this sample, data is written to the file when the put function is called on the consumer side, and data is transferred by reading data from the file on the provider side.
Consumer class of data port interface (Push type). Must inherit from InPortProvider. Inheritance of the Task class is not required because it is unique to this sample.
Consumer class (InPortTestConsumer)
Consumer class of data port interface (Push type). In case of Push type, a consumer is created on the InPort side and a provider is created on the OutPort side. When the put function is called on the consumer side, it is necessary to transfer data to the provider side in some way. In this sample, data is written to the file when the put function is called on the consumer side, and data is transferred by reading data from the file on the provider side.
Consumer class of data port interface (Push type). Must inherit from InPortConsumer.
Provider and consumer registration function (InPortTestInterfaceInit)
The OpenRTM-aist manager calls the “XXXInit” function when the dynamic link library “XXX.dll” is loaded. For this sample, load "InPortTestInterface.dll" and call the following "InPortTestInterfaceInit" function.
1. Prepare an environment where OpenRTM-aist is installed.
2. Create a CMake configuration file (CMakeLists.txt) for building.
The following is a CMake configuration file for building a custom interface sample.
3. Generate a Visual Studio project file with CMake.
4. Build with Visual Studio.
After building, InPortTestInterface.dll is generated in the Debug folder.
5. Create rtc.conf # br Create rtc.conf and specify InPortTestInterface.dll in the module that loads when Manager starts.
If InPortTestInterface.dll is different from the directory where RTC is executed, set the module search path separately.
6. Load the above rtc.conf and start RTC.
7. Specify "test" for Interface Type when connecting the port.
Interface Type can be specified from RTSystemEditor.