見出し画像

【前編】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.2

CoreS3:

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 :8642

8642番ポートが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

これちゃんとつながるようにして
一般の人が試せるようなファームウエアーにしたら
もしかして需要があるんでは…
という妄想を抱きつつ
後編へ

いいなと思ったら応援しよう!