ソフトウェアモジュールを組み合わせてロボット技術を用いたシステム(RTシステム)を構築するための標準規格。OMG RTC。 詳細はWikipediaでも見てください。
規格の詳細は以下のページから見れます。
主に以下の機能が定義されています。
RTCの情報取得の機能が規格で定義されており、どのような機能、ポートのRTCなのか分かりやすいのは特徴の一つです。
ロボット技術を用いたソフトウェアモジュールのことをRTコンポーネント( Robot Technology Component、RTC)といいます。 RTCにはコンポーネントの基本情報(コンポーネントプロファイル)、他のRTCとやり取りするためのポート(データポート、サービスポート)、コンフィギュレーションパラメータ、ライフサイクルという要素から成り立っています。
OpenRTM-aist付属のIDLファイルに定義されたインターフェースは以下のようになっています。
RTミドルウェアの規格はプラットフォーム独立モデルで定義されているため、上記のインターフェースが定義できればCORBA以外のRPCができる通信ライブラリでも実装できます。ただし既存のOpenRTM-aist等とは通信できなくなります。
RT System EditorからRTCを操作するためには、最低でもコンポーネントプロファイルを取得するget_component_profile
、ポート一覧を取得するget_ports
、RTCを終了させるexit
が必要になるため、最低でもRTC::RTObject
の実装が必要になります。
RTC::RTObject
の実装のためにはRTC::ComponentAction
、RTC::LightweightRTObject
、SDOPackage::SDOSystemElement
、SDOPackage::SDO
の実装が必要になります。
RTC::ComponentAction
インターフェースで定義されたオペレーションは以下の通りです。
名前 | 意味 |
---|---|
on_initialize | 初期化時のコールバック関数 |
on_finalize | 終了時のコールバック関数 |
on_startup | 実行コンテキスト開始時のコールバック関数 |
on_shutdown | 実行コンテキスト停止時のコールバック関数 |
on_activated | アクティブ状態遷移時のコールバック関数 |
on_deactivated | 非アクティブ状態遷移時のコールバック関数 |
on_aborting | エラー状態遷移時のコールバック関数 |
on_error | エラー状態時のコールバック関数、周期実行の場合には周期的に呼び出される |
on_reset | リセット実行時のコールバック関数 |
上記の太字のオペレーションは実行コンテキストから呼び出されます。
on_initialize
、on_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を取得 |
initialize
、finalize
は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_configuration
、get_organizations
のみ。
使わないオペレーションが大量に定義されているため、ビルド後のバイナリのサイズが大きくなる原因の1つになっている。
get_configuration
で取得したSDOコンフィギュレーションはコンポーネントオブザーバー等のサービスの設定、コンフィギュレーションパラメータの設定を行う機能を提供します。
get_organizations
は複合コンポーネントの親コンポーネントを取得します。
上記の機能が必要ない場合は実装の必要はありません。
RTC::RTObject
インターフェースで定義されたオペレーションは以下の通りです。
名前 | 意味 |
---|---|
get_component_profile | コンポーネントプロファイルの取得 |
get_ports | ポートの一覧取得 |
これらのオペレーションをCORBAで実装すればRTSystemEditorから情報取得ができるようになります。
コンポーネントプロファイルは以下のような構造になっています。
RTSystemEditorではport_profiles
に格納したポートプロファイル一覧を取得後、PortProfile
からポートの種類、接続したコネクタ一覧の情報を取得しています。
PortProfile
のproperties
には以下の情報を格納します。
パラメータ名 | 意味 |
---|---|
port.port_type | ポートの種類(DataOutPort、DataInPort、CorbaPort) |
dataport.data_type | データ型 |
サービスポートの場合は、interfaces
にインターフェースの情報を格納します。
RTSystemEditorで情報を取得するためにはコンポーネントプロファイルを取得する機能を実装すれば充分であり、見た目上は既存のRTミドルウェアと変わらない動きをします。
データポートはデータを連続的に転送するためのポートです。
インターフェースとしてはデータポート、サービスポートに違いはなく、以下の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
の引数で渡したコネクタプロファイルに格納したポートの順番に依存します。
notify_connect
内でどのような処理をするかは規格では定義されていません。
とりあえず、notify_connect
処理後にget_connector_profiles
で取得できるコネクタプロファイルが追加されていたら、RT System Editorからはポートが接続されているように見えます。
InPort
はOutPort
からデータを受信するポートです。
前述の通り、InPort、OutPortにインターフェースの違いはなく、get_port_profile
で取得できるポートプロファイルの内容が違うだけです。
OutPort
はInPort
にデータを送信するポートです。
InPort
をデータが受信するポート、OutPort
をデータを送信するポートにするためには、notify_connect
内でコネクションを確立する処理をする必要があります。例えば、ソケット通信をする場合はnotify_connect
内でソケットの作成、接続を行い、InPort
側ではrecv関数で待ち受け、OutPort
側ではsend関数でデータ送信という事をします。
データ型には転送するデータの内容のことです。
データ型はOMG IDL構文で定義されています。
OpenRTM-aistにはBasicDataType.idl
、ExtendedDataTypes.idl
、InterfaceDataTypes.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ファイルを選択します。
するとデータ型一覧に独自データ型が追加されます。
インターフェース型はデータを転送する方法を定義しています。
OpenRTM-aist 2.0ではcorba_cdr
、data_service
、shared_memory
、direct
の4種類のインターフェース型が利用できます。
OpenRTM-aistのRTCと通信するためには、notify_connect
の中でこれらのインターフェースのコネクションを確立するための処理をする必要があります。
corba_cdr
はCORBA通信でデータを転送するインターフェース型です。
DataPort_OpenRTM.idl
ファイルでInPortCdr
インターフェースとOutPortCdr
インターフェースが定義されています。
InPortCdr
のput
オペレーションはOutPort
からInPort
にデータを渡すPush
型の通信の場合に使用します。
OutPortCdr
のput
オペレーションはInPort
がOutPort
からデータを取得する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のオブジェクトリファレンスを先に格納しているためです。
ここで、(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
からOutPort
のnotify_connect
を呼び出す時にInPortCdr
のオブジェクトリファレンスが取得できるようになっている必要があります。
他にOutPort
のconnect
を呼び出す場合、ports
の順序で以下の処理順序があります。
data_service
もCORBA通信のインターフェースですが、こちらは規格標準のインターフェースです。
DataPort.idl
で定義されています。
動作としてはcorba_cdr
と同じです。
shared_memory
は共有メモリによるデータ転送を行うインターフェース型です。
direct
は同一プロセス内で変数渡しによりデータの転送を行うインターフェース型です。
データフロー型はデータを転送する際の流れを定義します。
Push
型はOutPort
からInPort
にデータを送る方式で、Pull
型はInPort
からOutPort
のデータを取る方式です。
以下はPush型の通信です。
以下はPull型の通信です。
現在はPush型、Pull型の2種類ですが、例えばメッセージブローカーを介して通信する場合はPush型やPull型に当てはまらない通信になります。
現状、OpenRTM-aistではデータフロー型については拡張できるようになっていません。
データフロー型がPush型の場合のみ、データの送信タイミングをflush
、new
、periodic
から選択できます。
OutPortのwrite
関数を呼び出した時点で即座にデータを送信する方式です。
OutPortのwrite
関数を呼び出した時点ではリングバッファに格納しておいて、別スレッドでデータを送信する方式です。
write
関数を呼び出すとデータ送信処理を1回実行するようにデータ送信スレッドに指令します。
既にデータ送信処理中に指令を送ってもさらに1回実行することはないため、データ送信処理中にwrite
関数を呼び出すと、データが送信されない場合があります。
OutPortのwrite
関数を呼び出した時点ではリングバッファに格納しておいて、別スレッドでデータを送信する方式です。
new
型と違う点はデータ送信スレッドがデータ送信処理を周期的に実行している点です。
new
型のようにデータの欠損が発生することはありませんが、データがすぐに送信されない場合があります。
サービスポートはコマンドレベルの操作を提供する機能であり、単純なデータの転送だけではなく、特定の処理の呼び出し、処理結果の取得ということができます。 データポートを使うべきか、サービスポートを使うべきかは場合によりますが、例えば以下のような場合に使われる事があります。
データポート、サービスポートにインターフェースの違いはなく、get_port_profile
で取得できるポートプロファイルの内容が違うだけです。
サービスポートの操作を呼び出す方法については特に規格では定義されておらず、OpenRTM-aistではCORBAによるリモート関数呼び出しで処理しています。
サービスポートには関数の処理を実装したプロバイダ
と、関数をリモート呼び出しする側のコンシューマ
のインターフェースを保持しています。
connect
を呼び出すときのコネクタプロファイルを以下のように設定します。
名前 | 型 | 値 |
---|---|---|
name | string | 適当な名前 |
connector_id | string | 空白 |
ports | PortServiceList | {ServicePort1のオブジェクトリファレンス、ServicePort2のオブジェクトリファレンス} |
properties | NVList | {} |
そしてServicePort1
のconnect
を呼び出すと、以下の順序で接続処理を行います。
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
の順番を入れ替えると以下のような処理となります。
コンフィギュレーションパラメータはRTC実行中に内部パラメータを外部から変更可能な機能です。
データポートかサービスポートかコンフィギュレーションパラメータのどれを使うかは場合によって違います。
データポートを使っても内部の処理を工夫すればパラメータを変更する事はできますが、1回変更すればいいところにデータポートを使うのは適切ではありません。
パラメータの変更にサービスポートを使うのは一つの方法です。 ただ、それも場合によります。他のRTCからパラメータを変更する必要があるときにはサービスポートを使うのが有効です。
例えば、RTCがファイルをロードする必要がある場合に、そのファイルパスを設定したいとします。 確かにサービスポートでも設定できるのですが、設定するためのRTCが別個必要になるため手軽ではありません。 他のRTCから変更する必要がない場合は、コンフィギュレーションパラメータで設定することをお勧めします。
コンフィギュレーションの設定には、get_configuration
オペレーションでConfiguration
オブジェクトを取得後に設定します。
RTCの重要な要素としてライフサイクルがあります。
RTCにはCreated
、Inactive
、Activate
、Error
の4種類の状態があります。
ここで重要なのはRTCが個別に状態を持っているのではなく、RTCが関連付けしている実行コンテキストごとに状態を持っているという点です。
以下の例では、実行コンテキストA
にはRTC1
を、実行コンテキストB
にはRTC1
とRTC2
を関連付けています。
この場合、RTC1
は実行コンテキストA
での状態と実行コンテキストB
での状態があることになります。
RTC1
は実行コンテキストA
ではInactive状態、実行コンテキストB
ではActive状態になっており、実行コンテキストごとに別々の状態になることがあります。
Inactive
状態(非アクティブ状態、非活性状態)は、RTCが処理を実行していない状態です。
この状態ではon_execute
オペレーションも実行されず、またコンフィギュレーションパラメータの変更は(原則)反映されません。
サービスポートも機能が停止するのが動作としては正しいのですが、使いづらくなるだけなのでOpenRTM-aist 1.2以降ではInactive状態でもサービスポートは機能するようになっています。
Active
状態(アクティブ状態、活性状態)は、RTCが処理を実行している状態です。
この状態では、実行コンテキストによりon_execute
オペレーションが実行され、on_state_update
オペレーションでコンフィギュレーションパラメータの更新が行われます。
RTCのonExecute
関数にはロボットを制御するなどのメインとなる処理を実装します。
またActive
状態遷移直後にon_activated
、他の状態に遷移するときにon_deactivated
を実行します。
RTCのonActivated
関数にはサーボをオンにするなどの初期化処理、onDeactivated
関数にはサーボをオフにするなどの後処理を実装します。
Error
状態(エラー状態、異常状態)は、RTCに問題が発生した事を検知して処理を停止した状態です。
この状態では、実行コンテキストによりon_error
オペレーションが実行されます。
RTCのonError
関数にはロボットを安全に停止するなどの、エラーに対応した処理を実装します。
実行コンテキスト(Execution Context、EC)はRTCの状態を管理する機能です。 RTC単体では処理を実行することができず、実行コンテキストがRTCの操作を呼び出すことで処理を実行します。
RTCと実行コンテキストを分離することによって、実行コンテキストの変更のみで通常の周期実行、リアルタイム処理、シミュレータからのトリガ駆動を使い分けることができます。
実行コンテキストはRTC.idl
、OpenRTM.idl
で以下のようなインターフェースが定義されています。
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
は周期実行を行う実行コンテキストです。
ExtTrigExecutionContext
は外部からトリガ駆動で実行する実行コンテキストです。
tick
のオペレーションの実装が必要になるため、ExtTrigExecutionContextService
インターフェースで実装する必要があります。
tick
を呼び出した時点では即座には実行されず、実行スレッドに指令して、RTCの処理は別スレッドで実行されます。
このため、tick
の処理が戻ってきてもRTCの処理は終了していません。
OpenHRPExecutionContext
は外部からトリガ駆動で実行する実行コンテキストです。
ExtTrigExecutionContext
と違い、OpenHRPExecutionContext
はtick
実行時にRTCの処理を実行するため、RTCの処理終了までtick
の処理は戻ってきません。
SimulatorExecutionContext
は外部からトリガ駆動で実行する実行コンテキストです。
OpenHRPExecutionContext
はactivate_component
等のRTCを状態を遷移する操作を実行してもtick
でRTCの処理を実行しない限り状態は遷移しません。
RTPreemptEC
はPeriodicExecutionContext
と同じく周期実行の実行コンテキストですが、RT-Preemptパッチを適用したLinuxカーネルにより実時間処理を行うための実行コンテキストです。
マネージャはRTCを管理する仕組みです。 1プロセスで1つのマネージャが起動し、モジュールのロード、RTCの生成、生存しているRTCの管理等を行います。
インターフェースはManager.idl
で定義されています。RTM標準の規格ではなく、OpenRTM-aist固有のインターフェースです。
マネージャはマスターマネージャ
とスレーブマネージャ
に分類されます。
マスターマネージャはスレーブマネージャを管理するマネージャです。
通常、マスターマネージャはRTCを生成しません。
またデフォルトでは2810
のポート番号で起動するようになっており、RTSystemEditor等のツールからはそのポート番号にアクセスします。
スレーブマネージャはマスターマネージャにぶら下がっているマネージャです。 デフォルトで起動するマネージャはスレーブマネージャであり、RTCを生成することができます。 通常、スレーブマネージャはRTSystemEditor等のツールから直接操作することができず、マスターマネージャを介して操作することになります。 動的なRTCの生成、生成可能なモジュール名の取得などができます。
単一、もしくは複数のRTCのポートの接続などを行い、RT(ロボットテクノロジー)を活用した処理を実行するためのシステムのことをRTシステム
と言います。
複合コンポーネントは複数のRTCを1つに複合する仕組みの事です。
例えば、以下の例の場合RTC1
とRTC2
、RTC2
とRTC3
のポートは外に見せる必要がないということで隠蔽してあります。
こうすることで、複雑なRTシステムが見た目上は単純になるため、システムの概要を理解しやすくなります。
また、実行の同期
、状態の同期
を行う場合があります。
実行の同期
を行う場合には、子コンポーネントを1つの実行コンテキストに関連付けて同期実行を行うようになっています。
状態の同期
はOpenRTM-aistでは実装されていません。
IDL
(Interface Description Language、インターフェース記述言語)は、ソフトウェアモジュールの間のやり取りを行うためのインターフェースを記述する言語です。
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からオペレーションを呼び出します。
コンポーネントオブザーバーはRTCからRTSystemEditor等のツールに状態変化、ハートビートなどを通知する機能です。
RTC::ComponentObserver
はFSM4RTC規格標準のインターフェースであり、OpenRTM::ComponentObserver
はOpenRTM-aist独自のインターフェースです。
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(Finite State Machine for RTC)は、有限状態機械の仕組みをRTCの導入するための規格です。
OMG RTCの規格では、RTCにはInactive状態、Active状態、Error状態の3種類の状態がありましたが、例えば以下のようにイベントでロボットを制御する場合などは複雑な状態変化を設定できるようにする必要があります。
現状のOpenRTM-aistでこのような仕組みを実装するためには、独自にStateパターンやswitch文によりステートマシンを実装し、データポートやサービスポートの入力で状態を変化させるという仕組みが必要になるため、実装が簡単ではありません。 FSM4RTCの仕組みを導入することで、FSMの実装が容易になります。
CSP(Communicating Sequential Processes)は、並列に動作するシステムを記述して検証するための形式手法の一つです。
CSPで記述した並列システムは、FDR4
等のツールでデッドロックが発生しないかなどの問題を検証することができます。
FSM4RTCで実装したRTシステムをCSPで検証するという試みが行われています。
RTC実行中のログをファイル、もしくは標準出力する機能です。特に規格では定義されていません。 OpenRTM-aistにはFluent Bitでログを収集する機能もあります。
例えば、OpenRTM-aistでSample
という名前のRTCを起動した場合、インスタンス名はSample0
となります。
同一プロセスでSample
を複数起動した場合、Sample0
、Sample1
、Sample2
と番号が増えていく仕組みになっています。
ただしこれは同一プロセス内の話で、別プロセスでSample0
が起動している場合にもカウントを増やしてほしい場合は、デフォルト以外の設定が必要になります。
デフォルトの設定。上述の通りプロセス内でカウントする。
ネームサーバーに登録されたRTC名が被らないように番号付けする。
rtc.conf
に以下のように記述することで利用できる。
manager.components.naming_policy:ns_unique
同一ノード内でRTC名が被らないように番号付けする。 マスターマネージャに登録されたスレーブマネージャで起動している全てのRTCを調べて番号付けをする。
naming.type:corba,manager manager.components.naming_policy:node_unique
CORBA(Common Object Request Broker Architecture)は分散環境で透過的にソフトウェアモジュールの相互利用を行うための標準規格です。 IDLファイルで定義されたインターフェースでプログラミング言語を問わずに関数のリモート呼び出しができます。
ORB(Object Request Broker)はネットワークを介してプログラムの呼び出しを行うためのミドルウェアのことです。 CORBAもORBの一つです。
POA(Portable Object Adapter)はオブジェクトリファレンスとサービスの実体を関連付けて、リモート呼び出しに対して適切なサービスを呼び出すための仕組みです。
OpenRTM-aistが利用しているCORBAの実装です。 C++、Pythonの実装があります。
フリーCORBA御三家の一つ。残りはORBacusとMICO。C++による実装。 UDPの通信、Real-Time CORBA等の機能が充実している。 OpenRTM-aistがサポートしている実装の一つ。
商用CORBAの1つ。軽量であり、様々な独自プロトコルを追加できる。 OpenRTM-aistがサポートしている実装の一つ。
RtORBはC言語で実装されているCORBA実装。 OpenRTM-aistで使用していないAPIが省かれているため非常に軽量。
.NET系のプログラミング言語で使用可能なCORBA実装。 OpenRTM.NETが使用している。
Luaで実装されたCORBA実装。 OpenRTM Luaが使用している。
クライアント側で使用するオブジェクトの参照。 オブジェクトリファレンスによりリモートにCORBAオブジェクトの実体側の操作を呼び出せる。
CDR(Common Data Representation)は、CORBAで使用されているデータの表現方法の1つです。 サーバー、クライアントで通信する場合にデータはCDR形式のバイト列に変換(マーシャリング、符号化)し送信、受信側でバイト列を元のデータに戻す(アンマーシャリング、復号化)することでデータの受け渡しを行います。
IOR(Interoperable Object Reference)はCORBAオブジェクトの情報を文字列で表現する形式です。
IOR:
から始まる文字列となっており、ホスト名、ポート番号等の情報が含まれています。
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(Interoperable Naming Service)はCORBAオブジェクトを名前解決する機能。
coabeloc
、corbaname
形式が利用できる。
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: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
はサポートしていません。
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オブジェクトの参照を名前で登録して検索しやすくする仕組みです。
OpenRTM-aist
は産業技術総合研究所が開発しているRTミドルウェアの実装です。
C++版、Python版、Java版にRTSystemEditorやRTCBuilder等のツールが含まれています。
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のJITコンパイラ。Javaにも匹敵する非常に高速な処理が可能。
Luaのパッケージ管理システムの1つ。 以下のサイトで運営されている。 2018年11月現在2400個のモジュールが登録されている。