はじめに
ROSのTopicをJavaScriptでブラウザ上で操作することで、様々なUIを作成できるようになります。
今回は、roslibjsとrosbridgeによるTopicのPub/Sub通信についてまとめます。
実行環境
CPU | Core i7-10875H |
Ubuntu | 18.04.5 |
ROS | Melodic |
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_a
とvalue_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]";
}