1. はじめに
前回の記事Ollama + ros2ai(ROS 2 Humble)で「自然言語で指示→/cmd_velを1回publish→Gazebo(TurtleBot3)が動く」を試してみたでは、ros2 ai exec にほぼ確定の ros2 topic pub コマンドを渡して、Gazebo 上の TurtleBot3 を動かしました。
今回は、次ステップとして、もう少し曖昧な自然言語指示を投げたときに、
- どんなプロンプトだと
/cmd_velに落ちるのか - どんなプロンプトだと変な ROS 2 コマンドになるのか
- 型確認のような「一段考える」要求がどこまで通るのか
を、ターミナルから1つずつ手で試して観察してみました。
2. 実行環境
- CPU: CORE i7 7th Gen
- メモリ: 32GB
- GPU: GeForce RTX 2070
- OS: Ubuntu22.04(WSL2ではなくPCに直接インストール)
3. 構築手順
ターミナル構成
以下のように4つのターミナルを使います。
- T1: Ollama
- T2: Gazebo + TurtleBot3
- T3: ros2ai に実験プロンプトを投げる
-
T4:
/cmd_velを観測する
Step 1. T1 で Ollama を起動する
まず T1 で Ollama を起動します。
ollama serve
別ターミナルで、使うモデルがあるか確認します。
ollama list
もし llama3.2:3b があることを確認。
Step 2. T2でGazebo+TurtleBot3を起動する
T2 では Gazebo 上に TurtleBot3 Burger を起動します。
source /opt/ros/humble/setup.bash
export TURTLEBOT3_MODEL=burger
ros2 launch turtlebot3_gazebo empty_world.launch.py
Step 3. T3でros2ai環境を読み込み、Ollamaに接続する
T3ではROS 2とros2aiの環境を読み込み、Ollamaをエンドポイントとして設定します。
source /opt/ros/humble/setup.bash
source ~/ros2ai_ws/install/setup.bash
unset OPENAI_API_KEY
export OPENAI_MODEL_NAME=llama3.2:3b
export OPENAI_ENDPOINT=http://127.0.0.1:11434/v1
Step 4. T4で/cmd_velを観測する
実験のたびに Twist が流れたかを確認したいので、T4 では /cmd_vel を監視します。
source /opt/ros/humble/setup.bash
ros2 topic echo /cmd_vel
Step 5. T3でログ保存用ディレクトリを作る
実験ログを個別に残すため、T3 で次を実行します。
mkdir -p ~/ros2ai_ws/prompt_logs
cd ~/ros2ai_ws/prompt_logs
以降、各試行で
RLOG=名前
... |& tee -a ${RLOG}.log
の形でログを保存していきます。
Step 6. まず基準点(コントロール)を打つ
環境が壊れていないことを確認するため、T3で最初に前回成功した以下のコマンドを打ちます。
RLOG=CTRL_01
ros2 ai exec "Run this exactly once: ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist '{linear: {x: 0.1, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}'. Do not do anything else." |& tee -a ${RLOG}.log
このケースでは、以下のログがでまして、linear.x=0.1, angular.z=0.0 の Twist が1回 publish されたことが確認できました。
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.1, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0))
Step 7. 実験
ここから、曖昧さの強さを変えながら実験していきます。
各コマンドのあとに、
- T4 の
/cmd_velに Twist が出たか - T3 のログに何が出たか
- T2 で起動したGazebo でロボが動いたか
を確認していきます。
Step 7-1. かなり曖昧な前進指示(本記事での識別コード:L2_FWD_01)
RLOG=L2_FWD_01
ros2 ai exec "Move forward slowly once using /cmd_vel. Publish only once." |& tee -a ${RLOG}.log
結果は以下でした。
Package 'myrobot' not found
つまり、/cmd_vel に publish するのではなく、存在しない package を実行しようとしました。
Step 7-2. かなり曖昧な右回転指示(本記事での識別コード:L2_ROT_01)
RLOG=L2_ROT_01
ros2 ai exec "Rotate right slightly once using /cmd_vel. Publish only once." |& tee -a ${RLOG}.log
結果は以下でした。
/bin/sh: 1: Bad substitution
このケースは package not found ではなく、生成されたシェル文字列そのものが壊れました。
Step 7-3. かなり曖昧な停止指示(本記事での識別コード:L2_STOP_01)
RLOG=L2_STOP_01
ros2 ai exec "Stop once using /cmd_vel. Publish only once." |& tee -a ${RLOG}.log
結果は以下でした。
Package 'my_robot' not found
停止でも、/cmd_vel publish ではなく package 実行側になりました。
Step 7-4. topic 名と型だけ明示した前進指示(本記事での識別コード:L2_FWD_02)
RLOG=L2_FWD_02
ros2 ai exec "Move forward slowly once. Use /cmd_vel with message type geometry_msgs/msg/Twist. Publish only once." |& tee -a ${RLOG}.log
結果は以下でした。
Package 'my_robot' not found
topic 名と型を明示しても、まだ package 実行側に寄っていることが確認できました。
Step 7-5. topic 名と型だけ明示した右回転指示(本記事での識別コード:L2_ROT_02)
RLOG=L2_ROT_02
ros2 ai exec "Rotate right slightly once. Use /cmd_vel with message type geometry_msgs/msg/Twist. Publish only once." |& tee -a ${RLOG}.log
結果は以下でした。
/bin/sh: 1: Syntax error: Unterminated quoted string
このケースは、クォート崩れで失敗しています。
Step 7-6. 手段を ros2 topic pub に限定した前進指示(本記事での識別コード:L2_FWD_03)
RLOG=L2_FWD_03
ros2 ai exec "Move forward slowly once. Use ONLY ros2 topic pub to publish to /cmd_vel geometry_msgs/msg/Twist. Publish only once." |& tee -a ${RLOG}.log
結果は以下でした。
Warning: Multiple commands detected in "ros2 run geometry_msgs cmd_vel 5 0 -1 3.14 && ros2 pub /cmd_vel geometry_msgs/msg/Twist '{linear: {"x": 0, "y": 0, "z": 0}, angular: {"x": 0, "y": 0, "z": 5}}' --period 1". Only the first 'ros2' command will be executed.
No executable found
ros2 topic pub を使えと書いても、複数コマンドを勝手に作って壊れました。
Step 7-7. 手段を ros2 topic pub に限定した右回転指示(本記事での識別コード:L2_ROT_03)
RLOG=L2_ROT_03
ros2 ai exec "Rotate right slightly once. Use ONLY ros2 topic pub to publish to /cmd_vel geometry_msgs/msg/Twist. Publish only once." |& tee -a ${RLOG}.log
結果は以下でした。
usage: ros2 [-h] [--use-python-default-buffering]
Call `ros2 <command> -h` for more detailed usage. ...
ros2: error: argument Call `ros2 <command> -h` for more detailed usage.: invalid choice: 'topics' (choose from 'action', 'ai', 'bag', 'component', 'control', 'daemon', 'doctor', 'extension_points', 'extensions', 'interface', 'launch', 'lifecycle', 'multicast', 'node', 'param', 'pkg', 'plugin', 'run', 'security', 'service', 'topic', 'wtf')
usage: ros2 [-h] [--use-python-default-buffering]
Call `ros2 <command> -h` for more detailed usage. ...
ros2: error: unrecognized arguments: Period 1 --
このケースは、ros2 topic ではなく ros2 topics を作ってしまい、さらに不正引数も混ざりました。
Step 7-8. 出力形式を強く縛った前進指示(本記事での識別コード:L2_FWD_04)
RLOG=L2_FWD_04
ros2 ai exec "Output ONLY one single-line command and nothing else. No markdown. The command must start with ros2 topic pub. Publish once to /cmd_vel geometry_msgs/msg/Twist with linear.x=0.1 and angular.z=0.0." |& tee -a ${RLOG}.log
結果は以下でした。
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.1, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.5))
publishing #2: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.1, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.5))
...
publishing #8: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.1, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.5))
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.1, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0))
前進 publish 自体は通り、gazebo内のturtlebotも前進を確認できました。
ただし最初は angular.z=0.5 が混ざっており、最後に angular.z=0.0 の publish が出ている。
その際の動画は以下です
Step 7-9. 出力形式を強く縛った右回転指示(本記事での識別コード:L2_ROT_04)
RLOG=L2_ROT_04
ros2 ai exec "Output ONLY one single-line command and nothing else. No markdown. The command must start with ros2 topic pub. Publish once to /cmd_vel geometry_msgs/msg/Twist with linear.x=0.0 and angular.z=-0.6." |& tee -a ${RLOG}.log
このケースは、ログに有効な publish とエラーの両方が混ざっていました。
まず、エラー系としては以下が出ています。
ros2 topic pub: error: argument -1/--once: ignored explicit argument '.02'
/bin/sh: 1: Syntax error: Unterminated quoted string
Warning: Multiple commands detected in "ros2 topic pub /cmd_vel geometry_msgs/msg/Twist '{linear: {x: 0.0}} && wait 4 && {angular: {z: -0.6}}'". Only the first 'ros2' command will be executed.
/bin/sh: 1: Syntax error: Unterminated quoted string
一方で、有効な publish も長く続いている。例えばログの前半には次の結果があります。
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=-0.6))
publishing #2: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=-0.6))
...
publishing #31: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=-0.6))
さらに後半にも publish が続いています。
publishing #32: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=-0.6))
publishing #33: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=-0.6))
publishing #34: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=-0.6))
publishing #35: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=-0.6))
このケースは、ログ全体としてはエラーもありますが、angular.z=-0.6 の publish はかなり長く成功しています。
この際の動画は以下です
Step 7-10. --once ではなく「約1秒だけ動かす」指示(本記事での識別コード:L2_FWD_05)
RLOG=L2_FWD_05
ros2 ai exec "Output ONLY one single-line command. Use ros2 topic pub to publish to /cmd_vel geometry_msgs/msg/Twist for about 1 second and then exit automatically. Prefer using --rate and --times. Use linear.x=0.1 and angular.z=0.0." |& tee -a ${RLOG}.log
結果は以下でした。
usage: ros2 [-h] [--use-python-default-buffering]
Call `ros2 <command> -h` for more detailed usage. ...
ros2: error: unrecognized arguments: --duration seconds 2
このケースは、--duration seconds 2 という存在しない引数を生成して失敗しました。
Step 7-11. 1回の exec で「型確認→前進」(本記事での識別コード:L3_ONE_01)
RLOG=L3_ONE_01
ros2 ai exec "Check the message type of /cmd_vel, then publish a small forward motion once." |& tee -a ${RLOG}.log
このケースでは、少なくともログの抜粋では以下の Twist が連続 publish されていました。
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.5, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.0))
publishing #2: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.5, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.0))
...
publishing #7: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.5, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.0))
型確認の結果が見えるより先に、かなり強い前進+回転の Twist が出ています。
Step 7-12. 1回の exec で「詳細確認→前進」(本記事での識別コード:L3_ONE_02)
RLOG=L3_ONE_02
ros2 ai exec "Check detailed info of /cmd_vel, then publish a small forward motion once." |& tee -a ${RLOG}.log
結果は以下でした。
/bin/sh: 1: cannot open node-name: No such file
このケースは、生成したシェル文字列が壊れて失敗しました。
Step 7-13. 許可サブコマンドを明示して「型確認→前進」(本記事での識別コード:L3_ONE_03)
RLOG=L3_ONE_03
ros2 ai exec "Allowed ros2 topic subcommands are only: list, type, info, pub, echo, hz, bw, delay, find. Do not use any other subcommand. Now check the type of /cmd_vel, then publish a small forward motion once." |& tee -a ${RLOG}.log
結果は以下でした。
geometry_msgs/msg/Twist
少なくとも型確認そのものは成功しました。
Step 8. 検証が終わったら Ollama を止める
T1 の ollama serve を Ctrl + C で終了します。
4. まとめ
今回の結果を、ログに出た文字列ベースで整理するとこうなります。
| 識別コード | 実際に投げた指示の要点 | ログに出た結果 |
|---|---|---|
| 前回の記事 | 確定 ros2 topic pub --once
|
publishing #1: ... linear.x=0.1 ... angular.z=0.0 (成功) |
| L2_FWD_01 | Move forward slowly once |
Package 'myrobot' not found (失敗) |
| L2_FWD_02 | 前進 + topic/型指定 |
Package 'my_robot' not found (失敗) |
| L2_FWD_03 | 前進 + ros2 topic pub 限定 |
Multiple commands detected ... / No executable found (失敗) |
| L2_FWD_04 | 前進 + 1行コマンド + 出力縛り |
linear.x=0.1, angular.z=0.5 が複数回、最後に angular.z=0.0 (前進に成功) |
| L2_FWD_05 | 約1秒だけ前進 |
unrecognized arguments: --duration seconds 2 (失敗) |
| L2_ROT_01 | 右回転 + 曖昧指示 |
/bin/sh: 1: Bad substitution (失敗) |
| L2_ROT_02 | 右回転 + topic/型指定 |
Syntax error: Unterminated quoted string (失敗) |
| L2_ROT_03 | 右回転 + ros2 topic pub 限定 |
invalid choice: 'topics' / unrecognized arguments: Period 1 -- (失敗) |
| L2_ROT_04 | 右回転 + 1行コマンド + 出力縛り |
angular.z=-0.6 の publish が長く続く+途中でクォート崩れ等 (部分成功) |
| L2_STOP_01 | Stop once |
Package 'my_robot' not found (失敗) |
| L3_ONE_01 | 型確認→前進 |
linear.x=0.5, angular.z=1.0 の publish が連続 (失敗) |
| L3_ONE_02 | 詳細確認→前進 |
cannot open node-name (失敗) |
| L3_ONE_03 | 許可サブコマンド明示 |
geometry_msgs/msg/Twist (部分成功) |
5. おわりに
今回は、ros2ai + Ollama に対して曖昧な自然言語指示をどこまで /cmd_vel に落とせるかを、ターミナルから1つずつ試しました。
今回のログから、少なくとも次のことは確認できたと考えられます。
- 曖昧すぎる前進・停止指示は package 実行側に飛びやすい。
-
出力形式まで強く縛ると、実際の Twist publish がかなり出やすくなる。特に前進の
L2_FWD_04と回転のL2_ROT_04では publish ログが明確に残りました。
今後は、前進・回転だけではなくて、行先の指示ができるのかやロボットアームを動かせるかなどについても取り組んでいきたいと考えています。