ROS 2 実践コース|#14 発表と、シミュレーションで SLAM・Nav2 を動かす

最後の回です。前半は発表、後半は自分の 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 つだけです。コードは見せません。

  1. #12 で描いた設計のグラフと、実際の rqt_graph
  2. 動いている様子(囲いの中で、その場で動かして見せる)
  3. うまくいかなかったこと 1 つと、どのツールで原因を突き止めたか

1 つめは、#12 で描いた設計のグラフと、#13 で撮った rqt_graph を並べて見せます。設計どおりの形になったか、違ったならどこが違ったかを話します。

2 つめで床の上を歩かせるときも、#13 の段階 3 と同じく、先生の合図があってから自分でコマンドを打ちます。ロボットの周りに人や物がないことを確かめてから動かします。

3 つめは、たとえば次のような形になります。

うまくいかなかったこと疑ったこと使ったツール分かったこと
近いのに止まらない距離の計算ros2 topic echo /front_distance値は正しかった。判断側のしきい値の向きが逆だった
ノードは動くのに何も届かない名前か型ros2 topic info -vAI が Float64 で作っていた
ときどき急に止まる自分のノードros2 topic hz /scanWi-Fi が混んで /scan が途切れていた

4 つの列には、それぞれ次のことを書きます。#13 の試験の記録から 1 つ選び、同じ形で話してください。

列書くことなぜ要るか
うまくいかなかったこと見たままの様子(例:「近いのに止まらない」)。原因の予想はまだ書かない聞く人が、同じ場面を思い浮かべられるようにするため
疑ったこと最初に「ここが悪いのでは」と考えた場所。はずれていてもかまわないなぜその順番で調べたのかが伝わるため
使ったツール実際に打ったコマンド聞いた人が、同じ調べ方をそのまま使えるようにするため
分かったことツールの出力から分かった本当の原因と、どう直したか「疑ったこと」と並べると、思い込みと確かめた事実の違いが見えるため

ほかの人の発表からは、自分のまとめ課題に使えそうな調べ方を 1 つ書き留めてください。誰の発表の、どのツールの使い方かが分かるように書きます。レポートに書く項目です。

動画は撮りません

このコースでは、発表用の動画もレポート用の動画も撮りません。動いている様子は、発表のときに実物で見せます。提出するのは Word のファイル 1 つだけで、中身は画面のスクリーンショットと、測った値と、その測り方です。

後半:シミュレーションで SLAM と Nav2 を動かす

ここまでで、ノード・トピック・サービス・アクション・パラメータ・QoS・TF・記録を扱ってきました。この 8 つで、地図を作って自分で移動するシステムまで読めることを、自分の PC で確かめます。ロボットは使いません。シミュレーションの中の車輪ロボット(TurtleBot3)を動かします。

SLAM と Nav2 も、習ってきた部品の組み合わせでできている
SLAM と Nav2 も、習ってきた部品の組み合わせでできている

後半は次の順に進めます。

  1. シミュレーションを起動する(下の 0)
  2. 地図作り(SLAM)のノードとトピックを、これまでのコマンドで調べる(1)
  3. Nav2 に行き先を渡し、アクションとして動いていることを確かめる(2)
  4. 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:=FalseNav2 のノードを 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 を含むノードで、/slam_toolbox と /lifecycle_manager_slam の 2 つです。/map を出しているのは /slam_toolbox のほうで、/lifecycle_manager_slam はほかのノードを順番に起動する係です(topic info -v の Publisher の行で確かめられます)。トピックの数は <strong>78</strong>——自分のまとめ課題では 20 前後だったはずです。下は /map の QoS。Durability: TRANSIENT_LOCAL に目を留めてください。地図は毎秒流れてくるものではなく、<strong>あとから参加したノードにも、最後の 1 枚が届く</strong>設定になっています。#09 の実験 2 で読んだ /scan の Durability は VOLATILE(あとから来た受け手には前のデータを渡さない)でしたが、/map では TRANSIENT_LOCAL になっています
上は名前に slam を含むノードで、/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 つあります。

  1. RViz の上に並んだボタンの Nav2 Goal を押し、地図の上の行き先でマウスのボタンを押したまま、機体を向けたい方向へ引いてから離す
  2. 端末から、アクションとして渡す(下のコマンド)

どちらでも、機体が経路を決めて走ります。

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
結果を見る(予想を書き、自分で実行してから開く)
アクションが <strong>12 個</strong>並んでいます。/spin(その場で回る)、/backup(下がる)、/wait(待つ)——名前を見るだけで、何をするものか見当が付きます。/navigate_to_pose を -t 付きで調べると、型は nav2_msgs/action/NavigateToPose、送る側が 4 つ(/rviz など)、受ける側は /bt_navigator 1 つだけ。#05 の turtlesim で見た「頼む側」と「引き受ける側」が、そのままの形で出てきます
アクションが 12 個並んでいます。/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 週で覚えたのはこの読み方です。

結果を見る(予想を書き、自分で実行してから開く)
Nav2 が動いているときの rqt_graph。窓に入りきらないほどノードがあります。まん中あたりを左から右へたどってください——/controller_server から /cmd_vel_nav が出て、/velocity_smoother を通り、/cmd_vel という名前になって車輪(/turtlebot3_diff_drive)へ入ります。<strong>出口は、自分のまとめ課題と同じ /cmd_vel です。</strong>線の多くを占めている /bond は、ノードどうしが「まだ生きているか」を確かめ合うためのものです。左に浮いている /transform_listener_impl_… は TF を受け取る部品で、この図では TF の線を隠しているため、線が付いていません
Nav2 が動いているときの 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 に作らせ、ツールで確かめる。その繰り返しです。

トップへ戻る