TinyML 异常检测:工业设备预测性维护边缘方案

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 中继,异常时推送通知。

第一步:采集训练数据

异常检测属于无监督学习——你只需要采集设备”正常状态”的数据,模型就能学会什么是正常的,后续检测到偏离正常模式的情况就会报警。

数据采集要点

  1. 采集频率:LSM9DS1 支持最高 952Hz,电机振动建议至少 200Hz 采样
  2. 采集时长:每个正常状态样本至少 10 秒,推荐 60 秒以上
  3. 覆盖工况:在不同转速、不同负载下各采集一段数据
  4. 安装位置:加速度计要紧贴电机外壳,避免松动引入额外噪声

实际采集代码

先把 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 创建项目并上传数据

  1. 注册 Edge Impulse 账号,新建项目
  2. 选择 Data acquisition → Upload existing data
  3. 把采集到的 CSV 文件全部上传
  4. 确保所有数据标记为 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:模型误报率太高

原因:训练数据不够多样,或者阈值设置过低。

排查步骤:

  1. 检查训练数据是否覆盖设备所有正常工况(不同转速、温度、负载)
  2. 在 Edge Impulse 的 Live classification 中观察正常状态下的分数分布
  3. 把阈值从 0.5 提高到 0.6-0.7,观察误报率变化
  4. 增加训练数据量,至少 30 分钟以上的正常状态数据

Q2:模型检测不到真正的异常

原因:异常特征太微弱,或者窗口大小不合适。

排查步骤:

  1. 尝试增大 window size(比如从 2000ms 改为 4000ms),捕获更多周期信息
  2. 检查传感器安装是否松动——松动会产生大量虚假信号
  3. 尝试更换 DSP block,加入 “Raw data” 特征而不是只用频谱
  4. 考虑引入已知异常数据做有监督学习(Supervised Learning),效果通常更好

Q3:推理速度太慢

原因:模型过大或 MCU 主频不够。

排查步骤:

  1. 在 Edge Impulse 部署页面查看模型 RAM/Flash 占用,确保 Nano 33 BLE Sense 的 256KB RAM 够用
  2. 尝试 k-NN 模型替代 Neural Network,内存占用减少约 60%
  3. 在 Deployment 时选择 “EON Compiler” 优化选项,可提升 20-30% 推理速度
  4. 降低采样率(200Hz → 100Hz),如果异常频率特征在 50Hz 以下,100Hz 采样足够了

Q4:加速度计读数不稳定

原因:电源纹波、焊接不良、或 I2C/SPI 通信干扰。

排查步骤:

  1. 用万用表检查 3.3V 供电电压是否稳定(波动应 < 50mV)
  2. 如果使用外接传感器,检查 I2C 上拉电阻(4.7kΩ 标准值)
  3. 在代码中加软件滤波:ax = ax * 0.8 + last_ax * 0.2(一阶低通滤波)
  4. 检查加速度计量程设置是否正确——4g 量程适合大多数工业振动场景

性能与成本对比

方案延迟月成本离线可用开发难度
云端 ML(AWS IoT)1-5 秒¥500+❌中
树莓派 + TensorFlow100-500ms¥300+✅中
TinyML(本方案)10-20ms¥0✅低

对于需要毫秒级响应的工业场景(比如紧急停机保护),TinyML 是唯一能同时满足低延迟和低成本需求的方案。

进阶方向

  • 连续学习(Continuous Learning):Edge Impulse 支持 FOMO 架构的持续学习,模型可以在线更新,适应设备老化带来的基准漂移
  • 多传感器融合:同时采集振动、声音、温度数据,融合模型准确率可提升 20%+
  • 迁移学习:用一台设备的模型微调后适配另一台相似设备,大幅减少数据采集工作量
  • 生产级部署:用 PlatformIO 管理项目、OTA 远程更新模型、看门狗保证系统可靠性

预测性维护是工业 4.0 的基石之一。随着 TinyML 生态的成熟,这个曾经需要专业团队才能实现的方案,现在一个工程师 + 一块开发板就能搞定。下次你的工厂里设备”感觉不太对”的时候,也许 TinyML 已经提前三天就告诉你了。