ROS 2 実践コース|#04 設計シートを書いて AI に作らせ、ツールで確かめる

前の回では、トピックは名前と型が合えばつながり、合わなくてもエラーが出ないことを確かめました。この回では、自分でノードを 2 つ作ります。ただし、コードは AI に書かせてかまいません。自分でやるのは、何を作るかを決めることと、できたものが決めたとおりかを確かめることです。

課題:「1 秒に 2 回、0 から数を数えて送るノード」と、「受け取った数が偶数のときだけ表示するノード」を作る。

この回の流れ。1 と 4 を自分で行い、2 は AI に任せる
この回の流れ。1 と 4 を自分で行い、2 は AI に任せる
順やること記事の節
1設計シートを 2 ノード分書く(分からない欄は、AI に聞き返してもらいながら自分で決める)1
2AI にコードを書かせ、パッケージに入れる2・3
3ビルドして動かす4
4ツールで調べ、設計シートと並べて記録する5
5隣の人の設計シートから送るノードを作り、自分の受けるノードとつなぐ6

この先の本文で「5 で確かめます」のように数字だけで書いたところは、右の列の記事の節の番号です。

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

この回で撮っておく画面

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

  • TZ=Asia/Tokyo date の画面
  • ros2 topic info -v /count(型と送り手・受け手)
  • ros2 topic hz /count の average rate
  • ros2 node info /counter
  • 受ける側の端末(偶数だけ出ていること)
  • 隣の学生の設計シートから作った送るノードと、自分の受けるノードを動かしたときの、受ける側の表示

1. 設計シートを書く

AI に「数を数えるノードを作って」とだけ頼むと、トピック名や型、周期は AI が決めてしまいます。それで動いたとしても、ほかの人が作ったノードとつながるとは限りません。そこで、つながりに関わることを先に自分で決めて、シートに書きます。1 ノードにつき 1 枚です。

■ ノード名:

■ このノードの仕事(1 文):

■ 受け取るもの
  トピック名 | 型 | QoS(reliable / best effort) | 期待する周期
  -----------|----|-----------------------------|-------------
             |    |                             |

■ 出すもの
  トピック名 | 型 | QoS | 周期
  -----------|----|-----|-----
             |    |     |

■ パラメータ
  名前 | 型 | 初期値 | 単位 | 意味
  -----|----|--------|------|-----
       |    |        |      |

■ 座標系(使うときだけ):

■ 止まる条件(速度指令を出すノードは必ず書く):
  例)入力が 1 秒以上届かなければ、速度 0 を出す

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

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

シートに出てくる QoS は、データの届け方の約束です。いまは 2 つだけ覚えてください。reliable は「届くまで送り直す」、best effort は「届かなくても、そのまま次へ進む」です。数えた数のように 1 つも落としたくないものは reliable、センサーの値のように新しいものが次々に来るものは best effort にします。送る側と受ける側でここが食い違うと、名前と型が合っていてもつながりません。この回は、どちらのノードも reliable にします(詳しくは #09 で扱います)。

座標系は、位置や向きの値が「どこを基準にした値か」を表す名前です。この回では位置を扱わないので、空欄のままでかまいません。

書き方の例:counter(数を数えて送るノード)

はじめてだと、どの欄に何を書けばよいか分からないと思います。そこで、送る側の counter を例に、1 欄ずつ書き方を説明します。書き終わったシートは次のようになります。

■ ノード名:counter

■ このノードの仕事(1 文):0 から 1 ずつ増える整数を、1 秒に 2 回送る。

■ 受け取るもの:なし

■ 出すもの
  トピック名 | 型                  | QoS      | 周期
  -----------|---------------------|----------|------
  /count     | std_msgs/msg/Int32  | reliable | 2 Hz

■ パラメータ
  名前   | 型    | 初期値 | 単位 | 意味
  -------|-------|--------|------|---------------
  rate   | float | 2.0    | Hz   | 送る周期
  start  | int   | 0      | ―    | 数え始める値

■ 座標系:使わない

■ 止まる条件:速度指令を出さないので不要

■ 検証の方法:
  1. ros2 topic hz /count → average rate が 2.0 前後
  2. ros2 topic echo /count → data が 0, 1, 2, … と 1 ずつ増える
  3. ros2 run count_demo counter --ros-args -p start:=100 → data が 100 から始まる

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

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

欄counter で書いたこと何を書くか・なぜそう決めたか
ノード名counterノードに付ける名前です。ros2 node list にこの名前で出ます(#03 の talker・listener と同じ)。仕事が分かる短い英語にします。
このノードの仕事0 から 1 ずつ増える整数を、1 秒に 2 回送る課題の文を 1 文で書きます。ここがはっきりしないと、ほかの欄が決まりません。
受け取るものなしほかのノードから受け取るトピックを書きます。counter は自分で数を作るので、何も受け取りません。
出すもの:トピック名/countデータを流す通り道の名前です(#03 の /chatter にあたります)。名前は自分で決めてかまいません。ただし受ける側(even_printer)の「受け取るもの」と一字一句同じにします。
出すもの:型std_msgs/msg/Int32送るデータの形です。整数を 1 つ送るので Int32(#03 の実験 4 で送った型)にします。文字列なら std_msgs/msg/String(#03 の talker が送っていた型)です。
出すもの:QoSreliable上で説明した届け方の約束です。数えた数は 1 つも落としたくないので reliable にします。
出すもの:周期2 Hz1 秒に何回送るかです。Hz(ヘルツ)は「1 秒あたりの回数」なので、1 秒に 2 回は 2 Hz です。
パラメータrate(2.0 Hz)と start(0)コードを書きかえずに、起動するときに外から変えられる値です。送る周期 rate と、数え始める値 start をパラメータにしておくと、5 で -p start:=100 のように変えて試せます。型の float は小数、int は整数です。
座標系使わない位置や向きを扱わないので書きません。
止まる条件不要ロボットを動かす速度指令を出すノードだけ、必ず書きます。counter は数を送るだけなので要りません。
検証の方法3 つのコマンドと、期待する結果できたノードが設計どおりかを、どのコマンドで確かめるかを先に決めておきます。ros2 topic hz などは #03 で使いました。ここに書いたことを、5 で実際に確かめます。
使った AI とプロンプト(ここに書く)設計シートを AI と対話して埋めたときのプロンプトと、聞き返されて決めたこと、3 で AI にコードを頼んだときのプロンプトを書きます。

自分で書く:even_printer(偶数だけを表示するノード)

同じ書き方で、受ける側の even_printer のシートを自分で書いてください。counter との違いは、「受け取るもの」があって「出すもの」がないことです。受け取るもののトピック名・型・QoS・周期は、counter の「出すもの」を見て決めます。

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

分からない欄があっても、空欄のまま AI に「書いて」と頼んではいけません。AI が勝手に決めた値になり、自分で決めたことになりません。かわりに、AI に質問役をしてもらい、対話しながら埋めていきます。AI が 1 欄ずつ聞いてくるので、自分で答えます。分からなければ「分からない」と答えると、その欄の意味と選び方の手がかりを説明してから、もう一度聞いてくれます。

書けたところまでのシートと counter のシートを、次のプロンプトに貼って AI に渡します。

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

作るノード:受け取った整数が偶数のときだけ、画面に表示するノード(ROS 2 Humble・Python)
つなぐ相手:counter というノード。counter の設計シートは次のとおりです。
(ここに counter の設計シートを貼る)

私が書いたところまでの設計シート:
(ここに書きかけのシートを貼る)

やりとりの進め方です。

  1. AI の質問に、自分の言葉で答える。当てずっぽうで答えず、分からないときは「分からない」と言う
  2. 説明を読んでも納得できなければ、「なぜそうするのですか」「ほかの決め方はありますか」と聞き返す
  3. AI に「おかしい」と言われたら、どこが違ったかを考えてから答え直す
  4. 最後に AI が書き出したシートを、自分で確かめる。とくに「受け取るもの」のトピック名・型・QoS が、counter の「出すもの」と一字一句同じかを見る

AI の説明が正しいとは限りません。このシートが正しかったかどうかは、5 でコマンドを使って確かめます。使ったプロンプトと、聞き返されて決めたこと(「QoS を reliable にしたのは、偶数を 1 つも取りこぼしたくないから」など)は、シートの「使った AI とプロンプト」の欄に書いておきます。

記入例:even_printer(自分で書いてから開く)
■ ノード名:even_printer

■ このノードの仕事(1 文):/count で受け取った整数が偶数のときだけ、画面に表示する。

■ 受け取るもの
  トピック名 | 型                  | QoS      | 期待する周期
  -----------|---------------------|----------|-------------
  /count     | std_msgs/msg/Int32  | reliable | 2 Hz

■ 出すもの:なし

■ パラメータ:なし

■ 座標系:使わない

■ 止まる条件:速度指令を出さないので不要

■ 検証の方法:
  1. ros2 node info /even_printer → Subscribers に /count: std_msgs/msg/Int32
  2. counter と一緒に動かす → 0, 2, 4, … と偶数だけが表示される

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

ポイントは、送る側の「出すもの」と受ける側の「受け取るもの」の行が、トピック名も型も一字一句そろっていることです。ここがそろっていれば、コードを誰が書いてもつながります。

2. パッケージを作る

ROS 2 のノードは、ファイル 1 つで動かすのではなく、パッケージという入れ物に入れて使います。そして、そのパッケージを置く場所がワークスペースです。

この環境では、ワークスペースとして ~/ros2_ws が最初から用意されています。自分でフォルダを作る必要はありません。パッケージは、その中の src に作ります。作業はすべて、下の図の 3 つの段階をたどります。

ワークスペースの中身は、作業を進めるにつれて増えていきます。自分で書くのは src の中だけで、ほかは colcon build が作ります
ワークスペースの中身は、作業を進めるにつれて増えていきます。自分で書くのは src の中だけで、ほかは colcon build が作ります

では、src に移動して、Python のパッケージ count_demo を作ります(cd は #02 の「4. Linux のフォルダの形」「8. フォルダを移動する(cd)」)。

cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python --node-name counter count_demo --dependencies rclpy std_msgs
ros2 pkg create を実行したところ。作られたファイルの名前が順に表示されます
ros2 pkg create を実行したところ。作られたファイルの名前が順に表示されます
find count_demo -type f | sort
できあがったファイルの一覧。--node-name counter を付けたので、ひな形の counter.py も入っています
できあがったファイルの一覧。--node-name counter を付けたので、ひな形の counter.py も入っています
ワークスペース全体から見たところ。~/ros2_ws にはまだ src しかなく、その中に count_demo が 1 つあるだけです
ワークスペース全体から見たところ。~/ros2_ws にはまだ src しかなく、その中に count_demo が 1 つあるだけです
ファイル役目
package.xmlパッケージの名前と、使うほかのパッケージ(rclpy・std_msgs)を書く
setup.pyros2 run で起動できる実行ファイルの名前を登録する
count_demo/counter.pyノードのコード。ここを AI が書いたものに置き換える

3. AI にコードを書かせる

この節では、1 で書いた 2 枚の設計シートを AI に渡してコードを書かせ、2 で作ったパッケージ count_demo の中に入れます。やることは次の 4 つです。

  1. AI に頼む(counter と even_printer の 2 回)
  2. 返ってきたコードを、設計シートと突き合わせる
  3. コードを VSCodium に貼って保存する(counter.py はひな形を上書き、even_printer.py は新しく作る)
  4. setup.py に even_printer を登録する

ここまで終われば、次の 4 でビルドして動かせます。

3-1. AI に頼む

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

次の設計シートどおりに、ROS 2 Humble で動く Python(rclpy)のノードを書いてください。
パッケージ名は count_demo、ファイルは count_demo/counter.py です。
設計シートにないトピックやパラメータは足さないでください。

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

counter のコードが返ってきたら、もう 1 回頼みます。even_printer を頼むときは、プロンプトのファイル名を count_demo/even_printer.py にして、even_printer の設計シートを貼ります。

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

AI が返したコードの一例(自分で AI に頼んでから開く)

counter.py

"""0 から 1 ずつ増える整数を /count に送るノード。"""
import rclpy
from rclpy.node import Node
from std_msgs.msg import Int32


class Counter(Node):
    def __init__(self):
        super().__init__('counter')
        self.declare_parameter('rate', 2.0)   # 送る周期 [Hz]
        self.declare_parameter('start', 0)    # 数え始める値
        rate = self.get_parameter('rate').value
        self.value = self.get_parameter('start').value
        self.publisher = self.create_publisher(Int32, 'count', 10)
        self.timer = self.create_timer(1.0 / rate, self.on_timer)

    def on_timer(self):
        msg = Int32()
        msg.data = self.value
        self.publisher.publish(msg)
        self.get_logger().info(f'送信: {msg.data}')
        self.value += 1


def main(args=None):
    rclpy.init(args=args)
    node = Counter()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        rclpy.try_shutdown()


if __name__ == '__main__':
    main()

even_printer.py

"""/count で受け取った数が偶数のときだけ表示するノード。"""
import rclpy
from rclpy.node import Node
from std_msgs.msg import Int32


class EvenPrinter(Node):
    def __init__(self):
        super().__init__('even_printer')
        self.subscription = self.create_subscription(Int32, 'count', self.on_count, 10)

    def on_count(self, msg):
        if msg.data % 2 == 0:
            self.get_logger().info(f'偶数: {msg.data}')


def main(args=None):
    rclpy.init(args=args)
    node = EvenPrinter()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        rclpy.try_shutdown()


if __name__ == '__main__':
    main()

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

返ってきたコードを、パッケージに入れる前に設計シートと 1 行ずつ突き合わせます。見るところは次の 4 つです。

  • create_publisher(Int32, 'count', 10):型が Int32、トピック名が count。シートの「出すもの」と同じか
  • create_timer(1.0 / rate, ...):rate が 2.0 なら 0.5 秒ごと。シートの周期と同じか
  • declare_parameter('start', 0):シートのパラメータ名と初期値が同じか
  • create_subscription(Int32, 'count', ...)(even_printer):シートの「受け取るもの」と型・トピック名が同じか

説明できない行があったら、そのままにせず AI に「この行は何をしていますか」と聞き返してください。

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

counter.py は、2 でパッケージを作ったときにひな形ができています。これを開き、中身をすべて AI のコードに置き換えて、Ctrl+S で保存します。VSCodium の使い方と、保存しないとファイルが変わらないことは #02 の「13. ファイルを書きかえる(VSCodium)」で練習しました。

codium ~/ros2_ws/src/count_demo/count_demo/counter.py

AI の答えは Windows 側のブラウザに出るので、そのままではデスクトップの中に貼り付けられません。#00 の「4. ブラウザのデスクトップの使い方」と同じように、Windows でコピーしたコードを noVNC のクリップボードの入力欄に貼ってから、VSCodium の中で Ctrl+V を押します。

VSCodium で count_demo のフォルダを開き、counter.py を AI が書いたコードに置き換えたところ
VSCodium で count_demo のフォルダを開き、counter.py を AI が書いたコードに置き換えたところ

even_printer.py のほうは、まだ存在しないファイルです。ですが、先にファイルを作っておく必要はありません。まだ無い名前を付けて codium を実行すると、その名前の新しいファイルとして開きます。

codium ~/ros2_ws/src/count_demo/count_demo/even_printer.py
まだ無い even_printer.py を、名前を付けて開いたところ。中身は空で、タブの名前の横に白い丸(●)が付いています。この時点では、ファイルはまだできていません。コードを貼り付けて <strong>Ctrl+S で保存すると、はじめてファイルができます</strong>
まだ無い even_printer.py を、名前を付けて開いたところ。中身は空で、タブの名前の横に白い丸(●)が付いています。この時点では、ファイルはまだできていません。コードを貼り付けて Ctrl+S で保存すると、はじめてファイルができます

3-4. setup.py に even_printer を登録する

counter はパッケージを作ったときに登録されていますが、あとから足した even_printer は自分で登録します。setup.py を開き、console_scripts に 1 行足して保存します(1 行目の最後のカンマを忘れないでください)。

codium ~/ros2_ws/src/count_demo/setup.py
    entry_points={
        'console_scripts': [
            'counter = count_demo.counter:main',
            'even_printer = count_demo.even_printer:main'
        ],
    },

保存したら、2 行とも入ったかを確かめます。grep は、ファイルの中から指定した文字を含む行を探して表示するコマンドです。-n で行番号を付け、-A4 でその下の 4 行もいっしょに出します。

grep -n -A4 console_scripts ~/ros2_ws/src/count_demo/setup.py
grep で確かめたところ。27 行目と 28 行目に 2 つのノードが登録されています
grep で確かめたところ。27 行目と 28 行目に 2 つのノードが登録されています

登録を忘れると、ビルドは通っても ros2 run count_demo even_printer で「No executable found」と表示されます。

4. ビルドして動かす

コードを書いただけでは、ros2 run では動きません。ビルドという作業をして、書いたコードを「ROS 2 から呼び出せる形」に整える必要があります。それをするのが colcon build です。

cd ~/ros2_ws && colcon build --symlink-install && source install/setup.bash

&& は、「左が成功したら、続けて右を実行する」という意味です。ここでは 3 つのコマンドを 1 行にまとめています。途中で失敗すれば、そこで止まります。1 つずつ順に打っても同じことです。

ビルドが終わると Summary: 1 package finished と表示されます
ビルドが終わると Summary: 1 package finished と表示されます

ビルドが終わると、~/ros2_ws の中に build・install・log の 3 つのフォルダが増えています。中を開く必要はありませんが、ros2 run が探しに行くのは install の中だ、というのは覚えておいてください。

左:ビルドする前。src しかありません。右:ビルドしたあと。build・install・log が増えています
左:ビルドする前。src しかありません。右:ビルドしたあと。build・install・log が増えています

--symlink-install を付けておくと、Python のファイルを直したときにビルドし直さなくても反映されます。ただし setup.py を変えたときは、必ずビルドし直してください。

ビルドしたあとに開いた端末では、作ったパッケージがそのまま使えます。講義用の環境では、端末を開くときに ~/ros2_ws/install を自動で読み込むようにしてあるからです。気をつけるのはビルドより前から開いていた端末で、そちらには新しいパッケージのことが伝わっていません。その端末で source ~/ros2_ws/install/setup.bash を打つか、端末を開き直してください。なぜそうなるのかは #02 の「14. 環境変数と source」に書いてあります。

# 端末 1
source ~/ros2_ws/install/setup.bash
ros2 run count_demo counter
# 端末 2
source ~/ros2_ws/install/setup.bash
ros2 run count_demo even_printer

打つ前に、端末 2 にどの数がどんな間隔で出るかを、2 枚の設計シートから予想しておきます(レポートでは、5 の表の「偶数だけ表示する」の行の「設計で決めた値」に書きます)。

結果を見る(予想を書き、自分で実行してから開く)
左の counter が 0, 1, 2, … を送り、右の even_printer が偶数だけを表示しています
左の counter が 0, 1, 2, … を送り、右の even_printer が偶数だけを表示しています

うまくいかないとき

ここが、いちばんつまずくところです。「直したのに変わらない」と思ったら、下の 4 つのうち、どれかが抜けていないかを確かめてください。

直す → 保存 → ビルド → 実行。どれを飛ばすと、何が起きるか
直す → 保存 → ビルド → 実行。どれを飛ばすと、何が起きるか

よく出る 2 つのエラーは、画面を覚えておくと早く気づけます。どちらも「壊れた」わけではないので、あわてなくて大丈夫です。

Package 'count_demo' not found。<strong>ビルドより前から開いていた端末</strong>で ros2 run を打つと、こうなります。その端末で source ~/ros2_ws/install/setup.bash を打つか、端末を開き直してください
Package 'count_demo' not found。ビルドより前から開いていた端末で ros2 run を打つと、こうなります。その端末で source ~/ros2_ws/install/setup.bash を打つか、端末を開き直してください
No executable found。パッケージは見つかっているのに、その中に even_printer が無い、という意味です。setup.py への登録を忘れたか、登録したあとにビルドし直していません
No executable found。パッケージは見つかっているのに、その中に even_printer が無い、という意味です。setup.py への登録を忘れたか、登録したあとにビルドし直していません

もう 1 つ、知っておいてほしいことがあります。--symlink-install を付けた Python のパッケージでは、colcon build は Python の書き間違いを見つけてくれません。コードの中身が壊れていても、ビルドは 1 package finished と表示されて通ってしまいます。書き間違いが分かるのは、ros2 run で動かしたときです。つまり、「ビルドが通った」は「コードが正しい」ではありません。

5. ツールで調べ、設計シートと並べる

「動いた」で終わりにせず、設計シートに書いたとおりになっているかを、前の回で使ったコマンドで 1 つずつ確かめます。

コマンドを打つ前に、設計シートを見て「何が表示されるはずか」を書いておきます(下の表の「設計で決めた値」の列)。結果の画面は「結果を見る」をクリックすると開きます。予想を書き、自分で実行してから開いてください。

端末 1 の counter と端末 2 の even_printer は動かしたままにして、このあとのコマンドは 3 つめの端末で打ちます。

ノードが出しているもの

ros2 node info /counter

表の「ノードの入出力」の行を書くために、受ける側も同じように ros2 node info /even_printer で調べます。

結果を見る(予想を書き、自分で実行してから開く)
Publishers に /count: std_msgs/msg/Int32 があります。シートの「出すもの」と同じか見比べます
Publishers に /count: std_msgs/msg/Int32 があります。シートの「出すもの」と同じか見比べます

トピックの相手と QoS

ros2 topic info -v /count
結果を見る(予想を書き、自分で実行してから開く)
-v を付けると、つながっている相手のノード名と QoS まで表示されます。Reliability: RELIABLE がシートの QoS と合っています
-v を付けると、つながっている相手のノード名と QoS まで表示されます。Reliability: RELIABLE がシートの QoS と合っています

届いている周期

ros2 topic hz /count
結果を見る(予想を書き、自分で実行してから開く)
average rate: 2.000。シートの周期 2 Hz のとおりです
average rate: 2.000。シートの周期 2 Hz のとおりです

グラフ

rqt_graph
結果を見る(予想を書き、自分で実行してから開く)
/counter → /count → /even_printer とつながっています
/counter → /count → /even_printer とつながっています

パラメータ

counter を Ctrl+C で止め、数え始める値を 100 にして起動し直します。コードは変えません。

ros2 run count_demo counter --ros-args -p start:=100
結果を見る(予想を書き、自分で実行してから開く)
-p start:=100 を付けると、100 から数え始めます。右の even_printer は起動したままです
-p start:=100 を付けると、100 から数え始めます。右の even_printer は起動したままです

結果は、設計シートと並べて次のように記録します。レポートの第 2 回「B」の表と同じ行です。「設計で決めた値」は自分の設計シートから写し、「実際の値」は画面に出たとおりに写します。

設計シートの項目確かめるコマンド・方法設計で決めた値実際の値一致?
送るトピックの名前と型ros2 topic info -v /count
周期(2 Hz)ros2 topic hz /count
ノードの入出力ros2 node info /counter と /even_printer
偶数だけ表示する受ける側の端末の表示
記入例(自分の表を書いてから開く)
設計シートの項目確かめるコマンド・方法設計で決めた値実際の値一致?
送るトピックの名前と型ros2 topic info -v /count/count・std_msgs/msg/Int32・reliable/count・std_msgs/msg/Int32・RELIABLE○
周期(2 Hz)ros2 topic hz /count2 Hzaverage rate: 2.000○
ノードの入出力ros2 node info /counter と /even_printercounter が /count を出し、even_printer が /count を受けるPublishers と Subscribers に /count: std_msgs/msg/Int32○
偶数だけ表示する受ける側の端末の表示0, 2, 4, … だけ0, 2, 4, 6, 8○

パラメータ start のように、表にない項目も確かめたときは、行を足して書いてかまいません。

6. 隣の人の設計シートでつなぐ

最後に、隣の人と「送るノード」の設計シートを 1 枚ずつ交換します。コードは見せ合いません。受け取ったシートだけを AI に渡して、相手の送るノードを自分の PC で作り、自分の受けるノード(even_printer)とつなぎます。シートに書いてあることだけで同じノードが作れて、つながるか。それが、設計シートの出来を確かめることになります。

講義の環境は PC ごとに分かれているので、隣の PC で動いているノードとは直接つながりません。そのため、相手のノードを自分の PC で作り直します。

  1. 自分の counter を Ctrl+C で止めておく(動いたままだと、どちらのノードから届いたのか分からなくなる)
  2. 隣の人の設計シートを、下のプロンプトの最後に貼って AI に渡す
  3. codium ~/partner_sender.py で開き、返ってきたコードを貼り付けて Ctrl+S で保存する
  4. 端末 1 で python3 ~/partner_sender.py、端末 2 で ros2 run count_demo even_printer を実行する
  5. 偶数が表示されなければ、ros2 topic list と ros2 topic info -v で調べ、2 枚の設計シートを並べて食い違った行を探す
次の設計シートどおりに、ROS 2 Humble で動く Python(rclpy)のノードを書いてください。
パッケージは作らず、1 つのファイル partner_sender.py にしてください。
python3 partner_sender.py で起動できるようにしてください。
設計シートにないトピックやパラメータは足さないでください。

(ここに隣の人の「送るノード」の設計シートを貼る)

partner_sender.py はパッケージに入れていないので、ビルドは要りません。python3 で直接動かせます。

食い違っていたらどうなるか

隣の人とつながった人も、ここから先の再現手順をやってください。わざと食い違わせたとき何が起きるかを、自分の目で見ておくためです。ひとりで学んでいる人は、ここから先の再現手順だけをやってください。1 台で同じことが確かめられます。

ここでは、相手のシートではトピック名が /number だった場合を、remap(名前のつなぎ替え)を使って再現します。--ros-args -r 元の名前:=新しい名前 の書き方は、#03 の「実験 3」に書いてあります。

# 端末 1
ros2 run count_demo counter
# 端末 2(受ける側が /number を待っている状態を再現する)
ros2 run count_demo even_printer --ros-args -r count:=number

端末 3 のコマンドを打つ前に、端末 2 の even_printer に数が表示されるか、ros2 topic info /number に何が出るかを予想して、レポートの第 2 回の「食い違いの再現」の欄に書いてください。

# 端末 3
ros2 topic list
ros2 topic info /number
結果を見る(予想を書き、自分で実行してから開く)
counter は /count に送り、even_printer は /number を待っています。/number の Publisher count は 0 で、どちらのノードにもエラーは出ていません
counter は /count に送り、even_printer は /number を待っています。/number の Publisher count は 0 で、どちらのノードにもエラーは出ていません

前の回の実験 4 と同じで、つながらなくても何も知らせてくれません。原因はコードを読まなくても、2 人の設計シートの「トピック名」の行を並べればすぐに見つかります。コードを見せ合わなくても、契約(名前・型・周期)が合っていればつながり、合っていなければつながらない、ということです。

本質の問い

授業の最後に、次の問いに答えてください。

  • コードを見せ合わずにつながった(または、つながらなかった)のはなぜか。設計シートのどの行が効いたかを答える。

レポートに書くもの

この回の記録は、コースの最後に出す実習レポートの第 2 回の欄に書きます。毎回出すものではありません。

  1. 設計シート(2 ノード分。レポートの付録をコピーして使う)
  2. 設計シートと調べた結果を並べた表(5 の表と同じ形)
  3. 隣の人の設計シートから作ったノードとつないだ結果。つながらなかった場合は、設計シートのどこが食い違っていたか
  4. 食い違いの再現(remap で /number にしたとき)の予想と結果
  5. 本質の問いの答え

まとめ

  • AI に渡す前に、トピック名・型・周期・パラメータを設計シートに書く
  • できたノードは、ros2 node info・topic info -v・topic hz・rqt_graph で調べ、設計シートと並べて確かめる
  • つながらないときは、コードより先に設計シートどうしを見比べる

次の回からは第 2 週です。turtlesim を使って、トピックのほかにサービスとアクションという通信の形を試し、名前空間でノードを分ける方法を調べます。

トップへ戻る