ROS 2 実践コース|#06 コードを変えずにつなぎ替える(launch)

前の回の実験 6 で、名前空間を付けると同じノードを 2 つ動かせることを確かめました。この回はその続きです。

課題:コードを 1 行も変えずに、square_walker で /sim1 の亀に正方形を、/sim2 の亀に 2 倍の大きさの正方形を描かせる launch ファイルを作る。

square_walker は、決まった時間だけ前に進んで 90° 回る、を繰り返して正方形を描くサンプルのノードです。来週はこの同じノードを、四足歩行ロボットに出します。

この回は、次の順で進めます。

順やること
1サンプルの launch ファイルを動かし、中身を読む(remap とパラメータの渡し方を知る)
2設計シートを書く(まずサンプルの分を例として読み、次に課題の分を自分で書く)
3AI に launch ファイルを作らせ、設計シートと突き合わせてから保存する
4動かして、つながり・パラメータ・亀の向きのずれをコマンドで確かめる
5課題に答える

4 では、コマンドを打つ前に予想を書きます。何を予想すればよいかは、次の表のとおりです。結果の画面と説明は「結果を見る」をクリックすると開きます。予想を書き、自分で実行してから開いてください。

確かめること予想すること手がかり
4-1. ノードの一覧ros2 node list に、どんな名前のノードがいくつ出るか#05 の実験 6(名前空間を付けると、ノードの名前の前に名前空間が付く)
4-2. rqt_graph2 つの square_walker から出る線は、どのトピックを通ってどの亀につながるか。線は交差するか自分の設計シートの「できあがるつながり」
4-3. トピックの相手/sim1/turtle1/cmd_vel に、送る側・受ける側がそれぞれいくつ、どの名前空間のノードがつながっているか#03 の実験 3(ros2 topic info で送る側・受ける側の数が分かる)
4-4. パラメータros2 param get で読んだ linear_speed と side_time の値自分の設計シートの「パラメータ」の欄
4-5. 描いた正方形/sim2 の正方形は /sim1 の何倍の大きさになるか1 辺の長さ=速さ × 時間
4-6. 亀の向きのずれ正方形を 1 周したあと、亀の向き(theta)はスタートと同じになるか。ずれるなら、どちらにどれくらいかsquare_walker は「角速度 × 時間」で 90° 回ったことにしている(1 の抜き出したコード)

予想は外れてかまいません。点になるのは、予想と結果が違ったときに「なぜ違ったか」を考えて書くところです。分からないときも空欄にせず、「分からない」と書いて、手がかりにしたことを 1 つ書きます。

授業で受ける人は、この回の記録を実習レポート(Word)の「第 4 回」のシートに書きます。スクリーンショットは、シートの中の「画面:」の欄(実験や記録の表のすぐ下)に貼ります。ひとりで学ぶ人も、予想と結果を同じ形でノートに残しておくと、あとで見返せます。

この回で撮っておく画面

動画は撮りません。そのかわり、下の画面を撮って残します。授業で受ける人は、実習レポートの「第 4 回」の、それぞれの「画面:」の欄に貼ります。ひとりで学ぶ人も、同じ画面を残しておくと、あとで値を見直せます。最初の 1 枚は、実習を始める前に端末で TZ=Asia/Tokyo date と打ち、日付と時刻が出た画面です。授業の日に実習したことの記録になります。講義用の環境の時計は世界標準時(UTC)なので、TZ=Asia/Tokyo を付けて日本時間で出します。

  • TZ=Asia/Tokyo date の画面
  • ros2 node list(4 つのノードと名前空間)
  • rqt_graph(2 組の線が交差していないこと)
  • ros2 param get で読んだ linear_speed と side_time
  • スタート時の ros2 topic echo /sim1/turtle1/pose --once(theta)
  • 1 周したあとの同じコマンドの theta
  • パラメータを変えて 2 倍の正方形を歩かせたあとの turtlesim の画面

1. サンプルの launch ファイルを動かして読む

launch ファイルは、いくつものノードを、名前やパラメータを付けてまとめて起動するためのファイルです。これまでは、ノード 1 つごとに端末を開いて ros2 run を打っていました。launch ファイルを使うと、1 回のコマンドで全部を起動できます。この節では、次の 3 つをします。

  1. サンプルの launch ファイルを起動し、亀が正方形を描くのを見る
  2. launch ファイルの中身を読み、remap とパラメータがどこに書いてあるかを確かめる
  3. square_walker のコードの一部を読み、コードに何が書かれていて、何が書かれていないかを確かめる

1-1. サンプルを起動する

ros2 launch のあとには、パッケージの名前と launch ファイルの名前を書きます。

ros2 launch sakigake_samples turtle_square.launch.py
亀の画面が開き、亀が正方形を 2 周描きます。右の端末には「n / 8 辺目が終わりました」と進み具合が表示されます
亀の画面が開き、亀が正方形を 2 周描きます。右の端末には「n / 8 辺目が終わりました」と進み具合が表示されます

square_walker は 2 周描くと自分で終わりますが、亀の画面は残ります。見終わったら、launch の端末で Ctrl+C を押します。launch で起動したノードは、Ctrl+C 1 回で全部止まります。

1-2. launch ファイルの中身を読む

この launch ファイルの中身です。

"""turtlesim の亀に正方形を描かせる(ロボットがなくても動く)。

ros2 launch sakigake_samples turtle_square.launch.py
"""
from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():
    return LaunchDescription([
        Node(
            package='turtlesim',
            executable='turtlesim_node',
            name='turtlesim',
        ),
        Node(
            package='sakigake_samples',
            executable='square_walker',
            name='square_walker',
            output='screen',
            # square_walker は cmd_vel に出す。亀が聞いているのは /turtle1/cmd_vel なのでつなぎ替える
            remappings=[('cmd_vel', '/turtle1/cmd_vel')],
            parameters=[{
                'linear_speed': 1.0,
                'angular_speed': 0.8,
                'side_time': 2.0,
                'laps': 2,
            }],
        ),
    ])
  • Node(...) 1 つが、ros2 run 1 回分にあたります。package と executable が、ros2 run のあとに書く 2 つ(パッケージと実行ファイル)です。
  • name はノードの名前、output='screen' は、そのノードが出す表示を launch の端末に出すという意味です。
  • remappings:square_walker は cmd_vel という名前のトピックに速度を出します。一方、亀が聞いているのは /turtle1/cmd_vel です。そこで、名前をつなぎ替えています。#03 の実験 3 で使った -r A:=B を、launch ファイルで書いたものです。
  • parameters:前進の速さや 1 辺の時間などを、コードを変えずに外から渡しています。#05 の実験 5 で ros2 param set を使って動いているノードの設定を変えたのに対し、こちらは起動するときに渡します。

1-3. square_walker のコードを読む

square_walker のコードのうち、パラメータとトピックに関わる部分を抜き出すと次のとおりです。コードの中にはトピック名 cmd_vel しか書かれておらず、どの亀に出すかは書かれていません。

        self.declare_parameter('linear_speed', 0.5)   # 前進の速さ [m/s]
        self.declare_parameter('angular_speed', 0.8)  # 旋回の速さ [rad/s]
        self.declare_parameter('side_time', 2.0)      # 1辺を進む時間 [s]
        self.declare_parameter('laps', 1)             # 何周するか
        self.declare_parameter('rate', 10.0)          # 送信の周期 [Hz]
        ...
        # 90度回るのにかかる時間 = 角度 / 角速度
        self.turn_time = (math.pi / 2.0) / abs(self.angular_speed)
        ...
        self.publisher = self.create_publisher(Twist, 'cmd_vel', 10)

declare_parameter の 2 つめの数が、パラメータの初期値です。launch ファイルで値を渡さなかったパラメータは、この初期値のまま動きます。たとえばサンプルでは linear_speed を 1.0 にしているので、初期値の 0.5 ではなく 1.0 の速さで進みます。

2. 設計シートを書く

今回は launch ファイルの設計シートです。#04 ではノード 1 つに 1 枚書きましたが、今回は「どのノードを、どんな名前空間・remap・パラメータで起動するか」を 1 枚にまとめます。この節では、次の順で進めます。

  1. 名前空間と、トピック名の先頭の / の関係を知る(remap を書くのに必要)
  2. サンプルの launch ファイルを設計シートに書いたものを、例として 1 欄ずつ読む
  3. 課題の設計シートを自分で書く。分からない欄は、AI に質問役をしてもらう

設計シートの形は次のとおりです。

■ 起動するノード
  名前空間 | パッケージ / 実行ファイル | remap | パラメータ
  ---------|--------------------------|-------|-----------
           |                          |       |
           |                          |       |

■ できあがるつながり(送る側 → トピック → 受ける側)

■ 検証の方法(実行するコマンドと、期待する結果)
  1.
  2.

■ 使った AI とプロンプト:

2-1. 名前の先頭の / と名前空間

トピックの名前には、先頭に / が付くものと、付かないものがあります。

  • 先頭に / が付く名前(/turtle1/cmd_vel など)は、そのまま使われます。ノードにどんな名前空間を付けても変わりません。
  • 先頭に / が付かない名前(turtle1/cmd_vel など)には、ノードの名前空間が前に付きます。名前空間が /sim1 なら /sim1/turtle1/cmd_vel になります。

#05 の実験 6 で、名前空間 /sim1 を付けた亀が /sim1/turtle1/cmd_vel を聞いていたのは、turtlesim のコードの中の名前が / なしで書かれているからです。remap の「つなぎ替え先」も同じ決まりで名前が決まります。課題の設計シートでは、ここがいちばん大事です。

2-2. 書き方の例:サンプルの launch ファイル

1 で読んだサンプル(亀 1 匹と square_walker 1 つ)を設計シートに書くと、次のようになります。

■ 起動するノード(2 つ)
  名前空間 | パッケージ / 実行ファイル            | remap                       | パラメータ
  ---------|--------------------------------------|-----------------------------|-----------------------------------
  なし     | turtlesim / turtlesim_node           | なし                        | なし
  なし     | sakigake_samples / square_walker     | cmd_vel → /turtle1/cmd_vel  | linear_speed 1.0, side_time 2.0, laps 2

■ できあがるつながり
  /square_walker → /turtle1/cmd_vel → /turtlesim

■ 検証の方法
  1. ros2 node list → /square_walker と /turtlesim の 2 つ
  2. ros2 topic info -v /turtle1/cmd_vel → 送る側 square_walker、受ける側 turtlesim が 1 つずつ
  3. rqt_graph → /square_walker → /turtle1/cmd_vel → /turtlesim とつながっている

■ 使った AI とプロンプト:(ここに書く)

それぞれの欄に何を書いたか、なぜそう書いたかは次のとおりです。

欄サンプルで書いたこと何を書くか・なぜそう書いたか
起動するノードturtlesim と square_walker の 2 行launch ファイルで起動するノードを 1 行に 1 つ書きます。1 行が launch ファイルの Node(...) 1 つ、つまり ros2 run 1 回分です。
名前空間なしノードを入れる名前空間です。サンプルは亀が 1 匹だけで、名前がぶつからないので付けていません。課題では亀が 2 匹になるので、#05 の実験 6 と同じように /sim1 と /sim2 に分けます。
パッケージ / 実行ファイルturtlesim / turtlesim_node などros2 run のあとに書く 2 つです。亀は turtlesim の turtlesim_node、正方形を描くノードは sakigake_samples の square_walker です。
remapcmd_vel → /turtle1/cmd_vel「コードの中の名前 → つなぎ替え先」を書きます。square_walker のコードの中の名前は cmd_vel(1-3 のコード)、亀が聞いているのは /turtle1/cmd_vel なので、こう書きます。名前空間がないので、つなぎ替え先の先頭に / を付けても付けなくても同じ名前になります。亀のほうは、もともと自分の名前で聞いているので、つなぎ替えは要りません。
パラメータlinear_speed 1.0, side_time 2.0, laps 2初期値から変えたいものだけを書きます。1 辺の長さは「速さ × 時間」なので、1.0 × 2.0 で 2.0 です。laps(何周するか)は初期値が 1 なので、2 周させるために書いています。angular_speed などは初期値のままでよいので書いていません(launch ファイルには 0.8 と書いてありますが、初期値と同じです)。
できあがるつながり/square_walker → /turtle1/cmd_vel → /turtlesim起動したあと、送る側からどのトピックを通って受ける側につながるはずかを書きます。rqt_graph で見える形を、先に書いておくということです。
検証の方法3 つのコマンドと、期待する結果つながりが設計どおりかを確かめるコマンドを書きます。ros2 node list・ros2 topic info -v・rqt_graph は #03 と #04 で使いました。
使った AI とプロンプト(ここに書く)設計シートを AI と対話して埋めたときのプロンプトと、聞き返されて自分で決めたこと、3 で launch ファイルを頼んだときのプロンプトを書きます。

2-3. 自分で書く:課題の launch ファイル

同じ書き方で、課題(亀 2 匹と square_walker 2 つ)の設計シートを自分で書いてください。サンプルとの違いは次の 3 つです。

  • 起動するノードが 4 つになる(亀 2 匹、square_walker 2 つ)
  • それぞれのノードに名前空間 /sim1 か /sim2 を付ける
  • /sim2 の正方形を 2 倍の大きさにする

1 辺の長さは「速さ × 時間」なので、2 倍にするには linear_speed を 2 倍にするか、side_time を 2 倍にします。どちらにするかは自分で決めてください。

remap の欄は、2-1 の決まりを使って考えます。名前空間 /sim1 の中の square_walker の出す先を /sim1/turtle1/cmd_vel にしたいとき、つなぎ替え先の先頭に / を付けるとどうなるか、付けないとどうなるかを、それぞれ書き出してから決めてください。

2-4. 分からない欄は、AI に聞き返してもらう

分からない欄があっても、空欄のまま AI に「書いて」と頼んではいけません。AI が勝手に決めた値になり、自分で決めたことになりません。#04 の「分からない欄は、AI に聞き返してもらう」と同じように、AI に質問役をしてもらい、1 欄ずつ自分で答えて埋めていきます。書けたところまでのシートとサンプルの設計シートを、次のプロンプトに貼って AI に渡します。

ROS 2 の launch ファイルの設計シートを書いています。分からない欄があるので、手伝ってください。
次のルールを守ってください。
・答えを先に書かないでください。空欄を 1 つずつ取り上げて、私に質問してください。
・私が「分からない」と答えたら、その欄が何を決めるものかを高校生にも分かる言葉で説明し、選ぶための手がかりを出してから、もう一度聞いてください。
・私の答えがおかしいと思ったら、どこがおかしいかを言って聞き返してください。
・全部の欄が埋まったら、シート全体を書き出してください。

作るもの:同じ square_walker ノードを 2 つ起動し、名前空間 /sim1 の亀に正方形、/sim2 の亀に 2 倍の大きさの正方形を描かせる launch ファイル(ROS 2 Humble)
square_walker のコードは変えません。square_walker は cmd_vel というトピックに速度を出し、パラメータ linear_speed・angular_speed・side_time・laps・rate を持っています。
亀(turtlesim_node)は turtle1/cmd_vel で速度を受け取ります。
参考にしたサンプルの設計シートは次のとおりです。
(ここにサンプルの設計シートを貼る)

私が書いたところまでの設計シート:
(ここに書きかけのシートを貼る)
  1. AI の質問に、自分の言葉で答える。当てずっぽうで答えず、分からないときは「分からない」と言う
  2. 説明を読んでも納得できなければ、「なぜそうするのですか」「ほかの書き方はありますか」と聞き返す
  3. 最後に AI が書き出したシートを、自分で確かめる。とくに remap のつなぎ替え先の先頭の / を、2-1 の決まりで確かめる

使ったプロンプトと、聞き返されて自分で決めたこと(「linear_speed のほうを 2 倍にしたのは、描き終わるまでの時間をそろえたいから」など)は、シートの「使った AI とプロンプト」の欄と、レポートの「C. AI とのやりとり」に書いておきます。

記入例(自分で書いてから開く)
■ 起動するノード(4 つ)
  名前空間 | パッケージ / 実行ファイル            | remap                      | パラメータ
  ---------|--------------------------------------|----------------------------|-----------------------------------
  /sim1    | turtlesim / turtlesim_node           | なし                       | なし
  /sim2    | turtlesim / turtlesim_node           | なし                       | なし
  /sim1    | sakigake_samples / square_walker     | cmd_vel → turtle1/cmd_vel  | linear_speed 1.0, side_time 2.0, laps 2
  /sim2    | sakigake_samples / square_walker     | cmd_vel → turtle1/cmd_vel  | linear_speed 2.0, side_time 2.0, laps 2

■ できあがるつながり
  /sim1/square_walker → /sim1/turtle1/cmd_vel → /sim1/turtlesim
  /sim2/square_walker → /sim2/turtle1/cmd_vel → /sim2/turtlesim

■ 検証の方法
  1. ros2 node list → 4 つのノードがすべて名前空間の下にある
  2. ros2 topic info -v /sim1/turtle1/cmd_vel → 送る側 /sim1 の square_walker、受ける側 /sim1 の turtlesim が 1 つずつ
  3. rqt_graph → /sim1 と /sim2 の線が交差していない
  4. ros2 param get /sim2/square_walker linear_speed → 2.0

■ 使った AI とプロンプト:(ここに書く)

この記入例では、side_time ではなく速さ(linear_speed)を 2 倍にしています。remap のつなぎ替え先は turtle1/cmd_vel で、先頭に / を付けていません。こうすると名前空間が前に付き、/sim1 の中では /sim1/turtle1/cmd_vel、/sim2 の中では /sim2/turtle1/cmd_vel になります。

記入例のつながり。/sim1 と /sim2 の中で、それぞれ閉じてつながる
記入例のつながり。/sim1 と /sim2 の中で、それぞれ閉じてつながる

3. AI に launch ファイルを作らせる

この節では、2 で書いた設計シートを AI に渡して launch ファイルを書かせ、設計シートと突き合わせてから保存します。やることは次の 3 つです。

  1. AI に頼む
  2. 返ってきた launch ファイルを、設計シートと突き合わせる
  3. VSCodium に貼って、~/ros2_ws/two_squares.launch.py に保存する

3-1. AI に頼む

Windows 側のブラウザで AI を開き、次のプロンプトの最後に自分の設計シートを貼って送ります。

次の設計シートどおりに、ROS 2 Humble の Python の launch ファイル two_squares.launch.py を書いてください。
square_walker のコードは変えません。
パッケージには入れず、ros2 launch でファイルの場所を指定して起動できるようにしてください。
設計シートにないノードやパラメータは足さないでください。

(ここに設計シートを貼る)

AI が返した launch ファイルの一例を、下に閉じて載せています。まず自分で AI に頼み、返ってきたものを読んでから開いて見比べてください。AI や聞き方によって書き方は変わりますが、設計シートどおりなら、同じように動きます。

AI が返した launch ファイルの一例(自分で AI に頼んでから開く)
"""/sim1 の亀に正方形、/sim2 の亀に 2 倍の正方形を描かせる。

ros2 launch ~/ros2_ws/two_squares.launch.py
"""
from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():
    return LaunchDescription([
        Node(package='turtlesim', executable='turtlesim_node', namespace='sim1', name='turtlesim'),
        Node(package='turtlesim', executable='turtlesim_node', namespace='sim2', name='turtlesim'),
        Node(
            package='sakigake_samples',
            executable='square_walker',
            namespace='sim1',
            name='square_walker',
            output='screen',
            # 名前空間の中で cmd_vel → turtle1/cmd_vel(先頭に / を付けないので /sim1/turtle1/cmd_vel になる)
            remappings=[('cmd_vel', 'turtle1/cmd_vel')],
            parameters=[{'linear_speed': 1.0, 'angular_speed': 0.8, 'side_time': 2.0, 'laps': 2}],
        ),
        Node(
            package='sakigake_samples',
            executable='square_walker',
            namespace='sim2',
            name='square_walker',
            output='screen',
            remappings=[('cmd_vel', 'turtle1/cmd_vel')],
            # 時間は同じで速さを 2 倍にすると、1 辺の長さが 2 倍になる
            parameters=[{'linear_speed': 2.0, 'angular_speed': 0.8, 'side_time': 2.0, 'laps': 2}],
        ),
    ])

この一例には、記入例のシートに書いていない angular_speed の 0.8 が入っています。初期値(1-3 のコード)と同じ値なので動きは変わりませんが、次の 3-2 で見つけたい「シートにない行」の例です。こういう行を見つけたら、消すか、シートに書き足すかを自分で決めます。

3-2. 設計シートと突き合わせる

返ってきた launch ファイルを、保存する前に設計シートと 1 行ずつ突き合わせます。見るところは次の 4 つです。

  • Node(...) が 4 つあり、package と executable がシートの「パッケージ / 実行ファイル」と同じか
  • namespace:シートの名前空間と同じか
  • remappings:つなぎ替え元が cmd_vel、つなぎ替え先がシートと同じか(先頭の / も含めて)
  • parameters:シートに書いたパラメータの名前と値が同じか。シートにないパラメータが足されていないか

特に remap の行を見てください。先頭に / がない名前には名前空間が付くので、turtle1/cmd_vel なら /sim1/turtle1/cmd_vel になります(2-1)。

よくある間違いは、サンプルのまま /turtle1/cmd_vel と書いてしまうことです。先頭が / の名前には名前空間が付かないので、2 つの square_walker がどちらも /turtle1/cmd_vel に出してしまい、どちらの亀も動きません。しかもエラーは出ません。

説明できない行があったら、そのままにせず AI に「この行は何をしていますか」と聞き返してください。設計シートと違うところを見つけたら、どこが違ったかをレポートの「C. AI とのやりとり」に書きます。

3-3. VSCodium に貼って保存する

作ったファイルは ~/ros2_ws/two_squares.launch.py に保存します。launch ファイルは、パッケージに入れなくても、ファイルの場所を指定すれば起動できます。パッケージに入れないので、ビルド(colcon build)も要りません。まだ無いファイルなので、#04 の「3-3. VSCodium に貼って保存する」と同じように、名前を付けて開きます。

codium ~/ros2_ws/two_squares.launch.py

AI の答えは Windows 側のブラウザに出るので、noVNC のクリップボードの入力欄に貼ってから、VSCodium の中で Ctrl+V を押します(#00 の「4. ブラウザのデスクトップの使い方」)。貼ったら Ctrl+S で保存します。保存しないと、ファイルはできません。

4. 動かして、つながりを確かめる

自分の launch ファイルで 4 つのノードを起動し、設計シートの「検証の方法」のとおりになっているかを、コマンドで 1 つずつ確かめます。

  1. launch ファイルを起動する
  2. 亀が歩いている間に、別の端末でノードの一覧・rqt_graph・トピックの相手・パラメータを調べる(4-1〜4-4)
  3. 描き終わった正方形の大きさを比べる(4-5)
  4. 亀を 1 周だけ歩かせ直し、向きがどれだけずれるかを測る(4-6)
ros2 launch ~/ros2_ws/two_squares.launch.py

square_walker は 1 辺ごとに前進 2 秒と旋回およそ 2 秒をくり返し、2 周(8 辺)描くと終わります。記入例の設定なら、30 秒ほどです。終わると square_walker はノードの一覧から消えるので、4-1〜4-4 はその前に打ちます。間に合わなかったときは、launch の端末で Ctrl+C を押し、もう一度起動し直せば何度でもやり直せます。コマンドは、起動する前に別の端末に打っておき、起動したら Enter を押すだけにしておくと間に合います。

4-1. ノードの一覧

ros2 node list
結果を見る(予想を書き、自分で実行してから開く)

次の 4 つが表示されれば、すべてのノードが名前空間の下に入っています。

/sim1/square_walker
/sim1/turtlesim
/sim2/square_walker
/sim2/turtlesim

4-2. rqt_graph

rqt_graph

rqt_graph が開いたら、#03 の実験 1 と同じように、左上のメニューを「Nodes/Topics (active)」にして更新ボタンを押します。

結果を見る(予想を書き、自分で実行してから開く)
/sim1 の square_walker は /sim1/turtle1/cmd_vel だけに、/sim2 の square_walker は /sim2/turtle1/cmd_vel だけにつながり、線が交差していません
/sim1 の square_walker は /sim1/turtle1/cmd_vel だけに、/sim2 の square_walker は /sim2/turtle1/cmd_vel だけにつながり、線が交差していません

4-3. トピックの相手

ros2 topic info -v /sim1/turtle1/cmd_vel
結果を見る(予想を書き、自分で実行してから開く)
送る側は名前空間 /sim1 の square_walker、受ける側は /sim1 の turtlesim で、1 つずつです
送る側は名前空間 /sim1 の square_walker、受ける側は /sim1 の turtlesim で、1 つずつです

4-4. パラメータ

ros2 param get は、動いているノードのパラメータの値を読むコマンドです。#05 の実験 5 の ros2 param set と同じく、ノードの名前、パラメータの名前の順に書きます。名前空間の付いたノードなので、ノードの名前は /sim1/square_walker のように名前空間から書きます。

ros2 param get /sim1/square_walker linear_speed
ros2 param get /sim1/square_walker side_time
ros2 param get /sim2/square_walker linear_speed
ros2 param get /sim2/square_walker side_time
結果を見る(予想を書き、自分で実行してから開く)

Double value is: 2.0 のように値が表示されます。設計シートに書いた値と同じなら、launch ファイルがパラメータを正しく渡しています。初期値(1-3 のコードの declare_parameter の値)が出たら、launch ファイルの parameters の書き方か、パラメータの名前が違っています。

Node not found と出たら、square_walker がもう描き終わって止まっています。launch を起動し直してから打ってください。

4-5. 描いた正方形

2 匹とも描き終わったら、2 つの亀の画面を並べて、正方形の大きさを比べます。

結果を見る(予想を書き、自分で実行してから開く)
左が /sim1、右が /sim2 の亀。右の正方形は、左の 2 倍の大きさです
左が /sim1、右が /sim2 の亀。右の正方形は、左の 2 倍の大きさです

4-6. 1 周で向きがどれだけずれるかを測る

正方形を 1 周すると、亀は 90° を 4 回回るので、元の向きに戻るはずです。本当に戻るかを、亀の向き theta を読んで確かめます。

  1. launch は止めずに、2 匹とも描き終わるまで待つ(亀の画面は残っています)
  2. 別の端末で、/sim1 の亀の向きを読む(スタートの theta)
  3. /sim1 の亀だけを、square_walker でもう 1 周歩かせる
  4. 描き終わったら、もう一度向きを読む(ゴールの theta)
  5. /sim2 の亀でも、2〜4 を同じようにする

亀の位置と向きは、/sim1/turtle1/pose というトピックに流れています。--once を付けると、メッセージを 1 つだけ表示して終わります。表示される x・y が位置、theta が向き(rad)です。

ros2 topic echo /sim1/turtle1/pose --once

次に、/sim1 の亀だけを 1 周歩かせます。launch ファイルに書いた名前空間・remap・パラメータを、ros2 run の書き方で付けています。__ns は #05 の実験 6、-r は #03 の実験 3、-p はパラメータを渡す書き方です(#04 の -p start:=100 と同じ)。laps:=1 で 1 周だけにしています。

ros2 run sakigake_samples square_walker --ros-args -r __ns:=/sim1 -r cmd_vel:=turtle1/cmd_vel -p linear_speed:=1.0 -p side_time:=2.0 -p laps:=1

「正方形を描き終えました」と表示されたら、もう一度 ros2 topic echo /sim1/turtle1/pose --once を打って、ゴールの theta を読みます。/sim2 の亀では、/sim1 を /sim2 に、パラメータを自分の設計シートの /sim2 の値に変えて、同じことをします。

ずれは、「ゴールの theta − スタートの theta」を度に直して書きます。1 rad はおよそ 57.3° です。theta は -3.14〜3.14(-180°〜180°)の範囲で表されるので、ちょうど左向きのあたりでは、3.1 から -3.1 のように符号が飛ぶことがあります。そのときは、差に 360° を足すか引くかして、小さいほうのずれにします。読んだ値は、レポートの「1 周したあとの亀の向き」の表に書きます。

結果を見る(予想を書き、自分で実行してから開く)
1 周の前後で /sim1/turtle1/pose を読んだところ。theta が -0.394 から -0.597 に変わりました
1 周の前後で /sim1/turtle1/pose を読んだところ。theta が -0.394 から -0.597 に変わりました

この例では、theta が 1 周で約 -0.20 rad 変わりました。度に直すと約 -11.6° で、亀は元の向きより時計回りにずれています。/sim2 の亀でも同じく約 -11.6° で、何周させても毎回ほぼ同じだけずれました。

スタートの theta が 0 でないのは、launch で 2 周したときのずれ(約 -23°)が残っているからです。測りたいのは 1 周の前後の差なので、スタートが 0 でなくてもかまいません。

5. 課題に答える

  1. 2 倍の正方形にするために、linear_speed と side_time のどちらを変えましたか。もう一方を変えた場合と、何が違いますか。
  2. 正方形の角の位置は、少しずれることがあります。なぜでしょうか。4-6 で読んだ theta の値を使って説明してください。
  3. 同じ square_walker をロボットに出すと(第 6 回、#08)、ずれは大きくなるでしょうか、小さくなるでしょうか。予想と理由を書いてください。

手がかりです。1 は、1 辺の長さ・描き終わるまでの時間・亀の速さの 3 つで比べます。2 は、1-3 のコードで square_walker が 90° 回ったことをどうやって決めているか(亀の実際の向きを見ているか)を読み直します。3 は、亀はシミュレーターの中で指令どおりの速さで回りますが、ロボットは脚で床を蹴って回る、という違いから考えます。3 の答えは第 6 回で確かめます。

考え方の例(答えを書いてから開く)
  • 1:どちらを 2 倍にしても 1 辺は 2 倍になります。速さを変えると描き終わるまでの時間は同じで、時間を変えると同じ速さで 2 倍の時間がかかります。
  • 2:square_walker は「角速度 × 時間」で 90° 回ったことにしているだけで、亀が実際にどちらを向いているか(/sim1/turtle1/pose)を見ていません。しかも時間は 0.1 秒ごとにしか確かめないので、計算では 1.963 秒のはずの旋回が、実際には 1.9 秒で終わります(旋回を終える回は止める指令を送るため)。0.8 rad/s × 1.9 秒=1.52 rad(約 87.1°)なので、1 回の旋回で約 2.9°、4 回で約 11.6° 回り足りません。4-6 で読んだずれと同じです。足りない分を直さずに次の辺へ進むので、周を重ねるごとに正方形が少しずつ回っていきます。同じ理由で、前進も 2.0 秒ではなく 1.9 秒になり、1 辺は計算より少し短くなります。

来週への予告

来週は、同じ square_walker を四足歩行ロボット DOGZILLA S2 に出します。ロボットは /cmd_vel で速度指令を聞いています。そのとき remap はどう書けばよいか、考えてきてください。

まとめ

道具変えられることこの回の使い方
名前空間ノードとトピックの名前の前に付く部分/sim1 と /sim2 に分ける
remapコードに書かれたトピック名を、起動するときに別の名前へつなぎ替えるcmd_vel → turtle1/cmd_vel
パラメータコードに書かれた設定値linear_speed を 1.0 と 2.0 にする
launch ファイル上の 3 つを付けて、複数のノードをまとめて起動する4 つのノードを 1 回で起動する

コードを変えずに、つなぎ方と設定だけで違う仕事をさせられることが、ROS 2 でノードを小さく分けて作る理由の 1 つです。

トップへ戻る