Windows で ROS のシミュレーションを行う (3)
Turtlesim で ROS を体験する

本ページでは、Turtlesim という ROS のサンプルプログラムを用いて ROS を体験する。
前ページで紹介した TurtleBot3 ではなくまず Turtlesim を用いるのは、
設定や操作がシンプルであり、ROS の本質を理解しやすいと考えられるためである。

本ページは以下の内容で構成される。

ターミナルにおけるタブの利用

演習の前にターミナルに関する注意を述べておく。
新しいターミナルを開き、キーボードで Ctrl + Shift + t を実行しよう (CtrlキーとShiftキーを押しながらt)。
すると、ターミナルに2つめの「タブ」が現れる。



タブを3つに増やすには、再び Ctrl + Shift + t を実行しても良いし、タブの横に現れた「+」ボタンをクリックしても良い。

本ページ以降、複数のコマンドを同時に実行する機会が増える。そのたびに新しいターミナルを起動すると、
ターミナルの枚数が増えすぎて収拾がつかなくなる。

そのため、複数のコマンドを実行する場合、一つのターミナル上に複数のタブを作成してその上でそれぞれのコマンドを実行するようにしよう
それでやっていることの見通しがかなり立つはずである。


Turtlesim の手動操作

それでは、Turtlesim を手動で操作するという演習を行ってみよう。 まず、ターミナルの一つのタブで以下の roscore コマンドを実行する。
 roscore
ターミナルには様々な情報が表示されるが、最終的に以下のような表示になる。
(略)

setting /run_id to c6dca014-89dc-11ea-b237-0800277fc154
process[rosout-1]: started with pid [6981]
started core service [/rosout]
これで roscore が起動された。ターミナル上のこのタブはこのままにしておこう。
なお、これから ROS の「ノード」と呼ばれるプログラムをどんどん実行していくことになる。
roscore はこれらの複数のノードを管理するために最初に実行しておく必要があるものである。

次に、ターミナルの新しいタブで、以下のコマンドで Turtlesim のノードを起動する。
 rosrun turtlesim turtlesim_node
すると、以下のような画面が現れる。中央に見えるのは Turtle (亀) である。
この見ためは起動するたびにランダムに変化するので、見ためが違っても気にする必要はない。



この亀を、仮想空間上に存在するロボットだと思うことにしよう。ロボットは仮想空間上で静止している。
これをキーボードで操作するための簡易的なプログラムがあるので、そのノードを起動しよう。
ターミナルの新しいタブで以下のコマンドを実行しよう。
 rosrun teleop_twist_keyboard teleop_twist_keyboard.py cmd_vel:=/turtle1/cmd_vel _speed:=2.0 _turn:=2.0
すると、画面に以下のようなメッセージが表示される。
Moving around:
   u    i    o
   j    k    l
   m    ,    .

For Holonomic mode (strafing), hold down the shift key:
---------------------------
   U    I    O
   J    K    L
   M    <    >

t : up (+z)
b : down (-z)

anything else : stop

q/z : increase/decrease max speeds by 10%
w/x : increase/decrease only linear speed by 10%
e/c : increase/decrease only angular speed by 10%

CTRL-C to quit

currently:	speed 2.0	turn 2.0
これは、ターミナルのこのタブ上でキーボードを入力すると、ロボットを操作できることを意味している。
ロボットの操作に最低限用いるキーは以下の4 つである。 これらのキーは、右手(あるいは左手)の、3本の指で操作するのが良いだろう。

動作を表すキーは、どれも「一定時間動作する」という挙動なのだが、
動作中でも別コマンドは受け付けられる。色々試して操作に慣れてみよう。

なお、操作時に注意して欲しいのは、「teleop_twist_keyboard」にフォーカスが合っているときのみ、亀を操作できる、ということである。
Turtlesim のウインドウにフォーカスが合っているときは亀は操作できないことに注意すること。



既に述べたように、この亀をロボットであるとイメージして欲しい。
実際、前ページで紹介した TurtleBot3 を、このプログラムで操作することができる。

さて、ここまでの状況を整理するために、ターミナルの新しいタブで以下のコマンドを実行しよう。
 rosrun rqt_graph rqt_graph
以下のウインドウが開くはずである。図中の赤丸の部分が「Nodes only」になっていなかったら「Nodes only」にセットしよう。



上図は、キー入力プログラム (teleop_twist_keyboard) とロボット (turtlesim) が
/turtle1/cmd_vel というもの (トピックと呼ばれる) を通じて結び付いていることを示している。

cmd_vel は command for velocity (速度コマンド) の略であろう。
すなわち、ロボットが cmd_vel という速度コマンドを受け付けるよう設計されており、
キー入力プログラムでその cmd_vel を発行してロボットを制御していることを上図は意味している。

なお、赤丸の部分を下図のように「Nodes/Topic (all)」にすると、「トピック」というものも表示されるようになる。
ROS 上で動作するプログラムを書くためには、このトピックについても理解しなければならないが、本資料では省略するので、
いずれ教科書などで勉強して欲しい。



以上が終ったら、ターミナル上の全てのタブでプログラムを終了しよう。
この時点で4つのプログラムが動いているので、それを実行している4つのタブで
それぞれ「Ctrl-c」 (Ctrlキーを押しながら c) を入力すればよい。


Turtlesim の自律制御

さて、ROS の演習を行うと、どうしても「既存のサンプルを動作させる」ことが多くなるので、
「ROS で動作するプログラムを書く」ということがピンと来なくなることが多い。
そこで、さきほどの亀を自律制御するための簡単なプログラムを書く演習を行ってみよう。
用いる言語は Python である。

ROS では、プログラムを配置する場所が決っている。
まず、パッケージというものを作る必要がある。
そして、Python プログラムの場合 パッケージの中の scripts というディレクトリ (フォルダ) にファイル置くことになる。

以上を行うために以下の3つのコマンドをターミナルの一つのタブの中で順に実行しよう。
「ros_practice」というパッケージを作成し、その下に scripts というディレクトリを作成している。
 cd ~/catkin_ws/src

 catkin_create_pkg ros_practice

 mkdir ros_practice/scripts
そして、この場所にロボットの自律制御用のプログラムを書く。そのためにテキストエディターを起動しよう。
下図のように検索窓に text と入力すると「テキストエディター」が現れるのでクリックすると
gedit と呼ばれるテキストエディターが起動する。



現れたテキストエディターに以下のプログラムを記述しよう。 (結局はコピーして貼り付けるだけになってしまうが)
#!/usr/bin/env python

import rospy
from geometry_msgs.msg import Twist
from turtlesim.msg import Pose

cmd_vel = Twist()
cmd_vel.linear.x = 2.0
cmd_vel.angular.z = 0.0

pose = Pose()
nowRotating = False

def update_pose(data):
    global pose
    pose.x = data.x
    pose.y = data.y

def update_cmd_vel():
    global cmd_vel
    global nowRotating
    boundary = 1.0
    if (pose.x < boundary or pose.x > 11.08-boundary or pose.y < boundary or pose.y > 11.08-boundary) and not nowRotating:
        cmd_vel.linear.x = 0.0
        cmd_vel.angular.z = 2.0
        nowRotating = True
    else:
        cmd_vel.linear.x = 2.0
        cmd_vel.angular.z = 0.0
        nowRotating = False

def autonomous_controller():
    rospy.init_node('autonomous_controller')
    pub = rospy.Publisher('cmd_vel', Twist, queue_size=10)
    sub = rospy.Subscriber('pose', Pose, update_pose)

    rate = rospy.Rate(10) # 10hz
    while not rospy.is_shutdown():
        update_cmd_vel()
        pub.publish(cmd_vel)
        rate.sleep()

if __name__ == '__main__':
    try:
        autonomous_controller()
    except rospy.ROSInterruptException:
        pass

記述したらファイルを保存する。メニューから「ファイル」→「保存」を選択し、
現れた画面でディレクトリを 「catkin_ws」→「src」→「ros_practice」→「scripts」とダブルクリックしてたどる。
そして、「名前」欄にファイル名として autonomous_controller.py と記入して「保存」ボタンを押すこと。

「名前」を間違えると以下の演習が実行できないので、これも貼り付けにより正確なファイル名で保存すること。
「名前」欄へのファイル名の貼り付けは Ctrl-v でできる。

保存したファイルを実行可能なプログラムにするため、ターミナルで以下のコマンドを実行する。
(これは一回実行するだけで良い)
 chmod 755 ~/catkin_ws/src/ros_practice/scripts/autonomous_controller.py 
以上で、ロボットを自律制御するためのプログラムが完成したので早速実行してみよう。

ターミナルに複数のタブを開き、以下の3つのコマンドを別々のタブで実行しよう。

一つ目のタブ:roscore の起動
 roscore

二つ目のタブ:turtlesim の起動
 rosrun turtlesim turtlesim_node

三つ目のタブ:自律制御用プログラム
 rosrun ros_practice autonomous_controller.py cmd_vel:=/turtle1/cmd_vel pose:=/turtle1/pose

うまく実行できると、下図のように、壁に近付くと向きを変えて壁にぶつからないようにする挙動が実現される
(簡易的なプログラムなので、実際にはぶつかっているが)。



このプログラムの解説は本資料の範囲を超えるが、エッセンスだけを簡単に解説する。

まず、プログラム中にある以下の部分は、ロボットに左旋回命令を与えることを意味する。
(キーボードの j と同じ)
cmd_vel.linear.x = 0.0
cmd_vel.angular.z = 2.0
一方、プログラム中にある以下の部分は、ロボットに直進命令を与えることを意味する。
(キーボードの i と同じ)
cmd_vel.linear.x = 2.0
cmd_vel.angular.z = 0.0
そして、プログラムの以下の部分は、
「ロボットが boundary の領域に入っていたらロボットを回転させ、
そうでなかったら直進させる」
という制御に対応する。
    if (pose.x < boundary or pose.x > 11.08-boundary or pose.y < boundary or pose.y > 11.08-boundary) and not nowRotating:
        cmd_vel.linear.x = 0.0
        cmd_vel.angular.z = 2.0
        nowRotating = True
    else:
        cmd_vel.linear.x = 2.0
        cmd_vel.angular.z = 0.0
        nowRotating = False
ちなみに、以下の部分を「-2.0」に変更して保存してから三つ目のタブの自律制御用プログラムを実行し直すと、
左旋回でなく右旋回で壁をさける制御になるので試してみるとよい。
        cmd_vel.angular.z = 2.0
boundary については下図を参照。



さて、以上の自律制御が動作している状態で、ターミナルの新しいタブで以下のコマンドを実行し、ノードの関係を観察してみよう。
 rosrun rqt_graph rqt_graph
「Node only」を選択すると以下のような関係が現れるはずである。
この図は、自律制御プログラム ( /autonomouse_controller ) は、
ロボット ( /turtlesim ) の状態 (/turtle1/pose ) を観察し、
ロボットに速度コマンド (/turtle1/cmd_vel) を与えている、
という関係を示している。

このような関係は、ロボットの制御において頻繁に見られることは想像できるだろう
(例:カメラで人間を認識してロボットを移動させる、など)。



なお、この例ではロボットの状態として観察されたのは、ロボットの二次元座標 (x, y) である。
天井に設置したカメラからロボットの移動範囲を撮影すれば (x, y) は取得可能であるとはいえ、
現実のロボットでは、このように (x, y) が容易に得られることはあまりないことに注意して欲しい。

その点は、これが簡易的な演習であるということで御容赦いただきたい。

さて、以上が終ったらプログラムが動作している全てのタブで Ctrl-c を入力してプログラムを終了しよう。


Launch ファイルによる複数プログラムの同時起動

さて、ここまでの演習で、ROS の演習ではたくさんのプログラムを同時に動かさなければならないことに気づいただろう。

Turtlesim の手動操作では「roscore」+「turtlesim」+「キー入力プログラム」の3つ、
Turtlesim の自律制御では「roscore」+「turtlesim」+「自律制御プログラム」の3つである
(ノード間の関係を表示する rqt_graph は省いて数えた)。

毎回これらを一つ一つ実行するのは大変なので、一つのコマンドで複数のプログラムをまとめて実行する仕組みが用意されている。
その際に用いるのが Launch ファイルである。

Launch ファイルはパッケージ内の launch ディレクトリに置くことになっているので、それを作ろう。
ターミナルで以下のコマンドを実行すると、ros_practice パッケージに launch ディレクトリが作成される。
 mkdir ~/catkin_ws/src/ros_practice/launch
まず、Turtlesim を手動操作するためのプログラムを一気に起動するための Launch ファイルを作成しよう。

テキストエディタを起動し、以下の内容を記述しよう。
<launch>
  <node name="turtlesim" pkg="turtlesim" type="turtlesim_node" />
  <node name="teleop_twist_keyboard" pkg="teleop_twist_keyboard" type="teleop_twist_keyboard.py">
    <remap from="cmd_vel" to="turtle1/cmd_vel"/>
    <param name="speed" type="double" value="2.0" />
    <param name="turn" type="double" value="2.0" />
  </node>
</launch>
保存する際、メニューから「ファイル」→「保存」を選択し、
現れた画面で保存先のディレクトリを 「catkin_ws」→「src」→「ros_practice」→「launch」とダブルクリックしてたどる。
そして、「名前」欄にファイル名として、turtlesim_manual.launch と貼りつけで記入して保存しよう。

保存したらテキストエディタを閉じ実行してみよう。まず、ターミナルの全てのタブで ROS のプログラムが実行されていないことを確認してから、
以下のコマンドを実行しよう。
 roslaunch ros_practice turtlesim_manual.launch
この一つの命令を実行しただけで、「roscore」+「turtlesim」+「キー入力プログラム」の3つが実行されている。
ただし、以下に注意しよう。 以上、動作を確認したら、roslaunch を実行したターミナル上で Ctrl-c を二回実行し、全てのプログラムを終了しよう。
キー入力を受け付けるプログラムが Launch ファイルに含まれていると、Ctrl-c が二回必要なようである。

同様に、Turtlesim の自動起動プログラムも、一コマンドで実行できるようにしよう。
新たにテキストエディタを起動し、以下の内容を記述する。
<launch>
  <node name="turtlesim" pkg="turtlesim" type="turtlesim_node" />
  <node name="autonomous_controller" pkg="ros_practice" type="autonomous_controller.py">
    <remap from="cmd_vel" to="turtle1/cmd_vel"/>
    <remap from="pose" to="turtle1/pose"/>
  </node>
</launch>
保存する際、メニューから「ファイル」→「保存」を選択し、
現れた画面で保存先のディレクトリを 「catkin_ws」→「src」→「ros_practice」→「launch」とダブルクリックしてたどる。
そして、「名前」欄にファイル名として、turtlesim_autonomous.launch と貼りつけで記入して保存しよう。

保存したらテキストエディタを閉じ実行してみよう。まず、ターミナルの全てのタブで ROS のプログラムが実行されていないことを確認してから、
以下のコマンドを実行しよう。
 roslaunch ros_practice turtlesim_autonomous.launch
一コマンドで Turtlesim の自律制御プログラムが実行されたはずである。

成功を確認したら、roslaunch を実行したターミナルで Ctrl-c を入力しよう。
キー入力を含まないため、Ctrl-c 一回で全てのプログラムが終了する。



前のページ「Windows で ROS のシミュレーションを行う (2) ROS のセットアップ」/
次のページ「Windows で ROS のシミュレーションを行う (4) TurtleBot3 をプログラムで制御する

トップページに戻る