RTM-Lua

View the Project on GitHub Nobu19800/RTM-Lua

用語集

RTミドルウェア

ソフトウェアモジュールを組み合わせてロボット技術を用いたシステム(RTシステム)を構築するための標準規格。OMG RTC。 詳細はWikipediaでも見てください。

規格の詳細は以下のページから見れます。

主に以下の機能が定義されています。

RTCの情報取得の機能が規格で定義されており、どのような機能、ポートのRTCなのか分かりやすいのは特徴の一つです。

RTコンポーネント

ロボット技術を用いたソフトウェアモジュールのことをRTコンポーネント( Robot Technology Component、RTC)といいます。 RTCにはコンポーネントの基本情報(コンポーネントプロファイル)、他のRTCとやり取りするためのポート(データポート、サービスポート)、コンフィギュレーションパラメータ、ライフサイクルという要素から成り立っています。

rtc1

OpenRTM-aist付属のIDLファイルに定義されたインターフェースは以下のようになっています。

rtobject

RTミドルウェアの規格はプラットフォーム独立モデルで定義されているため、上記のインターフェースが定義できればCORBA以外のRPCができる通信ライブラリでも実装できます。ただし既存のOpenRTM-aist等とは通信できなくなります。

RT System EditorからRTCを操作するためには、最低でもコンポーネントプロファイルを取得するget_component_profile、ポート一覧を取得するget_ports、RTCを終了させるexitが必要になるため、最低でもRTC::RTObjectの実装が必要になります。

RTC::RTObjectの実装のためにはRTC::ComponentActionRTC::LightweightRTObjectSDOPackage::SDOSystemElementSDOPackage::SDOの実装が必要になります。

RTC::ComponentActionインターフェースで定義されたオペレーションは以下の通りです。

名前 意味
on_initialize 初期化時のコールバック関数
on_finalize 終了時のコールバック関数
on_startup 実行コンテキスト開始時のコールバック関数
on_shutdown 実行コンテキスト停止時のコールバック関数
on_activated アクティブ状態遷移時のコールバック関数
on_deactivated 非アクティブ状態遷移時のコールバック関数
on_aborting エラー状態遷移時のコールバック関数
on_error エラー状態時のコールバック関数、周期実行の場合には周期的に呼び出される
on_reset リセット実行時のコールバック関数

上記の太字のオペレーションは実行コンテキストから呼び出されます。

on_activated

on_initializeon_finalizeはOpenRTM-aistでは内部からしか呼び出されない。

実行コンテキストが別のプロセス、別のマシン上のRTCを操作する機能を削る場合は、ComponentActionインターフェースのオペレーションはリモート呼び出しする必要がないためCORBAで実装する必要もありません。

RTC::LightweightRTObjectインターフェースで定義されたオペレーションは以下の通りです。

名前 意味
initialize 初期化時に呼び出す
finalize 終了時に呼び出す
is_alive 指定実行コンテキストで生存しているか確認
exit 終了処理実行
attach_context 実行コンテキストを関連付ける
detach_context 実行コンテキストの関連付け解除
get_context 指定IDの実行コンテキストを取得
get_owned_contexts 自身がオーナーの実行コンテキストを取得
get_participating_contexts 自身以外がオーナーの実行コンテキストを取得
get_context_handle 指定実行コンテキストのIDを取得

initializefinalizeはOpenRTM-aistでは内部からしか呼び出されない。 外部の実行コンテキストと関連付ける必要がない場合はexit以外のオペレーションはCORBAで実装する必要はありません。

RTC::DataFlowComponentActionインターフェースで定義されたオペレーションは以下の通りです。

名前 意味
on_execute アクティブ状態時のコールバック関数、周期実行の場合には周期的に呼び出される
on_state_update 状態更新時のコールバック関数、アクティブ状態、エラー状態の時に周期実行の場合には周期的に呼び出される
on_rate_changed 実行周期変更時のコールバック関数

この中で重要なのはon_executeオペレーション。 内部の実行コンテキストとしか関連付けしない場合はCORBAで実装する必要はない。

SDOPackage::SDOSystemElementインターフェースで定義されたオペレーションは以下の通りです。

名前 意味
get_owned_organizations 自身が保持している構成要素の取得

get_owned_organizationsは自身が複合コンポーネントの場合に、複合コンポーネントを構成している子コンポーネントを取得できます。 よって、複合コンポーネントを実装しない場合はget_owned_organizationsオペレーションを実装する必要もありません。

SDOPackage::SDOインターフェースで定義されたオペレーションは以下の通りです。

名前 意味
get_sdo_id 実質的に機能していない
get_sdo_type 実質的に機能していない
get_device_profile 実質的に機能していない
get_service_profiles 実質的に機能していない
get_service_profile 実質的に機能していない
get_sdo_service 実質的に機能していない
get_configuration コンフィギュレーション取得
get_monitoring 実質的に機能していない
get_organizations 構成要素の取得
get_status_list 実質的に機能していない
get_status 実質的に機能していない

実質的に機能しているのはget_configurationget_organizationsのみ。 使わないオペレーションが大量に定義されているため、ビルド後のバイナリのサイズが大きくなる原因の1つになっている。

get_configurationで取得したSDOコンフィギュレーションはコンポーネントオブザーバー等のサービスの設定、コンフィギュレーションパラメータの設定を行う機能を提供します。 get_organizationsは複合コンポーネントの親コンポーネントを取得します。

上記の機能が必要ない場合は実装の必要はありません。

RTC::RTObjectインターフェースで定義されたオペレーションは以下の通りです。

名前 意味
get_component_profile コンポーネントプロファイルの取得
get_ports ポートの一覧取得

これらのオペレーションをCORBAで実装すればRTSystemEditorから情報取得ができるようになります。

コンポーネントプロファイルは以下のような構造になっています。

profile

RTSystemEditorではport_profilesに格納したポートプロファイル一覧を取得後、PortProfileからポートの種類、接続したコネクタ一覧の情報を取得しています。

PortProfilepropertiesには以下の情報を格納します。

パラメータ名 意味
port.port_type ポートの種類(DataOutPort、DataInPort、CorbaPort)
dataport.data_type データ型

サービスポートの場合は、interfacesにインターフェースの情報を格納します。

RTSystemEditorで情報を取得するためにはコンポーネントプロファイルを取得する機能を実装すれば充分であり、見た目上は既存のRTミドルウェアと変わらない動きをします。

データポート

データポートはデータを連続的に転送するためのポートです。 インターフェースとしてはデータポート、サービスポートに違いはなく、以下のPortServiceインターフェースで定義されています。

portservice

名前 意味
get_port_profile ポートプロファイル取得
get_connector_profiles コネクタプロファイル一覧取得
get_connector_profile 指定IDのコネクタプロファイルを取得
connect コネクタ接続
disconnect コネクタ切断
disconnect_all 全てのコネクタ切断
notify_connect コネクタ接続を通知
notify_disconnect コネクタ切断を通知

RTSystemEditorで操作する際は上記のオペレーションはすべて実装が必須です。 PortServiceではデータを転送するインターフェースはdata_serviceインターフェースのみが規格で定義されており、他にユーザーが独自に作成したインターフェース等も拡張可能です。

notify_connect内でコネクションを確立するための処理を行います。

RTSystemEditorからはconnectオペレーションを呼び出します。 その後はPortServiceの間でnotify_connectを呼び出します。 ただし、notify_connectがどの順序で呼び出されるかは、connectの引数で渡したコネクタプロファイルに格納したポートの順番に依存します。

connect1 connect2

notify_connect内でどのような処理をするかは規格では定義されていません。 とりあえず、notify_connect処理後にget_connector_profilesで取得できるコネクタプロファイルが追加されていたら、RT System Editorからはポートが接続されているように見えます。

InPort

InPortOutPortからデータを受信するポートです。 前述の通り、InPort、OutPortにインターフェースの違いはなく、get_port_profileで取得できるポートプロファイルの内容が違うだけです。

OutPort

OutPortInPortにデータを送信するポートです。 InPortをデータが受信するポート、OutPortをデータを送信するポートにするためには、notify_connect内でコネクションを確立する処理をする必要があります。例えば、ソケット通信をする場合はnotify_connect内でソケットの作成、接続を行い、InPort側ではrecv関数で待ち受け、OutPort側ではsend関数でデータ送信という事をします。

データ型

データ型には転送するデータの内容のことです。 データ型はOMG IDL構文で定義されています。 OpenRTM-aistにはBasicDataType.idlExtendedDataTypes.idlInterfaceDataTypes.idlのIDLファイルが付属しており、多数のデータ型が定義されています。 BasicDataType.idlには単純なDouble型のデータの送信、配列のデータの送信など基本的なデータ型が定義されています。 ExtendedDataTypes.idlには移動ロボットの速度指令など、拡張データ型が定義されています。 InterfaceDataTypes.idlにはカメラ画像のデータなど、複雑なデータ型が定義されています。

詳細は以下のページを参考にしてください。

独自データ型

データ型にはOpenRTM-aist標準のデータ型以外に、独自IDLファイルによる独自データ型が定義できます。 以下はOpenRTM-aist 1.2での独自データ型作成手順です。

まずはIDLファイル(今回はtest.idl)を作成します。

OpenRTM-aist 1.2からは必ずデータ型にタイムスタンプが必要になったため、独自データ型作成の難易度が大幅に上がっています。 BasicDataType.idlをインクルードして、データ型にタイムスタンプ(RTC::Time tm;)を追加してください。

#include "BasicDataType.idl"

module Sample {
    struct SampleDataType
    {
        RTC::Time tm;
        double data1;
        short data2;
    };
};

次にRTC Builderのデータポート設定画面でIDLファイルの横のBrowse…ボタンを押してIDLファイルを選択します。

rtcb1

するとデータ型一覧に独自データ型が追加されます。

rtcb2

インターフェース型

インターフェース型はデータを転送する方法を定義しています。 OpenRTM-aist 2.0ではcorba_cdrdata_serviceshared_memorydirectの4種類のインターフェース型が利用できます。 OpenRTM-aistのRTCと通信するためには、notify_connectの中でこれらのインターフェースのコネクションを確立するための処理をする必要があります。

corba_cdr

corba_cdrはCORBA通信でデータを転送するインターフェース型です。 DataPort_OpenRTM.idlファイルでInPortCdrインターフェースとOutPortCdrインターフェースが定義されています。

dataport1

dataport2

InPortCdrputオペレーションはOutPortからInPortにデータを渡すPush型の通信の場合に使用します。 OutPortCdrputオペレーションはInPortOutPortからデータを取得するPull型の通信の場合に使用します。

CORBA通信を行う場合には、CORBAオブジェクトリファレンス(InPortCdr、OutPortCdr)をクライアント側に渡す必要があります。

connectオペレーションはOutPort、InPortどちら側からも呼び出される可能性があります。

例えば、connectの引数で渡すコネクタプロファイルを以下のように設定します。

名前
name string 適当な名前
connector_id UniqueIdentifier 空白
ports PortServiceList {InPortのオブジェクトリファレンス、OutPortのオブジェクトリファレンス}
properties NVList {“dataport.interface_type”:”corba_cdr”, “dataport.dataflow_type”,”push”}

この場合にInPort側のconnectを呼び出すと以下のような処理になります。 これは、コネクタプロファイルのportsにInPortのオブジェクトリファレンスを先に格納しているためです。

connect5

ここで、(1)と(2)ではコネクタプロファイルの内容が変わっています。

名前  
name string 適当な名前  
connector_id string 空白  
ports UniqueIdentifier {InPortのオブジェクトリファレンス、OutPortのオブジェクトリファレンス}  
properties PortServiceList NVList {“dataport.interface_type”:”corba_cdr”, “dataport.dataflow_type”,”push”, “dataport.corba_cdr.inport_ior”:InPortCdrのIOR文字列, “dataport.corba_cdr.inport_ref”:InPortCdrのオブジェクトリファレンス}

Push型のためInPort側にInPortCdrオブジェクトがあり、OutPort側でInPortCdrのオブジェクトリファレンスを取得してput関数をリモート呼び出しするということになります。

このため、InPortからOutPortnotify_connectを呼び出す時にInPortCdrのオブジェクトリファレンスが取得できるようになっている必要があります。

他にOutPortconnectを呼び出す場合、portsの順序で以下の処理順序があります。

connect6 connect3 connect4

data_service

data_serviceもCORBA通信のインターフェースですが、こちらは規格標準のインターフェースです。 DataPort.idlで定義されています。

dataport3 dataport4

動作としてはcorba_cdrと同じです。

shared_memory

shared_memoryは共有メモリによるデータ転送を行うインターフェース型です。

direct

directは同一プロセス内で変数渡しによりデータの転送を行うインターフェース型です。

データフロー型

データフロー型はデータを転送する際の流れを定義します。 Push型はOutPortからInPortにデータを送る方式で、Pull型はInPortからOutPortのデータを取る方式です。

以下はPush型の通信です。

push

以下はPull型の通信です。

pull

現在はPush型、Pull型の2種類ですが、例えばメッセージブローカーを介して通信する場合はPush型やPull型に当てはまらない通信になります。

topic

現状、OpenRTM-aistではデータフロー型については拡張できるようになっていません。

サブスクリプション型

データフロー型がPush型の場合のみ、データの送信タイミングをflushnewperiodicから選択できます。

flush

OutPortのwrite関数を呼び出した時点で即座にデータを送信する方式です。

new

OutPortのwrite関数を呼び出した時点ではリングバッファに格納しておいて、別スレッドでデータを送信する方式です。 write関数を呼び出すとデータ送信処理を1回実行するようにデータ送信スレッドに指令します。 既にデータ送信処理中に指令を送ってもさらに1回実行することはないため、データ送信処理中にwrite関数を呼び出すと、データが送信されない場合があります。

periodic

OutPortのwrite関数を呼び出した時点ではリングバッファに格納しておいて、別スレッドでデータを送信する方式です。 new型と違う点はデータ送信スレッドがデータ送信処理を周期的に実行している点です。 new型のようにデータの欠損が発生することはありませんが、データがすぐに送信されない場合があります。

サービスポート

サービスポートはコマンドレベルの操作を提供する機能であり、単純なデータの転送だけではなく、特定の処理の呼び出し、処理結果の取得ということができます。 データポートを使うべきか、サービスポートを使うべきかは場合によりますが、例えば以下のような場合に使われる事があります。

データポート、サービスポートにインターフェースの違いはなく、get_port_profileで取得できるポートプロファイルの内容が違うだけです。

サービスポートの操作を呼び出す方法については特に規格では定義されておらず、OpenRTM-aistではCORBAによるリモート関数呼び出しで処理しています。

rtse2

サービスポートには関数の処理を実装したプロバイダと、関数をリモート呼び出しする側のコンシューマのインターフェースを保持しています。

connectを呼び出すときのコネクタプロファイルを以下のように設定します。

名前
name string 適当な名前
connector_id string 空白
ports PortServiceList {ServicePort1のオブジェクトリファレンス、ServicePort2のオブジェクトリファレンス}
properties NVList {}

そしてServicePort1connectを呼び出すと、以下の順序で接続処理を行います。

connect7

ServicePort1がプロバイダインターフェースを保持している場合、(2)以降は以下のようにコネクタプロファイルにオブジェクトリファレンスが設定されます。

名前
name string 適当な名前
connector_id string 空白
ports PortServiceList {ServicePort1のオブジェクトリファレンス、ServicePort2のオブジェクトリファレンス}
properties NVList {“MyServiceProvider0.port.MyService.provided.MyService.myservice0”:”IOR文字列”, “port.MyService.myservice0”:”IOR文字列”}

RTCのインスタンス名.port.型名.provided.インターフェースのインスタンス名、もしくはport.型名.インターフェースのインスタンス名にオブジェクトのIOR文字列が格納されています。 型名にはIDLファイルで定義したインターフェース名が格納されるため、型名が一致しないとポートの接続はできません。 サービスポートは複数のインターフェースを持つことが可能ですが、インターフェース名が一致したプロバイダとコンシューマインターフェースを関連付けます。

portsの順番を入れ替えると以下のような処理となります。

connect8

コンフィグレーションパラメータ

コンフィギュレーションパラメータはRTC実行中に内部パラメータを外部から変更可能な機能です。

rtse1

データポートかサービスポートかコンフィギュレーションパラメータのどれを使うかは場合によって違います。

データポートを使っても内部の処理を工夫すればパラメータを変更する事はできますが、1回変更すればいいところにデータポートを使うのは適切ではありません。

パラメータの変更にサービスポートを使うのは一つの方法です。 ただ、それも場合によります。他のRTCからパラメータを変更する必要があるときにはサービスポートを使うのが有効です。

例えば、RTCがファイルをロードする必要がある場合に、そのファイルパスを設定したいとします。 確かにサービスポートでも設定できるのですが、設定するためのRTCが別個必要になるため手軽ではありません。 他のRTCから変更する必要がない場合は、コンフィギュレーションパラメータで設定することをお勧めします。

コンフィギュレーションの設定には、get_configurationオペレーションでConfigurationオブジェクトを取得後に設定します。

configuration

ライフサイクル

RTCの重要な要素としてライフサイクルがあります。 RTCにはCreatedInactiveActivateErrorの4種類の状態があります。

rtstatemachine

ここで重要なのはRTCが個別に状態を持っているのではなく、RTCが関連付けしている実行コンテキストごとに状態を持っているという点です。

以下の例では、実行コンテキストAにはRTC1を、実行コンテキストBにはRTC1RTC2を関連付けています。 この場合、RTC1実行コンテキストAでの状態と実行コンテキストBでの状態があることになります。 RTC1実行コンテキストAではInactive状態、実行コンテキストBではActive状態になっており、実行コンテキストごとに別々の状態になることがあります。

activity

Inactivate

Inactive状態(非アクティブ状態、非活性状態)は、RTCが処理を実行していない状態です。 この状態ではon_executeオペレーションも実行されず、またコンフィギュレーションパラメータの変更は(原則)反映されません。 サービスポートも機能が停止するのが動作としては正しいのですが、使いづらくなるだけなのでOpenRTM-aist 1.2以降ではInactive状態でもサービスポートは機能するようになっています。

Activate

Active状態(アクティブ状態、活性状態)は、RTCが処理を実行している状態です。 この状態では、実行コンテキストによりon_executeオペレーションが実行され、on_state_updateオペレーションでコンフィギュレーションパラメータの更新が行われます。 RTCのonExecute関数にはロボットを制御するなどのメインとなる処理を実装します。

またActive状態遷移直後にon_activated、他の状態に遷移するときにon_deactivatedを実行します。 RTCのonActivated関数にはサーボをオンにするなどの初期化処理、onDeactivated関数にはサーボをオフにするなどの後処理を実装します。

Error

Error状態(エラー状態、異常状態)は、RTCに問題が発生した事を検知して処理を停止した状態です。 この状態では、実行コンテキストによりon_errorオペレーションが実行されます。 RTCのonError関数にはロボットを安全に停止するなどの、エラーに対応した処理を実装します。

実行コンテキスト

実行コンテキスト(Execution Context、EC)はRTCの状態を管理する機能です。 RTC単体では処理を実行することができず、実行コンテキストがRTCの操作を呼び出すことで処理を実行します。

RTCと実行コンテキストを分離することによって、実行コンテキストの変更のみで通常の周期実行、リアルタイム処理、シミュレータからのトリガ駆動を使い分けることができます。

実行コンテキストはRTC.idlOpenRTM.idlで以下のようなインターフェースが定義されています。

executioncontext

ExecutionContextで定義されたオペレーションは以下の通りです。

名前 意味
is_running 実行状態かを確認
start 実行コンテキストの実行を開始する
stop 実行コンテキストの実行を停止する
get_rate 実行周期を取得する
set_rate 実行周期を設定する
add_component RTCを関連付ける
remove_component RTCの関連付けを解除する
activate_component RTCをアクティブ化する
deactivate_component RTCを非アクティブ化する
reset_component RTCをリセットする
get_component_state RTCの状態を取得する
get_kind 実行コンテキストの種類を取得する

RTSystemEditorで操作するためには実行コンテキストの情報を取得するget_profileオペレーションが必要なため、ExecutionContextServiceインターフェスの実装が必要になります。

名前 意味
get_profile 実行コンテキストのプロファイルを取得

ExtTrigExecutionContextServiceでは以下のオペレーションが定義されています。 規格標準ではなく、OpenRTM.idlで定義されたOpenRTM-aist独自のインターフェースです。

名前 意味
tick RTCの処理を1回実行する

イベント駆動の実行コンテキストには、実質的にrateの設定は意味がありません。

PeriodicExecutionContext

PeriodicExecutionContextは周期実行を行う実行コンテキストです。

ExtTrigExecutionContext

ExtTrigExecutionContextは外部からトリガ駆動で実行する実行コンテキストです。 tickのオペレーションの実装が必要になるため、ExtTrigExecutionContextServiceインターフェースで実装する必要があります。

tickを呼び出した時点では即座には実行されず、実行スレッドに指令して、RTCの処理は別スレッドで実行されます。 このため、tickの処理が戻ってきてもRTCの処理は終了していません。

OpenHRPExecutionContext

OpenHRPExecutionContextは外部からトリガ駆動で実行する実行コンテキストです。 ExtTrigExecutionContextと違い、OpenHRPExecutionContexttick実行時にRTCの処理を実行するため、RTCの処理終了までtickの処理は戻ってきません。

SimulatorExecutionContext

SimulatorExecutionContextは外部からトリガ駆動で実行する実行コンテキストです。 OpenHRPExecutionContextactivate_component等のRTCを状態を遷移する操作を実行してもtickでRTCの処理を実行しない限り状態は遷移しません。

RTPreemptEC

RTPreemptECPeriodicExecutionContextと同じく周期実行の実行コンテキストですが、RT-Preemptパッチを適用したLinuxカーネルにより実時間処理を行うための実行コンテキストです。

マネージャ

マネージャはRTCを管理する仕組みです。 1プロセスで1つのマネージャが起動し、モジュールのロード、RTCの生成、生存しているRTCの管理等を行います。

rtse6

インターフェースはManager.idlで定義されています。RTM標準の規格ではなく、OpenRTM-aist固有のインターフェースです。

manager

マスターマネージャ

マネージャはマスターマネージャスレーブマネージャに分類されます。 マスターマネージャはスレーブマネージャを管理するマネージャです。 通常、マスターマネージャはRTCを生成しません。 またデフォルトでは2810のポート番号で起動するようになっており、RTSystemEditor等のツールからはそのポート番号にアクセスします。

rtse5

スレーブマネージャ

スレーブマネージャはマスターマネージャにぶら下がっているマネージャです。 デフォルトで起動するマネージャはスレーブマネージャであり、RTCを生成することができます。 通常、スレーブマネージャはRTSystemEditor等のツールから直接操作することができず、マスターマネージャを介して操作することになります。 動的なRTCの生成、生成可能なモジュール名の取得などができます。

RTシステム

単一、もしくは複数のRTCのポートの接続などを行い、RT(ロボットテクノロジー)を活用した処理を実行するためのシステムのことをRTシステムと言います。

rtse4

複合コンポーネント

複合コンポーネントは複数のRTCを1つに複合する仕組みの事です。

例えば、以下の例の場合RTC1RTC2RTC2RTC3のポートは外に見せる必要がないということで隠蔽してあります。 こうすることで、複雑なRTシステムが見た目上は単純になるため、システムの概要を理解しやすくなります。

rtse3

また、実行の同期状態の同期を行う場合があります。

実行の同期を行う場合には、子コンポーネントを1つの実行コンテキストに関連付けて同期実行を行うようになっています。

状態の同期はOpenRTM-aistでは実装されていません。

IDLファイル

IDL(Interface Description Language、インターフェース記述言語)は、ソフトウェアモジュールの間のやり取りを行うためのインターフェースを記述する言語です。

SDOサービス

SDOサービスは後述のコンポーネントオブザーバー等、RTCに機能を追加するための仕組みです。 SDOサービスは片方にコンシューマ、片方にプロバイダとなる機能を実装する必要があります。

SDOサービスを追加するためには、Configurationインターフェースのadd_service_profileオペレーションを使う必要があります。

add_service_profileで渡すサービスプロファイルには、例えば以下のような情報を渡します。

名前
id string 適当な名前
interface_type string 空白
properties NVList {}
service SDOService SDOサービスのオブジェクトリファレンス

オブジェクトリファレンスは上記のservice変数に格納する必要があるため、SDOServiceインターフェースを継承して開発する必要があります。

add_service_profileでSDOサービス登録後、RTCからオペレーションを呼び出します。

sdoservice

コンポーネントオブザーバ

コンポーネントオブザーバーはRTCからRTSystemEditor等のツールに状態変化、ハートビートなどを通知する機能です。 RTC::ComponentObserverはFSM4RTC規格標準のインターフェースであり、OpenRTM::ComponentObserverはOpenRTM-aist独自のインターフェースです。

componentobserver

status_kindに通知内容の種別を設定します。 RTC::StatusKindには以下の値が列挙されています。

名前 意味
COMPONENT_PROFILE コンポーネントプロファイルの変更を通知
RTC_STATUS RTCの状態変化を通知
EC_STATUS ECの状態変化を通知
PORT_PROFILE ポートプロファイルの変更を通知
CONFIGURATION コンフィギュレーションの変更を通知
RTC_HEARTBEAT 定期的にRTCの生存確認を通知
EC_HEARTBEAT 定期的にECの生存確認を通知
FSM_PROFILE FSMプロファイルの変更を通義
FSM_STATUS FSMステータスの変更を通知
FSM_STRUCTURE FSMストラクチャの変更を通知
USER_DEFINED 上記以外

ローカルサービス

SDOサービスが外部と相互運用する機能を追加するのに対して、ローカルサービスはManagerに対して単純に機能を追加します。 例えば、現状のManagerでは終了時に起動していたRTCの情報を保存、復元という事はできませんが、Managerの開始時、終了時のリスナで処理をするローカルサービスを追加すれば可能になります。

FSM4RTC

FSM4RTC(Finite State Machine for RTC)は、有限状態機械の仕組みをRTCの導入するための規格です。

OMG RTCの規格では、RTCにはInactive状態、Active状態、Error状態の3種類の状態がありましたが、例えば以下のようにイベントでロボットを制御する場合などは複雑な状態変化を設定できるようにする必要があります。

humanoid

現状のOpenRTM-aistでこのような仕組みを実装するためには、独自にStateパターンやswitch文によりステートマシンを実装し、データポートやサービスポートの入力で状態を変化させるという仕組みが必要になるため、実装が簡単ではありません。 FSM4RTCの仕組みを導入することで、FSMの実装が容易になります。

CSP

CSP(Communicating Sequential Processes)は、並列に動作するシステムを記述して検証するための形式手法の一つです。 CSPで記述した並列システムは、FDR4等のツールでデッドロックが発生しないかなどの問題を検証することができます。

FSM4RTCで実装したRTシステムをCSPで検証するという試みが行われています。

ロガー

RTC実行中のログをファイル、もしくは標準出力する機能です。特に規格では定義されていません。 OpenRTM-aistにはFluent Bitでログを収集する機能もあります。

ナンバリングポリシー

例えば、OpenRTM-aistでSampleという名前のRTCを起動した場合、インスタンス名はSample0となります。 同一プロセスでSampleを複数起動した場合、Sample0Sample1Sample2と番号が増えていく仕組みになっています。

ただしこれは同一プロセス内の話で、別プロセスでSample0が起動している場合にもカウントを増やしてほしい場合は、デフォルト以外の設定が必要になります。

process_unique

デフォルトの設定。上述の通りプロセス内でカウントする。

ns_unique

ネームサーバーに登録されたRTC名が被らないように番号付けする。 rtc.confに以下のように記述することで利用できる。

manager.components.naming_policy:ns_unique

node_unique

同一ノード内でRTC名が被らないように番号付けする。 マスターマネージャに登録されたスレーブマネージャで起動している全てのRTCを調べて番号付けをする。

naming.type:corba,manager
manager.components.naming_policy:node_unique

CORBA

CORBA(Common Object Request Broker Architecture)は分散環境で透過的にソフトウェアモジュールの相互利用を行うための標準規格です。 IDLファイルで定義されたインターフェースでプログラミング言語を問わずに関数のリモート呼び出しができます。

ORB

ORB(Object Request Broker)はネットワークを介してプログラムの呼び出しを行うためのミドルウェアのことです。 CORBAもORBの一つです。

POA

POA(Portable Object Adapter)はオブジェクトリファレンスとサービスの実体を関連付けて、リモート呼び出しに対して適切なサービスを呼び出すための仕組みです。

CORBAの実装例

omniORB

OpenRTM-aistが利用しているCORBAの実装です。 C++、Pythonの実装があります。

TAO

フリーCORBA御三家の一つ。残りはORBacusとMICO。C++による実装。 UDPの通信、Real-Time CORBA等の機能が充実している。 OpenRTM-aistがサポートしている実装の一つ。

ORBexpress

商用CORBAの1つ。軽量であり、様々な独自プロトコルを追加できる。 OpenRTM-aistがサポートしている実装の一つ。

RtORB

RtORBはC言語で実装されているCORBA実装。 OpenRTM-aistで使用していないAPIが省かれているため非常に軽量。

IIOP.NET

.NET系のプログラミング言語で使用可能なCORBA実装。 OpenRTM.NETが使用している。

OiL

Luaで実装されたCORBA実装。 OpenRTM Luaが使用している。

オブジェクトリファレンス

クライアント側で使用するオブジェクトの参照。 オブジェクトリファレンスによりリモートにCORBAオブジェクトの実体側の操作を呼び出せる。

corba1

CDR

CDR(Common Data Representation)は、CORBAで使用されているデータの表現方法の1つです。 サーバー、クライアントで通信する場合にデータはCDR形式のバイト列に変換(マーシャリング、符号化)し送信、受信側でバイト列を元のデータに戻す(アンマーシャリング、復号化)することでデータの受け渡しを行います。

IOR

IOR(Interoperable Object Reference)はCORBAオブジェクトの情報を文字列で表現する形式です。 IOR:から始まる文字列となっており、ホスト名、ポート番号等の情報が含まれています。

GIOP

GIOP(General Inter-ORB Protocol)はORBが通信するための通信プロトコル。 GIOPという文字(4byte)、バージョン(2byte)、メッセージフラグ(1byte)、メッセージ型(1byte)、メッセージ本体のサイズ(4byte)の合計12byteのヘッダーの後ろにメッセージ本体を格納する。 TCP/IP上のGIOPの実装をIIOP、UDP上のGIOPの実装をDIOP、共有メモリ上のGIOPの実装をSHMIOP、UNIXドメインソケット上のGIOPの実装をUIOP、SSL/TLSによる暗号化とサーバー・クライアント認証を行うSSLIOPというプロトコルがあります。

INS

INS(Interoperable Naming Service)はCORBAオブジェクトを名前解決する機能。 coabeloccorbaname形式が利用できる。

corbaloc

corbalocは指定アドレス、ポート番号で特定の名前に関連付けたCORBAオブジェクトの参照を取得する方式。

corbaloc:iiop:localhost:2810/manager

名前解決するCORBAオブジェクトは以下のように名前を関連付けておく必要がある。

local manager = orb:newservant(mgr, id, "IDL:RTM/Manager:1.0")

corbalocで名前解決してオブジェクトリファレンスを取得するには以下のようなコードを記述する。

local oil = require "oil"


oil.main(function()
    local orb = oil.init{ flavor = "cooperative;corba;intercepted;typed;base;"}


    orb:loadidlfile("idl/CosNaming.idl")
    orb:loadidlfile("idl/RTC.idl")
    orb:loadidlfile("idl/OpenRTM.idl")
    orb:loadidlfile("idl/Manager.idl")
    
     -- OiL 0.4
    local manager = orb:newproxy("corbaloc:iiop:localhost:2810/manager","IDL:RTM/Manager:1.0")
    -- OiL 0.5, 0,6
    --local manager = orb:newproxy("corbaloc:iiop:localhost:2810/manager",nil,"IDL:RTM/Manager:1.0")

    local profiles = manager:get_component_profiles()
    for k,profile in ipairs(profiles) do
        print(profile.instance_name)
    end
    
    oil.newthread(orb.run, orb)
end)

corbaname

corbanameはネームサーバーからオブジェクトリファレンスを名前解決して取得する方法です。

corbaname:iiop:localhost:2809#ConsoleIn0.rtc

omniORBpyでは以下のようなコードを記述します。

import sys
from omniORB import CORBA
import RTC

orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
obj = orb.string_to_object("corbaname:iiop:localhost:2809#ConsoleIn0.rtc")
rtc = obj._narrow(RTC.RTObject)

print(rtc.get_component_profile())

OiLではcorbanameはサポートしていません。

SSLIOP

OMG CORBA Security Service仕様では、セキュリティポリシーのモデル、認証、アクセス制御、メッセージ保護、委譲、監査、否認不可の機能を定義していますが、その一つとしてSSL/TLSによるサーバー・クライアント認証とGIOPメッセージの暗号化での通信プロトコルであるSSLIOPを定義しています。

OiL 0.6以降でもSSLIOPはサポートしていますが、OpenRTM Luaではrtc.confに設定を追加することで使用可能です。 OpenSSLで自己認証局と自己署名証明書を生成して確認してください。

corba.ssl.enable: YES
corba.security: required
corba.ssl.key_file: certs/server.pem
corba.ssl.certificate: certs/root.crt
corba.ssl.cafile: certs/root.crt
corba.ssl.protocol: tlsv1_2
corba.ssl.verify: peer, fail_if_no_peer_cert
オプション名 デフォルト値 意味
corba.ssl.enable NO YES:SSLIOPを有効にする、NO:SSLIOPを無効にする
corba.security required required:SSLIOP通信以外を拒否する、preferred:SSLIOP通信を優先する(IIOP通信も受け入れる)
corba.ssl.key_file   秘密鍵
corba.ssl.certificate   サーバー証明書兼クライアント証明書
corba.ssl.cafile   ルート証明書のファイル名
corba.ssl.capath   ルート証明書を格納したパス
corba.ssl.protocol tlsv1_2 有効にするSSL/TLSのバージョン(sslv23、tlsv1、tlsv1_1、tlsv1_2)
corba.ssl.verify peer, fail_if_no_peer_cert 認証方法(none、client_once、peer、fail_if_no_peer_cert)

ネームサーバー

ネームサーバー(もしくはネーミングサービス)はCORBAオブジェクトの参照を名前で登録して検索しやすくする仕組みです。

nameserver

OpenRTM-aist

OpenRTM-aistは産業技術総合研究所が開発しているRTミドルウェアの実装です。 C++版、Python版、Java版にRTSystemEditorやRTCBuilder等のツールが含まれています。

rtc.conf

rtc.confはマネージャを起動する際に読み込む設定ファイルです。 例えば、rtc.confに以下のように記述することでログレベルの設定ができます。

logger.log_level:Debug

何も指定しなければ実行したフォルダのrtc.confを読み込みますが、以下のように-fのコマンドラインオプションで設定ファイルの指定ができます。

lua Sample.lua -f conf/rtc_test.conf

また、このような設定は必ずしもrtc.confに記述する必要はなく、-oのコマンドラインオプションで設定できます。 rtc.conf-oのコマンドラインオプションで同じ項目を設定している場合はコマンドラインオプションが優先されます。

lua Sample.lua -o logger.log_level:Debug

Lua

リオデジャネイロ・カトリカ大学が開発しているスクリプト言語。 軽量、高い移植性、スクリプト言語としては高速であることが特徴。

LuaJIT

LuaのJITコンパイラ。Javaにも匹敵する非常に高速な処理が可能。

LuaRocks

Luaのパッケージ管理システムの1つ。 以下のサイトで運営されている。 2018年11月現在2400個のモジュールが登録されている。