ROS 2 実践コース|#08 安全の層を理解してから歩かせる

前の回の実験 5 では、接続を切ってもデータを受ける側はエラーを出さず、ただ待ち続けることを確かめました。この回は、PC からロボットへ速度指令 /cmd_vel を送ります。速度指令が途中で途切れたら、ロボットは最後に受け取った速度のまま歩き続けるかもしれません。

そこで、いきなり歩かせるのではなく、次の順に進めます。

  1. /cmd_vel がロボットの中のどこを通るかを調べる(実験 1・2)
  2. ロボットに出さずに、止まるしくみを数字で確かめる(実験 3 の前半)
  3. 囲いの中の床で、脚が止まるまでの時間を測る(実験 3 の後半)
  4. 周りの安全を確かめてから(授業では先生の合図で)、床の上に正方形を歩かせる(実験 4)

ロボットを動かすのは、授業では先生が「始めてよい」と言ってからです。ひとりで学ぶ人は、ほかの人に見ていてもらい、すぐに電源を切れるようにしてから動かします。実験 1・2 と実験 3 の前半は、ロボットを机の上に置いたまま、動かさずに進めます。

この回で予想することは、次の表のとおりです。各実験の結果の画面と説明は、「結果を見る」をクリックすると開きます。予想を書き、自分で実行してから開いてください。ただし、ロボットを動かすときの注意は、開かなくても読めるところに書いてあります。

実験予想すること手がかり
1. /cmd_vel はどこへ行くかPC で /cmd_vel を受け取っているのは誰か#07 の実験 1・2。PC にはロボットのノードが見えず、ブリッジがトピックを運んでいた
3. 止まるしくみを確かめるA〜E の 5 つの場面で、送られる指令と脚がどうなるか実験 2 の cmd_vel_guard のパラメータとコード。#07 の実験 5(切れても受ける側はエラーを出さない)
4. 床の上で正方形を歩かせる1 辺の長さが指令どおりになるか。スタート地点に戻ってくるか#06 で turtlesim の亀に描かせた正方形。1 辺は「速さ × 時間」で決めていた

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

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

この回で撮っておく画面

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

  • TZ=Asia/Tokyo date と、つないだ直後の robot-status
  • ros2 topic info -v /cmd_vel(受け手が PC 側のブリッジだけであること)
  • 机の上で、キーを押したときの ros2 topic echo /cmd_vel_test
  • 前半の E で linear.x: 2.0 を送ったときの ros2 topic echo /cmd_vel_test(PC の中では 2.0 のまま届くこと。上限で切るのはロボットの中の cmd_vel_guard)
  • 安全の層の図(手描きでよい。写真)
  • 床で歩いたあとの、スタート地点とゴール地点(写真。メジャーが写るように)

準備 ロボットにつなぐ

前の回と同じように、ホットスポットをオンにしてロボットの電源を入れ、OLED の 4 行目が ROS: ready (no PC) になったらつなぎます。IP が前の回と同じなら、IP を省けます。

robot-connect

OLED の 2 行目の IP が前の回と違うときは、robot-connect 192.168.137.134 のように IP を付けて実行します。

つながったら、日時とつながり具合を表示し、画面を撮っておきます(撮る画面の 0)。

TZ=Asia/Tokyo date
robot-status

実験 1 /cmd_vel はどこへ行くか

この実験では、次の 3 つをします。

  1. PC で /cmd_vel を受け取っているのが誰かを調べる
  2. 先生がロボットの中で調べた結果を読み、その先を追いかける
  3. /cmd_vel がどこを通って脚に届くかを、自分で図に描く(レポートに写真で貼る)

PC で、名前に cmd_vel を含むトピックを探し、/cmd_vel を受け取っているのが誰かを調べます。|(パイプ)は、左のコマンドの出力を右のコマンドに渡す記号です。grep cmd_vel は、渡された行のうち cmd_vel を含む行だけを表示します。ros2 topic info に -v を付けると、送る側・受ける側のノードの名前まで詳しく出ます。

打つ前に、受け取っているのは誰かを予想してください。#07 の実験 2 で、PC の ros2 node list に何が出たかが手がかりです。

ros2 topic list | grep cmd_vel
ros2 topic info -v /cmd_vel
結果を見る(予想を書き、自分で実行してから開く)
PC から見える速度指令のトピックは /cmd_vel だけ。受け取っている(Subscription)のは zenoh_bridge_pc の 1 つで、送っている(Publisher)ノードはまだありません
PC から見える速度指令のトピックは /cmd_vel だけ。受け取っている(Subscription)のは zenoh_bridge_pc の 1 つで、送っている(Publisher)ノードはまだありません

PC から見ると、/cmd_vel を受け取っているのはブリッジだけです。ブリッジは受け取った指令を Wi-Fi でロボットに運びます。

ブリッジの先は、PC からは見えません。そこで、先生がロボットの中で同じようなコマンドを実行した結果で追いかけます。Reliability や History (Depth) の行は QoS(#04 の設計シートで書いた、届け方の約束)で、第 4 週で詳しく調べます。いまは Node name の行と、送る側(PUBLISHER)か受ける側(SUBSCRIPTION)かだけを見れば十分です。

$ ros2 topic list | grep cmd_vel
/cmd_vel
/cmd_vel_safe
$ ros2 topic info -v /cmd_vel_safe
Type: geometry_msgs/msg/Twist

Publisher count: 1

Node name: cmd_vel_guard
Endpoint type: PUBLISHER
  Reliability: RELIABLE
  History (Depth): KEEP_LAST (10)

Subscription count: 1

Node name: yahboom_base
Endpoint type: SUBSCRIPTION
  Reliability: RELIABLE
  History (Depth): KEEP_LAST (1)

ロボットの中には、PC からは見えなかった /cmd_vel_safe というトピックがあります。送っているのは cmd_vel_guard、受け取っているのは yahboom_base です。

$ ros2 node info /yahboom_base
/yahboom_base
  Subscribers:
    /cmd_vel_safe: geometry_msgs/msg/Twist
  Publishers:
    /parameter_events: rcl_interfaces/msg/ParameterEvent
    /rosout: rcl_interfaces/msg/Log

yahboom_base は、ロボットの脚を動かすマイコンに歩き方の指令を出すノードです。このノードが聞いているのは /cmd_vel_safe だけで、/cmd_vel は聞いていません。

安全の層を図に描く

ここまでに分かったことを、紙に図で描きます。答えの図を見る前に自分で描くことで、どこが分からないかがはっきりします。#03 の rqt_graph と同じように、ノードは丸、トピックは四角で描き、矢印でつなぎます。

描くもの何を描くかなぜ描くか
PC のノード/cmd_vel を送るノード(まだ無いので「自分のノード」と書く)と zenoh_bridge_pc指令の出発点
ロボットのノードロボット側のブリッジ、cmd_vel_guard、yahboom_base指令が通る順番を見るため
トピック/cmd_vel と /cmd_vel_safe。どちらをどのノードが送り、どのノードが受けるかを矢印で上の実行結果の PUBLISHER と SUBSCRIPTION から読み取れる
境目の線PC とロボットの間(Wi-Fi)に線を引き、PC から見えたもの・見えなかったものが分かるようにする#07 で、PC から見えないものがあると分かったため

描いたら、写真に撮ってレポートの第 6 回の「安全の層の図」の欄に貼ります。図から分かったことも、その下に書きます。

図の例(自分で描いてから開く)
PC の /cmd_vel は、ロボットの中の cmd_vel_guard を通って /cmd_vel_safe になり、歩行ノード yahboom_base に届く
PC の /cmd_vel は、ロボットの中の cmd_vel_guard を通って /cmd_vel_safe になり、歩行ノード yahboom_base に届く

PC から送った速度指令は、必ず cmd_vel_guard を通ってから脚に届きます。yahboom_base に直接届く道はありません。

yahboom_base はもともと /cmd_vel を聞くように作られています。起動するときに remap(#06 で使ったつなぎ替え)で /cmd_vel_safe に変えてあります。コードを変えずにつなぎ替えるしくみが、ここでは安全のために使われています。

実験 2 cmd_vel_guard は何をしているか

ノードの設定値(パラメータ)を見ると、何をしているかの見当がつきます。ロボットの中で実行した結果です(2026 年 9 月に測定)。

$ ros2 param dump /cmd_vel_guard
/cmd_vel_guard:
  ros__parameters:
    max_angular_z: 1.5
    max_linear_x: 0.6
    max_linear_y: 0.45
    resend_period: 1.0
    timeout: 1.0
    use_sim_time: false
パラメータ値意味
max_linear_x0.6前後の速さの上限。これより大きい値が来たら 0.6 に切り詰める
max_linear_y0.45横の速さの上限
max_angular_z1.5旋回の速さの上限
timeout1.0/cmd_vel がこの秒数届かなければ、停止指令(速さ 0)を出す
resend_period1.0動いている間、同じ指令をこの秒数ごとに送り直す

コードの中心は次の部分です。AI に書かせたコードを読むときと同じように、上の表と対応する行を探してみてください。

# ファイルの上のほうにある関数
def clamp(value, limit):
    if not math.isfinite(value):
        return 0.0
    return max(-limit, min(limit, value))

# ……(ここからはクラスの中のメソッド)
    def on_input(self, linear_x, linear_y, angular_z, now):
        """cmd_vel を受け取ったとき。流すべき指令があれば (x, y, z) を返す。"""
        self.target = (
            clamp(linear_x, self.max_linear_x),
            clamp(linear_y, self.max_linear_y),
            clamp(angular_z, self.max_angular_z),
        )
        self.last_input_time = now
        self.timed_out = False
        return self._decide(now)

    def on_tick(self, now):
        """周期的に呼ぶ。途絶えていたら停止指令を返す。"""
        if (self.last_input_time is not None and not self.timed_out
                and now - self.last_input_time > self.timeout):
            self.timed_out = True
            self.target = ZERO
        return self._decide(now)
  • clamp は、値を -limit から limit の範囲に収めます。math.isfinite で、数でない値(無限大や NaN)が来たら 0 にしています。
  • on_input は /cmd_vel が届くたびに呼ばれ、届いた時刻を last_input_time に覚えます。
  • on_tick は 0.05 秒ごとに呼ばれ、最後に届いてから timeout を過ぎていたら、目標を 0(ZERO)にします。

考える:なぜ PC ではなくロボットの中に置くのか

速さを制限したり、途切れたら止めたりするだけなら、PC のノードに書いても同じことができそうです。なぜロボットの中に置いているのでしょうか。自分の考えを書いてから開いてください。

手がかり:#07 の実験 5 で接続を切ったとき、PC の側では何が起きたか。PC で /cmd_vel を送るノードは、この先だれが書くか。実験 1 で、PC から見えなかったものは何か。

考え方の例(自分の考えを書いてから開く)
  • Wi-Fi が切れたり、PC が止まったりすると、PC の中の見張り役ごと止まってしまい、停止指令を出せない。途切れたことに気づけるのは、受け取る側(ロボット)だけ。
  • PC のノードは、学生が書いたり AI に書かせたりして毎回変わる。どのノードが /cmd_vel を送っても、同じ上限と停止のしくみを必ず通るようにするには、受け口に 1 つ置くのがよい。
  • cmd_vel_guard と /cmd_vel_safe はブリッジの許可リストに入れていないので、PC から見えず、PC から /cmd_vel_safe に直接送ることもできない。

実験 3 止まるしくみを、数字で見てから床で測る

足を浮かせる台は使いません。かわりに、実験を 2 つに分けます。前半は、速度指令の出し先を /cmd_vel_test につなぎ替えて、ロボットに届かない状態にします。机の上に置いたままで脚は動かないので、「何が送られ、いつ送られなくなるか」を数字だけで落ち着いて見られます。

後半は、囲いの中の床で同じことをして、脚が実際に止まるまでの時間を測ります。床で動かすのは、先生の合図があってからです。

この実験は、次の順に進めます。前半でコマンドの打ち方と画面の見方に慣れておくと、床の上で慌てずにすみます。

  1. A〜E の 5 つの場面について、予想を書く(3-1)
  2. 前半:出し先を /cmd_vel_test にして、キーボードで指令を送り、数字を見る(A・B、3-2)
  3. 前半:出し先を /cmd_vel_test にして、コマンドで指令を送り続け、数字を見る(C・D・E、3-3)
  4. 後半:先生の合図のあと、出し先を /cmd_vel に戻して床で A〜E を行い、脚が止まるまでの時間を測る(3-4)

3-1. 予想する

まず、次の表の「予想」の列を書きます。実験 2 のパラメータとコードを手がかりにしてください。

番号すること予想(前半:送られる指令はどうなるか/後半:脚はどうなるか)結果(前半:机)結果(後半:床)
Aキーボード操作のノードで、前に進むキー i を 1 回だけ押す
Bi を押し続けている途中で、Ctrl+C でノードを止める
Cros2 topic pub で前に進む指令を送り続け、Ctrl+C で止める
DC と同じく送り続けている途中で、別の端末で robot-disconnect を実行する
E上限より大きい速さ(linear.x を 2.0)を送る

それぞれの行は、次のことを手がかりに考えます。

  • A:i を 1 回押すと、指令は 1 回だけ送られます(3-2 で説明します)。そのあと何も届かなくなったとき、cmd_vel_guard の timeout は何をするでしょうか。
  • B・C:ノードが Ctrl+C で終わるときに、最後に「止まれ」を送るかどうかは、まだ分かりません。送る場合と送らない場合の両方を考え、どちらだと思うかを書きます。
  • D:接続が切れても、受ける側はエラーを出さずに待ちます(#07 の実験 5)。待っている間に、cmd_vel_guard の on_tick は何をするでしょうか。
  • E:max_linear_x の値と、clamp のはたらきを見ます。
  • 前半の出し先 /cmd_vel_test は、実験 1 で描いた図のどこにもありません。cmd_vel_guard を通るかどうかを考えます。

レポートの第 6 回の実験 1〜3 の欄には、後半(床)で測った B・D・E を書きます(実験 1 が B、実験 2 が D、実験 3 が E)。

3-2. 前半:キーボードで送る(A・B)

teleop_twist_keyboard は、押したキーに応じて /cmd_vel を送るノードです。前半では、出し先を /cmd_vel_test につなぎ替えて起動します。--ros-args -r cmd_vel:=/cmd_vel_test は、#03 の実験 3 で使った「置きかえ」(-r A:=B)と同じ書き方で、「cmd_vel のかわりに /cmd_vel_test に送る」という意味です。ロボットの中に /cmd_vel_test を受け取るノードはいないので、キーを押しても脚は動きません。

# 端末 1。出し先をつなぎ替えるので、ロボットには届かない
ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r cmd_vel:=/cmd_vel_test
起動したところ。キーの割り当てが表示され、最後の行に今の速さ(speed 0.5・turn 1.0)が出ます
起動したところ。キーの割り当てが表示され、最後の行に今の速さ(speed 0.5・turn 1.0)が出ます

キーは、このノードを動かしている端末をクリックして選んでから押します。ほかのウィンドウを選んでいると、キーはノードに届きません。

キー動き
i前に進む
,(カンマ)後ろに進む
j / l左に回る / 右に回る
k止まる(割り当ての無いキーはすべて「止まる」になる)
z速さ(speed と turn)を 1 回につき 1 割下げる

teleop_twist_keyboard は、キーを 1 回押すごとに /cmd_vel を 1 回だけ送ります。押し続けたときに動き続けるのは、キーボードの「押しっぱなしで同じ文字を繰り返し入力する」はたらきで、何度も送っているからです。

端末をもう 1 つ開き、送られている指令を見ます。echo は、そのままだと 1 回ぶんが 9 行になって流れていきます。前後の速さだけを見たいときは、--field linear.x を付けると 1 行で出ます。

# 端末 2。送られている指令を見る
ros2 topic echo /cmd_vel_test --field linear.x
先に echo を打つと「型が分からない」と言われる

まだ誰も送っていないトピックを echo しようとすると、WARNING: topic [/cmd_vel_test] does not appear to be published yet、Could not determine the type for the passed topic と出て止まります。トピックの型は、送っている側から教わるものだからです。送る側を先に起動してから、見る側を起動してください。

  1. 端末 1 をクリックし、はじめに z を 7 回押して、最後の行の speed が 0.24 ぐらいになったことを確かめる。速さを半分以下にしておくと、床で動かしたときに止まるまでに進む距離が短くてすみます。後半で床に下ろすときは、必ずこれを先にします。
  2. A:i を 1 回だけ押し、端末 2 に何が出るかを見る。
  3. B:i を押し続け、押している途中で端末 1 の Ctrl+C を押す。端末 2 に最後に何が出たかを見る。
結果を見る(予想を書き、自分で実行してから開く)
前半のようす。左が teleop_twist_keyboard で、z を 7 回押したので、いちばん下の speed が 0.50 から <strong>0.24</strong> まで下がっています。右は出し先の /cmd_vel_test を見ている端末です。z を押したときは速さ 0 の指令が送られるので 0.0 が並び、i を 1 回押したところだけ 0.23914845… が出ています。<strong>左で下げた速さが、そのまま届いている</strong>のが読めます。脚は動きません。つなぎ替えてあるので、この数字はロボットに届いていないからです
前半のようす。左が teleop_twist_keyboard で、z を 7 回押したので、いちばん下の speed が 0.50 から 0.24 まで下がっています。右は出し先の /cmd_vel_test を見ている端末です。z を押したときは速さ 0 の指令が送られるので 0.0 が並び、i を 1 回押したところだけ 0.23914845… が出ています。左で下げた速さが、そのまま届いているのが読めます。脚は動きません。つなぎ替えてあるので、この数字はロボットに届いていないからです

前半の /cmd_vel_test は cmd_vel_guard を通りません。端末 2 に出るのは、送る側が送ったものそのままです。止まるしくみが脚にどう効くかは、後半で確かめます。

3-3. 前半:コマンドで送り続ける(C・D・E)

ros2 topic pub は、指定したトピックにメッセージを送り続けるコマンドです(#03 の実験 4 でも使いました)。--rate 10 は 1 秒に 10 回送る指定です。"{linear: {x: 0.2}}" は送る中身で、linear.x(前後の速さ)を 0.2、ほかは 0 にします。

前半では、出し先を /cmd_vel_test にして打ちます。teleop のときと違って --ros-args は要りません。トピックの名前を、そのまま書き替えるだけです。3-2 の端末 1 は Ctrl+C で止めておき、端末 2 の echo はいったん止めて、端末 1 を起動してからもう一度打ちます。

# 前半(端末 1)。出し先が違うので、ロボットには届かない
ros2 topic pub --rate 10 /cmd_vel_test geometry_msgs/msg/Twist "{linear: {x: 0.2}}"

# 前半(端末 2)
ros2 topic echo /cmd_vel_test --field linear.x
--rate を付けないとどうなるか

ros2 topic pub は、何も指定しないと 1 秒に 1 回送ります。cmd_vel_guard は 1.0 秒届かないと止めるので、送る間隔と止める時間がほぼ同じになり、動いたり止まったりをくり返すことがあります。送る側の周期は、受ける側の timeout より十分短くします。

  1. C:端末 2 に 0.2 が並んだら、端末 1 で Ctrl+C を押す。端末 2 の表示がどうなるかを見る。
  2. D:端末 1 のコマンドをもう一度動かし、3 つめの端末で robot-disconnect を実行する。端末 2 の表示が変わるかを見る。確かめたら、先に端末 1 を Ctrl+C で止めてから、robot-connect でつなぎ直す。
  3. E:端末 1 で、x を 0.6 にしたときと 2.0 にしたときを、1 つずつ送る。どちらも端末 2 の値を見たら Ctrl+C で止める。

D で先に端末 1 を止めるのは、後半のためです。送り続けたままつなぎ直すと、指令がまたロボットに届き、歩き出してしまいます。前半のうちから同じ順番で手を動かしておきます。

# 端末 3(D)
robot-disconnect

# 端末 3(D を確かめ、端末 1 を止めたあと)
robot-connect
# 端末 1(E)。1 つずつ実行し、それぞれ Ctrl+C で止める
ros2 topic pub --rate 10 /cmd_vel_test geometry_msgs/msg/Twist "{linear: {x: 0.6}}"
ros2 topic pub --rate 10 /cmd_vel_test geometry_msgs/msg/Twist "{linear: {x: 2.0}}"
結果を見る(予想を書き、自分で実行してから開く)
左が送っている側です。publishing #85、#86……と番号が増えていきます。--rate 10 なので、1 秒に 10 ずつ進む勘定です。右が見ている側で、--field linear.x を付けて前後の速さだけを 1 行ずつ出しました。0.2 がずっと並んでいます——<strong>送った linear.x が、そのまま届いている</strong>ということです。前半は出し先が /cmd_vel_test なので、この数字はロボットに届かず、脚は動きません
左が送っている側です。publishing #85、#86……と番号が増えていきます。--rate 10 なので、1 秒に 10 ずつ進む勘定です。右が見ている側で、--field linear.x を付けて前後の速さだけを 1 行ずつ出しました。0.2 がずっと並んでいます——送った linear.x が、そのまま届いているということです。前半は出し先が /cmd_vel_test なので、この数字はロボットに届かず、脚は動きません

前半では、D で接続を切っても端末 2 には 0.2 が出続け、E では 2.0 がそのまま出ます。送る側も見る側も PC の中にいて、/cmd_vel_test は cmd_vel_guard を通らないからです。上限や「届かなければ止める」が効くのは、/cmd_vel でロボットに送ったときだけです。

3-4. 後半:床で、脚が止まるまでを測る(先生の合図のあと)

ここからはロボットが歩きます。授業では、先生の合図があってから始めます。ひとりで学ぶ人は、ほかの人に見ていてもらいながら進めます。ロボットを囲いの中の床に下ろし、周りに人や物がないことを確かめます。止めたいときは、コマンドを打った端末で Ctrl+C を押します。それでも止まらないときは、ロボットの電源スイッチを切ります。

後半では、出し先を /cmd_vel に戻します。teleop_twist_keyboard は --ros-args から先を外し、ros2 topic pub はトピック名を /cmd_vel にします。手順は前半と同じです。teleop_twist_keyboard を起動したら、まず z を 7 回押して速さを下げてから A・B を行います。D は前半と同じく、端末 1 を止めてからつなぎ直します。

# A・B(端末 1)
ros2 run teleop_twist_keyboard teleop_twist_keyboard
# C・D(端末 1)
ros2 topic pub --rate 10 /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.2}}"

# D(端末 1 とは別の端末)
robot-disconnect

# D で脚が止まったのを確かめ、端末 1 を Ctrl+C で止めたあと(同じ端末)
robot-connect
# E(端末 1)。1 つずつ実行し、どちらも数秒見たら Ctrl+C で止める
ros2 topic pub --rate 10 /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.6}}"
ros2 topic pub --rate 10 /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0}}"

止まるまでの時間は、次のように測ります。

  • スマートフォンなどのストップウォッチを使います。Ctrl+C を押した瞬間(A では i を押した瞬間、D では robot-disconnect の Enter を押した瞬間)に計り始め、脚が止まった瞬間に止めます。操作する人と測る人を分けると測りやすいので、授業では隣の人と組みます。
  • ストップウォッチの押し遅れがあるので、0.1 秒の細かさは求めません。そのかわり、同じことを 3 回測り、3 つとも書きます。1 回だけだと、たまたまの値かどうかが分かりません。
  • E は時間ではなく、0.6 と 2.0 で速さに違いがあったかを比べます。同じくらいの時間送ったときに進んだ距離や、見た目の速さで比べ、どう比べたかも書きます。
  • レポートには、測った値と一緒に「何で測ったか」「何回測ったか」を書きます。
結果の見方(表の「結果」を書いてから開く)
番号止まり方止めているしくみ
A少し動いて、約 1 秒で止まるcmd_vel_guard の timeout(1 回しか届かないので、1.0 秒後に停止指令を出す)
BCtrl+C ですぐ止まるteleop_twist_keyboard が終わるときに、自分で速さ 0 の指令を送っている
CCtrl+C のあと、約 1 秒で止まるros2 topic pub は終わるときに何も送らない。cmd_vel_guard の timeout で止まる
D切断のあと、約 2 秒で止まるPC からの指令が届かなくなり、cmd_vel_guard の timeout で止まる。timeout は 1.0 秒なのに A・C より長くかかった。なぜ長くなるのかも考えてみてください
E2.0 を送っても、0.6 を送ったときより速くならないcmd_vel_guard が linear.x を 0.6 に切り詰める

B と C の違いに注目してください。止まるための指令を送ってくれるノードもあれば、送らないノードもあります。送る側がどう作られていても止まるように、受ける側の cmd_vel_guard が最後の砦になっています。

実験 4 床の上で正方形を歩かせる

授業では、ここは先生の合図があってから始めます。ひとりで学ぶ人も、ほかの人に見ていてもらいながら進めます。ロボットを床に下ろし、周り 1.5 m 以内に人や物がないことを確かめます。#06 の予告で考えてきた「ロボットに出すときの remap」の答え合わせもします。

この実験は、次の順に進めます。

  1. ロボットを床に下ろし、スタート地点に印を付ける
  2. 1 辺の長さと、スタート地点に戻ってくるかを予想する
  3. dog_square.launch.py で正方形を歩かせる
  4. 1 辺の長さ・向きのずれ・スタート地点とゴール地点の距離を測り、写真を撮る

4-1. スタート地点に印を付ける

ロボットの前足の先に合わせて床にテープを貼り、ロボットが向いている方向にもテープで線を引きます。歩き終わってから「どこから出発したか」を思い出すことはできないので、ずれを測るには、動かす前に印が要ります。

4-2. 予想する

linear_speed:=0.2 と side_time:=3.0 で歩かせるので、指令どおりなら 1 辺は 0.2 m/s × 3.0 秒 = 0.6 m です。#06 で亀に描かせた正方形と、#06 の「5. 課題に答える」の 3 番(レポートの第 4 回の問い 2)で「ロボットに出すとずれはどうなるか」と予想したことを思い出し、実際の 1 辺が 0.6 m より長くなるか短くなるか、スタート地点に戻ってくるかを書きます。

4-3. 歩かせる

床で歩かせる前に、新しく動かすノードが送る指令を、出し先を /cmd_vel_test に変えて確かめます。脚は動きません。1 つ目の端末で次を実行し、

ros2 run sakigake_samples square_walker --ros-args -p linear_speed:=0.2 -p side_time:=3.0 -r cmd_vel:=/cmd_vel_test

2 つ目の端末で、送られてくる前進の速さを見ます。

ros2 topic echo /cmd_vel_test --field linear.x

0.2 と 0.0 が交互に出て、1 周で終わることを確かめたら、両方の端末を Ctrl+C で止めます。続いて、サンプルの dog_square.launch.py で、#06 と同じ square_walker を床で起動します。

ros2 launch sakigake_samples dog_square.launch.py linear_speed:=0.2 side_time:=3.0

linear_speed:=0.2 と side_time:=3.0 は、launch の引数です。#06 ではパラメータを launch ファイルの中に書きましたが、ここではコマンドの後ろに 名前:=値 の形で書いて渡します。launch ファイルが受け取った値を、そのまま square_walker のパラメータにします。1 辺ぶん、速さ 0.2 の指令を 3 秒送ります。

turtlesim のときは cmd_vel を turtle1/cmd_vel に remap しました。ロボットは /cmd_vel を聞いている(実際にはブリッジが受け取って運ぶ)ので、この launch ファイルでは remap をしていません。

途中で止めたくなったら、launch の端末で Ctrl+C を押します。square_walker は終わるときに速さ 0 の指令を送ります。端末の操作が間に合わないときは、ロボットの電源スイッチを切ります。

4-4. 測って記録する

歩いている間は、ロボットに手を出さずに見ます。どの角で向きを変えたかは、床の目地を目印に覚えておくか、写真に撮っておきます。

記録すること測り方予想結果
1 辺の長さ(4 辺それぞれ)ロボットが向きを変えた位置どうしの間をメジャーで測る。4 辺で違うことがあるので、1 辺だけで済ませない
1 周したあとの向きのずれ(度)スタートで引いた向きの線と、止まったロボットの向きを比べる。真上から写真を撮り、あとで線を引いて測ってもよい
スタート地点とゴール地点の距離スタートのテープから、止まったロボットの前足の先までをメジャーで測る。写真にはメジャーも写るように撮る
正方形に見えたかどの角で、どちらにずれたかを見たまま書く
結果の見方(表の「結果」を書いてから開く)

turtlesim の亀は、指令どおりの速さで進み、指令どおりの角度だけ回りました。ロボットの脚は床ですべったり、速さの指令と実際の速さが違ったりします。square_walker は自分の位置を見ずに「速さ × 時間」だけで進むので、ずれは直されずにたまります。

片付け

  1. robot-disconnect で接続を切る。
  2. ロボットの電源を切り、元の場所に戻す。
  3. ほかに作業がなければ、stop.bat で講義用の環境を止める。

無線アダプタのワイヤレス モード(#07 の準備 1)は、授業期間中はそのままにしておきます。

本質の問い

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

  • 実験 3 の A〜E のうち、cmd_vel_guard が無かったら止まらなかったものはどれか。それぞれ、ロボットはどうなっていたと考えられるか。
  • 自分で /cmd_vel を送るノードを AI に作らせるとき、cmd_vel_guard があるからといって、ノードの側で気をつけなくてよいことはあるか。気をつけるべきことを 1 つ挙げ、理由を書く。
考え方の例(答えを書いてから開く)

1 つめ:C・D は、最後に届いた速さのまま歩き続けていた。E は、2.0 のまま速く歩こうとしていた。A は、1 回押しただけで歩き続けていた。B は teleop_twist_keyboard 自身が止めるので止まる。

2 つめ:たとえば、止めたいときに自分で停止指令を送ること。cmd_vel_guard が止めるのは 1 秒後なので、その間にロボットは進む。上限の 0.6 以内でも、狭い場所では速すぎることがある。cmd_vel_guard は最後の砦で、ふだんの止め方はノードの側で作る。

つまずきやすい点

症状見るところ
キーを押しても脚が動かないteleop_twist_keyboard を動かしている端末をクリックして選んでいるか。robot-status でブリッジが動作中か
ros2 topic pub で「Unknown topic type」などのエラーが出る型の名前 geometry_msgs/msg/Twist と、"{linear: {x: 0.2}}" のかっこ・コロンのあとの空白
ros2 topic pub で脚が動いたり止まったりする--rate 10 を付け忘れていないか
dog_square が 1 辺目の途中で止まるOLED の 4 行目と robot-status。Wi-Fi が切れると cmd_vel_guard が止める
正方形が大きくずれるずれるのは正常です。ずれ方を記録して、第 5 週でセンサーを使って直す材料にする

まとめ

確かめたことわかったこと
/cmd_vel の行き先(実験 1)PC から送った指令は、ブリッジ → cmd_vel_guard → /cmd_vel_safe → yahboom_base と進む。yahboom_base に直接届く道はない
cmd_vel_guard の中身(実験 2)速さを上限で切り詰め、1.0 秒届かなければ停止指令を出す
止まり方(実験 3)止まる理由は場合によって違う。送る側が止めない場合も、受ける側のしくみで止まる
正方形(実験 4)remap なしでロボットに出せる。速さ × 時間だけの動きは、実機ではずれがたまる

次の週は、ロボットの向きや位置を表す座標(TF)と、データに付いている時刻を調べ、rosbag で記録します。今日の正方形のずれを、ロボット自身がどう把握しているかを見ていきます。

トップへ戻る