前の回の実験 5 では、接続を切ってもデータを受ける側はエラーを出さず、ただ待ち続けることを確かめました。この回は、PC からロボットへ速度指令 /cmd_vel を送ります。速度指令が途中で途切れたら、ロボットは最後に受け取った速度のまま歩き続けるかもしれません。
そこで、いきなり歩かせるのではなく、次の順に進めます。
/cmd_velがロボットの中のどこを通るかを調べる(実験 1・2)- ロボットに出さずに、止まるしくみを数字で確かめる(実験 3 の前半)
- 囲いの中の床で、脚が止まるまでの時間を測る(実験 3 の後半)
- 周りの安全を確かめてから(授業では先生の合図で)、床の上に正方形を歩かせる(実験 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-statusros2 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 つをします。
- PC で
/cmd_velを受け取っているのが誰かを調べる - 先生がロボットの中で調べた結果を読み、その先を追いかける
/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 を受け取っているのはブリッジだけです。ブリッジは受け取った指令を 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_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_x | 0.6 | 前後の速さの上限。これより大きい値が来たら 0.6 に切り詰める |
max_linear_y | 0.45 | 横の速さの上限 |
max_angular_z | 1.5 | 旋回の速さの上限 |
timeout | 1.0 | /cmd_vel がこの秒数届かなければ、停止指令(速さ 0)を出す |
resend_period | 1.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 につなぎ替えて、ロボットに届かない状態にします。机の上に置いたままで脚は動かないので、「何が送られ、いつ送られなくなるか」を数字だけで落ち着いて見られます。
後半は、囲いの中の床で同じことをして、脚が実際に止まるまでの時間を測ります。床で動かすのは、先生の合図があってからです。
この実験は、次の順に進めます。前半でコマンドの打ち方と画面の見方に慣れておくと、床の上で慌てずにすみます。
- A〜E の 5 つの場面について、予想を書く(3-1)
- 前半:出し先を
/cmd_vel_testにして、キーボードで指令を送り、数字を見る(A・B、3-2) - 前半:出し先を
/cmd_vel_testにして、コマンドで指令を送り続け、数字を見る(C・D・E、3-3) - 後半:先生の合図のあと、出し先を
/cmd_velに戻して床で A〜E を行い、脚が止まるまでの時間を測る(3-4)
3-1. 予想する
まず、次の表の「予想」の列を書きます。実験 2 のパラメータとコードを手がかりにしてください。
| 番号 | すること | 予想(前半:送られる指令はどうなるか/後半:脚はどうなるか) | 結果(前半:机) | 結果(後半:床) |
|---|---|---|---|---|
| A | キーボード操作のノードで、前に進むキー i を 1 回だけ押す | |||
| B | i を押し続けている途中で、Ctrl+C でノードを止める | |||
| C | ros2 topic pub で前に進む指令を送り続け、Ctrl+C で止める | |||
| D | C と同じく送り続けている途中で、別の端末で 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
キーは、このノードを動かしている端末をクリックして選んでから押します。ほかのウィンドウを選んでいると、キーはノードに届きません。
| キー | 動き |
|---|---|
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 をクリックし、はじめに
zを 7 回押して、最後の行の speed が 0.24 ぐらいになったことを確かめる。速さを半分以下にしておくと、床で動かしたときに止まるまでに進む距離が短くてすみます。後半で床に下ろすときは、必ずこれを先にします。 - A:
iを 1 回だけ押し、端末 2 に何が出るかを見る。 - B:
iを押し続け、押している途中で端末 1 の Ctrl+C を押す。端末 2 に最後に何が出たかを見る。
結果を見る(予想を書き、自分で実行してから開く)

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 より十分短くします。
- C:端末 2 に
0.2が並んだら、端末 1 で Ctrl+C を押す。端末 2 の表示がどうなるかを見る。 - D:端末 1 のコマンドをもう一度動かし、3 つめの端末で
robot-disconnectを実行する。端末 2 の表示が変わるかを見る。確かめたら、先に端末 1 を Ctrl+C で止めてから、robot-connectでつなぎ直す。 - 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 がずっと並んでいます——送った 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 秒後に停止指令を出す) |
| B | Ctrl+C ですぐ止まる | teleop_twist_keyboard が終わるときに、自分で速さ 0 の指令を送っている |
| C | Ctrl+C のあと、約 1 秒で止まる | ros2 topic pub は終わるときに何も送らない。cmd_vel_guard の timeout で止まる |
| D | 切断のあと、約 2 秒で止まる | PC からの指令が届かなくなり、cmd_vel_guard の timeout で止まる。timeout は 1.0 秒なのに A・C より長くかかった。なぜ長くなるのかも考えてみてください |
| E | 2.0 を送っても、0.6 を送ったときより速くならない | cmd_vel_guard が linear.x を 0.6 に切り詰める |
B と C の違いに注目してください。止まるための指令を送ってくれるノードもあれば、送らないノードもあります。送る側がどう作られていても止まるように、受ける側の cmd_vel_guard が最後の砦になっています。
実験 4 床の上で正方形を歩かせる
授業では、ここは先生の合図があってから始めます。ひとりで学ぶ人も、ほかの人に見ていてもらいながら進めます。ロボットを床に下ろし、周り 1.5 m 以内に人や物がないことを確かめます。#06 の予告で考えてきた「ロボットに出すときの remap」の答え合わせもします。
この実験は、次の順に進めます。
- ロボットを床に下ろし、スタート地点に印を付ける
- 1 辺の長さと、スタート地点に戻ってくるかを予想する
dog_square.launch.pyで正方形を歩かせる- 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 は自分の位置を見ずに「速さ × 時間」だけで進むので、ずれは直されずにたまります。
片付け
robot-disconnectで接続を切る。- ロボットの電源を切り、元の場所に戻す。
- ほかに作業がなければ、
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 で記録します。今日の正方形のずれを、ロボット自身がどう把握しているかを見ていきます。

