ChatGPT APIを使って自然言語の指示でGazebo上のTurtleBot3を制御する

# はじめに
以下のMicrosoftの研究に触発され、ChatGPTを使用してROS2のロボットを言語指示で制御できるか試してみました。

言語指示によってロボットを動かすための手順は以下のようになります。

１. プロンプトで指示を入力（例：0.2m/sで前進する）
２. ChatGPTを使用してPythonのROS2ノードを生成
３. 生成されたROS2ノードを実行して、ロボットを制御する

上を実行するためのPythonスクリプトを作成する。

Microsoft、ChatGPTによる自然言語でロボットの制御に成功
https://pc.watch.impress.co.jp/docs/news/1482261.html


# 事前準備

## OpenAI APIの取得

以下の記事を参考に取得する。
取得したAPIはコピペして環境変数に登録しておく。


https://auto-worker.com/blog/?p=6988

.bashrcに以下を追記

```bash
export OPENAI_API_KEY="open-ai key"
```

## OpenAI APIのインストール

```bash
pip3 install openai
```


## ROS2 で動くロボットのGazebo環境をインストール

/cmd_velで動かすことのできるロボットのシミュレーション環境を用意する。
（ROS1 でも可　その場合後述する事前のpromptをROS1 のrospyで書かせるように調整する）

筆者はTurtlebot3 のGazeboシミュレーションを使用した。

```bash
sudo apt install ros-humble-turtlebot3-simulations
```


# Pythonスクリプトの説明

以下のようなPythonスクリプトを作成する。
説明はコメントの通り。

```python:generate_and_run_python_script.py
import openai
import subprocess
import os
import sys
# OpenAI APIキーの取得
openai.api_key = os.getenv("OPENAI_API_KEY")

# 事前promptをprompt.txtから読み込む
with open("prompt.txt", "r") as f:
    pre_prompt = f.read()

# ChatGPT APIでpromptを入力して返信を受け取る
def get_chat_response(prompt):
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "user", "content": prompt},
        ]
    )
    return response.choices[0]["message"]["content"].strip()

#返信の内容を.pyファイルに書いて保存する
def generate_python_script(res):
    python_code = res
    with open("generated_script.py", "w") as f:
        f.write(python_code)

# subprocessでpythonスクリプトを実行する
def run_python_script():
    result = subprocess.run(["python3", "generated_script.py"], capture_output=True)

def main(prompt):
    res = get_chat_response(prompt)
    generate_python_script(res)
    run_python_script()

if __name__ == "__main__":
    #prompt を入力する
    prompt = pre_prompt + input("")
    main(prompt)
```


事前情報となるpromptを上のPythonスクリプトと同じディレクトリにあるprompt.txtに書いておく
以下はpromptの例　
rclpyで差動2輪ロボットを制御するPythonコードを書くように指示を出している。
普通に”pythonコードを書け”だけだと余計な説明が入ってしまい、Pythonコードにならず実行時エラーがでるので、コードのみ出力させるように工夫する。

```txt:prompt.txt
I need rclpy code to run a differential two-wheeled robot.
Publish /cmd_vel every 0.1 seconds.
Please only write Python code in your replies.
Reply by. import rclpy Please start with
QoS is not set
```

### 使用方法


```bash
python3 generate_and_run_python_script.py 

0.2m/sで前に進む
```

実行後に指示をコンソールに入力する。


# 実行

TurtleBot3 Gazeboシミュレーションを起動

```bash
ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py 
```
generate_and_run_python_script.py を実行
指示を入力　

```bash
python3 generate_and_run_python_script.py 
```

以下は前に0.2m/sで進む 指示を実行した時の様子。（精度を少しでも上げるため英語を使用）

```bash
ros2 topic echo /cmd_vel
```

で確認するとちゃんと0.2m/sで前に動くトピックがPublishされている。



https://twitter.com/porizou1/status/1634882447803547648?s=20

以下はこの時にChatGPTで生成されたPythonスクリプト

```python:generated_script.py
import rclpy
from geometry_msgs.msg import Twist
from time import sleep

def run_robot():
    rclpy.init()

    node = rclpy.create_node('differential_robot')
    pub = node.create_publisher(Twist, '/cmd_vel', 10)

    while rclpy.ok():
        velocity_msg = Twist()
        velocity_msg.linear.x = 0.2
        velocity_msg.angular.z = 0.0
        pub.publish(velocity_msg)
        sleep(0.1)
    
    node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    run_robot()
```

# おわりに

一応言語の指示でROS2のロボットを動かすことができた。
しかし、まだまだ簡単な動きしかできず、実用的に使うには課題が多いと感じた。
執筆時時点でGPT-4のAPIが公開されているので、そちらの方でも試してみたい。


# 実行環境

OS : ubuntu22.04LTS
ROS : ROS 2 Humble
Python : Python3.10.6


# 参考

https://dev.classmethod.jp/articles/openai-api-chat-python-first-step/

https://auto-worker.com/blog/?p=6988