roslibjsとrosridgeによるROS TopicのPub/Sub通信

はじめに

ROSのTopicをJavaScriptでブラウザ上で操作することで、様々なUIを作成できるようになります。

今回は、roslibjsとrosbridgeによるTopicのPub/Sub通信についてまとめます。

実行環境

CPUCore i7-10875H
Ubuntu18.04.5
ROSMelodic

rosbridgeの起動

roswwwのパッケージのインストール方法については、以前の投稿にまとめています。

rosbridgeの起動方法は、下記のlaunchをターミナルで立ち上げれば良いです。

roslaunch roswww start_bridge.launch

これで、roswww/www内のHTMLファイルにアクセス出来ます。

ROSのPub/Sub通信

ROSのPub/Sub通信の概要と方法については、Python編C++編でそれぞれまとめています。

同様のROS Topicの受け渡しを、rosbridgeを使ってブラウザから行います。

Pub/Sub通信の記述

HTMLの記述

HTMLファイルは下記のように記述します。

8行目の記述により、robotwebtoolsのroslibjsを読み込みます。

HTMLファイルに直接、ROS TopicのPub/Subを記述しても良いですが、今回はscript.jsというファイルに記述します。

HTMLとして必要なコンテンツはbodyタグの中に記述します。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Robot Controller</title>
    <script src="https://static.robotwebtools.org/roslibjs/current/roslib.min.js"></script>
    <script src="script.js"></script>
  </head>

  <body>
    <div id="pose_x_indicator">0.0</div>
    <div id="pose_y_indicator">0.0</div>
  </body>
</html>

Publisherの記述

Webページを読み込んで、定期的にTopicをPublishしたい場合には、下記のように記述を行います。

// ros connection
var ros = new ROSLIB.Ros({
  url: 'ws://192.168.100.22:9090/'
});

// definition of a topic publisher
topic_publisher = new ROSLIB.Topic({
  ros: ros,
  name: "/topic_test",
  messageType: 'std_msgs/Int16MultiArray'
});

// initialize valiables
var value_a = 99;
var value_b = 0;

// function of publish topic
function ros_topic_pub(value_a, value_b) {
  var ros_topic = new ROSLIB.Message({
    data: [value_a, value_b]
  });  
  topic_puslisher.publish(ros_topic);
}

// set interval
function rostopic_publish_loop() {
  setInterval("ros_topic_pub(value_a, value_b)", 100);
}

window.onload = function () {
  rostopic_publish_loop();
}

以下に、ひとつずつ解説を記述します。

IPアドレスの設定

roscoreを起動しているPCと同じWifiに繋がっているタブレットやスマホからTopicを操作したい場合、roscoreの起動端末のIPアドレスを調べて下記に記載しておく必要があります。

// ros connection
var ros = new ROSLIB.Ros({
  url: 'ws://192.168.100.22:9090/'
});

IPアドレスを調べるには、ターミナルで下記を叩けば良いです。

ifconfig

Topicの定義

下記で、ROS Topicの宣言を行います。今回の例では、Topic名は”/topic_test“、型は”Int16MultiArray“で定義しています。

// definition of a topic publisher
topic_publisher = new ROSLIB.Topic({
  ros: ros,
  name: "/topic_test",
  messageType: 'std_msgs/Int16MultiArray'
});

変数の代入とpublish関数

ここでは、value_avalue_bという変数を宣言して、先程のTopicに値を格納しています。

値を何かの処理に応じて変更したい場合には、別の関数を定義してその中で値を変更すれば良いです。

// initialize valiables
var value_a = 99;
var value_b = 0;

// function of publish topic
function ros_topic_pub(value_a, value_b) {
  var ros_topic = new ROSLIB.Message({
    data: [value_a, value_b]
  });  
  topic_puslisher.publish(ros_topic);
}

setIntervalとwindon.onload関数

まず、setInterval関数を実行することで、先程定義したPublisherを0.1 sec毎に実行しています。

また、window.onload関数により、Webページが読み込まれた時点で、10HzでPublishする関数を読み込むようにしています。

// set interval
function rostopic_publish_loop() {
  setInterval("ros_topic_pub(value_a, value_b)", 100);
}

window.onload = function () {
  rostopic_publish_loop();
}

その他の型のTopicをPublishしたい場合にも、上記の容量で記述することで、ブラウザからTopicをPublishできます。

Subscriberの記述

ROS TopicのSubscriberは下記のように記述します。

今回の例では、”/odom“というTopic名のTopicをSubscribeする関数ros_topic_subを定義しています。

下の例では、HTMLに記載した2つの値をgetElementById関数で読み取り、Subscribeした値で置き換えて、画面に表示するようにしています。これで、指定したTopicが別のノードからPublishされている限りSubscribeすることができます。

// definition of a topic subscriber
var ros_topic_sub = new ROSLIB.Topic({
ros: ros,
name: '/odom',
messageType: 'nav_msgs/Odometry'
});

ros_topic_sub.subscribe(function(message){
var pose_x = message.pose.pose.position.x;
var pose_y = message.pose.pose.position.y;

var $baselink_x_showed = document.getElementById("pose_x_indicator");
var $baselink_y_showed = document.getElementById("pose_y_indicator");

$baselink_x_showed.innerHTML = "x: " + pose_x + " [m]";
$baselink_y_showed.innerHTML = "y: " + pose_y + " [m]";
}