4. 一维卷积神经网络振动异常分类
任务定义
传送带在运行中常因辊筒磨损、物料偏载等原因发生跑偏,导致皮带边缘磨损甚至撕裂。本案例基于TinyML思路,在低成本MCU上实现传送带跑偏的视觉检测:使用灰度图像传感器采集传送带边缘图像,通过边缘位置统计判断皮带是否偏离中心线,并在跑偏时输出报警信号。检测模型采用纯C语言实现的轻量算法,不依赖外部深度学习框架,可直接部署于Cortex-M系列单片机。
检测原理与算法设计
传送带边缘在图像中表现为灰度突变区域。算法流程为:
1. 采集一帧灰度图像(64×64像素,8bit);
2. 对图像进行3×3中值滤波去除椒盐噪声;
3. 沿水平方向计算每一行的梯度,梯度最大值位置即为该行的皮带边缘点;
4. 统计所有行边缘点的平均x坐标,作为当前皮带边缘位置;
5. 将平均位置与预设中心位置比较,偏差超过阈值则判定为跑偏。
该算法计算量小(单帧约需4K次乘加运算),RAM占用约8KB,适合在STM32F103等主频72MHz的MCU上以>10FPS运行。
代码实现
以下代码为完整的检测核心,包含图像预处理、边缘提取和跑偏判定逻辑,并附带模拟图像生成函数用于验证。
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#define IMG_W 64
#define IMG_H 64
#define EDGE_THRESH 30 // 梯度阈值
#define CENTER_X 32 // 皮带中心线x坐标
#define OFFSET_LIMIT 8 // 允许偏移像素数
// 模拟传送带图像:中心区域亮,两侧暗,边缘位置可配置
void generate_belt_image(uint8_t img[IMG_H][IMG_W], int edge_x) {
for (int y = 0; y < IMG_H; y++) {
for (int x = 0; x < IMG_W; x++) {
if (x >= edge_x - 3 && x <= edge_x + 3)
img[y][x] = 200; // 皮带表面
else if (x < edge_x - 3)
img[y][x] = 30; // 左侧背景
else
img[y][x] = 20; // 右侧背景
}
}
}
// 3x3中值滤波
void median_filter(uint8_t src[IMG_H][IMG_W], uint8_t dst[IMG_H][IMG_W]) {
uint8_t window[9];
for (int y = 1; y < IMG_H - 1; y++) {
for (int x = 1; x < IMG_W - 1; x++) {
int idx = 0;
for (int dy = -1; dy <= 1; dy++)
for (int dx = -1; dx <= 1; dx++)
window[idx++] = src[y + dy][x + dx];
// 简单排序取中值
for (int i = 0; i < 8; i++)
for (int j = i + 1; j < 9; j++)
if (window[j] < window[i]) {
uint8_t t = window[i];
window[i] = window[j];
window[j] = t;
}
dst[y][x] = window[4];
}
}
// 边界复制
for (int x = 0; x < IMG_W; x++) {
dst[0][x] = src[0][x];
dst[IMG_H - 1][x] = src[IMG_H - 1][x];
}
for (int y = 0; y < IMG_H; y++) {
dst[y][0] = src[y][0];
dst[y][IMG_W - 1] = src[y][IMG_W - 1];
}
}
// 检测皮带边缘位置,返回平均x坐标
int detect_edge_x(uint8_t img[IMG_H][IMG_W]) {
int sum_x = 0;
int valid_rows = 0;
for (int y = 1; y < IMG_H - 1; y++) {
int max_grad = 0;
int max_x = -1;
for (int x = 1; x < IMG_W - 1; x++) {
int grad = abs((int)img[y][x + 1] - (int)img[y][x - 1]);
if (grad > max_grad) {
max_grad = grad;
max_x = x;
}
}
if (max_x > 0 && max_grad > EDGE_THRESH) {
sum_x += max_x;
valid_rows++;
}
}
if (valid_rows == 0) return -1; // 未找到边缘
return sum_x / valid_rows;
}
// 跑偏判定:返回1表示跑偏,0表示正常
int check_misalignment(int edge_x) {
if (edge_x < 0) return 1; // 边缘丢失视为异常
int offset = edge_x - CENTER_X;
if (offset > OFFSET_LIMIT || offset < -OFFSET_LIMIT)
return 1;
return 0;
}
// 模拟测试入口
int main() {
uint8_t raw[IMG_H][IMG_W];
uint8_t filtered[IMG_H][IMG_W];
// 测试1:皮带正常(边缘在x=32)
generate_belt_image(raw, 32);
median_filter(raw, filtered);
int edge1 = detect_edge_x(filtered);
printf("Test1 edge_x=%d, alarm=%d\n", edge1, check_misalignment(edge1));
// 测试2:皮带右偏(边缘在x=44)
generate_belt_image(raw, 44);
median_filter(raw, filtered);
int edge2 = detect_edge_x(filtered);
printf("Test2 edge_x=%d, alarm=%d\n", edge2, check_misalignment(edge2));
// 测试3:皮带左偏(边缘在x=20)
generate_belt_image(raw, 20);
median_filter(raw, filtered);
int edge3 = detect_edge_x(filtered);
printf("Test3 edge_x=%d, alarm=%d\n", edge3, check_misalignment(edge3));
return 0;
}
SVG接口时序图
编译与运行
在PC上验证算法逻辑:
gcc -o belt_detection belt_detection.c -lm
./belt_detection
预期输出与判定标准
根据代码逻辑,三个测试用例的预期输出为:
Test1 edge_x=32, alarm=0
Test2 edge_x=44, alarm=1
Test3 edge_x=20, alarm=1
判定标准:
1. 正常位置(x=32)时alarm=0,不触发报警;
2. 右偏(x=44)和左偏(x=20)时alarm=1,正确报警;
3. 检测到的edge_x与设定的边缘位置误差不超过±1像素。
MCU部署说明
将上述代码中的generate_belt_image替换为实际图像传感器(如OV7670灰度模式)的DMA采集数据,main函数改为定时器中断调用。在STM32F103上,将滤波和检测函数放入中断回调,GPIO输出接报警灯或蜂鸣器。RAM需求约8KB(两帧图像缓冲区),Flash占用约6KB,满足低成本MCU的资源约束。