data port (advanced)

✏️ Edit this page on GitHub

#contents

In Data Port (Basics), we explained the basic usage of data ports. In this advanced section, we explain more in-depth usage.

Using Data Types

In data ports, in addition to predefined data types (for example, TimedLong, TimedDouble, etc.), you can also use data types that you define yourself. However, before creating a new data type yourself, we recommend checking whether a similar data type has already been defined, and defining a new data type only if the required data type is not among them.

In OpenRTM-aist, the data types used for data ports are defined in the following IDL files.

  • BasicDataType.idl
  • ExtendedDataTypes.idl
  • InterfaceDataTypes.idl

The storage locations are as follows. This is called the IDL directory.

  • For UNIX: {prefix}/include/rtm/idl,{prefix}/include/openrtm-x.y/rtm/idl ({prefix} is /usr/, /usr/local/, /opt/local/, etc.)
  • For Windows: {ProgramFiles}/OpenRTM-aist/x.y/rtm/idl, etc. ({Program Files} is C:/ProgramFiles, C:/Program Files (x86), etc.)

Creating an IDL File for a Custom Data Type

Create an IDL file that defines the data type. Data types are defined with the struct keyword. The following basic types, string types, and sequence types can be used.

Type Meaning Declaration Example
short short-type integer short shortVariable;
long long-type integer long longVariable;
unsinged short short-type integer unsigned short ushortVariable;
unsigned long long-type integer unsigned long ulongVariable;
float Single-precision floating point float floatVariable;
double Double-precision floating point number double doubleVariable;
char Character type char charVariable;
wchar wchar character type char charVariable;
boolean bool type bool shortVariable;
octet octet type octet octetVariable;
longlong longlong-type integer longlong longlongVariable;
ulonglong unsinged longlong-type integer ulonglong ulonglongVariable;
sequence <T> Sequence type sequence <double> doubleSeqVariable;

Here, we will define a data type named MyData in MyDataType.idl. Spaces are added at the beginning for display purposes, but they are unnecessary when actually using the IDL file, so remove them.

 // @file MyDataType.idl
 #include "BasicDataType.idl"

 module MyModule
{
  struct MyData
 {
    RTC::Time tm;
    short shortVariable;
    long longVariable;
    sequence<double> data;
 };
};

On the second line,

 #include "BasicDataType.idl"

is necessary in order to use the very first field tm (RTC::Time type) of the MyData type. Unless there is a particular reason, even for custom data types, declare the first field as RTC::Time tm; to store the timestamp. Also, module MyModule specifies the namespace. When defining a data type, always define an appropriate namespace and define the data type inside it.

Creating 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”; the generated project file will appear in the window on the left.

Display the "RTC Builder Project" window
Checking the idl folder

There is an idl folder where custom data types are placed, so place the custom data type IDL file (MyDataType.idl) there by drag and drop, [right-click] > [Paste], or similar.

If you proceeded with the default in “Select a directory as workspace” displayed immediately after starting RTCBuilder, the project folder is under the [ c:\Users\user name\workspase ] folder.

Creating a Data Port

Create a component using an IDL custom data type with RTCBuilder.

Open the data port settings tab and define the data ports (InPort/OutPort).

If you want to use a custom data type in the created data port, click [Reload]; MyDataType.idl in the idl folder will be loaded, and the newly defined MyData can be selected from the *Data Type dropdown.

Click [Reload] and select the MyData data type

After setting the other items required to create the component, return to the Basic tab and click the [Generate Code] button to generate the code.

Using Data Port and Connector Callbacks

As described earlier, an InPort checks whether data has arrived with isNew() and reads it with read(), while an OutPort sends data with write().

For example, after data arrives at an InPort, the data cannot be obtained until isNew() is called and read() is called inside a function such as onExecute(). Even if the onExecute() cycle is very fast, the timing at which data arrives at the InPort and the timing at which processing is actually performed are asynchronous.

What should you do if you want processing to be performed immediately after data arrives, that is, synchronously? To achieve this, OpenRTM-aist defines callbacks that are called at various processing timings of data ports and connectors.

Callbacks are broadly divided into four types: 1) InPort, 2) OutPort, 3) connector, and 4) port callbacks.

InPort Callbacks

The following two types of callbacks are provided for InPort. They are defined in rtm/PortCallback.h.

OnRead Called when InPort read() is called. Set with the InPort::setOnRead() function.
OnReadConvert Called to convert data when InPort read() is called. Set with the InPort::setOnReadConvert() function.

The OnRead callback is used when read() is called, and OnReadConvert is a callback used to return data that has undergone some kind of conversion to the caller when read() is called.

Each callback is implemented by inheriting from the corresponding functor base class defined in rtm/PortCallback.h.

A functor makes an object callable with syntax similar to an ordinary function. In C++, this can be achieved by overloading operator(). In C, callbacks are implemented by giving the caller a function pointer, but with only function pointers, it is difficult to give state variables to the callback itself. Since a functor is itself an object, it can have state variables and can be called in the same way as a C function.

Implementation examples are shown below.

 #include <rtm/Portcallback.h>

 template <class T>
 class MyOnRead
  : public RTC::OnRead<T>
{
 public:
   MyOnRead(std::ostream& os) : m_os(os) {};
   virtual void operator()()
  {
     m_os      << "read() 関数が呼ばれました。" << std::endl;
     std::cout << "read() 関数が呼ばれました。" << std::endl;
  }
 private:
   std::ostream& m_os;
};

 template <class T> 
 class MyOnReadConvert
  : public RTC::OnReadConvert<T>
{
 public:
   virtual T operator()(const T& value)
  {
     T tmp;
     tmp.data = value.data * value.data;
     return tmp;
  }
};

In the MyOnRead functor, which inherits from OnRead, an output stream std::ostream is passed in the constructor. This is intended to receive a file output stream std::ofstream or similar that has been opened somewhere. In operator()(), which is the actual body of the functor, a string is output to the output stream and to standard output. In this way, by passing state variables in advance through the constructor or similar, functors can also call other objects.

On the other hand, MyOnReadConvert, which inherits from OnReadConvert, implements only operator()(constT&). The argument of this function receives the data before it is read into the InPort variable when read() is called. Data processed in some way inside this function and returned with return is written to the InPort variable. In this example, the square is calculated and returned on the assumption that the data type has a member named data and that the multiplication operator is defined. If a variable type without an appropriate member is used, a compile error will occur.

Now, let us actually incorporate this functor into a component. As a sample that uses InPort, we will use ConsoleOut, a sample included in OpenRTM-aist. When the OpenRTM-aist source is extracted, ConsoleOut is under

 OpenRTM-aist-<version>/examples/SimpleIO/

and when installed from a package on Linux or similar systems, the source code is under

 /usr/share/OpenRTM-aist/examples/src/

First, write the above class definitions in ConsoleOut.h. Class definitions should originally be written in another source file, but since the functor classes are used only within this component and their contents are short, in such cases it is acceptable to define them including the implementation in the header.

 // ConsoleOut.h

  中略
 // Service Consumer stub headers
 // <rtc-template block="consumer_stub_h">

 // </rtc-template>

 using namespace RTC; 

 // ここから追加分
 template <class T>
 class MyOnRead

  : public RTC::OnRead<T>
{
 public:
   MyOnRead(std::ostream& os) : m_os(os) {};
   virtual void operator()()
  {
     m_os      << "read() 関数が呼ばれました。" << std::endl;
     std::cout << "read() 関数が呼ばれました。" << std::endl;
  }
 private:
   std::ostream& m_os;
};

 template <class T> 
 class MyOnReadConvert

  : public RTC::OnReadConvert<T>

{
 public:
   virtual T operator()(const T& value)
  {
     T tmp;
     tmp.data = value.data * value.data;
     return tmp;
  }
};
 // ここまで追加分

 class ConsoleOut

   : public RTC::DataFlowComponentBase

{

  中略

  protected:
   // DataInPort declaration
   // <rtc-template block="inport_declare">
   TimedLong m_in;
   InPort<TimedLong> m_inIn;

  中略

  private:
   //ここから追加分
   MyOnRead<TimedLong>* m_onread;
   MyOnReadConvert<TimedLong>* m_onreadconv;
   //ここまで追加分
};

First, before the declaration of the ConsoleOut class, declare the callback functors MyOnRead and MyOnReadConvert. To have pointer variables for these classes as members, declare each pointer variable in the private section. At this time, note that both MyOnRead and MyOnReadConvert are given TimedLong as the class template type argument, the same as the type of this component’s InPort.

OutPort Callbacks

The following two types of callbacks are provided for OutPort. They are defined in rtm/PortCallback.h.

OnWrite Called when OutPort write() is called. Set with the OutPort::setOnWrite() function.
OnWriteConvert Called to convert data when OutPort write() is called. Set with the OutPort::setOnWriteConvert() function.

The OnWrite callback is used when write() is called, and OnWriteConvert is used to send data that has undergone some kind of conversion when write() is called.

As with InPort, each callback is implemented by inheriting from the corresponding functor base class defined in rtm/PortCallback.h.

Implementation examples are shown below.

 #include <rtm/Portcallback.h>

 template <class T>
 class MyOnWrite

  : public RTC::OnWrite<T>

{
 public:
   MyOnWrite(std::ostream& os) : m_os(os) {};
   virtual void operator()()
  {
     m_os      << "write() 関数が呼ばれました。" << std::endl;
     std::cout << "write() 関数が呼ばれました。" << std::endl;
  }
 private:
   std::ostream& m_os;
};

 template <class T> 
 class MyOnWriteConvert

  : public RTC::OnWriteConvert<T>

{
 public:
   virtual T operator()(const T& value)
  {
     T tmp;
     tmp.data = 2 * value.data;
     return tmp;
  }
};

The way to write functors for callbacks is almost the same as InPort OnRead/OnReadConvert. In the MyOnWrite functor, which inherits from OnWrite, an output stream std::ostream is passed in the constructor. This is intended to receive a file output stream std::ofstream or similar that has been opened somewhere. In operator(), which is the actual body of the functor, a string is output to the output stream and to standard output. In this way, by passing state variables in advance through the constructor or similar, functors can also call other objects.

On the other hand, MyOnReadConvert, which inherits from OnReadConvert, implements only operator()(constT&). The argument of this function receives the data before it is read into the InPort variable when read() is called. Data processed in some way inside this function and returned with return is written to the InPort variable. In this example, the square is calculated and returned on the assumption that the data type has a member named data and that the multiplication operator is defined. If a variable type without an appropriate member is used, a compile error will occur.

Connector and Buffer Callbacks

Connector

A connector is an object that abstracts a buffer and communication path. As shown in the figure, it exists between an OutPort and an InPort; data is written from the OutPort by the write() function, and data is read from the InPort by the read() function. The connector abstracts and hides how data is transmitted from the OutPort to the InPort.

For the buffer inside the connector, an OutPort can:

  • write data,
  • perform various controls (readback, access to unread data, etc.),
  • notify or receive notification of buffer full status and timeouts.
  • read data,
  • perform various controls (readback, access to unread data, etc.),
  • notify or receive notification of buffer empty status and timeouts.

An OutPort can be connected to multiple InPorts, and one connector is generated for each connection. (In practice, an InPort can also have multiple connections at the same time, but this is not normally used because there is no way to distinguish the data.) In other words, if there are three connections, there are three connectors, and each has its own write status.

It can also be seen that for these functions, one connector must exist for each OutPort/InPort pair. Furthermore, when modeling connectors at the implementation level corresponding to subscription types, an object called a publisher was introduced for asynchronous communication.

When a data port connection is established, one connector object is generated for each connection. A connector is an abstract channel of the data stream that connects an OutPort and an InPort.

ON_BUFFER_WRITE When writing to the buffer
ON_BUFFER_FULL When the buffer is full
ON_BUFFER_WRITE_TIMEOUT When buffer write times out
ON_BUFFER_OVERWRITE When overwriting the buffer
ON_BUFFER_READ When reading from the buffer
ON_SEND When sending to InProt
ON_RECEIVED When sending to InProt is complete
ON_RECEIVER_FULL When the InProt-side buffer is full
ON_RECEIVER_TIMEOUT When the InProt-side buffer times out
ON_RECEIVER_ERROR When an error occurs on the InProt side
ON_BUFFER_EMPTY When the buffer is empty
ON_BUFFER_READTIMEOUT When the buffer is empty and times out
ON_SENDER_EMPTY OutPort-side buffer is empty
ON_SENDER_TIMEOUT When the OutPort side times out
ON_SENDER_ERROR When an error occurs on the OutPort side
ON_CONNECT When a connection is established
ON_DISCONNECT When a connection is disconnected

Port Callbacks

Status

Data ports return a status when sending or receiving data. Statuses are defined in rtm/DataPortStatus.h.

PORT_OK Normal completion
PORT_ERROR Abnormal completion
BUFFER_ERROR Buffer error
BUFFER_FULL Buffer full
BUFFER_EMPTY Buffer empty
BUFFER_TIMEOUT Buffer timeout
SEND_FULL Data was sent, but the peer side is in a buffer-full state
SEND_TIMEOUT Data was sent, but the peer side timed out
RECV_EMPTY Data was sent, but the data is empty
RECV_TIMEOUT An attempt was made to receive data, but it timed out
INVALID_ARGS Invalid argument
PRECONDITION_NOT_MET Precondition not met
CONNECTION_LOST Connection was disconnected
UNKNOWN_ERROR Unknown error

These error codes are used to convey error information from the location where an error occurred on the data path of the data port to the caller. Mainly, errors on the transmission path, errors at the transmission destination, and similar errors can be considered. Errors that occur in each part are shown below.

  • Push type
    • Return codes that occur between InPortConsumer and Publisher/Activity
      PORT_OK, PORT_ERROR, SEND_FULL, SEND_TIMEOUT, CONNECTION_LOST, UNKNOWN_ERROR
    • Return codes that occur between Activity and the OutPort Buffer/Connector
      PORT_OK, PORT_ERROR, BUFFER_ERROR, BUFFER_FULL, BUFFER_TIMEOUT, UNKNOWN_ERROR
  • Pull type
    • Return codes that occur between Activity and InPort
      PORT_OK, PORT_ERROR, RECV_EMPTY, RECV_TIMEOUT, CONNETION_LOST, UNKNOWN_ERROR


Creating a Custom Data Port Interface

An example of creating a custom data port interface is shown.

The following functions and classes must be defined.

  • Provider class (InPortTestProvider)
  • Consumer class (InPortTestConsumer)
  • Provider and consumer registration function (InPortTestInterfaceInit)

Provider Class (InPortTestProvider)

This is the provider class for the data port interface (Push type). When the put function is called on the consumer side, data must be transferred to the provider side by some method. In this sample, data is transferred by writing data to a file when the put function is called on the consumer side, and reading the data from the file on the provider side.

 //InPortTestProvider.cpp

 #include "InPortTestProvider.h"
 #ifdef WIN32
 #pragma warning( disable : 4290 )
 #endif

 namespace RTC
{
   InPortTestProvider::InPortTestProvider(void)

	  : m_buffer(0), m_running(true), m_filename("data.dat")

 {
    setInterfaceType("test");
    activate();
 }
 
  InPortTestProvider::~InPortTestProvider(void)
 {
	  m_running = false;
	  wait();
 }

  //プロバイダ生成時に呼び出される関数
  //コネクタプロファイル、ポートのプロパティの情報を受け取る
  void InPortTestProvider::init(coil::Properties& prop)
 {
 }

  void InPortTestProvider::
  setBuffer(BufferBase<cdrMemoryStream>* buffer)
 {
    m_buffer = buffer;
 }

  void InPortTestProvider::setListener(ConnectorInfo& info, ConnectorListeners* listeners)
 {
    m_profile = info;
    m_listeners = listeners;
 }

  void InPortTestProvider::setConnector(InPortConnector* connector)
 {
    m_connector = connector;
 }

  //別スレッドにより実行される関数
  //周期的にファイルからデータを読み込んでバッファに書き込む
  //この関数はこのサンプルでは必要ですが、独自インターフェースを作成するうえで
  //必須ではありません
  int InPortTestProvider::svc()
 {
     coil::sleep(1);
     while (m_running)
    {

	  std::ifstream  fin;
	  fin.open(m_filename, std::ios::in | std::ios::binary);

          if (fin)
         {
               while (!fin.eof())
              {
                    int data_size = 0;
                    fin.read((char*)&data_size, sizeof(int));
                    if (data_size > 0)
                   {
                        CORBA::OctetSeq data;
                        data.length(data_size);
                        fin.read((char*)&data[0], data_size);

                        //cdrMemoryStream型変数にデータを格納してバッファに書き込む
                        //以下の記述方法はomniORB特有なため、TAOやORBexpressに対応する場合は
                        //分ける必要がある
                        cdrMemoryStream cdr;
                        //エンディアンの設定を行う
                        bool endian_type = m_connector->isLittleEndian();
                        cdr.setByteSwapFlag(endian_type);
                        //データを書き込む
                        cdr.put_octet_array(&(data[0]), data.length());
                        //バッファに書き込む
                        m_buffer->write(cdr);
                   }
              }
               fin.close();

	  }

    }
     return 0;
 }

  //コネクタ接続時に呼び出される関数
  //この関数はコンシューマ側のsubscribeInterface関数よりも前に呼び出される
  //このため、publishInterface関数で設定した情報をコンシューマ側のsubscribeInterface関数で
  //取得することができる
  //何か問題があった時はfalseを返してコネクタを切断する
  bool InPortTestProvider::

	  publishInterface(SDOPackage::NVList& properties)

  {
        //データを書き込むファイル名の情報を格納する
        CORBA_SeqUtil::
                  push_back(properties,
                  NVUtil::newNV("dataport.test.filename", m_filename.c_str()));

	return true;

  }
};

 extern "C"
{
     //この関数をモジュールロード時に呼び出す必要がある
    void InPortTestProviderInit(void)
   {
         RTC::InPortProviderFactory& factory(RTC::InPortProviderFactory::instance());
         factory.addFactory("test",

                       ::coil::Creator< ::RTC::InPortProvider,
                                        ::RTC::InPortTestProvider>,
                       ::coil::Destructor< ::RTC::InPortProvider,
                                           ::RTC::InPortTestProvider>);

    }
};


This is the consumer class for the data port interface (Push type). It must inherit InPortProvider. Inheritance from the Task class is specific to this sample and is not mandatory.

 //InPortTestProvider.h

 #ifndef RTC_INPORTTESTPROVIDER_H
 #define RTC_INPORTTESTPROVIDER_H
 #include <rtm/BufferBase.h>
 #include <rtm/InPortProvider.h>
 #include <rtm/CORBA_SeqUtil.h>
 #include <rtm/Manager.h>
 #include <rtm/ConnectorListener.h>
 #include <rtm/ConnectorBase.h>
 #include <fstream>
 #ifdef WIN32
 #pragma warning( disable : 4290 )
 #endif

 namespace RTC
{
    class InPortTestProvider

      : public InPortProvider,
	public coil::Task

   {
    public:
       InPortTestProvider(void);
       virtual ~InPortTestProvider(void);
       virtual void init(coil::Properties& prop);
       virtual void setBuffer(BufferBase<cdrMemoryStream>* buffer);
       virtual void setListener(ConnectorInfo& info,
                             ConnectorListeners* listeners);
       virtual void setConnector(InPortConnector* connector);
       virtual bool publishInterface(SDOPackage::NVList& properties);
       virtual int svc();

  private:
      CdrBufferBase* m_buffer;
      ConnectorListeners* m_listeners;
      ConnectorInfo m_profile;
      InPortConnector* m_connector;
      bool m_running;
      std::string m_filename;
  }; 
};

 extern "C"
{

	DLL_EXPORT void InPortTestProviderInit(void);

};

 #ifdef WIN32
 #pragma warning( default : 4290 )
 #endif
 #endif


Consumer Class (InPortTestConsumer)

This is the consumer class for the data port interface (Push type). In the Push type, a consumer is generated on the InPort side and a provider is generated on the OutPort side. When the put function is called on the consumer side, data must be transferred to the provider side by some method. In this sample, data is transferred by writing data to a file when the put function is called on the consumer side, and reading the data from the file on the provider side.

 //InPortTestConsumer.cpp

 #include <rtm/NVUtil.h>
 #include "InPortTestConsumer.h"

 namespace RTC
{
    InPortTestConsumer::InPortTestConsumer(void)

    : rtclog("InPortTestConsumer")

   {
   }
 
    InPortTestConsumer::~InPortTestConsumer(void)
   {
       RTC_PARANOID(("~InPortTestConsumer()"));
   }

    //コネクタプロファイル、ポートのプロパティの情報を受け取る
    void InPortTestConsumer::init(coil::Properties& prop)
   {
       m_properties = prop;
   }
 
    //データ転送時に呼び出される関数
    //put関数内でプロバイダ側にデータを転送する処理を記述する
    InPortConsumer::ReturnCode InPortTestConsumer::

	  put(const cdrMemoryStream& data)

   {
         RTC_PARANOID(("put()"));

         //このサンプルでは、コンシュマー側でファイルにデータを書き込んで、プロバイダ側で
         //ファイル内のデータを読み込むことにしている
         //バイナリファイルを開く
         m_file.open(m_filename, std::ios::out | std::ios::binary | std::ios::trunc);
         //データサイズと生データをファイルに書き込む
         int data_size = data.bufSize();	
         m_file.write((char*)&data_size, sizeof(int));
         m_file.write((char*)data.bufPtr(), data_size);
         //ファイルを閉じる
         m_file.close();

         return PORT_OK;
     }

      //コネクタ接続時に呼び出される関数
      //この関数はプロバイダ側のpublishInterface関数よりも後に呼び出される
      //このため、プロバイダ側のpublishInterface関数で設定した情報を取得することができる
      //return: 何か問題があった時はfalseを返してコネクタを切断する

      bool InPortTestConsumer::
      subscribeInterface(const SDOPackage::NVList& properties)
     {
          //プロバイダ側で設定したファイル名を取得する
          CORBA::Long index = NVUtil::find_index(properties,
                                          "dataport.test.filename");
          const char* filename(0);
          properties[index].value >>= filename;

          //取得したファイル名のファイルを開く
          m_filename = filename;
          m_file.open(m_filename, std::ios::out | std::ios::binary | std::ios::trunc);
          m_file.close();
 
         return true;
    }
 
     //コネクタ切断時に呼び出される関数
     void InPortTestConsumer::
     unsubscribeInterface(const SDOPackage::NVList& properties)
    {
    }

     void InPortTestConsumer::publishInterfaceProfile(SDOPackage::NVList& properties)
    {
    }
};

 extern "C"
{ 
     //コンシューマ登録関数
     //この関数をモジュールロード時に呼び出す必要がある
     void InPortTestConsumerInit(void)
   {
        RTC::InPortConsumerFactory& factory(RTC::InPortConsumerFactory::instance());
        factory.addFactory("test",

                       ::coil::Creator< ::RTC::InPortConsumer,
                                        ::RTC::InPortTestConsumer>,
                       ::coil::Destructor< ::RTC::InPortConsumer,
                                           ::RTC::InPortTestConsumer>);

    }
};


This is the consumer class for the data port interface (Push type). It must inherit InPortConsumer.

 //InPortTestConsumer.h

 #ifndef RTC_INPORTTESTCONSUMER_H
 #define RTC_INPORTTESTCONSUMER_H
 #include <rtm/InPortConsumer.h>
 #include <rtm/Manager.h>
 #include <fstream>

 namespace RTC
{
     class InPortTestConsumer

       : public InPortConsumer

   {
       public:
        DATAPORTSTATUS_ENUM
        InPortTestConsumer(void);
        virtual ~InPortTestConsumer(void);
        virtual void init(coil::Properties& prop);
        virtual ReturnCode put(const cdrMemoryStream& data);
        virtual void publishInterfaceProfile(SDOPackage::NVList& properties);
        virtual bool subscribeInterface(const SDOPackage::NVList& properties);
        virtual void unsubscribeInterface(const SDOPackage::NVList& properties);

      private:
        mutable Logger rtclog;
        coil::Properties m_properties;
        std::ofstream  m_file;
        std::string m_filename;
  };
};

 extern "C"
{

	DLL_EXPORT void InPortTestConsumerInit(void);

};
 #endif


Provider and Consumer Registration Function (InPortTestInterfaceInit)

When the OpenRTM-aist manager loads a dynamic link library named “XXX.dll”, it calls the “XXXInit” function. In this sample, it loads “InPortTestInterface.dll” and calls the following “InPortTestInterfaceInit” function.

 //InPortTestInterface.cpp

 #include "InPortTestConsumer.h"
 #include "InPortTestProvider.h"

 extern "C"
{

	DLL_EXPORT void InPortTestInterfaceInit(RTC::Manager* manager)
	{
		InPortTestProviderInit();
		InPortTestConsumerInit();
	}

};

Confirmation Procedure

  1. Prepare an environment where OpenRTM-aist is installed.

  2. Create a CMake configuration file (CMakeLists.txt) for the build.
    The following is a CMake configuration file for building the custom interface sample.
 //OpenRTM-aistのライブラリを見つけるための記述

 cmake_minimum_required (VERSION 2.6)

 find_package(OpenRTM HINTS /usr/lib64/openrtm-1.1/cmake)
 if(${OpenRTM_FOUND})
   MESSAGE(STATUS "OpenRTM configuration Found")
 else(${OpenRTM_FOUND})
   message(STATUS "Use cmake/Modules/FindOpenRTM.cmake in the project")
   list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)
   find_package(OpenRTM REQUIRED)
 endif(${OpenRTM_FOUND})

 if (DEFINED OPENRTM_INCLUDE_DIRS)
   string(REGEX REPLACE "-I" ";"
     OPENRTM_INCLUDE_DIRS "${OPENRTM_INCLUDE_DIRS}")
   string(REGEX REPLACE " ;" ";"
     OPENRTM_INCLUDE_DIRS "${OPENRTM_INCLUDE_DIRS}")
 endif (DEFINED OPENRTM_INCLUDE_DIRS)

 if (DEFINED OPENRTM_LIBRARY_DIRS)
   string(REGEX REPLACE "-L" ";"
     OPENRTM_LIBRARY_DIRS "${OPENRTM_LIBRARY_DIRS}")
   string(REGEX REPLACE " ;" ";"
     OPENRTM_LIBRARY_DIRS "${OPENRTM_LIBRARY_DIRS}")
 endif (DEFINED OPENRTM_LIBRARY_DIRS)

 if (DEFINED OPENRTM_LIBRARIES)
   string(REGEX REPLACE "-l" ";"
     OPENRTM_LIBRARIES "${OPENRTM_LIBRARIES}")
   string(REGEX REPLACE " ;" ";"
     OPENRTM_LIBRARIES "${OPENRTM_LIBRARIES}")
 endif (DEFINED OPENRTM_LIBRARIES)

 include_directories(${OPENRTM_INCLUDE_DIRS})
 include_directories(${OMNIORB_INCLUDE_DIRS})
 add_definitions(${OPENRTM_CFLAGS})
 add_definitions(${OMNIORB_CFLAGS})

 link_directories(${OPENRTM_LIBRARY_DIRS})
 link_directories(${OMNIORB_LIBRARY_DIRS})

 //プロジェクト名設定
 project (InPortTestInterface)

 //動的ライブラリを作成する
 add_library(InPortTestInterface SHARED InPortTestProvider.cpp InPortTestConsumer.cpp InPortTestProvider.h InPortTestConsumer.h InPortTestInterface.cpp)

 //リンクするライブラリの設定
 target_link_libraries(InPortTestInterface ${OPENRTM_LIBRARIES})
  1. Generate the Visual Studio project file with CMake.

  2. Build with Visual Studio.
    After the build, InPortTestInterface.dll is generated in the Debug folder.

  3. Create rtc.conf
    Create rtc.conf and specify InPortTestInterface.dll as the module to load when starting the Manager.
 manager.modules.preload: InPortTestInterface.dll

If InPortTestInterface.dll is in a directory different from the directory where the RTC is executed, separately set the module search path.

 manager.modules.load_path: C:¥workspace¥InPortTestInterface¥build¥Debug


  1. Start the RTC by loading the above rtc.conf.
     ConsoleInComp.exe -f ../rtc.conf
    


  2. Specify “test” as the Interface Type when connecting the port.
    The Interface Type can be specified from RTSystemEditor.