引き継ぎ: #72 実機デバッグ継続ガイド
最終更新: 2026-05-30 / 対象: 別セッションで実機を接続してデバッグを再開する人 前提ナレッジ: 仕様書 architecture.md / melotts handoff
#72 のコードは main にマージ済(PR #72)。firmware はビルド済だが最終版は未フラッシュ。 このドキュメントだけ見れば実機検証を再開できるようにまとめてある。
0. 30秒サマリ — 今どこ?
- 「発話=on-device melotts(UART)、思考=WSS接続でClaude/切断でqwen0.5B」の tiered 構成を実装・マージ済。
- 実機で確認済: melotts(ja-jp) setup/発話、qwen+melotts 共存(~1s)、CoreS3 画面表示(Debug HUD)、bridge
TTS_ENGINE=none接続。 - 未検証(device 未接続で中断): ①音声ループ全体の体感 ②応答が**~30秒**かかる問題の内訳特定と短縮 ③standalone 暴走対策の実機確認 ④喋り出し途切れ ⑤HUDフリッカ ⑥I2C 2/1 実配線。
- 直近のトラブル: Module-LLM の USB 電源不足で切断/再起動し ASR が止まった(無反応)。電源付きUSBハブ必須。
1. 接続・起動手順
1-1. 物理
- Module-LLM は電源付き USB ハブ経由で給電(電源不足だと頻繁に切断→UART/ASR が死ぬ)。
- CoreS3 を Mac に USB-C 接続 →
ls /dev/cu.usbmodem*でポート確認。 - Module-LLM 側 USB-C は adb 用。音声ループ検証中は adb を切る(下記§4参照)。
1-2. firmware を焼く
bash
cd firmware
pio run -e m5stack-cores3 -t upload --upload-port /dev/cu.usbmodemXXXX接続先(Funnel URL)・on-device melotts/qwen・HUD は platformio.ini / コード既定に入っているので追加フラグ不要。
1-3. Mac 側サービス (Mac Studio)
bash
# JCARVIS :8181 (Claude サブスク)
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 # {"ok":true,...,"engine":"ClaudeEngine"}
# bridge :7780 (#72: テキストのみ返却。発話は 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 & )
# Funnel (常駐のはず。無ければ)
/Applications/Tailscale.app/Contents/MacOS/Tailscale funnel --bg 7780
/Applications/Tailscale.app/Contents/MacOS/Tailscale funnel status # /stackchan/ws -> 127.0.0.1:77802. 画面(Debug HUD)の読み方
HUD は M5GFX 直接描画(avatar 非依存)。レイアウト:
Donack[BRIDGE] W:OK S:OK ← モード(BRIDGE/STANDALONE/INIT) / WiFi / WSS (右上に表情)
<状態> ← 待機中 / 考え中(母艦)… Ns / 考え中(単体)… / 発話中 / (自分の声を無視)
聞: <取得ワード(ASR)>
答: <応答テキスト>
思考N.Ns 発話N.Ns 計N.Ns ← 応答完了後に出る内訳 (30秒問題の診断にこれを読む)3. 検証チェックリスト
- 起動・表示: 焼いた直後、画面に HUD が出るか。シリアルログで
M5.getBoard()=が 0以外(CoreS3検出成功)、melotts ready・llm OK・voice pipeline readyを確認。bashpython3 mac-studio/scripts/cores3-serial.py --seconds 60 # 起動ログ観測 (リセットせず) - bridge モード(WiFi/WSS接続時): 「ねえドナック、〇〇」→ HUD の 思考/発話/計 を読む。→ §4 の30秒診断へ。
- standalone モード(WiFi切断 or bridge停止): 「ドナック…」と wake 入りで話す → qwen が ~1s で応答・melotts発話。
- 暴走しないことを確認: wake 無しの雑談/環境ノイズ/自分の発話のエコーで連続発話しない(#72のエコーガード+wakeゲート)。
- CLI 単体テスト (音声を介さず):bash
python3 mac-studio/scripts/cores3-serial.py --send "tts:オンデバイス発話テスト" --seconds 15 # melotts 単体 python3 mac-studio/scripts/cores3-serial.py --send "ask:今日はいい天気だね" --seconds 15 # qwen 単体 python3 mac-studio/scripts/cores3-serial.py --send "claude:こんにちは" --seconds 30 # bridge 経路
4. 未解決課題 — 仮説と診断手順
(A) 応答 ~30秒 ★最優先
- 診断: bridge モードで話し、HUD の
思考N.Ns 発話N.Ns 計N.Nsを読む。シリアルにも[tts] melotts done rc=.. (think=..ms tts=..ms total=..ms)が出る。 - 思考が大 → Claude(JCARVISサブスク, first token~5s)が遅い。対策候補: 返答を1-2文に短縮(JCARVIS donack プロンプト)/ 速いモデル / 間つなぎ発話(喋り出しだけ先に on-device で「えーっと」)。
- 発話が大 → 返答が長文 → melotts 合成が長い。対策: 短文化 + 文単位ストリーミング発話(現状は agent.done 後に全文を一括 melotts 送信)。
(B) standalone 暴走(「あー」連発) — 実機確認
- 原因(解決済のはず): standalone は firmware が直接応答するため、wake判定+エコーガードを #72 で追加。
normalizeJa(カタカナ→ひらがな/促音長音除去)で正規化照合。g_tts_playing(再生中ドロップ)+tail 1500ms が主防御、テキストエコーガードが補助。 - 確認: WiFi 切断で standalone にし、何も呼ばずに喋る/雑音を出す → 反応しない(wake 必須)こと。発話直後に自分の声で再発話しないこと。
- もし再発するなら: tail guard を伸ばす / wake ワードを絞る /
normalizeJaの漢字↔読み限界(下記)を考慮。 - 既知の限界: テキストエコーガードは漢字↔かな(例「元気」↔「げんき」)を吸収できない。主防御は時間ガード+wakeゲート。
(C) 喋り出しの途切れ
- 仮説: llm-audio 再生が 48kHz/period=160(=3.3ms)/buffer=1280 と小さく、AO 起動時に頭が欠ける。
- 対策候補:
/opt/m5stack/share/audio.jsonのplay_param.stAttr.u32PeriodSize/u32PeriodCountを増やす、または melotts 側で先頭に無音パディング。実機で audio.json を調整して試す(バックアップaudio.json.bakあり)。
(D) HUD フリッカ (低優先・#72レビュー指摘)
drawHud()が毎回全画面fillScreen→ ちらつき。対策:M5Canvas(320x240, PSRAM) に描いてpushSprite。- 実機未検証リスクで今回見送り(せっかく直った表示を再度壊さないため)。実機があるセッションで sprite 化を試す。
(E) I2C ピン 2/1 の実配線確認
- #72 で Port.A を 内部バス 12/11 → 外部 2/1 に変更(画面電源を壊さないため)。
- センサ(PIR/ToF)を実際に挿すなら、Bottom3 経由の実ピンが 2/1 で合っているか実機確認。違えば
firmware/include/stackchan_config.hを実配線に合わせる。M5.Ex_I2C利用も検討。
(F) ASR 16bit 品質 (記事の I2S バグ)
- zenn記事: AX630C I2S ドライバは 16bit 録音時にピッチが半分になるバグ。Whisper の録音(
cap_param.bit:16)に効いている可能性。 - 対策候補: cap を 24bit 化(llm-asr が受けるか要検証)、またはドライバ修正。ASR 誤認識(「スタッフクチャン」等)の一因かも。
5. 重要なハマりどころ (再発させないдля)
- adb 接続中は CoreS3↔Module-LLM の UART が不安定。音声ループ検証時は
adb kill-server(または Module-LLM USB を抜く)。module-llm-rpc.pyを使うときだけ adb forward する。 - シリアル接続で CoreS3 がリセットする(USB-CDC の DTR)。
cores3-serial.pyは dtr/rts=False で回避するが、それでもリセットする環境あり → その場合は起動から観測。画面を直接見るのが一番速い。 - CoreS3 画面が真っ黒 → M5GFX が
board:0(unknown) で CoreS3 未検出。cfg.fallback_board=board_M5StackCoreS3(対応済)。再発したら getBoard ログを確認。詳細メモcores3-blank-display-fallback-board。 - Module-LLM USB 電源不足で切断/再起動 → UART/ASR が死んで無反応。電源付きハブ必須。
adb devicesで消えていたら電源/ケーブルを疑う。 - melotts ABRT(#67) → ja-jp の
mode_paramにtagger/verbalizer欠落が原因。install スクリプト STEP 5-d で修正済。手動確認はmodule-llm-rpc.py melotts-say "テスト"。
6. 診断ツール (今回作成)
mac-studio/scripts/cores3-serial.py— CoreS3 シリアルをリセットせず観測 / CLI コマンド送信。mac-studio/scripts/module-llm-rpc.py— Module-LLM の StackFlow デーモン(:10001)を直接叩いて melotts/qwen を単体テスト(要adb forward tcp:10001 tcp:10001)。- pyserial が無ければ PlatformIO 同梱 python:
$(ls /opt/homebrew/Cellar/platformio/*/libexec/bin/python|head -1)。
7. 関連
- 仕様:
architecture.md(各HW仕様/通信経路/TTS2経路/melotts FST修正) - 設計判断メモ:
stackchan_tiered_dual_mode/stackchan_standalone_tts_blocker/cores3_blank_display_fallback_board - firmware:
firmware/src/main.cpp(HUD/tiered/echo・wake/melotts),firmware/include/stackchan_config.h(ピン) - bridge:
mac-studio/bridge/src/server.ts(TTS_ENGINE=none/keepalive)