ESP32 計步器實作

專題做好了,一支會計步、會開 Wi-Fi 讓手機看資料的小裝置。然後,他的電腦壞了。

原始碼只存在那台電腦裡。手上只剩一台還會動的裝置,沒有任何一行程式。

這篇記錄我們怎麼把它救回來:先完整備份,再把它重做成一套中文、可以在瀏覽器裡跑、學生能自己改的教材。後半段是實際拿在手上用了兩天之後,老師回報的四個問題,以及每一個問題背後的「失敗路徑」。

👉 介紹影片(13 分 23 秒,有章節):一台壞掉的電腦,和一支重生的計步器
🔗 瀏覽器模擬器+韌體+焊接短片:pedometer-lab 專案網站
📘 講義 PDF(81 頁,附 113 個名詞的白話解釋):下載講義

第一步:先備份,不要急著修

拿到別人的裝置,第一個動作不是燒新程式,而是把整片 4 MB 快閃記憶體唯讀備份下來,讀兩次,比對兩次的雜湊值完全一樣,才算備份成功。任何會寫入的動作,都要等到能完整還原之後才做。

從備份裡取回網頁、畫面上的英文字串、設定欄位,但機器碼要反推回原始碼,在 ESP32 上沒有可靠的方法證明「還原得對」。所以我們換一條路:把取回的文字當成「行為規格」(只寫它會做什麼、不寫它怎麼做),重新設計一個中文版。

可以直接拿去上課的觀念一:先在瀏覽器裡跑,再燒進板子

新版的核心是分層:計步、畫面、選單這些功能邏輯完全不碰硬體,中間隔一層「硬體抽象層」,上層只說「畫字」「讀加速度」,不管底下是真的板子還是瀏覽器。

結果是:同一份 C++ 程式,既能燒進 ESP32,也能編成 WebAssembly 在網頁裡跑成模擬器。學生不用每改一行就等兩分鐘燒錄,可以在模擬器裡拖傾斜盤、按「開始走路」、600 倍速快轉時間,馬上看到結果。

但要跟學生講清楚模擬器的極限:它測得到「邏輯對不對」,測不到「資源夠不夠」。下面兩條失敗路徑都是模擬器全過、真機卻出事。

硬體只有六條線:加速度計四條、蜂鳴器兩條。剝線、沾錫、焊接,每一條都是同樣三步,網站上有七段焊接短片可以直接放給學生看。

可以直接拿去上課的觀念二:沒有「真值」,就不能校正

第二輪改良裡最重要的一個問題,是老師回報「放在口袋走路,步數跳很快」。

要知道演算法準不準,需要真值,也就是「實際上走了幾步」。所以我們在裝置上做了「走路測試」:選好裝置放在哪裡、倒數三秒、邊走邊錄下每秒 50 筆加速度,走完再輸入自己數的步數。

老師走了「50 步」,裝置顯示 115。一問才知道,老師是同一隻腳落地才算一步;手機、手環則是左右腳每落地一次算一步。所以實際落地是 100 次,裝置多算了 15%。

課堂活動:請三位同學同時數同一位同學走路的步數,再比較每個人的數法。「一步」的定義不一樣,量出來的數字就不一樣——這就是為什麼校正前要先問清楚真值怎麼來的。

失敗路徑:頻譜最高的那根,不是步頻

這一條是我(AI)自己犯的錯。第一段錄音沒有真值,我看頻譜裡最強的頻率,就當成步頻,照它把演算法調成第二版。結果那其實是諧波(真正步頻的整數倍):放在口袋那條腿,同一步常常有兩三個波峰,頻譜就會被騙。第二版根本沒修好。

有了老師的真值之後,改用自相關:把最近 4 秒的訊號,和「自己往後挪一段時間」的版本比相似度,挪到剛好一個週期時最像,就知道每一步多久,不會被一步裡有幾個峰騙到。再加上「重新上膛」:算進一步後,訊號要先掉回 0 以下才接受下一個峰。

三段真機口袋錄音,第一版多算 13%~29%,第四版都在 ±3% 以內。三段錄音也存成回歸測試,以後誰改了演算法,跑一次就知道有沒有退步。

先量,再改:CPU 將近八成在空轉

老師另一個回報是「裝置會發燙」。我們先寫量測工具,才發現主程式每秒繞 18,000 圈,但真正在做事的時間只有兩成,其餘將近八成在空轉,像停紅燈還一直踩油門。

改了什麼實測結果
主迴圈做完事就休息時鐘畫面 CPU 活動比例 100% → 18.7%
畫面沒變就不重送設定畫面 CPU 11.5%
加速度計自己先存 32 筆(FIFO),每 0.1 秒拿一次不再漏資料
閒置關螢幕,輕敲兩下叫醒;螢幕關+用電池時進淺層睡眠30 秒裡睡了 28 秒
Wi-Fi 預設關閉,另加「完全關閉」開關最大的發熱來源用到才開

失敗路徑:藍牙一開,板子就無限重開機

為了不開 Wi-Fi 也能用手機看步數,我們加了藍牙低功耗(BLE)。第一次用 Arduino 內建的藍牙程式庫,藍牙一開,記憶體只剩 9.7 KB,板子當機;而且「藍牙開」已經存進設定,每次開機都重來一次。

先燒一版沒有藍牙的韌體把板子救回來(步數與設定都還在),再換成小得多的 NimBLE,開著藍牙還剩 68 KB。現在打開藍牙,螢幕會出現 QR 碼,Android 手機用 Chrome 掃了就能連;iPhone 因為 Apple 的限制,要改用 Bluefy 瀏覽器。

教訓:評估「做不做得到」,不能只量程式放不放得進快閃記憶體,也要量執行時要多少 RAM。

失敗路徑:做了兩版的功能,最後拿掉

老師希望倒過來拿時畫面跟著轉。第一版在模擬器上轉得很順,燒進真機卻完全不會轉:轉動要先借一塊 65 KB 的記憶體,真機最大的一塊連續空間只有 57 KB。改用螢幕晶片的硬體旋轉之後,桌上自測正常,但老師實際拿在手上還是一直不能用。

最後的決定是:不再追查,整個功能拿掉。一個常常失靈的功能,比沒有這個功能更糟。「桌上自測通過」不等於「使用者拿在手上能用」,知道什麼時候該停損,也是專題要學的事。

還有一個小的:上下兩顆按鍵,程式一直是接反的。橫著拿時兩顆鍵在同一側上下排列,程式卻照「左鍵、右鍵」命名,把下面那顆當成「上一項」。老師用了兩天才提出來。按鍵的名字要照使用者實際看到的位置取,也要主動問使用者「哪裡用起來怪怪的」。

給老師的教材包

  • 主選單一次一項:會動的小插圖+右側轉盤;番茄鐘、量角器依使用回饋刪掉,換成「音樂」(9 首公眾領域的兒歌與古典樂,用十二平均律換算頻率)。
  • 瀏覽器寫程式、燒錄:學生改遊戲卡帶程式,模擬器自動重新載入;用 Web Serial 直接從 Chrome 燒錄,找不到裝置時網頁會提示要裝哪個驅動。編譯要在老師電腦上執行 make ide。
  • 講義 81 頁:硬體、接線、演算法、模組選型、失敗路徑、逐步實作步驟,附錄 113 個名詞的白話解釋。

最後

這個專案想說的其實只有一句:原始碼要放進版本控制。而一個設計良好的系統,是可以被重建,也可以一直改得更好的。

🎬 13 分鐘介紹影片:YouTube 🔗 模擬器與所有教材:pedometer-lab 📘 講義 PDF

發表留言