嵌入式开发 TinyML 异常检测:工业设备预测性维护边缘方案
工厂里一台电机坏了,整条产线停摆。等维修师傅赶到已经损失了几小时产量。预测性维护的核心思路是:在设备彻底坏掉之前,提前从振动、声音、温度等信号中捕捉异常。而 TinyML 让这一切可以在几十块钱的单片机上完成,不用上云、不用买昂贵的工控机。
什么是 TinyML 异常检测?
TinyML 是”Tiny Machine Learning”的缩写,指的是把机器学习模型压缩到能在内存不到 256KB 的微控制器上运行。传统的异常检测方案通常把传感器数据发到服务器上做分析,延迟高、带宽成本大、离线场景直接歇菜。
TinyML 异常检测的做法完全相反:模型直接烧录到 MCU 里,传感器数据在本地完成推理,只有发现异常时才上报。整个过程延迟可以压到 10ms 以内,功耗只有几毫瓦,用电池就能跑几个月。
典型的工业应用场景包括:
- 电机轴承磨损检测:通过加速度计捕捉振动频谱变化,轴承早期磨损就能被发现
- 泵气蚀预警:液体泵内部气泡破裂产生异常振动,异常检测模型能区分正常波动和气蚀特征
- 风机叶片故障:风力发电机叶片出现裂纹或结冰时,振动模式会发生变化
- 传送带跑偏检测:通过振动频率偏移判断传送带是否偏离轨道
硬件清单
| 组件 | 型号 | 价格参考 | 说明 |
|---|---|---|---|
| 开发板 | Arduino Nano 33 BLE Sense | ¥180 | 内置 LSM9DS1 IMU(加速度计+陀螺仪),无需外接传感器 |
| 电机 | 小型直流电机 + 扇叶 | ¥20 | 作为被测对象,可用旧硬盘电机代替 |
| 面包板 + 杜邦线 | 若干 | ¥10 | 调试用 |
| USB-C 数据线 | 1根 | ¥10 | 供电与程序烧录 |
| 3D 打印外壳(可选) | 自制 | ¥15 | 固定传感器到电机外壳 |
总成本不到 ¥250,就能搭建一个完整的振动异常检测原型。如果你的工厂已经有现成的传感器(比如 ADXL345、MPU6050),也可以替换 LSM9DS1,代码稍改即可。
方案架构
┌─────────────────┐ ┌──────────────────┐ ┌──────────────┐
│ 加速度计 │────>│ Arduino Nano 33 │────>│ 异常判断 │
│ (LSM9DS1) │ │ BLE Sense │ │ LED / 串口 │
└─────────────────┘ └──────────────────┘ └──────────────┘
│ │ │
采集振动数据 模型推理 正常:绿灯
(<20KB RAM) 异常:红灯+上报
整个链路不需要云端参与。如果你需要远程监控,可以加一个 ESP32 做 WiFi/MQTT 中继,异常时推送通知。
第一步:采集训练数据
异常检测属于无监督学习——你只需要采集设备”正常状态”的数据,模型就能学会什么是正常的,后续检测到偏离正常模式的情况就会报警。
数据采集要点
- 采集频率:LSM9DS1 支持最高 952Hz,电机振动建议至少 200Hz 采样
- 采集时长:每个正常状态样本至少 10 秒,推荐 60 秒以上
- 覆盖工况:在不同转速、不同负载下各采集一段数据
- 安装位置:加速度计要紧贴电机外壳,避免松动引入额外噪声
实际采集代码
先把 Nano 33 BLE Sense 通过 USB 连接到电脑,安装 Arduino_LSM9DS1 库,然后烧录以下代码:
#include <Arduino_LSM9DS1.h>
#define SAMPLE_RATE_HZ 200
#define SAMPLE_INTERVAL_MS (1000 / SAMPLE_RATE_HZ)
void setup() {
Serial.begin(115200);
if (!IMU.begin()) {
Serial.println("IMU 初始化失败!");
while (1);
}
// 设置加速度计量程为 ±4g
IMU.setAccelerometerRange(4);
// 设置采样率
IMU.setContinuousMode();
Serial.println("开始采集,格式: ax,ay,az");
}
void loop() {
float ax, ay, az;
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(ax, ay, az);
Serial.print(ax, 6);
Serial.print(",");
Serial.print(ay, 6);
Serial.print(",");
Serial.println(az, 6);
}
delay(SAMPLE_INTERVAL_MS);
}
运行后用串口监视器收集 CSV 格式的数据。建议每个工况采集 5-10 个文件,命名为 normal_motor_600rpm_1.csv、normal_motor_600rpm_2.csv 等。
第二步:在 Edge Impulse 上训练模型
Edge Impulse 是目前最方便的 TinyML 开发平台,支持浏览器操作、自动特征提取、一键导出 Arduino 库。
2.1 创建项目并上传数据
- 注册 Edge Impulse 账号,新建项目
- 选择 Data acquisition → Upload existing data
- 把采集到的 CSV 文件全部上传
- 确保所有数据标记为
normal类别(无监督异常检测只需要正常数据)
2.2 配置信号处理
进入 Create impulse,设置:
- Window size: 2000ms(2秒窗口,覆盖足够多的振动周期)
- Window increase: 1000ms(50% 重叠,提高检测灵敏度)
- DSP blocks: 添加 “Spectral Analysis”(频谱分析)和 “Statistical features”(统计特征)
对于振动信号,频谱分析是关键。Edge Impulse 会自动计算 FFT,提取主频、谐波、频带能量等特征。
2.3 训练异常检测模型
添加 Anomaly Detection 学习块:
DSP Block (频谱分析 + 统计特征)
↓
Neural Network / k-NN 异常检测
↓
Anomaly Score (0~1)
- 模型类型选择 k-NN Anomaly(适合小数据集)或 Neural Network Autoencoder(数据量大时效果更好)
- k-NN 只需要几十 KB 内存,Neural Network 约 100-200KB
- 训练完成后,查看 Model performance 页面
关键指标:
- Anomaly threshold:默认 0.5,可根据实际测试调整
- Confusion matrix:正常数据的误报率应低于 5%
2.4 验证模型
用 Live classification 功能,把板子连到电脑,实时看模型输出。正常电机运行时 anomaly score 应该稳定在 0.1-0.3 之间。然后用手轻轻碰电机外壳或者给电机加点负载,观察 score 是否飙升到 0.8 以上——如果区分度明显,说明模型有效。
第三步:部署到 Arduino
模型训练完成后,在 Edge Impulse 上点击 Deployment → Arduino Library,下载 .zip 包。然后在 Arduino IDE 中通过 “Sketch → Include Library → Add .ZIP Library” 导入。
完整部署代码
// 引入 Edge Impulse 生成的库
#include <anomaly_detection_inferencing.h>
#include <Arduino_LSM9DS1.h>
#define SAMPLE_INTERVAL_MS 5
#define WINDOW_SIZE_MS 2000
#define ANOMALY_THRESHOLD 0.5
// 全局缓冲区
static const size_t feature_size = EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE;
static float features[feature_size];
static size_t feature_idx = 0;
// LED 指示
const int LED_GREEN = LED_BUILTIN;
const int LED_RED = LED_BUILTIN2; // 部分板子有第二个 LED
void setup() {
Serial.begin(115200);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_RED, OUTPUT);
// 初始化 IMU
if (!IMU.begin()) {
Serial.println("IMU 初始化失败");
digitalWrite(LED_RED, HIGH);
while (1);
}
IMU.setAccelerometerRange(4);
IMU.setContinuousMode();
Serial.println("TinyML 异常检测系统启动");
Serial.printf("窗口大小: %dms, 阈值: %.2f\n", WINDOW_SIZE_MS, ANOMALY_THRESHOLD);
}
void loop() {
float ax, ay, az;
// 采集加速度数据
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(ax, ay, az);
// 填充特征缓冲区(三轴数据交替存储)
features[feature_idx * 3 + 0] = ax;
features[feature_idx * 3 + 1] = ay;
features[feature_idx * 3 + 2] = az;
feature_idx++;
// 窗口满了,运行推理
if (feature_idx >= (WINDOW_SIZE_MS / SAMPLE_INTERVAL_MS)) {
run_inference();
feature_idx = 0;
}
}
delay(SAMPLE_INTERVAL_MS);
}
void run_inference() {
// 构造 signal_t
signal_t signal;
int err = numpy::signal_from_buffer(features, feature_size, &signal);
if (err != 0) {
Serial.println("信号缓冲区错误");
return;
}
// 运行推理
ei_impulse_result_t result = {0};
err = run_classifier(&signal, &result, false);
if (err != 0) {
Serial.printf("推理错误: %d\n", err);
return;
}
// 读取异常分数
float anomaly_score = result.anomaly;
Serial.printf("异常分数: %.3f\n", anomaly_score);
if (anomaly_score > ANOMALY_THRESHOLD) {
// 异常!亮红灯
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_RED, HIGH);
Serial.println("⚠️ 检测到异常!建议检查设备状态");
} else {
// 正常:亮绿灯
digitalWrite(LED_GREEN, HIGH);
digitalWrite(LED_RED, LOW);
Serial.println("✓ 设备运行正常");
}
}
代码说明
- 采样间隔 5ms(200Hz),2000ms 窗口 = 400 个采样点 × 3 轴 = 1200 个特征值
- 每次窗口填满后调用
run_classifier()推理 - 异常分数超过阈值时亮红灯并通过串口报警
- 推理耗时约 10-20ms,完全满足实时性要求
第四步:远程监控扩展(可选)
单机 LED 报警只是起步,工业场景通常需要远程通知。最简单的方式是用 ESP32 做 WiFi 中继,异常时通过 MQTT 推送消息:
// 在 run_inference() 的异常分支中加入
if (anomaly_score > ANOMALY_THRESHOLD) {
// 通过串口发送给 ESP32
Serial.println("ANOMALY_DETECTED");
// 或者直接上 WiFi(如果用的是 Nano 33 BLE Sense)
// 发送 HTTP POST 到后端 API
}
ESP32 端接收串口数据,通过 MQTT 发布:
#include <WiFi.h>
#include <PubSubClient.h>
WiFiClient espClient;
PubSubClient mqtt(espClient);
void check_anomaly() {
if (Serial.available() > 0) {
String msg = Serial.readStringUntil('\n');
if (msg == "ANOMALY_DETECTED") {
mqtt.publish("factory/motor001/anomaly", "DETECTED");
Serial.println("已发送异常通知");
}
}
}
常见问题排查
Q1:模型误报率太高
原因:训练数据不够多样,或者阈值设置过低。
排查步骤:
- 检查训练数据是否覆盖设备所有正常工况(不同转速、温度、负载)
- 在 Edge Impulse 的 Live classification 中观察正常状态下的分数分布
- 把阈值从 0.5 提高到 0.6-0.7,观察误报率变化
- 增加训练数据量,至少 30 分钟以上的正常状态数据
Q2:模型检测不到真正的异常
原因:异常特征太微弱,或者窗口大小不合适。
排查步骤:
- 尝试增大 window size(比如从 2000ms 改为 4000ms),捕获更多周期信息
- 检查传感器安装是否松动——松动会产生大量虚假信号
- 尝试更换 DSP block,加入 “Raw data” 特征而不是只用频谱
- 考虑引入已知异常数据做有监督学习(Supervised Learning),效果通常更好
Q3:推理速度太慢
原因:模型过大或 MCU 主频不够。
排查步骤:
- 在 Edge Impulse 部署页面查看模型 RAM/Flash 占用,确保 Nano 33 BLE Sense 的 256KB RAM 够用
- 尝试 k-NN 模型替代 Neural Network,内存占用减少约 60%
- 在 Deployment 时选择 “EON Compiler” 优化选项,可提升 20-30% 推理速度
- 降低采样率(200Hz → 100Hz),如果异常频率特征在 50Hz 以下,100Hz 采样足够了
Q4:加速度计读数不稳定
原因:电源纹波、焊接不良、或 I2C/SPI 通信干扰。
排查步骤:
- 用万用表检查 3.3V 供电电压是否稳定(波动应 < 50mV)
- 如果使用外接传感器,检查 I2C 上拉电阻(4.7kΩ 标准值)
- 在代码中加软件滤波:
ax = ax * 0.8 + last_ax * 0.2(一阶低通滤波) - 检查加速度计量程设置是否正确——4g 量程适合大多数工业振动场景
性能与成本对比
| 方案 | 延迟 | 月成本 | 离线可用 | 开发难度 |
|---|---|---|---|---|
| 云端 ML(AWS IoT) | 1-5 秒 | ¥500+ | ❌ | 中 |
| 树莓派 + TensorFlow | 100-500ms | ¥300+ | ✅ | 中 |
| TinyML(本方案) | 10-20ms | ¥0 | ✅ | 低 |
对于需要毫秒级响应的工业场景(比如紧急停机保护),TinyML 是唯一能同时满足低延迟和低成本需求的方案。
进阶方向
- 连续学习(Continuous Learning):Edge Impulse 支持 FOMO 架构的持续学习,模型可以在线更新,适应设备老化带来的基准漂移
- 多传感器融合:同时采集振动、声音、温度数据,融合模型准确率可提升 20%+
- 迁移学习:用一台设备的模型微调后适配另一台相似设备,大幅减少数据采集工作量
- 生产级部署:用 PlatformIO 管理项目、OTA 远程更新模型、看门狗保证系统可靠性
预测性维护是工业 4.0 的基石之一。随着 TinyML 生态的成熟,这个曾经需要专业团队才能实现的方案,现在一个工程师 + 一块开发板就能搞定。下次你的工厂里设备”感觉不太对”的时候,也许 TinyML 已经提前三天就告诉你了。