Help us understand the problem. What is going on with this article?

ROS講座53 ブラウザでpub subする

More than 1 year has passed since last update.

環境

この記事は以下の環境で動いています。

項目
CPU Core i5-8250U
Ubuntu 16.04
ROS Kinetic

インストールについてはROS講座02 インストールを参照してください。
またこの記事のプログラムはgithubにアップロードされています。ROS講座11 gitリポジトリを参照してください。

概要

rosbridgeはROSの通信とwebsocketを相互変換するROSパッケージです。javascriptでwebsocketの通信を扱えるので、これによってwebページ経由でROSと通信できます。
今回はTalkerとListenerのサンプルを解説します。

インストール

rosbridgeのインストールは以下のコマンドで行えます。

sudo apt-get install ros-kinetic-rosbridge-suite 

ソースコード

launch

前回使ったroswwwに加えて、rosbridgeのlaunchを起動させるだけです。

web_lecture/launch/bridge.launch
<launch>
  <include file="$(find roswww)/launch/roswww.launch" />
  <include file="$(find rosbridge_server)/launch/rosbridge_websocket.launch" />
</launch>

talker

publishを行うwebページ(javascript)の例です。

web_lecture/www/pub.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>ROS WEB Publisher</title>
    <script src="https://static.robotwebtools.org/EventEmitter2/current/eventemitter2.min.js"></script>
    <script src="https://static.robotwebtools.org/roslibjs/current/roslib.min.js"></script>
  </head>

  <body>
    <script type="text/javascript">

        <!--
if(!Talker){
    var Talker = {
        ros : null,
        name : "",
        init : function(){
            this.ros = new ROSLIB.Ros();
            this.ros.on('error', function(error) {
                document.getElementById('state').innerHTML = "Error";
            });
            this.ros.on('connection', function(error) {
                document.getElementById('state').innerHTML = "Connect";
            });
            this.ros.on('close', function(error) {
                document.getElementById('state').innerHTML = "Close";
            });
            this.ros.connect('ws://' + location.hostname + ':9090');
        },
        send : function(){
            if(document.getElementById("comment").value.length == 0) return;
            var comment = document.getElementById("comment").value;
            var pub = new ROSLIB.Topic({
                ros : this.ros,
                name : '/chatter',
                messageType : 'std_msgs/String'
            });

            var str = new ROSLIB.Message({data : comment});
            pub.publish(str);
        }
    }
    Talker.init();

    window.onload = function(){
    };
    window.onunload = function(){
        Talker.ros.close();
    };
}
        //-->
    </script>
    <p>status: <label id="state">Disconnect</label></p>

    <form action="javascript:Talker.send();" id="ui">
      <label>Comment: </label>
      <input type="text" id="comment" size="20" />
      <input type="submit" value="send" id="btn" /><br/>
    </form>
  </body>
</html>

詳しく解説していきます。
以下のような部分でTalkerの宣言を行っています。

Talkerの宣言
var Talker = {
...
}

以下の部分で初期化動作の宣言をしています。function以下の最初の行ではROSLIBを設定しています。その下の9行はrosbridgeのコネクションの状態が変わった時の処理です。下から2行目のthis.ros.connect('ws://' + location.hostname + ':9090');ではwebsocket通信を開始します。rosbridgeは標準では9090ポートで通信を行います。

Talkerの初期化の宣言
init : function(){
  this.ros = new ROSLIB.Ros();
  this.ros.on('error', function(error) {
    document.getElementById('state').innerHTML = "Error";
  });
  this.ros.on('connection', function(error) {
    document.getElementById('state').innerHTML = "Connect";
  });
  this.ros.on('close', function(error) {
    document.getElementById('state').innerHTML = "Close";
  });
  this.ros.connect('ws://' + location.hostname + ':9090');
}

以下がpublisherのコードです。今回のスクリプトでは「send」ボタンを押すと毎回publisherを生成してpublishします。
1行目は送る文字列(id:commentのテキストボックスから持ってくる)が0文字なら飛ばす処理です。
4~8行目がpublisherの生成です。トピック名とメッセージTypeを記述します。
var str = new ROSLIB.Message({data : comment});でメッセージを作っています。括弧の中でフィールド名を持つ構造体として生成します。

publishのコード
send : function(){
  if(document.getElementById("comment").value.length == 0) return;
  var comment = document.getElementById("comment").value;
  var pub = new ROSLIB.Topic({
    ros : this.ros,
    name : '/chatter',
    messageType : 'std_msgs/String'
  });

  var str = new ROSLIB.Message({data : comment});
  pub.publish(str);
}

listener

web_lecture/www/sub.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>ROS WEB Subscriber</title>
        <script src="https://static.robotwebtools.org/EventEmitter2/current/eventemitter2.min.js"></script>
        <script src="https://static.robotwebtools.org/roslibjs/current/roslib.min.js"></script>
      </head>
    <body>
    <script type="text/javascript">
    <!--
if(!Listener){
    var Listener = {
        ros : null,
        name : "",
        init : function(){
            this.ros = new ROSLIB.Ros();
            this.ros.on('error', function(error) {
                document.getElementById('state').innerHTML = "Error";
            });
            this.ros.on('connection', function(error) {
                document.getElementById('state').innerHTML = "Connect";
            });
            this.ros.on('close', function(error) {
                document.getElementById('state').innerHTML = "Close";
            });
            this.ros.connect('ws://' + location.hostname + ':9090');

            var sub = new ROSLIB.Topic({
                ros : this.ros,
                name : '/chatter',
                messageType : 'std_msgs/String'
            });
            sub.subscribe(function(message) {
                var res = message.data;
                var el = document.createElement("p");
                el.innerHTML = res
                document.getElementById("talk").appendChild(el);
            });
        }
    }
    Listener.init();

    window.onload = function(){
    };
    window.onunload = function(){
        Listener.ros.close();
    };
}
        //-->
    </script>
    <p>status: <label id="state">Disconnect</label></p>
    <div id="talk"><p></p></div>
  </body>
</html>

以下の部分でSubscriberを設定します。publisherと同じようにTopic名とメッセージTypeを宣言します。その下で、callback関数の設定をします。今回のスクリプトではやってきた文字列を<p>要素(id:talk)に追記していきます。

Subscriberの設定
var sub = new ROSLIB.Topic({
  ros : this.ros,
  name : '/chatter',
  messageType : 'std_msgs/String'
});
sub.subscribe(function(message) {
  var res = message.data;
  var el = document.createElement("p");
  el.innerHTML = res
  document.getElementById("talk").appendChild(el);
});

実行

launchを実行します。

roslaunch web_lecture bridge.launch

この後にブラウザを2つ開いてlocalhost:8085/web_lecture/pub.htmllocalhost:8085/web_lecture/sub.htmlのページにアクセスします。以下のようにpub.htmlのページでテキストボックスに文字を入れて「send」を押すと、sub.htmのページに表示されます。

web_pubsub.gif

参考

ROSのWebインタフェースを作る

目次ページへのリンク

ROS講座の目次へのリンク

srs
ロボットを日々こつこつと製作しています。ロボットやROSやC++、pythonに関心があります。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away