【前編】KITTに身体を与える――Hermes AgentをCoreS3のStack-chanにつなぐまで
この物語はとあるAI(KITT)にCoreS3のStack-chanを与えるという
計画の入り口である
スタックチャン タカオ版 ケースセット【SG90用】
サーボSG90
Hermesagent用 この組み合わせでファームウエアー選びの難易度よ…
AI_StackChan_Exにたどり着いて安定してサーボの調整まで
組み立て始めてから丸日日徹夜であるw
そこからHermesに同調させるという激闘が.…
共に戦ったchatGPTの制作の記録である記事化をお願いした
長いので前後編に分けてます
皆さん買うときは公式の完成品を買いましょう!!
https://www.switch-science.com/products/11129
はじめに
これまでKITTは、基本的にはPCの中にいた。
Hermes Agent Desktopを基盤として、LLM、外部記憶、Obsidian、各種ツールを組み合わせながら、長いこと「思考する側」の構築を続けてきた。
最近ではHermesそのものにも音声入出力が搭載され、PC上でKITTと声を使って会話することもできるようになっている。
ただ、今回は少し違うことをやってみた。
KITTに物理的な身体を与えてみる。
使ったのはM5Stack CoreS3と、自作ケースにSG90サーボを組み込んだStack-chan。
最終的には、
人間
↓
CoreS3
↓
Hermes Gateway
↓
KITT
↓
CoreS3
├─ 音声
└─ 首の動作という構成を目指す。
今回はその第一段階として、
CoreS3からHermes Agentへ文章を送り、KITTの回答をStack-chan自身の声として発声させる
ところまで実装した。
結果から先に言えば、
成功した。
しかもKITTの返答に合わせて、Stack-chanの首もちゃんと動いた。
ただし、そこへ到達するまでが思った以上の激闘だった。
この記事は、その作業記録兼、後から自分でも再現できるようにするための技術資料である。
1.今回使用したもの
今回の構成は以下。
PC側
Windows PC
Hermes Agent Desktop
Hermes Gateway
OpenAI互換API Server
Stack-chan側
M5Stack CoreS3
AI_StackChan_Ex
SG90 × 2
PWM制御
自作Stack-chanケース
ネットワーク
PC:
192.168.11.2CoreS3:
192.168.11.5同一LAN上で通信させる。
なお、IPアドレスは各自の環境によって当然変わる。
2.最初の構想――Realtime APIへつなごうとしていた
最初はAI_StackChan_ExのRealtime版を使用していた。
設定画面には、
OpenAI Realtime
Google Gemini Liveなどが表示される。
そこで、
「HermesにもOpenAI互換APIがあるなら、そのURLを入れればつながるのでは?」
と考えた。
ところが、ここで最初の大きな勘違いが判明した。
Hermes Gatewayが提供しているのは、今回確認した範囲では通常のOpenAI互換APIである。
例えば、
/v1/models
/v1/chat/completionsだ。
一方、AI_StackChan_ExのRealtime版はOpenAI Realtime APIを前提としている。
つまり、
OpenAI互換 Chat Completionsと
OpenAI Realtime APIは、名前は似ていても通信方式が違う。
ネットワーク設定やAPIキー以前の問題だった。
そこで方針を変更した。
3.Hermes GatewayのOpenAI互換APIをLANへ公開する
Hermes Desktop側では、GatewayのOpenAI互換API Serverを有効にした。
私の環境では設定ファイルは、
C:\Users\<ユーザー名>\AppData\Local\hermes\.envにあった。
設定した内容は、
API_SERVER_ENABLED=true
API_SERVER_HOST=0.0.0.0
API_SERVER_PORT=8642
API_SERVER_KEY=<自分で設定したAPIキー>である。
重要なのは、
API_SERVER_HOST=0.0.0.0の部分。
localhostだけではなく、LAN上のCoreS3からもアクセスできるようにする。
もちろん、そのままLAN全体へ無制限公開するのは避けたい。
そこでWindows Firewall側ではTCP 8642について、CoreS3のIP、
192.168.11.5からの受信だけを許可した。
4.まずPCだけでHermes APIを確認する
いきなりCoreS3から試さない。
まずPC上でHermes Gatewayが本当に待受しているかを確認した。
PowerShellで、
netstat -ano | findstr :86428642番ポートがLISTENしていることを確認する。
さらに、
curl.exe http://127.0.0.1:8642/v1/models `
-H "Authorization: Bearer <Hermes API_SERVER_KEY>"を実行。
実際に、
{
"object": "list",
"data": [
{
"id": "hermes-agent",
"object": "model",
"owned_by": "hermes"
}
]
}という応答が返った。
これで、
Hermes側のOpenAI互換APIそのものは正常
と切り分けられた。
この確認はかなり重要だった。
後からCoreS3で問題が起きても、
Hermesが悪いのか
CoreS3が悪いのか
ネットワークが悪いのかを分離できるからである。
5.AI_StackChan_Exを調べ直す
ここからAI_StackChan_Exのソースを確認した。
すると、最新版にはすでに、
OpenAI Compatible HTTP Endpoint用のLLMタイプが存在していた。
設定上は、
llm:
type: 4である。
つまり、当初考えていたような大規模な改造は必要なかった。
通常会話版のAI_StackChan_Exを使用し、
llm:
type: 4
model: "hermes-agent"
customEndpoint: "http://192.168.11.2:8642/v1/chat/completions"とすれば、Hermes Gatewayへ直接Chat Completionsリクエストを送れる。
ここで一気に道が見えた。
6.SG90の設定は絶対に壊さない
今回もう一つ重要だったのがサーボである。
私のStack-chanは公式キットそのままではなく、自作ケース+SG90を使用している。
そのため、別ファームをそのまま書き込むと首の制御を壊す可能性がある。
実機確認の結果、現在採用している設定は、
servo:
pin:
x: 17
y: 18
center:
x: 95
y: 90
lower_limit:
x: 82
y: 65
upper_limit:
x: 100
y: 115
servo_type: "PWM"とした。
特に可動域については安全上重要なので、LLM接続作業とは分離して扱った。
今回の基本方針は、
Hermes接続を追加しても、SG90、GPIO、PWM、中心角、安全可動域は不用意に変更しない
である。
7.ここでSDカード問題
AI_StackChan_Exでは設定をSDカードから読み込ませる想定がある。
ところが起動ログを見ると、
sdCommand(): Card Failed!
sdcard_mount(): f_mount failedとなった。
さらに、
Loading config from SPIFFS.と出ている。
つまりCoreS3はSDを読めず、内部SPIFFSへ保存されていた設定を使用していた。
このため、SDカード上のYAMLをいくら変更しても、
実際に起動時に使われる設定が変わらない
という状態になった。
ログを見ると、
"llm": {
"type": 0,
"enableMemory": false,
"mcpServers": []
}となっていた。
Hermes用に変更したはずなのに type: 0。
原因はここだった。
8.PlatformIOでも一度事故る
CoreS3用PlatformIO環境も少し特殊だった。
最終的に使用した環境は、
[env:m5stack-cores3]
platform = espressif32@6.3.2
board = esp32s3box
framework = arduinoだった。
環境名は m5stack-cores3 だが、内部のboard定義として esp32s3box を利用している。
途中でここを一般的なCoreS3定義へ変更してしまい、書き込み後にCoreS3が正常起動せず、
USB接続
↓
切断
↓
再接続
↓
切断を繰り返す状態になった。
一瞬「壊したか?」と思った。
最終的にはCoreS3をダウンロードモードへ入れて再書き込みし、無事復旧した。
この辺はかなり冷や汗ものだった。
9.SPIFFSへ直接設定を送る
SDカードが安定しないので、別ルートを使った。
幸いAI_StackChan_Exは起動時に、
FTP server startedと表示される。
そこでCoreS3のFTPサーバーを利用して、設定ファイルを直接SPIFFSへ送った。
Hermes用の SC_ExConfig.yaml を、
curl.exe --user <FTP_USER>:<FTP_PASSWORD> `
-T "SC_ExConfig.yaml" `
ftp://192.168.11.5/SC_ExConfig.yamlで転送。
その後、
curl.exe --user <FTP_USER>:<FTP_PASSWORD> `
ftp://192.168.11.5/SC_ExConfig.yamlで再取得し、
llm:
type: 4
model: "hermes-agent"
customEndpoint: "http://192.168.11.2:8642/v1/chat/completions"が実際にCoreS3内部へ保存されていることを確認した。
ここでようやく、
「編集したファイル」と「実機が読むファイル」が一致した。
10.しかしWeb設定画面で保存するとHermes設定が消える
ここでさらに問題が見つかった。
AI_StackChan_ExのWebAPIには、
String build_extend_yaml(JsonObjectConst ex)という、Web画面から受け取った設定をYAMLへ再構築する処理がある。
ところが、その処理では、
llm.type
enableMemory
mcpServersなどは保存するのに、
model
customEndpointを保存していなかった。
つまりHermes用設定を手作業で入れても、Web画面からSaveすると、
model: "hermes-agent"
customEndpoint: "..."が消える可能性がある。
そこで firmware/src/WebAPI.cpp の build_extend_yaml() のみを修正した。
方針は非常に限定した。
変更:
model
customEndpoint
を保存対象へ追加
変更しない:
SG90
GPIO
PWM
Servo設定
その他の機能ビルド成功を確認してからCoreS3へUpload。
ここでようやくHermes用設定を保持できる基盤ができた。
えーここまで長いものを見てくれた人ありがとう
まだ半分ですw
これちゃんとつながるようにして
一般の人が試せるようなファームウエアーにしたら
もしかして需要があるんでは…
という妄想を抱きつつ
後編へ
