最後の回です。前半は発表、後半は自分の PC のシミュレーションで、地図作り(SLAM)と自律移動(Nav2)を動かします。
発表で見せるのは、うまくいったところではありません。うまくいかなかったこと 1 つと、その原因をどのツールで突き止めたかです。このコースで身につけてほしいのは、動くものを作る腕前よりも、動かないものを調べる手順だからです。
授業で受ける人は、この回の記録を実習レポート(Word)の「第 12 回」のシートに書きます。スクリーンショットは、シートの中の「画面:」の欄(実験や記録の表のすぐ下)に貼ります。ひとりで学ぶ人も、予想と結果を同じ形でノートに残しておくと、あとで見返せます。
この回で撮っておく画面
動画は撮りません。そのかわり、下の画面を撮って残します。授業で受ける人は、実習レポートの「第 12 回」の、それぞれの「画面:」の欄に貼ります。ひとりで学ぶ人も、同じ画面を残しておくと、あとで値を見直せます。最初の 1 枚は、実習を始める前に端末で TZ=Asia/Tokyo date と打ち、日付と時刻が出た画面です。授業の日に実習したことの記録になります。講義用の環境の時計は世界標準時(UTC)なので、TZ=Asia/Tokyo を付けて日本時間で出します。
TZ=Asia/Tokyo dateと、発表でつないだ直後のrobot-status- 発表で見せた自分の rqt_graph
- シミュレーションの SLAM:地図ができていく RViz
- Nav2 にゴールを渡した端末(結果が
SUCCEEDEDなどと出たところ) ros2 action info /navigate_to_pose -t- Nav2 を動かしているときの rqt_graph
ros2 run tf2_tools view_framesの木(mapとodomがあること)
前半:発表
見せるのは次の 3 つだけです。コードは見せません。
- #12 で描いた設計のグラフと、実際の
rqt_graph - 動いている様子(囲いの中で、その場で動かして見せる)
- うまくいかなかったこと 1 つと、どのツールで原因を突き止めたか
1 つめは、#12 で描いた設計のグラフと、#13 で撮った rqt_graph を並べて見せます。設計どおりの形になったか、違ったならどこが違ったかを話します。
2 つめで床の上を歩かせるときも、#13 の段階 3 と同じく、先生の合図があってから自分でコマンドを打ちます。ロボットの周りに人や物がないことを確かめてから動かします。
3 つめは、たとえば次のような形になります。
| うまくいかなかったこと | 疑ったこと | 使ったツール | 分かったこと |
|---|---|---|---|
| 近いのに止まらない | 距離の計算 | ros2 topic echo /front_distance | 値は正しかった。判断側のしきい値の向きが逆だった |
| ノードは動くのに何も届かない | 名前か型 | ros2 topic info -v | AI が Float64 で作っていた |
| ときどき急に止まる | 自分のノード | ros2 topic hz /scan | Wi-Fi が混んで /scan が途切れていた |
4 つの列には、それぞれ次のことを書きます。#13 の試験の記録から 1 つ選び、同じ形で話してください。
| 列 | 書くこと | なぜ要るか |
|---|---|---|
| うまくいかなかったこと | 見たままの様子(例:「近いのに止まらない」)。原因の予想はまだ書かない | 聞く人が、同じ場面を思い浮かべられるようにするため |
| 疑ったこと | 最初に「ここが悪いのでは」と考えた場所。はずれていてもかまわない | なぜその順番で調べたのかが伝わるため |
| 使ったツール | 実際に打ったコマンド | 聞いた人が、同じ調べ方をそのまま使えるようにするため |
| 分かったこと | ツールの出力から分かった本当の原因と、どう直したか | 「疑ったこと」と並べると、思い込みと確かめた事実の違いが見えるため |
ほかの人の発表からは、自分のまとめ課題に使えそうな調べ方を 1 つ書き留めてください。誰の発表の、どのツールの使い方かが分かるように書きます。レポートに書く項目です。
動画は撮りません
このコースでは、発表用の動画もレポート用の動画も撮りません。動いている様子は、発表のときに実物で見せます。提出するのは Word のファイル 1 つだけで、中身は画面のスクリーンショットと、測った値と、その測り方です。
後半:シミュレーションで SLAM と Nav2 を動かす
ここまでで、ノード・トピック・サービス・アクション・パラメータ・QoS・TF・記録を扱ってきました。この 8 つで、地図を作って自分で移動するシステムまで読めることを、自分の PC で確かめます。ロボットは使いません。シミュレーションの中の車輪ロボット(TurtleBot3)を動かします。
後半は次の順に進めます。
- シミュレーションを起動する(下の 0)
- 地図作り(SLAM)のノードとトピックを、これまでのコマンドで調べる(1)
- Nav2 に行き先を渡し、アクションとして動いていることを確かめる(2)
rqt_graphで全体を並べ、出口のトピックを探す(3)
それぞれ、コマンドを打つ前に次のことを予想してノートに書いてください。結果の画面と説明は「結果を見る」をクリックすると開きます。予想を書き、自分で実行してから開いてください。
| 調べること | 予想すること | 手がかり |
|---|---|---|
| 1 トピックの数 | 自分のまとめ課題と比べて、多いか少ないか。どのくらいか | 自分のまとめ課題を動かしているときの ros2 topic list | wc -l の数。数えていなければ、発表のあとロボットを切り離す前に数えておく |
1 /map を出すノード | どんな名前のノードが出しているか | slam:=True で動き出したノードの名前 |
| 1 TF の木 | #09 のロボットの木と比べて、どんな座標系が増えるか | #09 の実験 3 の木(base_footprint → base_link → laser_frame)。地図は部屋に固定されている |
| 2 地図の外を行き先にする | 結果は何と返ってくるか | #05 の実験 4 で見た、アクションの終わり方(SUCCEEDED・CANCELED)。着けなかったときはどちらでもなく、ABORTED(失敗)という終わり方もある |
| 2 頼む側と引き受ける側 | /navigate_to_pose を引き受けるノードはいくつか | #05 の turtlesim の回転で、引き受けたのは誰だったか |
| 3 出口のトピック | Nav2 が車輪に向けて最後に出すトピックの名前 | 自分のまとめ課題の判断ノードの出口 |
予想は外れてかまいません。外れたときに「なぜ違ったか」を考えることが大事です。
0 シミュレーションを起動する
先に robot-disconnect でロボットを切り離します。発表でつないだままだと、Nav2 が出す /cmd_vel がロボットにも届き、ロボットの /scan とシミュレーションの /scan も混ざります。robot-status でブリッジが止まっていることを確かめてから、次のコマンドを打ちます。
# どの機体を使うかを、先に環境変数で決めておく(端末を開くたびに打つ)
export TURTLEBOT3_MODEL=waffle
# gazebo(画面なし)+ SLAM + Nav2 + RViz を一度に起動する
ros2 launch nav2_bringup tb3_simulation_launch.py \
slam:=True headless:=True use_composition:=False
TURTLEBOT3_MODEL は、TurtleBot3 のどの型の機体を使うかを決める環境変数です(環境変数は #02 の「14. 環境変数と source」)。export で決めた値はその端末の中だけで効くので、端末を開くたびに打ちます。2 つめのコマンドの行末の \ は「次の行に続く」という意味で、2 行で 1 つのコマンドです。
launch のうしろの 3 つは、#13 で使った 名前:=値 の引数です。
| 引数 | 意味 | なぜこうするか |
|---|---|---|
slam:=True | 地図作りのノード(slam_toolbox)を動かす | 用意された地図を読み込むのではなく、走りながら地図を作るため |
headless:=True | シミュレーター(gazebo)の画面を出さない | 見るのは RViz だけで足りるうえ、PC の負担が減るため |
use_composition:=False | Nav2 のノードを 1 つのプログラムにまとめず、1 つずつ別のプログラムとして動かす | #03 からの「ノード 1 つ=プログラム 1 つ」の形のまま、ros2 node list などで調べられるようにするため |
RViz の窓が開き、しばらくすると機体と、LiDAR の点が出ます。起動には時間がかかるので、点が出るまで待ってから次へ進みます。ほかの端末を開くときも、最初に export TURTLEBOT3_MODEL=waffle を打ちます。
1 地図を作る(SLAM)
slam:=True を付けたので、地図作りのノード(slam_toolbox)が動いています。RViz で、点の集まりが少しずつ壁の形になっていく様子を見ます。機体を動かすと、見えている範囲が広がって地図も広がります。機体は、次の 2 のやり方で行き先を渡すと動きます。地図ができていく RViz の画面は、レポートに貼るので撮っておきます。
入っていくのは /scan と TF です。どちらも #09 で自分で調べたものです。出てくるのは /map というトピックで、これも ros2 topic info で型を見られます。別の端末を開き、次のコマンドを打ちます。
ros2 node list | grep -i slam
ros2 topic list | wc -l
ros2 topic info /map
ros2 topic info -v /map | sed -n '1,/Subscription count/p'
1 行目は、ノードの一覧から「slam」を含む行だけを出します(grep は #02)。-i は、大文字と小文字を区別しないという指定です。2 行目の wc -l は、渡された行数を数えます(#01)。トピックの一覧の行数なので、トピックの数になります。
4 行目のうしろに付けた sed は、出力を切り取るためのものです。-v を付けると、発行している側と購読している側の両方が出ます。ここで見たいのは発行している側なので、Subscription count の行で止めています。
結果を見る(予想を書き、自分で実行してから開く)

/slam_toolbox と /lifecycle_manager_slam の 2 つです。/map を出しているのは /slam_toolbox のほうで、/lifecycle_manager_slam はほかのノードを順番に起動する係です(topic info -v の Publisher の行で確かめられます)。トピックの数は 78——自分のまとめ課題では 20 前後だったはずです。下は /map の QoS。Durability: TRANSIENT_LOCAL に目を留めてください。地図は毎秒流れてくるものではなく、あとから参加したノードにも、最後の 1 枚が届く設定になっています。#09 の実験 2 で読んだ /scan の Durability は VOLATILE(あとから来た受け手には前のデータを渡さない)でしたが、/map では TRANSIENT_LOCAL になっています次に、TF の木を PDF に書き出します。#09 の実験 3 と同じく、作業用のフォルダに移動してから実行し、できた PDF を atril で開きます。#09 で作ったフォルダと混ざらないよう、別の名前のフォルダにします。
mkdir -p ~/tf_sim && cd ~/tf_sim
ros2 run tf2_tools view_frames
atril frames_*.pdf
TF の木の画面は、レポートに貼るので撮っておきます。
結果を見る(予想を書き、自分で実行してから開く)
木は map → odom → base_footprint → base_link → LiDAR の座標系、の形になっています。#09 のロボットの木に無かったのは map と odom の 2 つです。map は部屋(地図)に固定された座標系、odom は機体が「自分はどれだけ動いたか」を数えて出す座標系です。LiDAR の座標系の名前も、この機体では laser_frame ではありません(自分の PDF で名前を確かめます)。授業で使うロボットは odom を出していないので、地図作りと自律移動はシミュレーションで試します。
2 行き先を渡す(Nav2)
できた地図の上で、行き先を渡します。渡し方は 2 つあります。
- RViz の上に並んだボタンの Nav2 Goal を押し、地図の上の行き先でマウスのボタンを押したまま、機体を向けたい方向へ引いてから離す
- 端末から、アクションとして渡す(下のコマンド)
どちらでも、機体が経路を決めて走ります。
ros2 action send_goal /navigate_to_pose nav2_msgs/action/NavigateToPose \
"{pose: {header: {frame_id: map}, pose: {position: {x: 0.5, y: 0.5}, orientation: {w: 1.0}}}}"
ros2 action send_goal は、#05 の実験 4 と同じく、アクションの名前・型・目標の中身の順に書きます。目標の中身は次のとおりです。
| 書いてあること | 意味 |
|---|---|
frame_id: map | 行き先の座標を、地図(map 座標系)を基準にして書くという意味 |
position: {x: 0.5, y: 0.5} | 地図の原点から x の向きに 0.5 m、y の向きに 0.5 m の場所 |
orientation: {w: 1.0} | 着いたときの向き。w: 1.0 だけを書くと「回さない」、つまり地図の x の向きを向く |
最後に SUCCEEDED と出れば、ゴールに着いています。この端末の画面は、レポートに貼るので撮っておきます。
次に、地図の外や壁の中を行き先にしてみます。x と y を大きな値(たとえば 20)にすると地図の外になります。打つ前に、どんな結果が返ってくるかを予想してノートに書き、返ってきた結果をレポートに書きます。答えはここには載せません。返ってきた終わり方と、そうなった理由を自分で考えてレポートに書きます。
このとき動いているのはアクションです。#05 で turtlesim の回転に使ったものと、仕組みは同じです。どんなアクションがあるかと、/navigate_to_pose を頼む側・引き受ける側を調べます。-t は、アクションの型もいっしょに出す指定です。
ros2 action list
ros2 action info /navigate_to_pose -t
結果を見る(予想を書き、自分で実行してから開く)

/spin(その場で回る)、/backup(下がる)、/wait(待つ)——名前を見るだけで、何をするものか見当が付きます。/navigate_to_pose を -t 付きで調べると、型は nav2_msgs/action/NavigateToPose、送る側が 4 つ(/rviz など)、受ける側は /bt_navigator 1 つだけ。#05 の turtlesim で見た「頼む側」と「引き受ける側」が、そのままの形で出てきます時間のかかる仕事で、途中経過が届き、途中で取り消せる。だからトピックでもサービスでもなくアクションである——という #05 の話が、そのまま出てきます。
3 全部を並べて見る
最後に、Nav2 が動いているときの全体を rqt_graph で見ます。ノードがとても多いので、そのままでは線が重なって読めません。窓の上にある Hide: の並びで、見たくないものを消せます。tf にチェックを入れて TF の線を消し、左上の更新ボタンを押してから、車輪に向かう出口のトピックを探してください。
rqt_graph
ノードの数は増えますが、線の意味は変わりません。丸がノード、四角がトピック、矢印が向きです。6 週で覚えたのはこの読み方です。
結果を見る(予想を書き、自分で実行してから開く)

rqt_graph。窓に入りきらないほどノードがあります。まん中あたりを左から右へたどってください——/controller_server から /cmd_vel_nav が出て、/velocity_smoother を通り、/cmd_vel という名前になって車輪(/turtlebot3_diff_drive)へ入ります。出口は、自分のまとめ課題と同じ /cmd_vel です。線の多くを占めている /bond は、ノードどうしが「まだ生きているか」を確かめ合うためのものです。左に浮いている /transform_listener_impl_… は TF を受け取る部品で、この図では TF の線を隠しているため、線が付いていませんNav2 が最後に出すのは /cmd_vel です。自分のまとめ課題と、出口は同じです。
全部を一度に見ようとせず、見たい線だけを残す——ノードが増えたときの読み方は、これに尽きます。
なぜ、自分のロボットではなくシミュレーションなのか
このシミュレーションの Nav2 を、そのまま自分のロボットで動かすことはできません。何が足りないのかを、トピックや座標系の名前で答えるのが、レポートの問いです。
手がかりは 2 つです。
- この回の
view_framesの木と、#09 の実験 3 でロボットにつないで書き出した木を並べ、ロボットの木に無い座標系を探す - この回の
ros2 topic listやrqt_graphに出ていて、#07 と #09 でロボットにつないだときには出ていなかったトピックを探す
理由を見る(レポートの問いに自分で答えてから開く)
| 理由 | 中身 |
|---|---|
| ロボットが走行距離を出していない | 今のロボットの設定では、脚の動きから求めた位置(/odom)が PC に出てきません。Nav2 に必要な情報がそろわないため、シミュレーションの中の機体で動かします |
| 同じ部屋で何台も地図を作れない | 20 台が同時に動くと、ほかのロボットが障害物として地図に写り込みます |
この 2 つは、どちらも「やってみたら分かった」たぐいの制約です。何ができないかを、理由まで含めて知っていることも、このコースで持って帰ってほしいものです。
6 週間のまとめ
| 本質 | 確かめた回 |
|---|---|
| 計算グラフ:ノードとトピックのつながりで全体ができている | #03・#06 |
| インターフェースは契約:名前・型・QoS が合って初めて届く | #03・#04・#09 |
| 疎結合と再利用:コードを変えずにつなぎ替えられる | #06・#12・#13 |
| 通信パターンの使い分け:トピック・サービス・アクション | #05・#14 |
| 境界:PC とロボットの間で、見えるものと見えないものが変わる | #07・#08 |
| 時間と座標:いつ・どの座標系で測ったかが要る | #09 |
| 記録と再現:ロボットが無くても確かめられる | #10・#12・#13 |
| 安全は層で守る:どれか 1 つに頼らない | #08・#11・#13 |
コードは AI に書かせました。それでも、ここまでの判断——何を測るか、どの段階で試すか、どのツールで確かめるか、どこで止めるか——は、自分でやってきたはずです。AI が書いたものが正しいかどうかを決められるのは、この判断ができる人だけです。
つまずきやすい点
| 起きたこと | 見るところ |
|---|---|
| 起動してもしばらく RViz に何も出ない | 起動には時間がかかります。端末のログが止まるまで 1〜2 分待ちます |
| PC が重くて動かない | メモリの少ない PC(8 GB 程度)では動かないことがあります。そのときは隣の人の画面で見て、自分のレポートには見た値を書きます |
/scan がおかしい・機体が勝手に動く | robot-disconnect を忘れて、ロボットとシミュレーションが混ざっていないか。robot-status で確かめます |
| RViz に地図が出ない | slam:=True を付けたか。左の Displays で Map が有効になっているか |
TURTLEBOT3_MODEL のエラーが出る | その端末で export TURTLEBOT3_MODEL=waffle を打ったか(echo $TURTLEBOT3_MODEL で確かめる) |
レポートの提出:Word のファイル 1 つを Google Classroom に出します。期限は、最後の実習の 1 週間後の 23:59 です。
このあと
このコースの続きとして、次のような延長を順に公開していきます。授業の進み具合や、興味に合わせて選べます。
- ROS 2 の部品を自分で作る(自作メッセージ・サービス・アクション)
- 脚の運動学(URDF と、脚の角度から足先の位置を求める計算)
- 画像認識(カメラの画像を ROS 2 で扱う)
- LLM とロボット(言葉での指示を、安全の層を通して動きに変える)
- 地図と自律移動(この回のシミュレーションを、もっと詳しく調べる)
- 総合制作
ひとりで進めてきた人も、ここまでで ROS 2 の基本的な読み方は身についています。次は、自分のロボットや題材に、同じ手順を当てはめてみてください。設計シートを書き、AI に作らせ、ツールで確かめる。その繰り返しです。
