ROS 2 実践コース|#D1 AI に道具だけを渡す(呼び出しを観察し、道具を設計する)

延長コース D は、LLM(大きな言語モデル)とロボットです。ただし、この授業で LLM にロボットを動かすコードを書かせることはしません。やるのは、人が決めた道具だけを呼ばせる、という設計です。

AI にコードを書かせるのは、コアの授業でずっとやってきたことです。違うのは、AI が書いたものがそのままロボットに届くかどうか。このコースでは、AI とロボットのあいだに、人が確かめる層と、道具が確かめる層を置きます。

AI は道具を選んで呼ぶだけ。範囲の確かめは道具の側に置き、実行の前に人が見る
AI は道具を選んで呼ぶだけ。範囲の確かめは道具の側に置き、実行の前に人が見る

この記事の位置

項目内容
コース延長コース D「LLM とロボット」(3 週・回 D1〜D6)
この記事第 1 週(回 D1・D2)
前に受けるコース延長コース A(自作サービスで道具を作るため)
ロボットこの週は使いません。回 D1 は turtlesim、回 D2 は #10 で記録した room_scan の再生で進めます
AI の使い方ブラウザの AI に聞き、返ってきた呼び出しを人が確かめてから自分で実行します。AI が自動でロボットを呼ぶ仕組みは使いません

AI に貼らないもの:ロボットの Wi-Fi のパスワード、個人が分かる情報。これはコアの授業と同じです。

この記事は延長コース Dの 2 回分(D1・D2)です。授業で受ける人は、記録を実習レポート(Word)の「回 D1」「回 D2」のシートに分けて書きます。スクリーンショットは、シートの中の「画面:」の欄(実験の表のすぐ下)に貼ります。延長コースのレポートは、コア(第 1〜12 回)とは別の 1 本にします。ファイルは Google Classroom で配られ、コースの最後に Google Classroom で 1 回だけ出します。期限は最後の実習から 1 週間後の 23:59 です。ひとりで学ぶ人も、予想と結果を同じ形でノートに残しておくと、あとで見返せます。

回 D1 LLM が出す呼び出しを観察する

D1-1 道具の一覧を用意する

使ってよい道具(この一覧にないものは呼べません)

1. /spawn
   引数:x(0.0〜11.0)、y(0.0〜11.0)、theta(-3.14〜3.14)、name(文字列)
   呼んではいけない条件:同じ name がすでにあるとき

2. /turtle1/teleport_absolute
   引数:x(0.0〜11.0)、y(0.0〜11.0)、theta(-3.14〜3.14)

3. /turtle1/set_pen
   引数:r, g, b(0〜255)、width(1〜10)、off(0 か 1)

答えるときは、呼び出しを 1 行ずつ、サービス名と引数の形で書いてください。

まず turtlesim の道具で試します。一覧には、名前・引数の型・範囲・呼んではいけない条件を書きます。この一覧が、AI に渡すすべてです。

turtlesim が持っているサービスの一覧と、TeleportAbsolute の引数。ここに出ているものだけが、AI に渡せる道具になる
turtlesim が持っているサービスの一覧と、TeleportAbsolute の引数。ここに出ているものだけが、AI に渡せる道具になる

「呼んではいけない条件」は、実際に呼んでみると分かります。たとえば同じ名前でもう一度 /spawn を呼ぶと、エラーにはならず、名前が空のまま返ってきます。こういう「失敗しても失敗に見えない呼び出し」を、一覧に書いておきます。

同じ名前 t2 で 2 回 spawn を呼んだところ。2 回目の返事は name='' で、亀は増えていない
同じ名前 t2 で 2 回 spawn を呼んだところ。2 回目の返事は name='' で、亀は増えていない

D1-2〜D1-3 返ってきた呼び出しを、実行する前に書き写す

ここでは、AI が返した呼び出しを書き写し、1 つずつ実行するかどうかを決めます。

一覧を貼って「亀で四角を描いて」と頼みます。返ってきた呼び出しを、実行する前に10 個以上書き写します(D1-2)。そのうえで、一覧の範囲と照らして「実行する・しない」と理由を付けます(D1-3)。実行してよいものだけを、自分で実行します。

書き写す表は、次の形にします。1 行目は書き方の例です。

番号返ってきた呼び出し一覧の範囲に入っているか実行する・しない理由
(例)1/turtle1/teleport_absolute x: 5.0, y: 5.0, theta: 0.0入っている(x・y は 0.0〜11.0、theta は -3.14〜3.14)実行する範囲の中で、四角の 1 つ目の角になる
(例)2/turtle1/teleport_absolute x: 20.0, y: 5.0, theta: 0.0入っていない(x が 11.0 を超える)実行しない一覧の範囲の外
3
欄書くこと
番号AI が返した順番。あとで「何番目で外れたか」を言えるようにする
返ってきた呼び出しサービス名と引数を、AI が書いたとおりに写す。直してから写さない
一覧の範囲に入っているかD1-1 の一覧と 1 つずつ照らし、外れていればどの引数かを書く
実行する・しない自分で決めた結果。迷ったら「しない」にする
理由なぜそう決めたかを短く書く。回 D3 で、どの層で止まるはずかを考える材料になる

実行するときは、次のように打ちます。ros2 service call のあとに、サービスの名前、型、引数の順に並べます。引数は "{x: 5.0, y: 5.0, theta: 0.0}" のように、波かっこの中に「名前: 値」をカンマで区切って書きます。行の終わりの \ は「次の行に続く」という意味です。型が分からないときは ros2 service list -t で、名前の横に出る型を見ます。

# 確かめてから、自分で実行する
ros2 service call /turtle1/teleport_absolute turtlesim/srv/TeleportAbsolute \
  "{x: 5.0, y: 5.0, theta: 0.0}"

# 道具の一覧と型を見る
ros2 service list -t
確かめてから 1 つずつ実行したところ。set_pen で線を付け、teleport を 5 回で四角になる
確かめてから 1 つずつ実行したところ。set_pen で線を付け、teleport を 5 回で四角になる

D1-4 わざとあいまいな指示を出す

「速く動かして」「壁の近くまで行って」のように、数字の入っていない頼み方をします。返ってきた呼び出しのうち、次の 3 つを数えます。

数えるもの意味
範囲外の呼び出し一覧に書いた範囲(0.0〜11.0 など)を外れているもの
道具にないもの一覧に無いサービス名を呼ぼうとしているもの
引数が足りないもの必要な引数が抜けているもの

予想 1:あいまいな指示にすると、どれが増えるでしょうか。手がかり:「速く」「近く」には数字がありません。AI は、数字をどこかから決めて埋めるしかありません。

予想 2:範囲外の呼び出し(たとえば x: 20.0)を実行すると、どうなるでしょうか。エラーで断られるか、そのまま通るか。手がかり:一覧の範囲は、AI に渡した文に書いただけです。turtlesim のサービスはその文を読んでいません。

予想を書いてから数えます。範囲外の呼び出しは、1 つだけ自分で実行して確かめます。

結果を見る(予想を書き、自分で数えてから開く)

範囲外の呼び出しは、実行してみるとそのまま通ってしまいます。一覧に「x は 0.0〜11.0」と書いてあっても、それを守るのは AI ではなく、呼び出しを実行する側です。

一覧の範囲を外れた x: 20.0 をそのまま実行したところ。サービスは受け付け、亀は壁ぎわの x=11.0889 に置かれる
一覧の範囲を外れた x: 20.0 をそのまま実行したところ。サービスは受け付け、亀は壁ぎわの x=11.0889 に置かれる

どの数が増えたかは、頼み方と AI によって変わります。自分の表の数を、予想 1 と並べて書いてください。

D1-5 一覧を渡さずに同じことを頼む

最後に、道具の一覧があるときと無いときで、返ってくるものを比べます。

同じ頼みごとを、道具の一覧を渡さずにしてみます。返ってくるものがどう変わるかを書きます。一覧があるときと無いときの数を、同じ表に並べます。

この回で撮っておく画面

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

  • TZ=Asia/Tokyo date(回の頭)
  • 道具の一覧(画面)(実験 D1-1 の欄)
  • AI が返した呼び出し(画面)(実験 D1-2 の欄)
  • 実行する・しないを書いた表(写真)(実験 D1-3 の欄)
  • 範囲外の呼び出しの例(画面)(実験 D1-4 の欄)
  • 実行した結果の turtlesim(実験 D1-3 の欄)

本質の問い(回 D1)

  • AI の出力を信用せずに使うために、どこで確かめるかを 2 か所以上挙げ、自分が集めた例で説明しなさい。
考え方のすじ道(答えを書いてから開く)

確かめる場所は、少なくとも 3 つあります。人が見る(実行する前に読む)、道具が見る(サービスの中で範囲を確かめる)、安全層が見る(cmd_vel_guard が速さを切る)。

大事なのは、それぞれが別のものを見ているという点です。人は「意図と合っているか」を見ますが、見落とします。道具は範囲を機械的に見ますが、意図までは分かりません。安全層はいちばん外側で、どんな経路から来た指令でも切ります。

レポートには、自分が集めた呼び出しのうち「どれがどの層で止まるはずか」を対応付けて書いてください。回 D3 で、実際にどの層で止まったかを確かめます。

回 D2 道具の設計

この回は、ロボット用の道具を自分で設計して作り、3 通りの値を送って確かめます。ロボットは使いません。前方の距離を答える道具は、コアの #10 で記録した room_scan を再生して、その /scan で試します。

  1. D2-1 設計シート:ロボット用の道具を 3 つ決めます。動かない道具(前方の距離を答える、状態を答える)から 2 つ、動く道具を 1 つ。それぞれ名前・引数の型・単位・範囲・呼んではいけない条件・失敗したときに返すものを書きます。
  2. D2-2 AI に実装させる:延長コース A でやった自作サービスとして作らせます。範囲の確かめは道具の中に必ず入れます。AI 任せにせず、その行を自分で読んで確かめます。
  3. D2-3 検証する:ros2 service call で、正しい値・範囲外の値・型の違う値の3 通りを送り、返るものを表にします。動く道具は、出し先を /cmd_vel_test にしたまま試します。

D2-1 設計シートの書き方

設計シートには、道具 1 つにつき次の欄を書きます。例は「前に進む道具」です。名前や型の名前(/my_tools/walk_forward、my_msgs/srv/WalkForward)は例なので、自分で決めた名前に置き換えます。

欄書くこと例(前に進む道具)
名前AI に渡す一覧に載せるサービス名/my_tools/walk_forward
引数の型引数の名前と型。型は ROS 2 の型(float64 など)で書くspeed:float64
単位引数の数がどの単位か。書かないと、AI も人も取り違えるm/s
範囲受け付ける値の幅。ロボットの上限(前後 0.6 m/s)より内側に、自分で決める0.0〜0.3
呼んではいけない条件値は範囲の中でも、断るべき場面前方 0.5 m 以内に物があるとき
失敗したときに返すもの断ったことと、その理由。文で返すと次に AI に頼むときの材料になるsuccess: false と「前 0.5 m 以内に物があるので断りました」

前方の距離を答える道具なら、引数は無し、返すものは距離(m)、「呼んではいけない条件」は「/scan がしばらく来ていないとき」のようになります。3 つとも同じ欄で書きます。

D2-3 3 通りを送って確かめる

ロボットにはつながず(#10 と同じく robot-disconnect した状態で)、端末を 4 つ開いて試します。

# 端末 1:#10 で記録した room_scan を流し続ける(ロボットの代わり)
cd ~/bags
ros2 bag play room_scan --loop

# 端末 2:自分の道具のノードを起動する。動く道具の出し先は /cmd_vel_test につなぎ替える
ros2 run my_tools tool_server --ros-args -r cmd_vel:=/cmd_vel_test

# 端末 3:動く道具が出した指令を見る
ros2 topic echo /cmd_vel_test

# 端末 4:3 通りを送る(名前と型は、自分で決めたものに置き換える)
ros2 service call /my_tools/get_front_distance my_msgs/srv/GetDistance "{}"
ros2 service call /my_tools/walk_forward my_msgs/srv/WalkForward "{speed: 0.2}"
ros2 service call /my_tools/walk_forward my_msgs/srv/WalkForward "{speed: 2.0}"
ros2 service call /my_tools/walk_forward my_msgs/srv/WalkForward "{speed: 'fast'}"
端末やること
端末 1room_scan を繰り返し再生する。距離を答える道具は、ここから流れる /scan を読む。~/bags は #10 で記録を置いた場所
端末 2自分の道具のノードを起動する。my_tools と tool_server は例なので、自分のパッケージ名とノード名に置き換える。-r cmd_vel:=/cmd_vel_test で、動く道具の出し先を試し用のトピックにつなぎ替える
端末 3/cmd_vel_test に何が出たかを見る。ロボットにはつないでいないので、本物は動かない
端末 43 通りを送る。{speed: 0.2} が正しい値、{speed: 2.0} が範囲外、{speed: 'fast'} が型の違う値(数のかわりに文字)

結果は次の表に書きます。

送るもの送ったコマンド返ってくるもの/cmd_vel_test に出たもの(動く道具)
正しい値
範囲外の値
型の違う値

距離を答える道具は、/cmd_vel_test の欄に「出ないはず」と書き、本当に何も出ないかを見ます。

失敗したときに何を返すかは、設計で決めることです。ただ失敗するのではなく、「なぜ断ったか」を文で返すようにすると、次に AI に頼むときの材料になります。回 D4 で、この文を直して結果が変わるかを試します。

この回で撮っておく画面

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

  • TZ=Asia/Tokyo date と robot-status(回の頭)
  • 設計シート(写真)(実験 D2-1 の欄)
  • ros2 service list -t(自分の道具が型つきで出ているところ)(実験 D2-2 の欄)
  • 正しい値での応答(実験 D2-3 の欄)
  • 範囲外の値での応答(実験 D2-3 の欄)
  • 型の違う値での応答(実験 D2-3 の欄)

つまずきやすい点

症状見るところ
AI が一覧にないサービスを呼ぶ一覧の書き方。「この一覧にないものは呼べません」と明記したか。これも D1-4 で数える対象
ros2 service call で型のエラー型名が合っているか。ros2 service list -t で確かめる
範囲外を送っても通ってしまう道具の中の確かめが入っていない。AI が書いた行を自分で読む(D2-2)
動く道具で本物が動いた出し先が /cmd_vel_test になっているか。この週はロボットを動かしません
AI の答えが毎回違うそういうものです。何回か試して、数を数えるときは回数も一緒に書く

まとめ

やったことわかったこと
道具の一覧を渡す渡した範囲の中でしか呼べない、という形を作れる
実行前に書き写すAI の出力は、そのまま実行しなくてよい
あいまいな指示を出す指示があいまいだと、範囲外や存在しない呼び出しが出る
道具を設計する範囲の確かめは、道具の中に置く
3 通りを送る断り方まで決めて、はじめて道具になる

次の #D2 では、人が見落としたことにして道具に範囲外を送り、どの層で止まるかを確かめます。

トップへ戻る