基于Wio Terminal与Edge Impulse的端侧异常检测系统实战

发布时间:2026/8/3 4:01:19
基于Wio Terminal与Edge Impulse的端侧异常检测系统实战 1. 项目概述当微控制器学会“听声辨位”几年前我在一个工业现场遇到一个棘手的问题一台关键的风机设备每隔几个月就会毫无征兆地出现轴承损坏导致整条生产线停机每次损失都以数十万计。维护团队疲于奔命要么过度保养要么事后救火。当时我就在想如果能有一种方法让设备自己“告诉”我们它快要不行了那该多好。今天我们要聊的这个项目就是实现这个想法的“平民化”方案利用Wio Terminal和Edge Impulse打造一个低成本、端侧智能的预测性维护异常检测系统。简单来说Wio Terminal是一款功能强大的开源硬件自带屏幕、传感器和无线连接而Edge Impulse是一个让机器学习变得像搭积木一样简单的在线平台。这个项目的核心就是教会Wio Terminal通过内置的麦克风“聆听”设备比如电机、泵、齿轮箱运行时的声音或振动利用在Edge Impulse上训练好的微型机器学习模型直接在设备端实时判断当前状态是“正常”还是“异常”。它不再需要将海量数据源源不断地发送到云端避免了网络延迟、带宽成本和隐私风险实现了真正的边缘智能。这适合谁呢如果你是嵌入式开发者想切入AIoT领域如果你是运维工程师或创客想用低成本方案解决实际工业痛点甚至如果你只是个对机器学习感兴趣的新手想找一个有明确应用场景的实战项目——这个从数据采集、模型训练到嵌入式部署的完整流程都将是一次绝佳的练手机会。接下来我将拆解整个实现过程分享每一步的关键细节和我踩过的坑。2. 核心思路与方案选型为什么是“端侧异常检测”在深入动手之前我们必须先理清逻辑为什么选择这个技术栈它解决了传统方案的哪些痛点2.1 从“定期维修”到“预测性维护”的范式转变传统的设备维护主要有两种模式事后维修和预防性维护。前者是坏了再修损失巨大后者是定期保养不管设备状态好坏都按计划执行容易造成过度维护或维护不足。而预测性维护的目标是基于设备实际运行状态的数据预测其剩余使用寿命或故障发生点从而在恰当时机进行干预。实现预测性维护的关键在于状态监测和异常检测。异常检测就是建立设备“健康”状态的基线模型当实时数据显著偏离这个基线时即触发警报。声音和振动信号是旋转机械类设备最直接、最丰富的状态信息载体。一个磨损的轴承、一个松动的螺丝其运行时的声学特征会发生微妙但可检测的变化。2.2 方案选型Edge AI vs. Cloud AI实现异常检测通常有两条路云端分析方案在设备端安装传感器持续将原始音频/振动数据通过Wi-Fi/4G发送到云端服务器利用强大的云计算资源进行实时或离线分析。边缘智能方案在设备端如Wio Terminal集成一个轻量级AI模型直接对采集到的信号进行实时分析只在检测到异常或需要聚合报告时才发送极简的结果如“异常代码123”到云端。我们选择边缘智能方案原因如下实时性工业现场故障发展可能很快云端来回通信的延迟通常几百毫秒到秒级可能导致错过最佳预警窗口。边缘分析是毫秒级响应。可靠性工厂网络可能不稳定。边缘计算不依赖网络保障了核心检测功能的持续运行。隐私与成本原始音频数据可能包含环境背景音甚至人声全部上传有隐私风险。同时传输连续的高采样率数据会消耗大量带宽成本高昂。边缘方案只上传结论解决了这两个问题。功耗持续的无线数据传输是功耗大户。边缘处理配合间歇性通信非常适合电池供电或低功耗场景。2.3 为什么是Wio Terminal Edge ImpulseWio Terminal它不仅仅是一个单片机。它集成了STM32微控制器、2.4英寸LCD屏幕、麦克风、惯性传感器、无线模块以及丰富的 Grove 接口。这意味着我们无需额外的声音采集模块开箱即用。其屏幕可以直观显示波形、频谱和检测结果极大方便了调试和演示。Edge Impulse它将机器学习中最复杂的数据处理、特征工程、模型训练和优化过程进行了可视化封装。你不需要是TensorFlow或PyTorch专家通过拖拽和配置就能完成一个面向嵌入式设备的模型开发并一键导出为兼容 Arduino、TinyML 等框架的 C 库。它完美地桥接了AI算法和嵌入式部署的鸿沟。这个组合将一个原本需要深厚算法和嵌入式功底的复杂项目变成了一个流程清晰、可逐步实现的工程任务。3. 硬件准备与开发环境搭建工欲善其事必先利其器。这部分我们搞定所有前置工作。3.1 Wio Terminal 基础配置首先确保你的 Wio Terminal 固件是最新的并且配置好了 Arduino 开发环境。驱动安装通过 USB-C 线连接电脑。如果电脑无法识别可能需要安装 Wio Terminal 的 USB 驱动通常是 CH340 或 CP210x具体根据版本而定。Arduino IDE 配置打开 Arduino IDE进入“文件 - 首选项”在“附加开发板管理器网址”中添加https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json打开“工具 - 开发板 - 开发板管理器”搜索“Seeed SAMD”安装Seeed SAMD Boards by Seeed Studio。安装完成后在“工具 - 开发板”中选择Seeed Wio Terminal。还需要安装一些核心库。打开“项目 - 加载库 - 管理库”搜索并安装Seeed Arduino FS(用于文件系统)Seeed Arduino SFUD(用于外部Flash)Seeed Arduino rpcWiFi(用于Wi-Fi功能数据上传时需用)Seeed Arduino rpcUnified(传感器统一库)PDM(用于驱动麦克风这个通常已包含在板支持包中)注意Arduino库版本兼容性是个经典坑。如果后续编译出现奇怪错误首先尝试将库回退到已知稳定的版本或者查看Wio Terminal的官方Wiki获取推荐的库版本组合。3.2 Edge Impulse 账户与设备连接Edge Impulse 提供了免费且功能强大的开发者账户。注册与创建项目访问 Edge Impulse 官网注册账号。登录后创建一个新项目项目类型选择“音频”或“振动”本质都是时间序列信号。将 Wio Terminal 注册为数据采集设备在 Edge Impulse 项目中进入 “Devices” 页面。点击 “Connect a new device” - “Show some options” - “Data forwarder”。根据指引在电脑上通过命令行安装 Edge Impulse CLI 工具 (npm install -g edge-impulse-cli)。运行edge-impulse-daemon命令按照提示登录你的账户并选择当前项目。关键一步此时你需要一个“桥接”程序。在 Arduino IDE 中打开示例File - Examples - Edge Impulse - YourProjectName - static_buffer(或类似的采集示例)。将这个程序烧录到 Wio Terminal。这个程序的作用是将 Wio Terminal 的麦克风数据通过串口转发给运行在电脑上的edge-impulse-daemon再由它上传到云端。烧录成功后重启 Wio Terminal在edge-impulse-daemon命令行界面应该能看到设备已连接。此时在 Edge Impulse 网页的 “Devices” 里你的 Wio Terminal 就会出现。现在硬件和云端平台之间的通道已经打通。Wio Terminal 成为了一个受控的数据采集器。4. 数据采集构建设备的声音“病历本”模型的好坏七分靠数据。对于异常检测我们通常采用无监督或半监督学习。因为获取大量“异常”样本设备坏的时候往往很困难但获取“正常”样本设备健康运行时相对容易。我们的策略是只采集正常状态的数据来训练模型让模型学会“正常”长什么样任何偏离正常模式的行为都会被判定为异常。4.1 采集策略与现场布置确定采集对象和目标以一台小型直流电机或风扇为例。目标是区分其“正常空载运行”声和“异常”声例如用笔尖轻轻触碰电机外壳模拟轻微摩擦或在扇叶上贴一小片胶带模拟动不平衡。传感器布置Wio Terminal 内置的 MEMS 麦克风灵敏度很高。为了获得更清晰的信号并减少环境噪声干扰建议将 Wio Terminal 固定在靠近设备约5-10厘米的稳定位置。如果环境噪声太大可以考虑使用海绵或软橡胶做一个简单的声学隔离罩套在麦克风周围。重要采集过程中确保麦克风与设备的相对位置不变否则同一状态下的声音特征也会因位置不同而差异巨大这会严重干扰模型。参数设置在 Edge Impulse 的 “Data acquisition” 页面设置采集参数Sample length (ms)样本长度。建议 1000 ms (1秒)。太短可能包含不完整的周期信息太长会增加计算负担和延迟。Sample rate (Hz)采样率。Wio Terminal 的 PDM 麦克风最高支持 16kHz。对于机械声音分析通常 8kHz 或 16kHz 足够捕捉主要特征。更高的采样率意味着更精细的频谱但也会增加数据量。从 16kHz 开始是个好选择。Sensor选择 “Microphone”。Label这是关键对于正常样本标签设为normal。对于异常样本可以按类型细分如imbalance,friction或者统一标为anomaly。4.2 实操采集过程与数据增强采集正常样本让设备在健康状态下运行。点击 “Start sampling” Edge Impulse 会指挥 Wio Terminal 录制一段音频并上传。重复此过程至少采集 50-100 个normal样本。采集时可以稍微改变设备的负载如果可能或电源电压让“正常”状态包含一定的正常波动增强模型的鲁棒性。采集异常样本人工模拟故障。例如让电机在扇叶不平衡状态下运行采集并标记为imbalance。用异物轻微摩擦电机轴采集并标记为friction。每种异常尽量采集 20-30 个样本。注意安全模拟轻微故障即可。数据增强在数据量不足时可以利用 Edge Impulse 的 “Augmentation” 功能。对于音频数据可以添加轻微的背景噪声如白噪声、进行时间拉伸微调速度或音高偏移。这能有效增加数据的多样性模拟真实环境下的变化防止模型过拟合。但增强要适度避免扭曲原始信号的本质特征。实操心得数据采集是最枯燥但最重要的一环。我建议在采集时用 Wio Terminal 的屏幕实时显示音频波形确保信号清晰、没有削顶波形上下不要超出屏幕范围。同时在 Edge Impulse 的数据列表里可以点击每个样本进行播放和可视化回放剔除掉那些明显是误操作比如采集时碰撞了设备的坏数据。干净的数据集是成功的一半。5. 脉冲设计从声音到模型特征的魔法采集到的原始音频数据是长达1秒、包含16000个数据点16kHz采样率的时间序列。直接把它扔给神经网络效率极低。我们需要进行脉冲设计即设计一个处理流水线从原始数据中提取有意义的特征。5.1 处理块MFCC特征提取在 Edge Impulse 的 “Impulse design” 页面的 “Processing blocks” 部分我们选择MFCC (Mel-Frequency Cepstral Coefficients)。为什么是MFCCMFCC是语音和音频识别领域的经典特征它模拟了人耳对声音频率的非线性感知特性。对于机械声音它同样有效因为它能很好地捕捉声音的频谱包络——即哪些频率成分的能量强哪些弱。轴承磨损、齿轮断齿等故障往往会改变声音频谱的能量分布MFCC 对这种变化非常敏感。参数配置Number of coefficients: 系数数量。通常选择 13 或 20。13个系数足以描述频谱的主要形状是计算量和信息量的良好平衡点。我们从13开始。Window size: 窗大小。建议设置为 0.02s 或 0.025s。这是进行短时傅里叶变换的窗口长度。Window stride: 窗移。建议设置为 0.01s。窗口每次向前滑动的距离。窗移小于窗长意味着窗口之间有重叠能让特征更平滑。FFT length: 可以设置为窗大小对应的采样点数如0.02s * 16000Hz 320点或者下一个2的幂次数512。点击 “Save parameters”然后点击 “Generate features”。Edge Impulse 会用你配置的 MFCC 参数处理所有训练数据并生成一个特征可视化图。这个图非常重要5.2 特征可视化与数据分析在特征生成页面你会看到一个二维或三维的散点图通过UMAP/t-SNE降维不同颜色的点代表不同标签的数据。理想情况所有normal样本点紧密地聚集在一个区域而各种anomaly样本点则远离这个区域并且彼此之间也可能有区分度。实际情况与调整如果normal点本身就很分散说明你的“正常”数据波动太大可能采集条件不稳定。需要重新检查数据采集过程。如果anomaly点混入了normal点群中说明当前 MFCC 特征无法区分这两种状态。你可能需要尝试增加 MFCC 的系数数量如从13增加到20获取更详细的频谱信息。回到数据采集思考你模拟的“异常”是否在声学特征上确实与正常有区别可能需要更显著的故障模拟。考虑添加其他特征例如时域特征过零率、能量作为补充。Edge Impulse 允许添加多个处理块。这个步骤是一个迭代过程可能需要反复调整采集数据和特征参数直到在特征图上看到清晰的聚类趋势。5.3 学习块K-Means异常检测模型在 “Learning blocks” 部分选择Anomaly Detection (K-Means)。这是我们本次项目的核心算法。原理简述K-Means 是一种聚类算法。在训练阶段它只使用normal标签的数据。算法会在高维特征空间即MFCC特征空间中寻找一个最能代表所有正常样本的“中心点”聚类中心并计算出一个“半径”或距离阈值。在推理部署后阶段对于一个新的样本计算其特征到这个中心点的距离。如果距离超过了训练时确定的阈值就被判定为异常。参数配置Number of clusters: 聚类数。对于“正常”状态只有一种模式的情况通常设置为1。如果你的设备有几种截然不同的正常运行模式例如高速模式和低速模式并且你都采集了数据可以设置为对应的模式数量。Minimum confidence rating: 可以理解为异常得分的缩放因子一般保持默认。隐藏层这里我们不需要神经网络层。K-Means直接在特征空间上操作模型极其轻量这正是边缘设备所需要的。点击 “Save parameters” 后切换到 “Impulse design” 顶部的 “NN Classifier” 标签虽然我们用的是K-Means但界面在这里配置。在这里你需要将Processing block的输出连接到Learning block的输入。6. 模型训练、测试与验证配置好脉冲后就可以开始训练了。模型训练在 “Train model” 页面Edge Impulse 会自动将数据集按比例如80/20划分为训练集和测试集。点击 “Start training”。训练一个K-Means模型速度极快通常几秒到一分钟内完成。训练结果分析训练完成后重点关注以下指标F1-score: 综合了精确率和召回率的指标。在测试集上我们希望它越高越好。混淆矩阵查看模型对normal和各类anomaly的分类情况。理想情况下对角线上的数字正确分类应该很高。异常阈值Edge Impulse 会给出一个自动计算的异常分数阈值。分数高于此阈值判为异常。你可以根据实际情况微调这个阈值。调高阈值降低误报率减少将正常误判为异常但可能会漏掉一些真实的轻微异常召回率降低。调低阈值提高灵敏度更容易检出异常但可能会增加误报精确率降低。模型测试在 “Model testing” 页面可以使用预留的测试集数据之前未参与训练的数据来评估模型在“未知”数据上的表现。点击 “Classify all”查看整体准确率。务必仔细查看分类错误的样本分析原因是数据本身有问题还是特征不够区分实时验证这是最激动人心的环节在 “Live classification” 页面你可以让已连接的 Wio Terminal 进行实时数据采集和分类。确保 Wio Terminal 已连接并运行着之前烧录的static_buffer或类似的采集固件。点击 “Start sampling”你会看到 Wio Terminal 麦克风采集的实时音频经过云端模型推理后返回分类结果和置信度。对着麦克风播放一段之前录制的正常或异常声音观察分类结果是否正确。你也可以现场制造一些声音进行测试。避坑技巧如果实时验证效果不佳但训练和测试集指标很好很可能是过拟合了。这意味着模型只记住了训练数据中的特定噪声而没有学到真正的声学模式。解决方法1) 增加训练数据的多样性和数量2) 在数据采集时引入更多真实的环境背景音3) 使用数据增强。7. 模型部署与Wio Terminal端侧推理当模型在云端验证通过后下一步就是让它“飞入寻常单片机”在 Wio Terminal 上独立运行。7.1 模型导出与库集成导出为Arduino库在 Edge Impulse 项目 “Deployment” 页面选择 “Arduino library”。在配置中勾选 “Enable EON Compiler” 以进一步优化模型大小和速度。然后点击 “Build” 开始生成。完成后下载生成的.zip文件。集成到Arduino项目在 Arduino IDE 中新建一个项目。通过“项目 - 加载库 - 添加.ZIP库…”选择刚才下载的.zip文件。打开示例代码。通常库中会包含一个edge-impulse-standalone示例。你也可以在File - Examples - 你的项目库名 - edge-impulse-standalone找到。这个示例代码包含了完整的模型推理流程是极好的起点。7.2 端侧推理代码解析与优化让我们深入看一下核心代码逻辑并做必要的优化以适应预测性维护场景。#include your_project_inferencing.h // Edge Impulse 生成的头文件 #include seeed_pwm_audio.h // 或对应的PDM麦克风库 // 声明一个静态缓冲区来存放音频样本 static signed short *sampleBuffer; // PDM数据缓冲区 static bool record_ready false; // 1. 音频采集回调函数 void pdm_data_ready() { // 当PDM缓冲区满时此函数被调用 record_ready true; } void setup() { Serial.begin(115200); // 初始化LCD屏幕用于显示结果 tft_init(); tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_GREEN); // 初始化PDM麦克风 PDM.onReceive(pdm_data_ready); // 配置PDM参数必须与Edge Impulse训练时一致例如16kHz采样率单声道 if (!PDM.begin(1, EI_CLASSIFIER_FREQUENCY)) { // 1代表单声道 Serial.println(Failed to start PDM!); while (1); } // 分配缓冲区内存大小需满足模型输入要求 sampleBuffer (int16_t *)malloc(EI_CLASSIFIER_SLICE_SIZE * sizeof(int16_t)); if (!sampleBuffer) { Serial.println(Failed to allocate sample buffer!); while (1); } } void loop() { // 2. 等待并填充音频缓冲区 if (record_ready) { PDM.read(sampleBuffer, EI_CLASSIFIER_SLICE_SIZE); record_ready false; // 3. 信号预处理如必要例如DC偏移移除 // 这里可以添加一个高通滤波或减去均值去除直流分量 int32_t mean 0; for (int i 0; i EI_CLASSIFIER_SLICE_SIZE; i) { mean sampleBuffer[i]; } mean / EI_CLASSIFIER_SLICE_SIZE; for (int i 0; i EI_CLASSIFIER_SLICE_SIZE; i) { sampleBuffer[i] - mean; } // 4. 创建信号结构体准备推理 signal_t signal; signal.total_length EI_CLASSIFIER_SLICE_SIZE; signal.get_data raw_feature_get_data; // 库提供的函数 // 5. 运行推理 ei_impulse_result_t result {0}; EI_IMPULSE_ERROR err run_classifier(signal, result, false); if (err ! EI_IMPULSE_OK) { Serial.printf(ERR: Failed to run classifier (%d)\n, err); return; } // 6. 解析结果 - 异常检测专用 // 对于K-Means异常检测模型result.classification数组通常只有一个“异常得分” float anomaly_score result.classification[0].value; // 假设第一个输出是异常分数 bool is_anomaly anomaly_score ANOMALY_THRESHOLD; // 与训练时确定的阈值比较 // 7. 显示与输出 tft.fillScreen(TFT_BLACK); tft.setCursor(0, 0); tft.printf(Score: %.3f\n, anomaly_score); if (is_anomaly) { tft.setTextColor(TFT_RED); tft.println(STATUS: ANOMALY DETECTED!); // 触发警报点亮LED发送网络通知等 digitalWrite(LED_BUILTIN, HIGH); // 可以在这里添加Wi-Fi代码将警报发送到服务器或MQTT } else { tft.setTextColor(TFT_GREEN); tft.println(STATUS: NORMAL); digitalWrite(LED_BUILTIN, LOW); } // 打印调试信息到串口 Serial.printf(Anomaly score: %.3f, Is anomaly: %s\n, anomaly_score, is_anomaly ? YES : NO); } }关键优化点阈值 (ANOMALY_THRESHOLD)这个值需要从 Edge Impulse 的训练结果中获取。在项目 “Dashboard” 或模型训练页面找到Anomaly threshold的值将其定义为代码中的常量。降低功耗如果用于长期监测loop()中连续不断的采集和推理会非常耗电。可以改为间歇性工作例如每10秒采集1秒数据进行推理。滑动窗口与平滑为了提高检测稳定性避免偶然噪声触发误报可以采用滑动窗口平均。例如连续记录最近5次的异常分数求平均值再与阈值比较。或者采用“5次中有3次异常才报警”的投票机制。结果上报通过 Wio Terminal 的 Wi-Fi 或 LoRa 模块仅在检测到异常时将时间戳、异常分数和设备ID发送到云端服务器或本地网关实现远程监控。7.3 编译与烧录将修改好的代码编译并烧录到 Wio Terminal。断开 USB 线用移动电源或电池给设备供电将其放置在待监测的设备旁。屏幕上应能实时显示状态和异常分数。8. 系统调优与实战问题排查项目上线后真正的挑战才开始。以下是我在实际部署中遇到的一些典型问题及解决方法。8.1 常见问题速查表问题现象可能原因排查步骤与解决方案误报率高正常运行时频繁报警1. 环境背景噪声变化大如人声、其他机器启停。2. 异常阈值设置过低。3. 训练数据中“正常”样本多样性不足未覆盖所有正常工况。1.物理隔离改进麦克风的声学屏蔽。2.软件滤波在代码中增加更严格的滑动窗口平均或投票机制。3.阈值调整适当提高ANOMALY_THRESHOLD。4.数据补充在多种背景噪声下重新采集“正常”数据重新训练。漏报率高发生异常时不报警1. 异常阈值设置过高。2. 模拟的“异常”与真实故障的声学特征不符。3. 麦克风位置不佳未能捕捉到故障信号。1.阈值调整适当降低阈值。2.故障模拟验证确保模拟故障能产生有效的声学特征变化。可先用电脑音频分析软件如Audacity观察频谱差异。3.传感器重定位尝试将麦克风固定在设备振动最直接传递的位置。模型推理速度慢导致检测延迟大1. 使用的MFCC系数过多或FFT长度过大。2. Wio Terminal主频未最大化。1.特征简化尝试减少MFCC系数如从20减到13或降低采样率如从16kHz降到8kHz。2.性能优化在Arduino IDE中将编译优化等级设置为“-O3”最快速度。3.代码剖析使用micros()函数测量run_classifier()的实际耗时。设备运行一段时间后死机1. 内存泄漏如缓冲区未正确释放。2. 堆栈溢出。3. 看门狗未复位。1.检查内存确保malloc和free成对出现避免在循环中不断分配内存。2.简化任务减少不必要的打印和屏幕刷新。3.启用看门狗在代码中合理使用硬件看门狗并在主循环中定期喂狗。Wi-Fi连接不稳定影响警报上传1. 现场Wi-Fi信号弱。2. 网络配置错误或重连逻辑不健壮。1.信号增强考虑使用外置天线或调整设备位置。2.增加重连机制在Wi-Fi连接代码中加入错误处理和指数退避重试算法确保断线后能自动恢复。8.2 从“异常检测”到“故障分类”的进阶当前系统只能回答“是否异常”。但运维人员更想知道“哪里异常”。我们可以扩展这个系统多分类模型如果我们采集了足够多的、标签明确的各类故障数据如bearing_fault,imbalance,looseness就可以在 Edge Impulse 中将学习块从 “Anomaly Detection (K-Means)” 改为 “Classification (Neural Network)”训练一个能直接输出故障类型的分类模型。这需要更多的数据和更复杂的模型如1D-CNN对Wio Terminal的计算能力是一个考验可能需要使用EON编译器进行深度优化或考虑性能更强的边缘设备。特征融合Wio Terminal 还有加速度计。结合振动信号和声音信号进行多传感器融合能大大提高检测的准确性和可靠性。在 Edge Impulse 中可以创建“融合”脉冲同时处理音频和加速度计数据。趋势分析即使不分类持续记录“异常分数”本身也极具价值。在云端或设备本地做一个简单的时序数据库绘制异常分数随时间变化的曲线。分数的逐渐上升趋势往往比单次超过阈值更能预示渐进性故障如轴承的缓慢磨损。这个基于 Wio Terminal 和 Edge Impulse 的异常检测项目就像给工业设备安装了一个经济实惠的“听觉神经系统”。它证明了在今天实现边缘智能的门槛已经大大降低。从数据采集到模型部署整个流程清晰可见可控可调。它可能无法替代专业的高精度振动分析仪但在大量对成本敏感的中低风险场景中它为预测性维护的普及提供了一条切实可行的路径。