引き継ぎ資料: Module-LLM オンデバイス melotts + tiered cognition (#69/#70/#71)
最終更新: 2026-05-29 / 作業機: Mac Studio(神田、bridge/JCARVIS/Module-LLM が集約) / リモート: MacBook
恒久ナレッジ:
troubleshooting/module-llm-onboard-melotts.md内部構造・ハード仕様書(各モジュールのスペック/対応範囲/通信経路の単一出典):../architecture.md🛠 実機デバッグを別セッションで再開する人へ →handoff-debug-72.md(接続手順・HUDの読み方・未解決課題と診断手順・診断スクリプト)
CoreS3 画面が真っ黒問題 (2026-05-29 解決)
- 症状: LCD 完全消灯(avatar/直接描画とも黒)。だが firmware は正常起動(WiFi/WSS/loop まで到達)=MCU は生きていて画面出力だけ死。
- 原因: M5GFX 自動検出が NVS から
board:0(unknown) で CoreS3 確定できず、パネル/バックライト電源(AXP2101)が未初期化。[M5GFX][Autodetect] load from NVS : board:0が目印。 - 修正(実機確認済):
M5.begin前にcfg.fallback_board = m5::board_t::board_M5StackCoreS3;。詳細メモcores3-blank-display-fallback-board。 - 要追加修正(電源サイクル耐性):
stackchan_config.hのBOTTOM3_PORT_A_SDA/SCL=12/11は CoreS3 内部システムI2Cピン。正しい外部 Port.A は GPIO 2/1。presence_sensor.cppのWire.begin(12,11)が内部バスを汚し再起動で再発し得る → 2/1 へ要変更。
standalone 化の方針 (2026-05-29 追加)
- 要望: 通常稼働は本体単独(Wi-Fi のみ)、PC 接続はデバッグ時のみにしたい。
- 現状: ASR はデバイス単独 ✅ / 頭脳は Wi-Fi 経由で可 △ / melotts 発話だけ USB-adb 依存 ❌(Module-LLM は IP を USB でしか持てず、TTS が非 StackFlow な TCP プロセスのため)。
- 採用方針 = 案 A: StackFlow
llm-melotts1.8 + ja-jp 0.6 の FST crash を修正し、SKIP_MELOTTS_SETUP=0で CoreS3→UART→Module-LLM 発話を復活(adb/Python 不要に)。調査手順は../architecture.md§5.2。最終確認は実機 + ADB 必須。
0. 30秒サマリ
- 声→ASR→Claude(JCARVIS)→Module-LLM オンデバイス発話 の遠隔ループは実機で動作確認済み ✅
- 課題: 間つなぎが ~4秒 → 高速化中 (#70 事前キャッシュをコミット済・実機検証待ち)
- 次フェーズ: 文脈ワードからの即時応答 (#70/#71)
- 運用ブロッカー: Module-LLM の USB が電源不足で頻繁に切断/再起動(セルフパワーUSBハブ推奨)
1. 達成済み (動作確認済み ✅)
- 実機フルループ: CoreS3 マイク→whisper ASR(Module-LLM)→Funnel WSS→bridge(Mac Studio)→JCARVIS:8181→Claude→melotts(Module-LLM)発話。間つなぎ→本答の順で実発話を確認。
- オンデバイス melotts: 合成(NPU)+tinyplay 再生(48k/stereo)、常駐サーバ+ストリーミング。
- bridge melotts 経路:
TTS_ENGINE=melottsで応答を Module-LLM へ。間つなぎ fire-and-forget。 - JCARVIS :8181: Claude(サブスク) 応答 + Discord ミラー(webhook 設定済)。
2. ブランチ / git
- ブランチ
feat/melotts-onboard-tts-67(origin に push 済み、本資料push後 ahead 0)。 - 主要コミット: #66 IR / #67 melotts単体 / #69 発話・常駐サーバ・ストリーミング・bridge melotts・間つなぎ / #70
25c2f4a間つなぎ事前キャッシュ。 - MacBook 側:
git fetch origin && git checkout feat/melotts-onboard-tts-67
3. アーキテクチャ (#72 で更新: 発話は常に on-device melotts/UART、思考だけ切替)
CoreS3 mic → whisper ASR(Module-LLM, StackFlow, UART) → CoreS3
├─[WSS接続中=BRIDGE]→ Funnel(wss://…/stackchan/ws) → bridge :7780 (TTS_ENGINE=none, backend=jcarvis)
│ → JCARVIS :8181 (Claudeサブスク) → 応答テキストのみ返す
│ → CoreS3 が agent.done 後に ↓ で発話
└─[WSS切断=STANDALONE]→ on-device qwen2.5-0.5B (~1s) で応答テキスト生成
↓ (両モード共通)
CoreS3 → UART → Module-LLM StackFlow llm-melotts (ja-jp) → スピーカー発話- TTS から adb / python(:5055) / VOICEVOX を排除。発話は StackFlow llm-melotts を UART で叩く一本化。
- tiered cognition: WSS 接続時は Claude(高品質)、切断時は on-device qwen(低品質だが PC 不要)。詳細メモ
stackchan_tiered_dual_mode/stackchan_tiered_cognition。 - 旧構成(bridge が adb/python melotts や VOICEVOX で発話)は廃止。
4. ロードマップ (1機能ずつ・別issue)
| issue | 内容 | 状態 |
|---|---|---|
| #69 | オンデバイス melotts 統合 | ✅ 実機動作確認 |
| #70 フェーズ1 | on-device ワード抽出(mecab,0トークン) + テンプレ間つなぎ + 間つなぎ事前キャッシュ | 🔨 事前キャッシュ(25c2f4a)コミット済・実機検証待ち。ワード抽出/テンプレ間つなぎは未着手 |
| #71 フェーズ2 | アドホックモードで JCARVIS 先読み (A:流暢間つなぎ事前生成 / B:本答コンテキスト下ごしらえ)、変化なしスキップ、専用DB、Discordログ活用 | 📋 設計のみ |
| #72 | StackFlow melotts(ja-jp) FST crash 修正 → UART発話一本化 / 頭脳2モード(Claude⇔qwen0.5B) / Debug HUD / CoreS3画面黒(fallback_board) / standalone暴走対策 | 🔨 実装・ビルド済。実機フラッシュ検証待ち(下記§6)。melotts/qwen/HUD/接続は実機確認済、音声ループ全体は未検証 |
| 将来 | (C) 投機的答え候補の先回り / 喋り出し途切れ / ASR 16bit品質 | 候補 |
5. 実行中サービス (Mac Studio。MacBook からは触れない)
bash
# JCARVIS :8181 (要 claude CLI ログイン)
cd /Volumes/AIWorkSSD/AIWorkSpace/github/aieo-product/AIEO_JCARVIS
( DISCORD_LOG_WEBHOOK_URL="$(security find-generic-password -s DISCORD_LOG_WEBHOOK_URL -a "$USER" -w)" \
AGENT_PROFILE=donack DONACK_ENGINE=claude nohup node connectors/stackchan/server.js \
> /tmp/jcarvis-8181.log 2>&1 < /dev/null & )
curl -s http://127.0.0.1:8181/healthz # engine":"ClaudeEngine"
# bridge :7780 (#72: TTS_ENGINE=none = テキストのみ返し、発話は firmware が on-device melotts で行う)
cd /Volumes/AIWorkSSD/AIWorkSpace/github/aieo-product/stackchan/mac-studio/bridge
( TTS_ENGINE=none nohup npm run start > /tmp/stackchan-bridge.log 2>&1 < /dev/null & )
# (2026-05-29 セッションでこのモードで起動中。PID は lsof -nP -iTCP:7780 -sTCP:LISTEN で確認)
# melotts.axera python サーバ(:5055/adb)はもう不要 (StackFlow llm-melotts/UART に一本化)。- 監視:
tail -f /tmp/stackchan-bridge.log | grep -E "forwarding|tts:none|wake"
6. 次にやること (device 復帰後) — #72 検証
前提: firmware は #72 をビルド済(未フラッシュの最新差分あり)。bridge は
TTS_ENGINE=noneで稼働。 Module-LLM は電源付きUSBハブ必須(電源不足で頻繁に切断/再起動 → UART/ASR が死ぬ。本セッションでも発生)。 検証中はできれば adb を切る(adb kill-server)。adb 接続は CoreS3↔Module-LLM の UART を不安定化させる。
- CoreS3 を接続 →
pio run -e m5stack-cores3 -t upload --upload-port /dev/cu.usbmodem83201で最新 #72 を焼く。 - 画面が出るか確認(fallback_board 修正済)。出ないなら起動ログの
M5.getBoard()=が 0(unknown) でないか確認。 - bridge モード(WiFi/WSS接続時): 「ねえドナック、〇〇」→ HUD の「思考N.Ns / 発話N.Ns / 計N.Ns」を読む。
- 30秒問題の内訳診断: 思考が大→Claude遅い(短文化/速モデル/間つなぎ)、発話が大→長文melotts(短文化+文ストリーミング)。
- standalone モード(WiFi切断 or bridge停止): 「ドナック…」と wake 入りで話す → on-device qwen が ~1s で応答・melotts発話。wake 無し/自己エコーは無視される(暴走しない)はず=#72 のエコーガード検証。
- I2Cセンサを実際に使うなら Port.A を 2/1(現設定)で配線確認。違えば実機に合わせて
stackchan_config.h修正。 - 余力: 喋り出し途切れ(48k/period160)・ASR 16bit品質(記事の I2S バグ)・HUD フリッカ(drawHud の全画面 fillScreen → M5Canvas sprite 化。実機未検証で見送り中)・#70/#71。
#72 マルチエージェントレビューで修正済 (2026-05-29, 実機なし)
firmware 変更を 4観点×検証エージェントでレビュー→7件確定→6件修正(ビルド/ロジック検証済):
- [HIGH] WSS 切断で
g_claude_in_flight固着→bridge 永久無反応: DISCONNECTED/ERROR でラッチ解除 + 30s ウォッチドッグ +enableHeartbeat(15s,3s,2)。 - [MED] エコー/wake が生バイト比較で弱い:
normalizeJa(カタカナ→ひらがな/促音長音除去) を C++ 移植し正規化照合に。短文しきい値見直し + tail guard 500→1500ms。 - [MED] 'どなく' 自己トリガー: 正規化で echo ガードが wake より先に効くよう整理。
- [LOW] FSM が Thinking/Talking に遷移しない: ASR 時に WakeDetected を先行 dispatch。
- [LOW・未対応] HUD 全画面再描画フリッカ: sprite 化は実機未検証リスクのため見送り(上記余力)。
7. ハマりどころ / 重要な学び
- CoreS3 接続先: 旧ファームは LAN IP
192.168.128.90:7780(Mac Studio) で、テザリングだと届かない。Funnel URL に reflash 済。reflash 例:PLATFORMIO_BUILD_FLAGS='-DSTACKCHAN_SERVER_URL=\"wss://takehiromac-studio.tail3ab66f.ts.net/stackchan/ws\" -DSKIP_MELOTTS_SETUP=1 -DSKIP_LLM_SETUP=1'+pio run -e m5stack-cores3 -t upload --upload-port /dev/cu.usbmodem83201 - CoreS3 が応答途中で WS 切断→再接続する。
bridge は WS close で→ 対策済み (2026-05-29, 実機なしで実装・スモーク検証):ac.abort()→Claude をアボートする実装。タイミング次第で本答消失リスク- melotts 経路では本答を adb 経由でデバイスへ直接発話する (WS 非依存) ため、WS close でアボートしないよう変更 (
server.tsonCloseを engine 別に分岐)。voicevox 経路は従来どおり close で abort。 send()をreadyState===OPENガードに変更 (close 後の送信で throw しない)。- WS keepalive 追加:
WS_KEEPALIVE_MS(既定 20s) 間隔で ping、pong 無応答ソケットをterminate()。「close は来ないが実質切れている」状態も検知。 - ⚠️ 本番 bridge(:7780, pid起動中) は旧コードのまま。反映には bridge の再起動が必要 (§5 の起動コマンド)。実機復帰時に併せて再起動推奨。
- melotts 経路では本答を adb 経由でデバイスへ直接発話する (WS 非依存) ため、WS close でアボートしないよう変更 (
- CoreS3 シリアル読み取り(pyserial)で DTR/RTS が立つと CoreS3 がリセット→WS切断。確認時は
dtr=False,rts=Falseで開く、もしくはシリアルを触らず bridge ログで確認。 - Module-LLM USB が電源不足で頻繁に切断/再起動(本セッションで5回以上)。再起動すると melotts サーバが落ちる→再起動要。セルフパワーUSBハブ/別給電推奨。
- pkill 自死:
pkill -f melotts_server.pyは実行中の adb shell 自身にマッチ→[m]elotts_server.pyで回避。 - playback フォーマット: AO は 48kHz/stereo/16bit 必須。再生(pcmC0D1p)と録音(pcmC0D0c)は別系統で llm-audio 稼働中でも再生可。tinyplay は
LD_LIBRARY_PATHに/opt/usr/lib要。 - サブスク Agent SDK 遅延: claude/JCARVIS とも first token ~5s。速い直 Haiku には Anthropic API キーが要るが Keychain に無し(OAuth サブスクのみ)。
- ワード解析は on-device 可: melotts 用の
mecab+unidicがデバイスにあり、名詞/固有名詞/数詞抽出に流用可(#70、0トークン)。 - pio python 流用: Mac に pyserial 無し→
/opt/homebrew/Cellar/platformio/*/libexec/bin/python(pyserial同梱) を使う。pip downloadはDYLD_LIBRARY_PATH=/opt/homebrew/opt/expat/lib。
8. リモート制御メモ
- Tailscale: Mac Studio=
takehiromac-studio(100.119.73.2)、MacBook=otani-macbook-pro(100.86.201.47, active)。 - Mac Studio→MacBook の SSH は鍵未設定(
Permission denied)。遠隔で MacBook 側 device を叩くなら ssh 鍵設定が要る。 - 今回の構成: Donack 本体(CoreS3+Module-LLM)を Mac Studio に直結、CoreS3 は Funnel 経由で bridge にリモート接続。
9. 関連ファイル
mac-studio/scripts/melotts-onboard/(01-05 + melotts_server.py + start_server_device.sh)mac-studio/bridge/src/tts/melotts.ts,src/server.ts(TTS_ENGINE/間つなぎ FILLERS)- JCARVIS:
AIEO_JCARVIS/connectors/stackchan/server.js(:8181),connectors/discord/mirror.js(DISCORD_LOG_WEBHOOK_URL) - firmware:
firmware/src/main.cpp(シリアルCLI: wifi:/ws-status/ask:/tts:/help、SKIP_*フラグ)