このページではOpenRTM Lua版について説明します。
RTミドルウェア(RTM)はソフトウェアモジュールを組み合わせてロボットシステムを構築するための標準規格です。 ソフトウェアモジュールをRTコンポーネント(RTC)、ロボットシステムをRTシステムと呼びます。 既存のRTミドルウェアの実装として以下のようなものがあります。
名称 | 開発元 | 言語 | OS | コメント |
---|---|---|---|---|
OpenRTM-aist | 産総研 | C++、Java、Python | Windows、Ubuntu、Debian、Fedora、VxWorks、QNX。Macは公式ではサポートしていない。 | もっとも使われているRTM実装(広く使われているとは言っていない)。OpenRTM-aistにはキラーアプリケーションと呼べるものが何もないため今一つ流行っていない。 |
OpenRTM.NET | SEC | .NET(C#、Visual Basic.NET等) | Windows | .NET版RTミドルウェア。更新の頻度が少なく、最近はあまり使っていない。GUI等、上位のアプリケーション向け。 |
RTM on Android | SEC | Java | Android | Android版RTミドルウェア。 |
HRTM | 本田R&D | C++ | Windows、Ubuntu、VxWorks | FSM4RTCのサポート等。オープンソースではないため外部では使われていない。 |
OpenRTM-erlang | 産総研 | Erlang | Linux? | Erlangはあまり使ったことが無いのでよく分かりません。RTCが落ちてもすぐに再起動するのは見ていて面白い。 |
RTMSafety | SEC | C言語 | QNX、TOPPERS、ETAS RTA-OS、OSなし | 機能安全の認証対応のRTミドルウェア。使ったことはない。 |
OPRoS | ETRI | よく知りません | ||
GostaiRTC | GOSTAI、THALES | C++ | よく知りません | |
ReactiveRTM | .NET | Windows? | 使ったことないです。 | |
OpenRTM Lua | Lua | Windows、Haiku、macOS、Ubuntu、Debian、FreeBSD | このページで説明します。 |
Luaはリオデジャネイロ・カトリック大学で開発されているスクリプト言語です。
LuaはC言語への組み込みを意識して設計されているため、ゲーム開発でイベントスクリプトを作成する際に使用されることが多いです。 Pythonと同じくスクリプト言語であるためコードを書いてすぐに動かすという事ができます。それでいてPythonよりも高速であり、LuaJITの使用によりC++に匹敵する速度で処理することができます。 また、言語仕様が小さいため処理系のサイズも小さく、単純であるため移植性も高くなっています。
OpenRTM Luaはプログラミング言語LuaによるRTミドルウェアの実装です。
OpenRTM Luaを使用することにより、Luaスクリプティング機能を有するアプリケーション上でRTCを起動してC++やPythonのRTCと接続したり、Luaのライブラリを活用したRTCを作成するという事ができます。
OpenRTM Lua版には以下の3つの特徴があります。
ソフトウェア一式で2MB程度と、他のRTミドルウェアの実装に比べて非常に軽量です。
Lua(1.84MB)>LuaJIT(2.14MB)»»Python(7.65MB)>=C++(8.05MB)»>Java
Luaスクリプティング機能のあるソフトウェアであれば組み込み可能です。
以下は手元で動作確認したソフトウェアです。
AviUtlやNScripter2上でもRTCを起動できますが、実用性は皆無です。
剛体シミュレータ、ゲーム開発ツール等と相性がいいです。
例:
JITコンパイラのLuaJIT利用により、C++に匹敵する速度で動作が可能です。
既存のRTMに対応していないアプリケーションをRTC化することにより、様々なRTシステムが開発可能になります。例えばLÖVEでロボット操作のGUIを作成して実機と連携するといったことが可能になります。
またPythonでは処理が遅い、メモリ使用量が大きい部分をLuaJITで動作するRTCで実装することで、スクリプト言語による効率的な開発と高速な処理を両立させることが可能です。
Luaスクリプト機能をサポートしているアプリケーションを様々なデバイス、あるいは他のアプリケーションと接続可能になるため、ロボットを専門にしない人がロボット技術(RT)を応用したアプリケーションを実装できるようになります。 例えばLaputan Blueprints上の車、飛行機等をLEGO Mindstorms EV3のデバイスで操作するということができます。
LuaのRTCとPythonのRTCを接続
LuaのRTCとJavaのRTCを接続
LuaのRTCとは別のマシンで起動したC++のRTCと接続
※OpenRTM LuaはOpenRTM-aistで使用しているOpenRTM.idlとDataPort.idlを同時にロードできません。詳細はここに記載してあります。このためDataPort.idlを削除してFSM4RTC標準のインターフェースのみが使える通常版と、OpenRTM.idlを改変してDataPort.idlを使えるようにしたcorba_cdr対応版を用意してあります。特に理由がなければcorba_cdr対応版を使用してください。 通常版はOpenRTM-aist 1.2以前のRTCとデータポートで接続ができません。
Windowsの場合はOpenRTM Luaをインストールしなくても動作を確認できます。
※RTSystemEditorの使用のためにOpenRTM-aistのインストールは必要です。
ダウンロードしたファイルを展開して、バッチファイルを起動するとサンプルコンポーネントが起動します。
RTSystemEditor、ネームサーバーはOpenRTM-aistのものを使用してください。
openrtm.orgが閉鎖している場合は以下のサイトから入手してください。
OpenRTM-aistのインストール手順は以下の通りです。
以下の手順で簡単な動作確認ができます。
以下のように様々なOSに対応しています。 OpenRTM Luaは世界で初めてHaiku OSに対応したロボット用ミドルウェアです。
※OpenRTM-aist 1.2.0のRTC Builderを使う場合はRTC作成手順を参考にしてください。
サンプルを例に、RTC作成方法を説明します。
以下のようにモジュールのロードを行います。
local openrtm = require "openrtm"
以下のようにRTCの仕様を定義したテーブルを作成します。
local consolein_spec = {
["implementation_id"]="ConsoleIn",
["type_name"]="ConsoleIn",
["description"]="Console output component",
["version"]="1.0",
["vendor"]="Vendor Name",
["category"]="example",
["activity_type"]="DataFlowComponent",
["max_instance"]="10",
["language"]="Lua",
["lang_type"]="script"}
RTCのテーブルを作成する関数を定義します。
local ConsoleIn = {}
ConsoleIn.new = function(manager)
local obj = {}
-- RTObjectをメタオブジェクトに設定する
setmetatable(obj, {__index=openrtm.RTObject.new(manager)})
-- 初期化時のコールバック関数
function obj:onInitialize()
(省略)
end
-- アクティブ状態の時の実行関数
function obj:onExecute(ec_id)
(省略)
end
return obj
end
アウトポート、インポート、サービスポートをonInitialize関数で追加します。
ConsoleIn.new = function(manager)
(省略)
-- データ格納変数
obj._d_out = openrtm.RTCUtil.instantiateDataType("::RTC::TimedLong")
-- アウトポート生成
obj._outOut = openrtm.OutPort.new("out",obj._d_out,"::RTC::TimedLong")
(省略)
function obj:onInitialize()
-- ポート追加
self:addOutPort("out",self._outOut)
return self._ReturnCode_t.RTC_OK
end
データの出力を行う場合は、self._d_out
に送信データを格納後、self._outOut
のwrite関数を実行します。
-- 出力データ格納
self._d_out.data = 1
-- データ書き込み
self._outOut:write()
ConsoleOut.new = function(manager)
(省略)
-- データ格納変数
obj._d_in = openrtm.RTCUtil.instantiateDataType("::RTC::TimedLong")
-- インポート生成
obj._inIn = openrtm.InPort.new("in",obj._d_in,"::RTC::TimedLong")
(省略)
function obj:onInitialize()
-- ポート追加
self:addInPort("in",self._inIn)
return self._ReturnCode_t.RTC_OK
end
openrtm.RTCUtil.instantiateDataType
関数により、データを格納する変数を初期化できます。
openrtm.OutPort.new("out",self._d_out,"::RTC::TimedLong")
のように、データ型は文字列で指定する必要があります。
入力データを読み込む場合は、self._inIn
のread関数を使用します。
-- バッファに新規データがあるかを確認
if self._inIn:isNew() then
-- データ読み込み
local data = self._inIn:read()
print("Received: ", data.data)
end
isNew
関数で新規データの有無を確認できます。
プロバイダ側のサービスポートを生成するためには、まずプロバイダのテーブルを作成します。
local MyServiceSVC_impl = {}
MyServiceSVC_impl.new = function()
local obj = {}
(省略)
function obj:echo(msg)
(省略)
end
function obj:get_echo_history()
(省略)
end
function obj:set_value(value)
(省略)
end
function obj:get_value()
(省略)
end
function obj:get_value_history()
(省略)
end
return obj
end
onInitialize関数内でポートの生成、登録を行います。
MyServiceProvider.new = function(manager)
(省略)
-- サービスポート生成
obj._myServicePort = openrtm.CorbaPort.new("MyService")
-- プロバイダオブジェクト生成
obj._myservice0 = MyServiceSVC_impl.new()
(省略)
function obj:onInitialize()
-- サービスポートにプロバイダオブジェクトを登録
self._myServicePort:registerProvider("myservice0", "MyService", self._myservice0, "idl/MyService.idl", "IDL:SimpleService/MyService:1.0")
-- ポート追加
self:addPort(self._myServicePort)
return self._ReturnCode_t.RTC_OK
end
self._myServicePort:registerProvider("myservice0", "MyService", self._myservice0, "../idl/MyService.idl", "IDL:SimpleService/MyService:1.0")
のように、IDLファイル名、インターフェース名を文字列で指定する必要があります。
コンシューマ側のサービスポートを追加するには、以下のようにonInitialize関数内でポートの生成、追加を行います。
self._myServicePort:registerConsumer("myservice0", "MyService", self._myservice0, "../idl/MyService.idl")
のようにIDLファイル名を文字列で指定する必要があります。
MyServiceConsumer.new = function(manager)
(省略)
-- サービスポート生成
obj._myServicePort = openrtm.CorbaPort.new("MyService")
-- コンシューマオブジェクト生成
obj._myservice0 = openrtm.CorbaConsumer.new("IDL:SimpleService/MyService:1.0")
(省略)
function obj:onInitialize()
-- サービスポートにコンシューマオブジェクトを登録
self._myServicePort:registerConsumer("myservice0", "MyService", self._myservice0, "idl/MyService.idl")
-- ポート追加
self:addPort(self._myServicePort)
return self._ReturnCode_t.RTC_OK
end
オペレーションを呼び出す場合は、CorbaConsumerの_ptr関数でオブジェクトリファレンスを取得して関数を呼び出します。
self._myservice0:_ptr():set_value(val)
コンフィグレーションパラメータの設定には、まずRTCの仕様定義にコンフィグレーションパラメータを追加します。
local configsample_spec = {
(省略)
["conf.default.int_param0"]="0",
["conf.default.int_param1"]="1",
["conf.default.double_param0"]="0.11",
["conf.default.double_param1"]="9.9",
["conf.default.str_param0"]="hoge",
["conf.default.str_param1"]="dara",
["conf.default.vector_param0"]="0.0,1.0,2.0,3.0,4.0"}
onInitialize関数で変数をバインドします。
値は_value
というキーに格納されます。
ConfigSample.new = function(manager)
(省略)
-- コンフィギュレーションパラメータをバインドする変数
obj._int_param0 = {_value=0}
(省略)
function obj:onInitialize()
-- コンフィギュレーションパラメータを変数にバインドする
self._int_param0 = {_value=0}
(省略)
self:bindParameter("int_param0", self._int_param0, "0")
(書略)
return self._ReturnCode_t.RTC_OK
end
onExecuteコールバックなどを定義する場合についても、関数を定義して処理を記述します。
function obj:onExecute(ec_id)
io.write("Please input number: ")
local data = tonumber(io.read())
self._d_out.data = data
openrtm.OutPort.setTimestamp(self._d_out)
self._outOut:write()
return self._ReturnCode_t.RTC_OK
end
以下のようにRTCの登録、生成関数を定義します。
ConsoleIn.Init = function(manager)
local prof = openrtm.Properties.new({defaults_map=consolein_spec})
manager:registerFactory(prof, ConsoleIn.new, openrtm.Factory.Delete)
end
local MyModuleInit = function(manager)
ConsoleIn.Init(manager)
local comp = manager:createComponent("ConsoleIn")
end
以下のようにRTC生成関数を設定してマネージャを起動します。
local manager = openrtm.Manager
manager:init(arg)
manager:setModuleInitProc(MyModuleInit)
manager:activateManager()
manager:runManager()
LGPLライセンス
現在配布しているOpenRTM Luaには通常版とcorba_cdr対応版があります。 これはOpenRTM-aist付属のIDLファイルの問題により、OpenRTM.idlとDataPort.idlをOiLで読み込むとエラーが発生する問題のため、DataPort.idlを読み込まずにFSM4RTC標準のインターフェースのみをサポートした通常版と、OpenRTM.idlを改変してDataPort.idlを読み込めるようにしたcorba_cdr対応版を用意してあります。
通常版を使用する場合は、OpenRTM-aist 1.2以前のRTCとデータポートが接続ができません。 このため、OpenRTM-aist 2.0のインストールが必要になります。
以下のページにインストール手順が記載してあります。
または、以下のブリッジコンポーネントを使用する方法があります。