MycobotをChatGPTで操作
※このページは、神奈川工科大学 コミュニケーションロボティクス研究室および 電気電子工学科/ホームエレクトロニクス開発学科の実習用チュートリアル用のページです。
1. はじめに
AIにどんな身体を持たせるか?AIの"知能"が急速に発展する中で、ますますおもしろさが増すテーマの一つです。
ここでは、
「ロボットアームを身体に持つAI」
をテーマに、ChatGPTと連携して音声対話で動くロボットアームを構築します。ロボットアームには、myCobot 280 M5を想定しています。
2. システムの概要
2.1 システムの概要
https://gyazo.com/bc50b922fac11c4fdc04c28a8ff7e6cf
音声入力:マイクから録音(5秒間)
音声認識:Whisper(OpenAI)
内容判定:ChatGPTで「握手」「あいさつ」「ティッシュを取る」を分類
ロボット操作:MyCobotが動作を実行(教示動作含む… けど使わなかった)
GUI:Tkinterで操作とログを表示
https://gyazo.com/8c6cd54ab9ec954d171cf8ab7fea7c4f
2.2 使用ライブラリ
table:使用ライブラリ
ライブラリ 用途
sounddevice マイク録音
scipy.io.wavfile 録音データの保存(WAV)
whisper 音声認識(日本語対応)
openai ChatGPT API呼び出し
pymycobot MyCobot制御
tkinter GUI(ポート選択・録音・ログ)
3. 構築の手順
Step 1 必要なライブラリをインストール
code:pip
pip install sounddevice scipy openai pyserial pymycobot tkinter whisper
Step 2 FFmpegをインストールしパスを通す
Step 3 ChatGPT APIの準備
OpenAIのAPIキーを取得しておく。
※(研究室内用のコメント)研究で使う場合は、研究室のAPIKEYを問い合わせてください
4. サンプルコード
code:myCobot_ChatGPT_demo.py
import threading
import time
import csv
import sounddevice as sd
import scipy.io.wavfile as wav
import whisper
from openai import OpenAI
from pymycobot.mycobot import MyCobot
import tkinter as tk
from tkinter import ttk, messagebox
import serial.tools.list_ports
# --- 設定 ---
AUDIO_FILENAME = "input.wav"
CSV_FILENAME = "tissue_motion.csv" # 使用してないです
RECORD_SECONDS = 5
SAMPLERATE = 16000
OPENAI_API_KEY = "YOUR-API-KEY" # 自分の環境に応じて書き換えてください
ALLOWED_COMMANDS = {"wave_hand", "handshake", "get_tissue"}
# --- 初期化 ---
client = OpenAI(api_key=OPENAI_API_KEY)
whisper_model = whisper.load_model("base")
mc = None # MyCobotインスタンス
# --- 音声録音 ---
def record_audio():
log("🎤 録音開始(しゃべってください)...")
recording = sd.rec(int(RECORD_SECONDS * SAMPLERATE), samplerate=SAMPLERATE, channels=1, dtype='int16')
sd.wait()
wav.write(AUDIO_FILENAME, SAMPLERATE, recording)
log("✅ 録音完了")
# --- Whisperで音声認識 ---
def transcribe_audio():
log("🧠 音声認識中...")
result = whisper_model.transcribe(AUDIO_FILENAME, language="ja")
text = result.get("text", "")
log(f"📝 認識結果: {text}")
return text
# --- ChatGPTで動作分類(これを元にプロンプトを追加して「気が利く」ようにしてみましょう) ---
def classify_command(text):
prompt = f"""
以下の音声入力に対応するアクションを返してください。
対応可能なアクションは:
- あいさつ → wave_hand
- 握手して, アクションして → handshake
- ティッシュとって → get_tissue
返すのは必ず「wave_hand」「handshake」「get_tissue」のいずれか1つのみです。
音声入力:「{text}」
"""
try:
log("🤖 ChatGPTでコマンド判定中...")
response = client.chat.completions.create(
model="gpt-4",
messages={"role": "user", "content": prompt}
)
command = response.choices0.message.content.strip()
log(f"✅ 判定結果: {command}")
if command not in ALLOWED_COMMANDS:
log("⚠️ 不明なコマンド: " + command)
return "unknown"
return command
except Exception as e:
log(f"❌ ChatGPT APIエラー: {e}")
return "unknown"
# --- MyCobotモーション制御 ---
def execute_motion(command):
log(f"🤖 ロボット動作: {command}")
if mc is None:
log("❌ MyCobotが接続されていません")
return
if command == "wave_hand":
for _ in range(3):
mc.send_angles(0, -10, 30, 90, 0, -45, 50)
mc.set_gripper_value(60, 10)
time.sleep(0.6)
mc.send_angles(0, -10, -40, 90, 0, -45, 50)
time.sleep(0.6)
time.sleep(1.0)
mc.send_angles(0, 0, 0, 0, 0, 0, 50)
time.sleep(0.6)
mc.set_gripper_value(0, 40)
elif command == "handshake":
mc.send_angles(-90, 0, 0, 0, 0, 0, 50)
time.sleep(0.6)
mc.set_gripper_value(40, 10)
mc.send_angles(-90, -105, 30, 75, 0, 0, 50)
time.sleep(2)
for _ in range(3):
mc.send_angles(-90, -120, 30, 60, 0, 0, 50)
mc.set_gripper_value(20, 40)
time.sleep(0.65)
mc.send_angles(-90, -105, 30, 75, 0, 0, 50)
time.sleep(0.65)
mc.set_gripper_value(40, 10)
mc.send_angles(0, 0, 0, 0, 0, 0, 50)
elif command == "get_tissue":
mc.send_angles(0, 0, -100, 20, 0, 45, 50)
time.sleep(0.6)
mc.set_gripper_value(40, 10)
time.sleep(1)
mc.set_gripper_value(0, 10)
time.sleep(1)
mc.send_angles(0, 0, -75, 15, 0, 45, 50)
time.sleep(0.6)
mc.send_angles(-90, -105, 30, 75, 0, 0, 50)
time.sleep(2)
mc.set_gripper_value(40, 10)
time.sleep(1)
mc.send_angles(0, 0, 0, 0, 0, 0, 50)
else:
log("⚠️ 実行スキップ(不明な動作)")
# --- 教示モーションを再生 (使用してないです) ---
def play_taught_motion():
log("📂 教示モーション再生中...")
try:
with open(CSV_FILENAME) as f:
reader = csv.reader(f)
for row in reader:
if len(row) != 6:
continue
angles = list(map(float, row))
mc.send_angles(angles, 50)
time.sleep(1)
except FileNotFoundError:
log(f"❌ CSVファイルが見つかりません: {CSV_FILENAME}")
# --- GUI ログ関数 ---
def log(message: str):
txt_log.config(state=tk.NORMAL)
txt_log.insert(tk.END, message + "\n")
txt_log.see(tk.END)
txt_log.config(state=tk.DISABLED)
# --- シリアルポート接続 ---
def connect_robot():
global mc
port = combo_ports.get()
if not port:
messagebox.showwarning("警告", "シリアルポートを選択してください。")
return
try:
mc = MyCobot(port)
log(f"🔌 MyCobot接続成功: {port}")
btn_record.config(state=tk.NORMAL)
btn_handshake.config(state=tk.NORMAL)
btn_wave.config(state=tk.NORMAL)
btn_tissue.config(state=tk.NORMAL)
except Exception as e:
messagebox.showerror("エラー", f"MyCobot接続失敗: {e}")
# --- 録音開始ボタン押下処理 ---
def on_record():
btn_record.config(state=tk.DISABLED)
threading.Thread(target=workflow).start()
# --- 全体ワークフロー ---
def workflow():
record_audio()
text = transcribe_audio()
command = classify_command(text)
execute_motion(command)
btn_record.config(state=tk.NORMAL)
# --- モーションボタン処理 ---
def run_handshake():
execute_motion("handshake")
def run_wave():
execute_motion("wave_hand")
def run_tissue():
execute_motion("get_tissue")
# --- GUI構築 ---
root = tk.Tk()
root.title("MyCobot 音声対話デモ")
root.geometry("500x500")
# シリアルポート選択
frame_top = ttk.Frame(root, padding=10)
frame_top.pack(fill=tk.X)
ttk.Label(frame_top, text="シリアルポート:").pack(side=tk.LEFT)
ports = port.device for port in serial.tools.list_ports.comports()
combo_ports = ttk.Combobox(frame_top, values=ports, state="readonly")
combo_ports.pack(side=tk.LEFT, padx=5)
btn_connect = ttk.Button(frame_top, text="接続", command=connect_robot)
btn_connect.pack(side=tk.LEFT, padx=5)
# 録音開始ボタン
btn_record = ttk.Button(root, text="録音開始(音声指示)", command=on_record, state=tk.DISABLED)
btn_record.pack(pady=10)
# 手動モーションボタン
frame_buttons = ttk.Frame(root, padding=10)
frame_buttons.pack()
btn_handshake = ttk.Button(frame_buttons, text="🤝 握手", command=run_handshake, state=tk.DISABLED)
btn_handshake.grid(row=0, column=0, padx=5, pady=5)
btn_wave = ttk.Button(frame_buttons, text="👋 あいさつ", command=run_wave, state=tk.DISABLED)
btn_wave.grid(row=0, column=1, padx=5, pady=5)
btn_tissue = ttk.Button(frame_buttons, text="🧻 ティッシュ", command=run_tissue, state=tk.DISABLED)
btn_tissue.grid(row=0, column=2, padx=5, pady=5)
# ログ出力テキスト
txt_log = tk.Text(root, height=15, state=tk.DISABLED)
txt_log.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
root.mainloop()
サンプルコードの動作手順
https://gyazo.com/8c6cd54ab9ec954d171cf8ab7fea7c4f
MyCobot接続
COMポート一覧から選択(Tkinterのドロップダウン)
MyCobot(COM番号) で接続
接続後にボタンが有効化される
音声対話ワークフロー
録音 → Whisperでテキスト化 → ChatGPTで分類 → MyCobot動作
例:「こんにちは」→ wave_hand → MyCobotが手を振る
モーション実行と教示再生
wave_hand、handshake、get_tissue:角度とグリッパー制御で再現
get_tissueは、当初はCSVに保存されたモーションを読み込み再生しようとしていた。ただSDカードの書き込みがうまくいかず断念。結局手作業でコードを作った。
今後の課題
ChatGPTでモーションをプログラミングできるようにしたい。今のところ、良いモーションはできないので、うまく修正のループを回せるフィードバックの仕方を考える。下はChatGPTにモーションをつくらせてみた例
モーションの修正
code:修正前
if command == "wave_hand":
mc.send_angles(0, 15, 0, 0, 0, 0, 50)
time.sleep(1)
mc.send_angles(0, -15, 0, 0, 0, 0, 50)
elif command == "handshake":
mc.send_angles(0, -40, 20, 0, 0, 0, 50)
elif command == "get_tissue":
play_taught_motion()
code:修正後
# 初期姿勢
mc.send_angles(0, 0, 0, 0, 0, 0, 30)
time.sleep(1)
# 腕を前に出す姿勢
mc.send_angles(0, -10, 60, -50, 0, 0, 30)
time.sleep(1)
# グリッパーで握手する動作
mc.set_gripper_value(0, 30) # 開く
time.sleep(1)
mc.set_gripper_value(60, 30) # 握る
time.sleep(1)
mc.set_gripper_value(30, 30) # 軽く緩める(挨拶の余韻)
time.sleep(1)
# 元に戻す
mc.send_angles(0, 0, 0, 0, 0, 0, 30)
# 初期姿勢
mc.send_angles(0, 0, 0, 0, 0, 0, 30)
time.sleep(1)
# 腕を前に出す姿勢
mc.send_angles(0, -10, 60, -50, 0, 0, 30)
time.sleep(1)
# グリッパーで握手する動作
mc.set_gripper_value(0, 30) # 開く
time.sleep(1)
mc.set_gripper_value(60, 30) # 握る
time.sleep(1)
mc.set_gripper_value(30, 30) # 軽く緩める(挨拶の余韻)
time.sleep(1)
# 元に戻す
mc.send_angles(0, 0, 0, 0, 0, 0, 30)
#ChatGPT #AI #IoT #ものづくりプロジェクトII
https://gyazo.com/71c7de59f100448c29cdb7f29fbd171b
Communication Robotics Lab.