環境
この記事は以下の環境で動いています。
項目 | 値 |
---|---|
CPU | Core i5-8250U |
Ubuntu | 16.04 |
ROS | Kinetic |
インストールについてはROS講座02 インストールを参照してください。
またこの記事のプログラムはgithubにアップロードされています。ROS講座11 gitリポジトリを参照してください。
概要
今までロボットを動かす場合は、geometry_msgs/Twist型が必要でした。しかし、JoyConを使ってtTwistを送る方法しかありませんでした。これではいつでもJoyConを持ち歩かないといけなく不便なので、GUIからTwistを送りたいです。
今回はHTMLのCanvas要素を使ってTwistを送ってみます。
ソースコード
<!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>
<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>
<title>HTML5</title>
<body>
<p>status: <label id="state">Disconnect</label></p>
<h1>/cmd_vel</h1>
<canvas id='canvas' style="background-color:#EEEEEE;"></canvas>
<p id="linearX" >linearX: 0.0 m/s</p>
<p id="angularZ">angularZ: 0.0 rad/s</p>
<script>
if(!Twist){
var Twist = {
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(linearX, angularZ){
var pub = new ROSLIB.Topic({
ros : this.ros,
name : '/cmd_vel',
messageType : 'geometry_msgs/Twist'
});
var twist = new ROSLIB.Message({
linear:{x:linearX, y:0.0, z:0.0},
angular:{x:0.0, y:0.0, z:angularZ}
});
pub.publish(twist);
}
}
Twist.init();
window.onload = function(){
};
window.onunload = function(){
Twist.ros.close();
};
}
//position -1.0~1.0
last_X=0.0;
last_Y=0.0;
last_enable=false;
window.onload=function(){
canvas=$('canvas');
expandCanvas();
reticle();
}
function expandCanvas(){
var b = document.body;
var d = document.documentElement;
canvas.width = 400;
canvas.height = 400;
}
canvas.onmousedown = function(e){
last_X=(e.pageX - canvas.offsetLeft - 200) / 200;
last_Y=(e.pageY - canvas.offsetTop - 200) / 200;
last_enable=true;
}
canvas.onmousemove = function(e){
last_X=(e.pageX - canvas.offsetLeft - 200) / 200;
last_Y=(e.pageY - canvas.offsetTop - 200) / 200;
}
canvas.onmouseup=function(e){
last_X=0.0
last_Y=0.0
last_enable=false;
Twist.send(0.0, 0.0);
}
function reticle(){
var target=$("canvas");
var context=target.getContext('2d');
center_x=200;
center_y=200;
line_a=10;
line_b=100;
context.beginPath();
context.moveTo(center_x+line_a, center_y);
context.lineTo(center_x+line_b, center_y);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(center_x-line_a, center_y);
context.lineTo(center_x-line_b, center_y);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(center_x, center_y+line_a);
context.lineTo(center_x, center_y+line_b);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(center_x, center_y-line_a);
context.lineTo(center_x, center_y-line_b);
context.closePath();
context.stroke();
}
function interval_process(){
if(last_enable){
var linearX = -0.5*last_Y;
var angularZ = -1.0*last_X;
document.getElementById("linearX" ).textContent = "linearX: " +linearX +" m/s" ;
document.getElementById("angularZ").textContent = "angularZ: "+angularZ+" rad/s" ;
console.log(linearX, angularZ);
Twist.send(linearX, angularZ);
}
}
setInterval("interval_process()",100);
function $(id){
return document.getElementById(id);
}
</script>
</body>
</html>
if(!Twist){}
の中はTwistを送るためにwebsocketの通信を行っているところです。前のpub.htmlとほぼ同じ内容です。jsonで複数階層のrosmsgを表すときは{a:{a0:0, a1:1}, b:{b0:2, b1:3}}
のようにします。
window.onload=function(){}
は起動時に呼ばれるcallbackを登録しています。
その下ではcanvas.onmousedown = function(e){}
のようにcanvasでいイベントが起きた時に実行するcallbackを登録しています。
今回登録したのは以下のようなイベントです。
イベント | xy座標 | enable |
---|---|---|
canvas.onmousedown | 現在位置にセット | trueにセット |
canvas.onmousemove | 現在位置にセット | 変化なし |
canvas.onmouseup | 0,0にセット | falseにセット |
その下のfunction interval_process(){}
とsetInterval("interval_process()",100);
では10Hzで実行するcallbackを設定しています。ここではenable==trueの時に保存されているxyに合わせてtwistを送信するTwist.pub()
を呼んでいます。
実行
以下のように2つのターミナルを開いて、そのうえでブラウザでlocalhost:8085/web_lecture/twist.html
にアクセスします。
roslaunch vis_lecture move_robot.launch
roslaunch web_lecture bridge.launch
参考
canvasオブジェクトを作る
javascriptで一定間隔にプログラムを実行
多階層のjsonの書き方
javascriptのイベント