ロボットをWebブラウザから色々操作できれば,便利なわけです.
個人的にも,人の入力を待つみたいな非同期イベントは,ロボット制御のループからは離しておきたいので,そういう意味でも非同期入力が得意なWebブラウザにお任せしておくのは良さそうだと思っています.
Webサーバを立ち上げる
なんとびっくりなんですが,ROSのパッケージの中に,簡単なWebサーバを実現するものがありました!roswww.
こいつをインストールすれば,最低限の機能は実現できそうです.
sudo apt-get install ros-indigo-roswww
実際に起動してみましょう.
roslaunch roswww roswww.launch
この状態で, http://localhost:8085/ にアクセスすると,インストール済みパッケージのリストを表示するページが開きます.また, http://localhost:8085/roswww/ にアクセスすると,「roswww, sup?」とだけ書かれたテストページが開きます.
roswwwは, rosインストール先/share/各パッケージ/www/ のフォルダを参照するので,自作のパッケージにも www フォルダを作って, share 下にインストールすれば, http://localhost:8085/自作パッケージ名/ というURLでアクセスできるようになります.
JavaScriptでTopicをPub/Subする
さて,静的なページだけだと,やはりつまらない.Webページ上からTopicを投げる方法がないかros-jpのメーリングリストで質問したら,roslibjsという,javascriptから直接ROS TopicのPub/SubやActionの発行など,ROSの緒機能にアクセスできるパッケージを紹介してもらいました!このパッケージは,rosbridgeで提供されるROSのwebsocketの口を利用するようです.
さっそくインストール.
sudo apt-get install ros-indigo-rosbridge-server
(もしかしたら,roswwwの依存関係で,もう入ってるかも)
んで,roswwwのlaunchフォルダに以下のようなlaunchファイルを書いて,
<launch>
<include file="$(find rosbridge_server)/launch/rosbridge_websocket.launch" />
<include file="$(find roswww)/launch/roswww.launch" />
</launch>
同じくroswwwのwwwフォルダに以下のようなhtmlファイルを入れます.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<style type="text/css">
<!--
*{ padding:0px; margin:0px;}
-->
</style>
<title>Sample Chat</title>
<script src="http://cdn.robotwebtools.org/EventEmitter2/current/eventemitter2.js"></script>
<script src="http://cdn.robotwebtools.org/roslibjs/current/roslib.js"></script> </head>
<body>
<script type="text/javascript">
<!--
if(!Chat){
var Chat = {
ros : null,
name : "",
init : function(){
this.ros = new ROSLIB.Ros();
this.ros.on('error', function(error) {
document.getElementById('state').innerHTML = "Error";
document.getElementById("btn").disabled = true;
});
this.ros.on('connection', function(error) {
document.getElementById('state').innerHTML = "Connect";
document.getElementById("btn").disabled = false;
});
this.ros.on('close', function(error) {
document.getElementById('state').innerHTML = "Close";
document.getElementById("btn").disabled = true;
});
this.ros.connect('ws://localhost:9090');
var sub = new ROSLIB.Topic({
ros : this.ros,
name : '/chat',
messageType : 'std_msgs/String'
});
sub.subscribe(function(message) {
var res = message.data;
var date = res.substring(1, res.indexOf("]"));
res = res.substring(res.indexOf("]")+1, res.length);
var name = res.substring(0, res.indexOf(":"));
res = res.substring(res.indexOf(":")+1, res.length);
var el = document.createElement("p");
el.innerHTML = "[" + date + "] <b>" + name + " :</b> " + res;
//document.getElementById("talk").appendChild(el);
document.getElementById("talk").insertBefore(el, document.getElementById("talk").childNodes[0]);
document.getElementById("btn").disabled = false;
document.getElementById("state").innerHTML = "received";
});
},
send : function(){
if(document.getElementById("comment").value.length == 0) return;
document.getElementById("btn").disabled = true;
document.getElementById("state").innerHTML = "sending";
var now = new Date();
var str_date = (now.getMonth()<10?"0":"") + (now.getMonth()+1) + "/";
str_date += (now.getDate()<10?"0":"") + now.getDate() + "/";
str_date += now.getFullYear() + " ";
str_date += (now.getHours()<10?"0":"") + now.getHours() + ":";
str_date += (now.getMinutes()<10?"0":"") + now.getMinutes() + ":";
str_date += (now.getSeconds()<10?"0":"") + now.getSeconds();
var comment = document.getElementById("comment").value;
var pub = new ROSLIB.Topic({
ros : this.ros,
name : '/chat',
messageType : 'std_msgs/String'
});
var str = new ROSLIB.Message({data : "[" + str_date + "]" + this.name + ":" + comment});
pub.publish(str);
document.getElementById("comment").value = "";
}
}
Chat.init();
window.onload = function(){
Chat.name = window.prompt("What's your name?", "Jane Doe");
document.getElementById("name").innerHTML = Chat.name;
};
window.onunload = function(){
Chat.ros.close();
};
}
//-->
</script>
<p>Connection status: <label id="state">Disconnect</label></p>
<p>Your name: <label id="name"></label></p>
<form action="javascript:Chat.send();" id="ui">
<label>Comment: </label>
<input type="text" id="comment" size="20" />
<input type="submit" value="send" id="btn" /><br/>
</form>
<div id="talk"><p></p></div>
</body>
</html>
それでは,いつものようにインストール.私はros_make_isolatedを愛用してます.ros_makeでも,たぶん同じ.
catkin_make_isolated --install --pkg roswww
そして,以下のコマンドで起動します.
roslaunch roswww chat.launch
ここまでできたら,ブラウザで http://localhost:8085/roswww/chat.html にアクセスしてください.名前の入力を促すダイアログが現れるので,適当に入力してください.
次に,さらにもう1つ別のウィンドウで同じページにアクセスしてください.この状態で,片方のウィンドウからコメントを送ると,rostopicを介して,もう片方のウィンドウにも表示されます!
プロジェクトの全文はGitHubにも置いてあるので,参考にしてくださいー.
以上,WebブラウザをROSのインタフェースにするお話しでしたっ!