小黃開發日記 06|桌上的她:Stack-chan(2026-09~10-01)

總結摘要
一台插著電就一直在的 ESP32 小機器人:耳朵和嘴巴長在殼上、16-bit 像素房間、跟著時間換的背景、手機掃 QR code 配網。

Mac 桌寵要開電腦,iPhone 要拿出來。我們想要的是一個抬頭喊一聲就在的她。所以第三個殼是 Stack-chan:一台放在書桌上的 M5Stack CoreS3 小機器人,插著電就一直在。v1.4.0 帶進第一版,v1.5.0 加上設定頁和手機配網。

ZOE 在書桌上的她是 16-bit 像素版;照片裡的她,在片場玩假鬍子。

同一組殼協定的另一個入口

腦沒有變,還是住在 Mac 上的同一顆。Stack-chan 跟桌寵說的是同一套殼協定:

1
2
Stack-chan 麥克風 ──區網──▶ Mac 上的小黃(辨識、思考、合成)
Stack-chan 喇叭   ◀──區網── 她的回答(整段串流,不會被砍斷)

ESP32 跑不了 Tailscale,所以走明文區網+一組共享密鑰。密鑰要夠長,而且只放在自己家的網路裡。

一個硬體限制決定了互動方式:麥克風和喇叭共用同一條 I2S,同時只能開一個。她講話時麥克風是關的,好處是物理上不會被自己的聲音觸發,代價是不能插話。

九期,一期一期長出來

期長出什麼
1~3聽得到、講得出來、有一張臉
4外殼和伺服馬達,可以轉頭
5臉兩側 12 顆燈,跟著她的四個狀態走
6~8圖片臉、視線,然後換成 16-bit 像素場景
10房間的背景跟著時間換
設定頁亮度、音量、手機配網

像素場景是最有感的一期:待機時她背對你,在書桌前寫字;喊「小黃」她會放下筆轉過來看你。在想的時候頭上冒思考泡泡,講話時換成對話框,隔兩公尺光看輪廓就分得出來。

時間換背景有早上、白天、晚上、深夜四張。板子先對 NTP 校時,再寫回有電池的 RTC 晶片,斷網重開也知道現在幾點。

為什麼加燈,不靠脖子:她在想、在聽、待機時麥克風都開著,伺服一動,馬達聲就會被自己聽成一段人聲。燈是無聲的,做得到脖子做不到的事。

配網:換 WiFi 不用接電腦。連不上時她會自己開熱點,手機掃螢幕上的 QR code 選網路、改位址,先試成功才存,送出位址時還會真的跟她握手驗證。

這段的坑(硬體的坑特別安靜)

  • WiFi 必須是 2.4 GHz:ESP32 沒有 5 GHz 無線電,接錯也不會報錯。
  • VOICE_PRESENCE_HOST 沒設:她只綁在 loopback,板子永遠連不上,而且兩邊都不會報錯。這是最容易漏的一項。
  • WiFi.status() 會說謊:iPhone 關掉熱點後(AUTH_EXPIRE),它在 120 秒內還一直回報 CONNECTED。改成看事件旗標和取得 IP 的次數。
  • 重燒韌體不會重設 base 上的 PY32 晶片:燈的控制器在 base 上,有自己的狀態,主板重燒了它還記著上一次的設定。
  • 鏡像測試抓不到左右一致對調:左右眼一起反過來時,「左右對稱」的測試照樣綠。
  • 側邊只有一顆鍵:短按開機、長按 6 秒關機、按住到亮綠燈進下載模式。我一度說成有兩顆。
  • USB 集線器會讓板子時有時無:直接插電腦就好。
  • 文字狀態面板還是唯一可靠的 log:USB 序列埠一重開機就斷,所以 WiFi、兩條連線、她的狀態、音量條這排面板一直保留著,出問題時它會自己跳回來。

沒做完的

  • NFC 鎖:做到一半暫停。
  • 連回家的隧道:在外面用 WSS 隧道連回家,量過是通的,但熱點上音訊斷斷續續,換網路後 DNS 不會更新,而且走隧道等於沒有密鑰驗證。整個進 backlog,等「隨身殼」再說。

下一篇:她開始在你的電腦上動手。