RTM-Lua

View the Project on GitHub Nobu19800/RTM-Lua

OpenResty上で動作するRTCの作成方法

概要

このページではWEBアプリサーバーOpenResty上で動作するRTCを作成して、以下のようにPython版サンプルコンポーネントのジョイスティックコンポーネントと接続してWEBブラウザ上でジョイスティックの位置を表示するシステムの作成を行います。

従来はWEBブラウザ上でRTCのデータを表示等をする場合は、以下のようにRTCとWEBサーバーで通信を行う必要がありましたが、

openrtmlua7102

WEBサーバー上でRTCを起動することで、以下のように構成が簡単になります。

openrtmlua7103

この構成にする事によって、従来の方法では難しかったWEBブラウザでの操作のタイミングでOutPortからデータを送信する、サービスポートの操作を呼び出すという事が容易に実現できます。

※このような使い方を見たわけではありませんが、OpenRTM-aist Python版+Twisted(もしくはDjango)でも同じ構成は可能かもしれません。

OpenRestyの入手

以下からopenresty-1.13.6.1-win32.zipをダウンロードして適当な場所に展開してください。

ディレクトリ構成

以下のサイトを参考にしてディレクトリを作成する。

rtc-server
    |
    |----conf
    |     |----mime.types
    |     |----nginx.conf
    |
    |----logs
    |     |----access.log
    |     |----error.log
    |
    |----luahooks
    |     |----image.lua
    |
    |
    |----public
    |      |----images
    |              |----index.html
    |              |----sample.html
    |              |----test.gif

nginx.confには以下のように記述してください。

worker_processes    1;
events {
    worker_connections  1024;
    accept_mutex_delay  100ms;
}

http {
    sendfile            on;
    tcp_nopush          on;
    include             mime.types;
    default_type        text/html;
    index               index.html;

    #
    # log settings
    #
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  logs/access.log main;

    # 
    # lua global settings
    #
    lua_package_path        '$prefix/luahooks/?.lua;;';
    lua_check_client_abort  on;
    lua_code_cache          on;

    #
    # initialize script
    #
    #init_by_lua_file        luahooks/init.lua;

    #
    # public
    #
    server {
        listen      1080;
        root        public/images;

        #
        # content handler
        #
        location /index.html {
            default_type text/html;
            content_by_lua_file        luahooks/image.lua;
        }
    }
}

test.gifには以下のような画像を用意してください。

test

sample.htmlには以下のように記述してください。

OpenRestyにOpenRTM Lua版をインストール

rtc-serverのフォルダにOpenRTM Lua版の各ファイルをコピーします。

以下から32bit用のOpenRTM Lua版ファイル一式(OpenRTM Lua x.y.z LuaJIT 32bit)をダウンロードしてください。

OpenRTM Lua版からOpenRestyにファイルをコピーします。

openrtm-lua-x.y.z-x86-LuaJIT\luaフォルダを、rtc-server以下にコピーしてください。

openrtmlua720

openrtm-lua-x.y.z-x86-LuaJIT\lua\idlフォルダを、rtc-server以下にコピーしてください。

openrtmlua730

openrtm-lua-x.y.z-x86-LuaJIT\clibsフォルダを、rtc-server以下にコピーしてください。

openrtmlua740

lua51.dllの上書きが必要なため、openrtm-lua-x.y.z-x86-LuaJIT\bin\lua51.dllopenresty-1.13.6.1-win32\以下にコピーしてください。

openrtmlua750

Lua CJSONのビルド

データはJSON形式で取得しますが、Lua CJSONはこちらでdllを用意していないのでビルドしてください。

以下からソースコードをダウンロードしてCMake、Visual Studioでビルドしてください。

Visual Stduio 2017の場合はビルド時にエラーが出ます。 CMakeLists.txtの以下の部分を削除してからビルドしてください。

add_definitions(-Dsnprintf=_snprintf)

openrtmlua700

RTC作成

RTC BuilderによるRTCの基本的な作成手順は以下のページを参考にしてください。

上のページの作成手順に従って、以下の仕様のRTCを作成してください。

基本プロファイル

   
モジュール名 OpenRestySample

アクティビティ

onExecuteを有効にしてください。

インポート

   
ポート名 in
データ型 RTC::TimedFloatSeq

OpenRestySample.luaの編集

データを格納する変数、取得する関数を定義します。

OpenRestySample.new = function(manager)
	local obj = {}
        (省略)
	obj.input_data = {0,0}
	function obj:getData()
		return self.input_data
	end

OpenRestySample.luaonExecute関数を以下のように編集してください。

	function obj:onExecute(ec_id)
		if self._inIn:isNew() then
			local data = self._inIn:read()
			self.input_data[1] = data.data[1]
			self.input_data[2] = data.data[2]
		end
		return self._ReturnCode_t.RTC_OK
	end

入力データはgetData関数で取得できます。

編集したOpenRestySample.luartc-server\luaにコピーしてください。

openrtmlua710

image.luaの編集

image.luaに以下のように記述してください。

package.path = package.path..";./lua/?.lua"
package.cpath = package.cpath..";./clibs/?.dll"
local oil  = require "oil"
local openrtm  = require "openrtm"
local OpenRestySample = require "OpenRestySample"
local cjson = require "cjson"

local args = ngx.req.get_uri_args()
local command = tostring( args.command )



if command == "start" then
	local f = io.open("public/images/sample.html", "r")
	local content = f:read("*all")
	f:close()
	

	local MyModuleInit = function(manager)
		OpenRestySample.Init(manager)
		local comp = manager:createComponent("OpenRestySample")
	end
	if oil.corba == nil then
		oil.corba = {}
		oil.corba.idl = {}
	end
	local manager = openrtm.Manager
	manager:init({"-o","logger.enable:NO","-o","exec_cxt.periodic.type:OpenHRPExecutionContext"})
	manager:setModuleInitProc(MyModuleInit)
	manager:activateManager()
	manager:runManager(true)
	
	ngx.say(content)

elseif command == "update" then
	local x = 0
	local y = 0
	
	local manager = openrtm.Manager
	manager:step()
	local comp = manager:getComponent("OpenRestySample0")
	local ec = comp:get_owned_contexts()[1]
	ec:tick()
	local data = comp:getData()
	x = data[1]
	y = data[2]
	ngx.say(cjson.encode({x=x,y=y}))
end

クエリパラメータcommandstartの場合はRTCを起動します。

commandupdateの場合はRTCのステップ処理を更新して入力データを取得します。

JSON形式によりサーバークライアントでデータのやり取りを行います。

動作確認

ネームサーバー起動

事前にネームサーバーの起動が必要です。

※OpenRTM-aist 1.2以降ではRT System Editorにネームサーバー起動ボタンがあるため、手順が簡単になっています。

TkJoyStickコンポーネントの起動

TkJoyStickコンポーネントを入手して、TkJoyStickComp.exeを実行してください。

WEBサーバーの起動

openresty-1.13.6.1-win32以下のディレクトリを環境変数PATHに設定してください。

rtc-serverの上のディレクトリで以下のコマンドを実行するとWEBサーバーが起動します。

> nginx.exe  -p ./

RTCの起動

Google Chrome等のWEBブラウザからhttp://localhost:1080/index.html?command=startにアクセスするとRTCが起動します。

RTSystem作成

まずRTCの起動に成功している場合は、以下のようにネームサービスビューにRTCが表示されます。

openrtmlua760

Open New System Editorボタンを押してシステムダイアグラムを表示してください。

openrtmlua770

ネームサービスビューからシステムダイアグラムにRTCをドラックアンドドロップしてください。

openrtmlua780

TkJoyStick0posのOutPortを、OpenRestySample0inのInPortにドラックアンドドロップしてください。

openrtmlua790

※ステップ実行をしている側のRTC(今回はOpenRestySample0)のconnect関数を呼び出すと接続に失敗します。必ず、今回の場合はTkJoyStick0posを選択してドラックアンドドロップしてください。

これで通信ができるようになります。

All Activateボタンを押すとTkJoyStick0からデータが送信されるためWEBブラウザ上の画像が動くようになります。

openrtmlua800

コネクタ接続、RTCのアクティブ化の自動化

imahe.luamanager:init関数の引数を以下のように変更してください。

manager:init({"-o","logger.enable:NO","-o","exec_cxt.periodic.type:OpenHRPExecutionContext", "-o", "manager.components.preconnect:OpenRestySample0.in?port=rtcname://localhost/TkJoyStick0.pos", "-o", "manager.components.preactivation:OpenRestySample0,rtcname://localhost/TkJoyStick0","-o","corba.step.count:4"})

-oオプションでパラメータの設定ができます。

起動時に接続するポートを指定します。 この場合はOpenRestySample0というRTCのinというデータポートを、TkJoyStick0というRTCのposというポートに接続します。

ただし、TkJoyStick0は別プロセスで起動しているため、rtcname形式による指定が必要になります。 rtcname形式はネームサーバーからRTCを取得する方法です。rtcname://アドレス/RTC名.ポート名で指定します。

起動時にアクティブ化するRTCを指定します。

ORBをステップ実行するときのみ有効なオプションです。 指定回数だけORBをステップ実行します。ORBから処理要求がない場合は、要求があるまで待ちます。 preconnect等で外部のRTCと接続する場合に必要です。

注意事項

今回はInPortのみを使用しましたが、OutPortを使用する場合についてはデータ転送の際に以下のようにoil.main関数で実行する必要があります。 また、サービスポートのプロバイダ側についても同じです。 oil.main関数で実行する必要があるのは、今回のようにORBをステップ実行した時のみです。

oil.main(function()
	self._outOut:write()
end)