▼點擊下方名片,關注公眾號,獲取更多精彩內容▼
大家好,我是賀老師,嵌入式 AI工程師,《嵌入式AI:讓單片機學會思考》課程主理人,專注AI在MCU上的落地實踐。
做 TinyML,最容易讓人興奮的是訓練模型:準確率、混淆矩陣、量化、部署、串口打印結果。可真正決定項目能否成功的,往往是最不起眼的數據采集。
今天賀老師帶領大家學習如何做一個靠譜的數據采集器。本文的講解步驟:
采集器應該輸出什么?
STM32/ESP32端應該怎么寫?
如何做標簽?
數據采集之后怎么做?
一個夠用的數據采集器,不需要一開始就做得很復雜。先能穩定輸出 CSV,就已經能支撐大部分入門項目。關鍵是字段要對,別只打印三軸數值。
以 IMU 動作識別或電機振動檢測為例,建議至少輸出這些字段:時間戳、樣本序號、三軸加速度、三軸陀螺儀、標簽、設備狀態。時間戳用毫秒或微秒都可以,但必須單調遞增。樣本序號用來查丟包,標簽用來訓練,設備狀態用來解釋異常。
推薦 CSV 格式:
timestamp_ms,seq,ax,ay,az,gx,gy,gz,label,state
1024,0,0.012,-0.044,0.981,0.12,-0.02,0.05,normal,run_5v
1025,1,0.014,-0.041,0.979,0.11,-0.01,0.04,normal,run_5v
1026,2,0.018,-0.039,0.982,0.13,-0.02,0.06,normal,run_5v如果做聲音項目,CSV 不是最好的選擇,應該保存 WAV 或者固定長度的 PCM 塊;如果做圖像項目,保存原圖和標注文件。傳感器不同,格式可以不同,但原則一樣:以后能復現當時的輸入。
Edge Impulse 支持 CSV 上傳,也提供 Data forwarder 通過串口轉發設備數據。課堂里可以先用串口 CSV,后面再接 Edge Impulse 或 Python 腳本。
采集器程序不要和模型推理程序混在一起。第一版先只做一件事:穩定采集、穩定輸出。模型晚一點再接。
定時器負責節拍,傳感器讀取負責拿數據,串口負責輸出。不要在主循環里用 HAL_Delay() 湊采樣率,那樣看起來簡單,實際抖動很大。
#define SAMPLE_HZ 1000
static volatile uint8_t sample_flag = 0;
static uint32_t seq = 0;
void TIMx_IRQHandler(void)
{
clear_timer_irq();
sample_flag = 1;
}
void loop(void)
{
if (!sample_flag) return;
sample_flag = 0;
float ax, ay, az, gx, gy, gz;
imu_read(&ax, &ay, &az, &gx, &gy, &gz);
uint32_t t = millis();
printf("%lu,%lu,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%s,%s\r\n",
t, seq++, ax, ay, az, gx, gy, gz, current_label, current_state);
}這段結構足夠講清楚采集器的核心,但真實項目里還要優化:高速采樣時不要頻繁 printf 浮點數,串口帶寬會吃緊;可以先存二進制,再由 PC 轉 CSV;也可以雙緩沖,湊夠一塊再發送。
常見錯誤是“串口打印速度跟不上采樣速度”。比如 1000 Hz,每行幾十個字符,115200 波特率很快就不夠。要么提高波特率到 921600 或更高,要么減少字段,要么用 SD 卡/USB CDC/二進制格式。
數據采集最怕“先采了再說”。一堆 CSV 放在那里,文件名叫 data1.csv、data2.csv,過兩天誰也說不清哪個是正常、哪個是松動、哪個是手持、哪個是桌面固定。
標簽最好在采集時就寫進去。按鍵切換標簽,串口命令切換標簽,或者 PC 端腳本發命令都可以。每次切換標簽時,單獨打一行事件日志,后面切窗口會方便很多。
#EVENT,23841,label,normal
23842,12001,0.012,-0.044,0.981,0.12,-0.02,0.05,normal,run_5v
23843,12002,0.014,-0.041,0.979,0.11,-0.01,0.04,normal,run_5v
#EVENT,35890,label,loose
35891,24001,0.032,-0.087,1.041,0.22,-0.04,0.09,loose,run_5v還要記錄環境條件。做動作識別,要記錄佩戴位置;做聲音識別,要記錄距離和噪聲;做振動檢測,要記錄電壓、轉速、安裝方式、故障制造方法。這些信息不進模型也沒關系,但必須進采集日志。
一個好習慣:每次采集開始先輸出一段元信息,包括板卡型號、傳感器型號、采樣率、量程、固件版本、標簽說明。半年后回頭看數據,不會像考古。
第一,畫波形。不要直接訓練。先看時間軸是不是連續,三軸有沒有飽和,是否有明顯丟點,標簽切換附近有沒有混入過渡動作。
第二,查采樣間隔。理想 1000 Hz 不代表真實就是 1 ms 一個點。用時間戳算相鄰樣本間隔,看看最大值、最小值、標準差。如果采樣間隔亂,后面的頻域特征會跟著亂。
第三,切窗口。窗口切分要按時間順序,不要把強相關的連續窗口隨機打散到訓練集和測試集。隨機打散會讓測試準確率虛高,真正上板時就露餡。
Python 快速檢查采樣間隔:
import pandas as pd
df = pd.read_csv("motor_normal.csv", comment="#")
dt = df["timestamp_ms"].diff().dropna()
print("mean:", dt.mean())
print("min :", dt.min())
print("max :", dt.max())
print("std :", dt.std())
print(df[["ax", "ay", "az"]].describe())這幾行檢查比盲目訓練模型更有價值。很多數據問題不是模型發現的,而是在訓練前就應該被肉眼和統計量發現。



