Skip to content

引き継ぎ資料: 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.hBOTTOM3_PORT_A_SDA/SCL=12/11 は CoreS3 内部システムI2Cピン。正しい外部 Port.A は GPIO 2/1presence_sensor.cppWire.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-melotts 1.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 フェーズ1on-device ワード抽出(mecab,0トークン) + テンプレ間つなぎ + 間つなぎ事前キャッシュ🔨 事前キャッシュ(25c2f4a)コミット済・実機検証待ち。ワード抽出/テンプレ間つなぎは未着手
#71 フェーズ2アドホックモードで JCARVIS 先読み (A:流暢間つなぎ事前生成 / B:本答コンテキスト下ごしらえ)、変化なしスキップ、専用DB、Discordログ活用📋 設計のみ
#72StackFlow 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 を不安定化させる。

  1. CoreS3 を接続 → pio run -e m5stack-cores3 -t upload --upload-port /dev/cu.usbmodem83201 で最新 #72 を焼く。
  2. 画面が出るか確認(fallback_board 修正済)。出ないなら起動ログの M5.getBoard()= が 0(unknown) でないか確認。
  3. bridge モード(WiFi/WSS接続時): 「ねえドナック、〇〇」→ HUD の「思考N.Ns / 発話N.Ns / 計N.Ns」を読む。
    • 30秒問題の内訳診断: 思考が大→Claude遅い(短文化/速モデル/間つなぎ)、発話が大→長文melotts(短文化+文ストリーミング)。
  4. standalone モード(WiFi切断 or bridge停止): 「ドナック…」と wake 入りで話す → on-device qwen が ~1s で応答・melotts発話。wake 無し/自己エコーは無視される(暴走しない)はず=#72 のエコーガード検証。
  5. I2Cセンサを実際に使うなら Port.A を 2/1(現設定)で配線確認。違えば実機に合わせて stackchan_config.h 修正。
  6. 余力: 喋り出し途切れ(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 で ac.abort()→Claude をアボートする実装。タイミング次第で本答消失リスク対策済み (2026-05-29, 実機なしで実装・スモーク検証):
    • melotts 経路では本答を adb 経由でデバイスへ直接発話する (WS 非依存) ため、WS close でアボートしないよう変更 (server.ts onClose を engine 別に分岐)。voicevox 経路は従来どおり close で abort。
    • send()readyState===OPEN ガードに変更 (close 後の送信で throw しない)。
    • WS keepalive 追加: WS_KEEPALIVE_MS(既定 20s) 間隔で ping、pong 無応答ソケットを terminate()。「close は来ないが実質切れている」状態も検知。
    • ⚠️ 本番 bridge(:7780, pid起動中) は旧コードのまま。反映には bridge の再起動が必要 (§5 の起動コマンド)。実機復帰時に併せて再起動推奨。
  • 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 downloadDYLD_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_*フラグ)

aieo-product / stack-chan project