Web連携機能の作成
eSEATでは、外部のソフトウェアとの連携のためにRTCのデータポート、サービスポート、ROSのPublisher/Subscriber、Service、actionの他にWebサーバーの機能が実装されています。
Webサーバーの基本機能はドキュメントの配信なのですが、WebクライアントであるWebブラウザとの連携としてWebSocketやCometという技術を用いることで非同期の双方向通信を行うことができます。
eSEATでは、この中でもCometによる非同期通信機能をサポートしています。
Webアダプタの設定
SEATMLにおけるWebアダプタは、type="web" で設定を行います。また、Webアダプタには、下記のような制限がります。
- 1つのSEATMLには1つのWebアダプタしか定義できません
- Webアダプタは、eSEATが起動するとすぐに有効になり、RTCとして動作する場合にも停止させることができません。
SEATML内でのWebアダプタの設定は下のように記述します。
<adaptor name="web" type="web" port="8080" dir="/usr/local/eSEAT/html" host="localhost" />
ここで、host属性は、接続を許すクライアントのホスト名またはIPアドレスになります。','区切りで複数のマシンを指定することができます。(ホワイトリストのアクセス制限)host属性が記載されていない場合には、どのクライアントからもアクセスすることができます。
また、port属性は、Webアクセスのためのポート番号ですので、eSEATのマシンの中で一意でなければいけませんのでご注意ください。(通常、HTTPサーバは、80番ですがapache等が利用している場合が多いですので、8080を使っています)
eSEATのWebアダプタは、通常のWebサーバと少し異なる動作をします。
通常、htt://localhost:8080/ でアクセスする場合、デフォルトのドキュメントがindex.html等になりますが、eSEATでは、''コンポーネント名(<general>要素のname属性値)+".html"''となりますのでご留意下さい。
Cometによる非同期通信
eSEATでは、WebブラウザとWebアダプタとの双方向通信のためにCometを使用しています。Cometは、AjaxとLong pollingを使って実現した非同期通信機構であり、通常のHTTPの仕様の範囲で動作します。eSEATのCometは、Webアダプタの機能とコンテンツのJavascriptの関数との連携で実現していますので、Comet通信あ必要な場合には、コンテンツに予め決めたJavascriptを設定する必要があります。
Cometに必要なライブラリ
eSEATでWebブラウザとCometによる非同期通信を行うには、jquery, jquery-midrateとcometのライブラリが必要です。したがって、コンテンツに、
<script src="jquery-1.11.3.min.js"></script>
<script src="jquery-migrate-1.2.1.min.js"></script>
<script type="text/javascript" src="comet.js"></script>
を記載する必要があります。(各ライブラリは、/usr/local/eSEAT/html にインストールされています)
comet.jsでは、主に下記の関数が定義されており、eSEATとの通信に利用します。
- requestComet(id, force)
- Webアダプタに識別子 id の Long pollingをセットします。
- sendComet(id, data, func)
- Webアダプタの識別子 idのLaong pollingにメッセージを送信し、成功すれば funcを実行します。
- sendValueToRtc(val, func)
- Webアダプタに val を送信します。eSEAT内では、このデータを引数にしてonDataメソッドの呼び出しを行います。成功すれば funcを実行します。
- sendMessageToRtc(msg, func)
- Webアダプタに msgを送信します。eSEAT内では、このデータを引数にして、processResultメソッドの呼び出しを行います。成功すれば funcを実行します。
- sendScriptToRtc(scr, func)
- Webアダプタに srcを送信します。srcはPythonスクリプトであり、eSEAT内ではexec関数で実行されます。ただし、Webアダプタのhostで設定されたクライアントからのみ有効です。成功すれば funcを実行します。
Webアダプタ内部での処理
WebアダプタがWebブラウザから comit.jsのリクエストがあった場合に、My_eSEAT_Keyを新規に生成したuuidに置き換えます。これによって、ブラウザ上のcomit.jsがeSEATからダウンロードされたかどうかを認識して、連携機能が使えるようになります。
また、COMITの各リクエストは、POSTリクエストに限定されており、URLによっては下のような処理を行っています。
- /request_comet
- ''requestComet関数''からの呼出しで実行され、CometReader.cometRequestを実行します。内部では、CometManagerのlong_pollingsスロットに送信されたidを登録します。
- /comet_event
- ''sendCometWeb関数''からの呼出しで実行され、CometReader.cometTriggerを実行します。CometReader.cometTriggerは、内部では CometManager.callHandlerを呼び出しています。デフォルトでは、meggesとして"Push message"とdate実行した時刻を返します。
- /rtc_onData
- ''sendValueToRtcWeb関数''からの呼出しで実行され、eSEAT.onDataを呼び出します。実行されれば、resultに'OK'を代入し、dateに実行完了の時刻を返します。
- /rtc_processResult
- ''sendMessageToRtc関数''からの呼出しで実行され、eSEAT.ptocessResultを呼び出します。実行されれば、resultに'OK'を代入し、dateに実行完了の時刻を返します。
- /evalCommand
- ''sendScriptToRtcWeb関数''からの呼出しで実行され、WebアダプタのWhiteListに登録している計算機からのリクエストかどうかをチェックし、exec関数で送信されてきたPythonスクリプトを実行します。実行終了後、resultに'OK'を代入し、dateに実行完了の時刻を返します。
Webアダプタを使った例
次に、Webアダプタを使った例について説明します。Webアダプタは、eSEATのGUIとして機能されるとともに、Webブラウザで(JavaScript経由で)取得可能なクライアントの情報を送信する機能があります。特に、スマートフォンではJavaScriptの関数からジャイロ等の内部のセンサにアクセスできるものもあり、通常、ROSやOpenRTM-aistが動作していない計算機をROSやOpenRTM-aistで構築したシステムに取り入れることが可能になります。
SimpleIO
OpenRTM-aistのサンプルにもありますが、Webブラウザから単純な数値入力を行い、eSEATに接続されたRTCに出力または、RTCからの入力データをWebブラウザに表示させるようなSEATMLとWebドキュメントを実装していきます。ここで実装するSEATMLファイルは、OpenRTM-aistのサンプルにあるConsoleInとConsoleOutに接続できるようにします。
SEATML(SimpleIO)の作成
まずは、SEATMLのひな形を生成します。
# source /usr/local/eSEAT/setup.bash
# gen_seatml SimpleIO_web
次にadaptorを設定します。今回は、RTCの入出力用のデータポート(TimedLong型)とWebアダプタです。
<adaptor name="in" type="rtcin" datatype="TimedLong" />
<adaptor name="out" type="rtcout" datatype="TimedLong" />
<adaptor name="web" type="web" port="8080" dir="/usr/local/eSEAT/html" />
次に、データ変換用のrule要素を作成します。
<rule source="in">
<script sendto="web">
seat.set_result(rtc_in_data.data)
</script>
</rule>
<rule source="web">
<script sendto="out">
seat.set_result(web_in_data)
</script>
</rule>
このコードでは、最初のrule要素では、RTCの入力ポート"in"からのデータをWebアダプタ"web"に送信し、2番目のrule要素では、Webアダプタ"web"からの入力をRTCの出力ポート"out"に送信しています。このコードは、ROSでのデータ変換と基本は同じです。
ここで注意しなければいけないのは、Webアダプタからのデータは、''web_in_data''に格納されるように実装しています。
Webドキュメント(SimpleIO)の作成
次に、SimpleIO_webと連携するWebページを作成していきます。上のSEATMLファイルでは、Webアダプタにdir属性値のディレクトリがドキュメントルートになります。そのため、SimpleIO_web.htmlを作成して /usr/local/eSEAT/html/SimpleIO_web.htmlにコピーしなければいけません。
では、SimpleIO_web.htmlを作成します。eSEATとcometで通信を行うために、下記のようなひな形を作成します。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SimpleIO_web</title>
<!-- comet通信用のライブラリの読込 -->
<script type="text/javascript" src="jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="jquery-migrate-1.2.1.min.js"></script>
<script type="text/javascript" src="comet.js"></script>
</head>
<body>
<!-- comet通信の応答を表示用のブロック -->
<div id="response"></div>
</body>
</html>
上記で<div id="response">は、Cometの処理メッセージの出力用のブロックです。
次に、ユーザインターフェースを作成します。ConsoleOutに送信するためのINPUTとConsoInからの入力を表示するTEXTAREAを下のように配置します。
このページのソースコードは、下のように書くことができます。
…
<body>
<h3>Test of WebAdaptor with SimpleIO component</h3>
<hr>
<!-- comet通信の操作UIフォーム -->
<form name="myform">
<table>
<!-- comet通信のメッセージ送信フォーム -->
<tr><td>Send: </td>
<td><input type="text" name="msg" size="40" value="" ></td>
<td><input type="button" value="Send" ></td></tr>
<!-- comet通信のメッセージ受信フォーム -->
<tr><td>Outcome: </td>
<td><textarea name="fromSeat" cols="50" rows="10"></textarea></td>
<td></td></tr>
</table>
</form>
<h3>RESPONSE</h3>
<hr>
<!-- comet通信の応答を表示用のブロック -->
<div id="response"></div>
</body>
</html>
最後に、Cometの登録とSendボタンを押下した際の実行関数を追加すると下記のようになります。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SimpleIO_web</title>
<!-- comet通信用のライブラリの読込 -->
<script type="text/javascript" src="jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="jquery-migrate-1.2.1.min.js"></script>
<script type="text/javascript" src="comet.js"></script>
<!-- SimpleIOの動作用の関数定義 -->
<script type="text/javascript">
/* ID=1 で long polling の登録をリクエスト */
function registerHandler(){ requestComet(1); }
/* name='msg'の INPUT の値を eSEATに送信する */
function sendEventToRtc(){ sendValueToRtc(s("input[name='msg']").val()); }
/* sendValueToRtc関数の返値の処理(デフォルトでは、processEvents関数をコールバックに設定されているため) */
function processEvents(event){
$('textarea[name="fromSeat"]').val($('textarea[name="fromSeat"]') + event.message+"\n");
}
</script>
</head>
<!-- ドキュメントのロード時に Long Polling を登録 -->
<body onLoad="registerHandler();">
<h3>Test of WebAdaptor with SimpleIO component</h3>
<hr>
<form name="myform">
<table>
<!-- comet通信のメッセージ送信フォーム -->
<tr><td>Send: </td>
<td><input type="text" name="msg" size="40" value="" ></td>
<td><input type="button" value="Send" onClick="sendEventToRtc();" ></td></tr>
<!-- comet通信のメッセージ受信フォーム -->
<tr><td>Outcome: </td>
<td><textarea name="fromSeat" cols="50" rows="10"></textarea></td>
<td></td></tr>
</table>
</form>
<h3>RESPONSE</h3>
<hr>
<!-- comet通信の応答を表示用のブロック -->
<div id="response"></div>
</body>
</html>
以上でSimpleIO_web.htmlの実装は終了です。このファイルをドキュメントルートである/usr/local/eSEAT/htmlにコピーしてください。
動作確認(SimpleIO)
最後に動作確認をします。動作確認には、ConsoleIn.py, ConsoleOut.py, eSEAT及び操作用の4つのターミナルとWebブラウザが必要になります。
- ターミナル1(ConsoleIn)
# python /usr/local/share/openrtm-1.1/example/python/ConsoleIn.py
- ターミナル2(ConsoleOut)
# python /usr/local/share/openrtm-1.1/example/python/ConsoleOut.py
- ターミナル3(eSEAT)
# eSEAT SimpleIO_web.seatml
- ターミナル4(操作パネル)
# rtcon /localhost/SimpleIO_web.rtc:out /localhost/ConroleOut0.rtc:in
# rtcon /localhost/ConsoleIn0.rtc:out /localhost/SimpleIO_web.rtc:in
# rtact /localhost/ConsoleOut0.rtc /localhost/ConroleIn0.rtc /localhost/SimpleIO_web.rtc
最後に、Webブラウザを起動し、''http://localhost:8080/'' にアクセスしてください。WebブラウザにSimpleIO_webの表示がでれば、ConsoleInから整数の入力またはWebブラウザの一行入力に整数を入力し、Sendボタンを押下し、データが送受信されていることを確認してください。
Virtual Joystick
Webブラウザ上で動作する仮想ジョイスティックの出力をeSEATのRTCのデータポートに出力するSEATMLとWebドキュメントを実装します。
ここで使用する仮想ジョイスティック(VirtualJoystick)は、Javascriptで実装されたもので、スマートフォン等で簡単に操作することができます。
ここで使用する仮想ジョイスティック(VirtualJoystick)は、Javascriptで実装されたもので、スマートフォン等で簡単に操作することができます。
ここでは、RTMとROSとの連携で使ったTkMobileSimulatorを操作するためのJoystickを実装したいと思います。実装するSEATMLファイルをJoystickWeb.seatmlとします。
SEATMLの作成(JoystickWeb)
まずは、SEATMLのひな形を生成します。
# source /usr/local/eSEAT/setup.bash
# gen_seatml JoystickWeb
次にadaptorを設定します。今回は、TkMobileSimulatorへの出力用のデータポート(TimedFloatSeq型)とWebアダプタです。
<adaptor name="vel" type="rtcout" datatype="TimedFloatSeq" />
<adaptor name="web" type="web" port="8080" dir="/usr/local/eSEAT/html" />
次に、Webアダプタからの入力に対する処理を追記します。1つは、Webアダプタの入力としてvirtualJoystickの位置を処理する部分です。そして、eSEATのアクティベートとディアクティベートもWebのボタンで出来きるようにしたいと思います。
VirtualJoystckからの位置データの処理を<rule>要素で書くと下のようになります。
<rule source="web">
<script>
print("From web:", web_in_data)
</script>
<script sendto="vel">
data = web_in_data.split(',')
if len(data) == 3:
vr = max(min(float(data[1].strip())/100,1), -1)
vl = max(min(float(data[2].strip())/100,1), -1)
seat.set_result(TimedFloatSeq(Time(0,0), [-vl, -vr]))
</script>
</rule>
次に、Webドキュメント上のボタンに対する処理を書きます。ここでは、メッセージでボタンの文字列が来ることを想定すると下のようになります。
<rule>
<key>activate</key>
<script>seat.activate()</script>
</rule>
<rule>
<key>deactivate</key>
<script>seat.deactivate()</script>
</rule>
以上で、SEATMLは完成です。
Webドキュメント(JoystickWeb)の作成
次に、JoystickWebと連携するWebページを作成していきます。作成したJoystickWeb.htmlは、 /usr/local/eSEAT/html/ にコピーする必要があります。
では、JoystickWeb.htmlを作成します。eSEATとcometで通信を行うために、下記のようなひな形を作成します。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SimpleIO_web</title>
<!-- comet通信用のライブラリの読込 -->
<script type="text/javascript" src="jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="jquery-migrate-1.2.1.min.js"></script>
<script type="text/javascript" src="comet.js"></script>
</head>
<body>
<!-- comet通信の応答の表示用ブロック -->
<div id="response"></div>
</body>
</html>
次に、ユーザインターフェースを作成します。下のようにeSEATのアクティベート、ディアクティベートのボタンとvirtualjoystickを配置します。
virtualjoystickを配置するには、JavaScriptの配置(id="contents"のdiv要素)とボタン等の配置をすると、Webドキュメントのデザイン部分は下のようになります。
<!-- virtualjoystickのライブラリを読み込む -->
<script src="virtualjoystick.js"></script>
....
<!--タイトルの表示 -->
<div id="topbar">
<table><tr>
<td> <img src="rtm_logo.png" /> </td> <td><span id="title">Test for VirtualJoystick</span></td>
</tr></table>
</div>
<!-- eSEATの状態変更のためのボタンを配置 -->
<div id="cmd">
<button>Activate</button>
<button>Deactivate</button>
</div>
<!-- virtualjoystickの操作結果の表示用のブロック -->
<div id="result"></div>
<!-- virtualjoystickの表示用のブロック -->
<div id="container" style="width:600px;height:600px;background-color:#aaaaaa"></div>
<hr>
<!-- comet通信の応答の表示用ブロック -->
<div id="response"></div>
最後にこのドキュメントに、ボタンの押下時とジョイスティックの操作時のスクリプトを挿入すると下のようになります。
<!-- ドキュメントのロード時に、”joystick”というIDでLong pollingをeSEATにセットする -->
<body onLoad="requestComet('joystick');">
<!--タイトルの表示 -->
<div id="topbar">
<table><tr> <td> <img src="rtm_logo.png" /> </td>
<td><span id="title">Test for VirtualJoystick</span></td> </tr></table>
</div>
<!-- eSEATの状態変更のためのボタンを配置 -->
<div id="cmd">
<button onClick="sendMessageToRtc('activate');" >Activate</button>
<button onClick="sendMessageToRtc('deactivate');" >Deactivate</button>
</div>
<!-- virtualjoystickの操作結果の表示用のブロック -->
<div id="result"></div>
<!-- virtualjoystickの表示用のブロック -->
<div id="container" style="width:600px;height:600px;background-color:#aaaaaa"></div>
<hr>
<div id="response"></div>
<!-- comet通信の応答の表示用ブロック -->
<script>
/* VirtualJoystickの生成と配置 */
var joystick = new VirtualJoystick({
container : document.getElementById('container'), mouseSupport : true,
});
var status = 0;
/* タッチ操作のイベントリスナの登録 */
joystick.addEventListener('touchEnd', function(){ sendValueToRtc('Stop, 0, 0'); } )
/* 周期実行の登録 (周期=100ms) */
setInterval(function(){
/* virtualJoystickの操作状況を 'result'のIDを持つ要素に追記 */
var outputEl = document.getElementById('result');
outputEl.innerHTML = '<b>Result:</b> ' + ' dx:'+joystick.deltaX() + ' dy:'+joystick.deltaY()
+ (joystick.right() ? ' right' : '')
+ (joystick.up() ? ' up' : '')
+ (joystick.left() ? ' left' : '')
+ (joystick.down() ? ' down' : '');
if(joystick._pressed){
/* virtualjoystickを押下されているときの処理(MoveコマンドをeSEATに送信し、status=1 にする) */
sendValueToRtc('Move,'+joystick.deltaY() + ',' + joystick.deltaX());
status = 1;
}else if(status == 1){
/* virtualjoystickの操作終了時の処理 */
sendValueToRtc('Stop, 0, 0');
status = 0;
}
}, 100);
</script>
このコードでは、各ボタンの押下に対しては、sendMessageToRtc関数でeSEATにメッセージを送信しています。また、body要素には、ドキュメントをロードした時にrequestComet関数でLongPollingをセットしています。末尾のscript要素では、VirtualJoystickの生成とsetIntval関数で周期的な情報送信を行っています。
動作確認(JoystickWeb)
最後に、VirtualJoystickの動作確認をします。この動作確認には、TkMobileSimulatorとeSEATおよび操作用の3つのターミナルを使います。また、VirtualJoystickの操作のためにWebブラウザを使います。
- ターミナル1(TkMobileSimulator)
# cd /usr/local/share/openrtm-1.1/example/python/MobileRobotCanvas
# python TkMobileRobotSimulator.py
- ターミナル2(eSEAT)
# source /opt/ros/kinetic/setup.bash
# cd ~/work
# eSEAT JoystickWeb.seatml
- ターミナル3(操作パネル)
# rtcon /localhost/JoystickWeb.rtc:vel /localhost/TkMobileRobotSimulator0.rtc:vel
# rtcact /localhost/JoystickWeb.rtc /localhost/TkMobileRobotSimulator0.rtc
最後にWebブラウザで http://localhost:8080/ にアクセスしてWebコンテンツを表示し、操作して下さい。TkMobileSimulatorのロボットが動けば動作完了です。
VirtualJoystickの操作は、iPhoneのSafariでも利用可能ですので、動作確認をしてみて下さい。
スマートフォンの内部センサの利用
iPhone等のスマートフォンでは、簡単なJavaScriptで実装したWebアプリから、本体に内蔵されている各種センサへのアクセスが可能です。この機能を利用し、iPhoneのジャイロセンサの値、GPSの値をRTCのデータポートから出力するSEATMLとWebドキュメントを実装していきます。
ここでも、RTMとROSとの連携で使ったTkMobileSimulatorをiPhoneの傾きで操作するための機能を実装したいと思います。
実装するSEATMLファイルをSensors.seatmlとします。
SEATML(Sensors)の作成
まずは、SEATMLのひな形を生成します。
# source /usr/local/eSEAT/setup.bash
# gen_seatml Sensors
次にadaptorを設定します。今回は、TkMobileSimulatorへの出力用のデータポート(TimedFloatSeq型)とWebアダプタです。
<adaptor name="vel" type="rtcout" datatype="TimedFloatSeq" />
<adaptor name="web" type="web" port="8080" dir="/usr/local/eSEAT/html" />
今回は、eSEAT側にRTCの状態操作とWebブラウザから送信されたデータを出力するTEXTAREA等のGUIも設定して下のようなパネルを生成してみたいと思います。
まずは、GUIの配置は、下のように書くことができます。
<state name="main_mode">
<label text="Sensors" colspan="3" bg_color="blue" />
<brk />
<button label="Exit"></button>
<button label="Activate"></button>
<button label="Deactivate"></button>
<brk />
<label text="Info:" />
<textarea id="textOut" width="50" height="5" colspan="2" ></textarea>
<brk />
<button label="Clear"></button>
</state>
次に、GUIの各操作に対しての処理を設定すると下のように書くことができます。
<state name="main_mode">
<label text="Sensors" colspan="3" bg_color="blue" />
<brk />
<button label="Exit"><script> seat.exit() </script></button>
<button label="Activate"><script> seat.activate() </script></button>
<button label="Deactivate"><scritp> seat.deactivate() </script></button>
<brk />
<label text="Info:" />
<textarea id="textOut" width="50" height="5" colspan="2" ></textarea>
<brk />
<button label="Clear"><script> seat.clearText("main_mode:textOut") </script></button>
</state>
最後にWebアダプタからのデータ受信時の処理なのですが、今回は、ロボット操作を継続的に行うように周期処理を付け加えたいと思います。周期実行処理を<general>要素に記述して、Webアダプタからの応答処理を<rule>要素で記述すると下のように書くことができます。
<general name="Sensors">
...
<script>
global vl, vr
vl=0
vr=0
</script>
<onexec>
<script sendto="vel">
seat.set_result(TimedFloatSeq(Time(0,0), [vl, vr]))
</script>
</onexec>
</general>
<state name="main_mode">
...
<rule source="web">
<script>
seat.appendText(web_in_data)
vl=float(web_in_data["X"])
vr=float(web_in_data["Y"])
</script>
</rule>
</state>
このSEATMLでは、RTCの実行周期で大域変数vl, vrの値を出力データポートからデータ送信を行い、Webアダプタから受信したデータ{'X': 0, 'Y':0, 'Z':0 }のようにJson形式のデータであることを前提にして、その値をvl, vrにセットするようにしています。
Webドキュメント(Sensors)の作成
次に、Sensorsと連携するWebページを作成していきます。作成したSensors.htmlは、 /usr/local/eSEAT/html/ にコピーする必要があります。
まず最初に、作成するWebドキュメントは、Javascriptからスマートフォン内のセンサにアクセスして、その情報を表示するようにJavascriptを実装していきます。ページのデザインは、下のようにしておきます。
このようなページを作成すると下のように書くことができます。
!DOCTYPE html>
html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>TEST: WebAdaptor for Sensors</title>
<link rel="stylesheet" href="style.css" type="text/css">
<!-- Comet通信用のライブラリの読込 -->
<script src="jquery-1.11.3.min.js"></script>
<script src="jquery-migrate-1.2.1.min.js"></script>
<script src="comet.js"></script>
<!-- スマートフォンの内のセンサを読み取り、フォームに表示する -->
<script>
// Direction
function findNorth(evt) {
if (evt.alpha < 5 || evt.alpha > 355) {
$("#directions").html("North!");
} else if (evt.alpha < 180) {
$("#directions").html("Turn Left");
} else {
$("#directions").html("Turn Right");
}
}
// GPS
function getLocation(position){
var lat = position.coords.latitude;
var lng = position.coords.longitude;
var alt = position.coords.altiude;
var acc = position.coords.accuracy;
var alc = position.coords.altiudeAccuracy;
var hed = position.coords.heading;
var spe = position.coords.speed;
var html ="";
html += "緯度:" + lat + "<br>";
html += "経度:" + lng + "<br>";
html += "高度:" + alt + "<br>";
html += "緯度経度誤差:" + acc + "<br>";
html += "高度誤差:" + alc + "<br>";
html += "方角:" + hed + "<br>";
html += "速度:" + spe + "<br>";
$("#geolocation").html( html );
}
//
window.addEventListener("deviceorientation", function(evt){
// Compass
var ch = evt.webkitCompassHeading;
var chAcc = evt.webkitCompassAccuracy;
$("#compass_heading").val(ch);
$("#compass_accuracy").val(chAcc);
// Gyro Sensor
var alpha = evt.alpha; // z-axis
var beta = evt.beta; // x-axis
var gamma = evt.gamma; // y-axis
$("#gyro_Z").val(alpha);
$("#gyro_X").val(beta);
$("#gyro_Y").val(gamma);
}, false);
//Accel sensor
window.addEventListener("devicemotion", function(evt){
//Accle
var x = evt.acceleration.x;
var y = evt.acceleration.y;
var z = evt.acceleration.z;
$("#accl_X").val(x);
$("#accl_Y").val(y);
$("#accl_Z").val(z);
//Rot
var xg = evt.accelerationIncludingGravity.x; // right/left
var yg = evt.accelerationIncludingGravity.y; // up/down
var zg = evt.accelerationIncludingGravity.z; // fornt/back
$("#rot_X").val(xg);
$("#rot_Y").val(yg);
$("#rot_Z").val(zg);
// Rotation Value
var a = evt.rotationRate.alpha;
var b = evt.rotationRate.beta;
var g = evt.rotationRate.gamma;
$("#rot_alpha").val(a);
$("#rot_beta").val(b);
$("#rot_gamma").val(g);
} , true);
</script>
</head>
<body>
<!-- タイトルの表示 -->
<div id="topbar">
<table><tr> <td> <img src="rtm_logo.png" /></td><td><span id="title">Test for Sensors on portable devices</span></td> </tr></table>
</div>
<hr>
<!-- GPSで現在のロケーションを取得用のボタン -->
GeoLocation: <button onClick="navigator.geolocation.getCurrentPosition(getLocation);">GetLoc</button>
<!-- GPSで現在のロケーション表示用ブロック -->
<div id="geolocation"></div>
<hr>
<!-- 各種センサの表示用のフォーム -->
Compass:
<div id="compass"></div>
<form>
Heading: <input id="compass_heading" type="text" value=""><br>
Accuracy: <input id="compass_accuracy" type="text" value="">
</form>
<hr>
Gyroscope:
<div id="gyroscope"></div>
<form>
Z-Axis: <input id="gyro_Z" type="text" value=""><br>
X-Axis: <input id="gyro_X" type="text" value=""><br>
Y-Axis: <input id="gyro_Y" type="text" value=""><br>
</form>
<hr>
Rotation:
<div id="rotation"></div>
Acceleration:<br>
X-Axis: <input id="accl_X" type="text" value=""><br>
Y-Axis: <input id="accl_Y" type="text" value=""><br>
Z-Axis: <input id="accl_Z" type="text" value=""><br>
<br>
Rotation:<br>
Right/Left: <input id="rot_X" type="text" value=""><br>
Up/Down : <input id="rot_Y" type="text" value=""><br>
Front/Back: <input id="rot_Z" type="text" value=""><br>
<br>
RotationValue:<br>
alpha(z): <input id="rot_alpha" type="text" value=""><br>
beta(x) : <input id="rot_beta" type="text" value=""><br>
gamma(y): <input id="rot_gamma" type="text" value=""><br>
<hr>
<!-- Comet通信の応答表示用ブロック -->
<div id="response"></div>
</body>
/html>
この時点でこのページでセンサーの値が取得できるかどうか確認してください。
最後に、Comet通信のためのLongPolligの設定と周期的にRotationのデータをWebアダプタに送信するコードを追加します。
...
<head>
...
<script>
setInterval(function(){
var val= {"X": $("#rot_X").val(), "Y": $("#rot_Y").val(), "Z": $("#rot_Z").val()};
sendValueToRtc(val, function(data){ $("#response").html(data.result + " on "+data.date); });
}, 100);
</script>
<head>
<body onLoad="requestComet('sensors');">
...
以上でWebドキュメントの作成は終了です。/usr/local/eSEAT/html にコピーすれば設定は完了です。
動作確認(Sensors)
最後に、動作確認を行います。この動作確認には、TkMobileSimulatorとeSEATおよび操作用の3つのターミナルを使います。また、スマートフォン(iPhone)とWebブラウザを使います。
- ターミナル1(TkMobileSimulator)
# cd /usr/local/share/openrtm-1.1/example/python/MobileRobotCanvas
# python TkMobileRobotSimulator.py
- ターミナル2(eSEAT)
# source /opt/ros/kinetic/setup.bash
# cd ~/work
# eSEAT Sensors.seatml
- ターミナル3(操作パネル)
# rtcon /localhost/Sensors.rtc:vel /localhost/TkMobileRobotSimulator0.rtc:vel
# rtcact /localhost/Sensors.rtc /localhostTkMobileRobotSimulator0.rtc
最後にスマートフォンのWebブラウザで http://<eSEATが動作するホスト名>:8080/ にアクセスしてWebコンテンツを表示し、操作して下さい。TkMobileSimulatorのロボットが動けば動作完了です。