|
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.csvnormal_motor_600rpm_2.csv 等。

第二步:在 Edge Impulse 上训练模型

Edge Impulse 是目前最方便的 TinyML 开发平台,支持浏览器操作、自动特征提取、一键导出 Arduino 库。

2.1 创建项目并上传数据

  1. 注册 Edge Impulse 账号,新建项目
  2. 选择 Data acquisitionUpload 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 上点击 DeploymentArduino 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 已经提前三天就告诉你了。