OpenRTM-aistのデータポートでは以下のようにデータをバイト列に変換するシリアライザ、データを送信する通信インターフェースの種類については複数の実装から選択可能です。
インターフェース型が選択可能のためRTC同士だけではなく、ROSのノード、あるいはROS2のようにDDSにより通信を行うプロセスとデータのやり取りが可能になります。 またシリアライザが選択可能のため、図のようにTimedLong型をTimedLong型のような別のデータ型に変換して様々なデータ型のポートと柔軟に接続することができます。
現在はC++版、Python版で使用可能です。
以下に独自シリアライザの作成手順を記載します。
OpenRTM-aist 2.0以上が必要なため、以下の手順でソースコードからビルドを行う必要がある。
ビルド終了後、特定の場所にインストールする。
cmake-guiでCMake_INSTALL_PREFIXを設定するか、cmake実行時のコマンドで設定する。
cmake -DOMNI_VERSION=42 -DOMNI_MINOR=3 -DOMNITHREAD_VERSION=41 -DORB_ROOT=C:/workspace/omniORB-4.2.3-win64-vc141 -DCORBA=omniORB -G "Visual Studio 15 2017" -A x64 .. -DCMake_INSTALL_PREFIX=C:/workspace/openrtm_install
ビルド後に、以下のコマンドでインストールする。
cmake --build .. --target INSTALL --config Release
Visual Studio上でINSTALLのプロジェクトをビルドしてもインストールできる。
独自シリアライザの実装には以下のファイルを作成する必要がある。
CMakeLists.txtにはOpenRTM-aistのパッケージの検出、動的ライブラリを生成するようにコマンドを記述します。
cmake_minimum_required (VERSION 3.0.2) project (TestSerializer VERSION 1.0 LANGUAGES CXX) message(STATUS ${MSVC_TOOLSET_VERSION}) #OpenRTM-aistの検出 find_package(OpenRTM) #インクルードディレクトリ、リンクディレクトリ、コンパイル時のフラグの設定 include_directories(${PROJECT_SOURCE_DIR}/include) include_directories(${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}) include_directories(${PROJECT_BINARY_DIR}) include_directories(${PROJECT_BINARY_DIR}/idl) include_directories(${OPENRTM_INCLUDE_DIRS}) add_definitions(${OPENRTM_CFLAGS}) link_directories(${OPENRTM_LIBRARY_DIRS}) #動的リンクライブラリの生成 add_library(${PROJECT_NAME} SHARED TestSerializer.cpp) #生成するライブラリ名をTestSerializer.dll(もしくは.so)に設定 set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") #OpenRTM-aistのライブラリとリンク target_link_libraries(${PROJECT_NAME} ${OPENRTM_LIBRARIES})
TestSerializer.cppを以下のように作成します。
#include <rtm/ByteDataStreamBase.h> #include <rtm/idl/BasicDataTypeSkel.h> #include <coil/Factory.h> #include <rtm/Manager.h> //以下はシリアライザの実装 template <class DataType> class TestSerializer : public RTC::ByteDataStream<DataType> { public: TestSerializer():m_buffer(NULL), m_length(0){}; void writeData(const unsigned char* buffer, unsigned long length) override { delete m_buffer; m_buffer = new unsigned char[length]; memcpy(m_buffer, buffer, length); m_length = length; } void readData(unsigned char* buffer, unsigned long length) const override { if (m_buffer) { memcpy(buffer, m_buffer, length); } } unsigned long getDataLength() const override { return m_length; } bool serialize(const DataType& data) override { delete m_buffer; m_buffer = new unsigned char[1]; m_buffer[0] = static_cast<unsigned char>(data.data); m_length = 1; return true; } bool deserialize(DataType& data) override { if (m_buffer) { data.data = static_cast<long>(m_buffer[0])+1; return true; } return false; } }; extern "C" { //以下はモジュールロード時に呼び出される関数 DLL_EXPORT void TestSerializerInit(RTC::Manager* manager) { //以下のファクトリはデータ型ごとに登録する必要がある coil::GlobalFactory <::RTC::ByteDataStream<RTC::TimedLong>>:: instance().addFactory("test", //addFactory関数の第1引数で登録名を設定。以下で独自シリアライザを利用するときはこの名前を使用する。 ::coil::Creator< ::RTC::ByteDataStream<RTC::TimedLong>, TestSerializer<RTC::TimedLong>>, ::coil::Destructor< ::RTC::ByteDataStream<RTC::TimedLong>, TestSerializer<RTC::TimedLong>>); }; }
シリアライザにはwriteData関数、readData関数、getDataLength関数、serialize関数、deserialize関数を実装する必要がある。 serialize関数はRTMのデータをunsigned char型に変換して内部のバッファに保存する。 保存したデータはreadData関数で取り出すことができる。 このため、データ送信時の処理は以下のようになっている。
writeData関数は内部のバッファにバイト列のデータを書き込む関数である。 deserialize関数は内部のバッファのデータをRTMのデータ型に変換して外部の変数に渡す。 このため、データ受信時の処理は以下のようになっている。
getDataLengthは内部で保持しているデータの長さを取得する関数である。
OpenRTM-aistをソースコードからビルド、インストールした場合は環境変数が設定されていないためcmake実行時にOpenRTMConfig.cmakeの場所を指定する必要がある。
cmake -G "Visual Studio 15 2017" -A x64 .. -DOpenRTM_DIR=C:/workspace/openrtm1/build/install/2.0.0/cmake
この後Visual Studio等でビルドを行う。
上記の作業でTestSerializer.dllが生成されているはずのため、TestSerializer.dllをRTC実行時にロードして利用できるようにする。
rtc.confに以下のように記述することでロードできる。モジュール探索パスは適宜変更する。
manager.modules.load_path: . manager.modules.preload: TestSerializer.dll
データポート接続時にmarshaling_typeのオプションでシリアライザを設定できる。
manager.components.preconnect: ConsoleOut0.in?port=ConsoleIn0.out&marshaling_type=test
RT System Editorで設定する場合はdataport.marshaling_typeといパラメータで設定する。
これで独自シリアライザ(TestSerializer)が使用可能になったため、ConsoleInとConsoleOutで通信すると標準入力した数値に1を足した数値が表示される。
以下はConsoleInとConsoleOutのデータポートを接続してアクティベートするrtc.confの例。
manager.modules.load_path: . manager.modules.preload: TestSerializer.dll, ConsoleOut.dll manager.components.precreate: ConsoleOut manager.components.preconnect: ConsoleOut0.in?port=ConsoleIn0.out&marshaling_type=test manager.components.preactivation: ConsoleOut0, ConsoleIn0
OpenRTM-aist 2.0以上が必要なため、以下の手順でソースコードからビルドを行う必要がある。
独自シリアライザの実装には以下のファイルを作成する必要がある。
TestSerializer.pyを以下のように作成します。
#!/usr/bin/env python # -*- coding: euc-jp -*-
import OpenRTM_aist import RTC
#以下はシリアライザの実装 class TestSerializer(OpenRTM_aist.ByteDataStreamBase): def __init__(self): pass def __del__(self): pass def serialize(self, data): if data._NP_RepositoryId == RTC.TimedLong._NP_RepositoryId: bdata = str(data.data) return OpenRTM_aist.ByteDataStreamBase.SERIALIZE_OK, bdata else: return OpenRTM_aist.ByteDataStreamBase.SERIALIZE_ERROR, "" def deserialize(self, cdr, data_type): if data_type._NP_RepositoryId == RTC.TimedLong._NP_RepositoryId: data_type.data = int(cdr)+1 return OpenRTM_aist.ByteDataStreamBase.SERIALIZE_OK, data_type else: return OpenRTM_aist.ByteDataStreamBase.SERIALIZE_ERROR, data_type #以下はモジュールロード時に呼び出される関数 def TestSerializerInit(mgr): OpenRTM_aist.SerializerFactory.instance().addFactory("test", #addFactory関数の第1引数で登録名を設定。以下で独自シリアライザを利用するときはこの名前を使用する。 TestSerializer, OpenRTM_aist.Delete)
シリアライザにはserialize関数、deserialize関数を実装する必要がある。 serialize関数はRTMのデータをバイト列のデータ等に変換してリターンコードと変換後のデータを返す。
deserialize関数はバイト列のデータなどをRTMのデータに変換してリターンコードと返還後のデータを返す。
TestSerializer.pyをRTC実行時にロードして利用できるようにする。
rtc.confに以下のように記述することでロードできる。モジュール探索パスは適宜変更する。
manager.modules.load_path: . manager.modules.preload: TestSerializer.py
データポート接続時にmarshaling_typeのオプションでシリアライザを設定できる。
manager.components.preconnect: ConsoleOut0.in?port=ConsoleIn0.out&marshaling_type=test
RT System Editorで設定する場合はdataport.marshaling_typeといパラメータで設定する。
これで独自シリアライザ(TestSerializer)が使用可能になったため、ConsoleInとConsoleOutで通信すると標準入力した数値に1を足した数値が表示される。
以下はConsoleInとConsoleOutのデータポートを接続してアクティベートするrtc.confの例。
manager.modules.load_path: . manager.modules.preload: TestSerializer.py, ConsoleOut.py manager.components.precreate: ConsoleOut manager.components.preconnect: ConsoleOut0.in?port=ConsoleIn0.out&marshaling_type=test manager.components.preactivation: ConsoleOut0, ConsoleIn0