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接口时序图

图像传感器 中值滤波 边缘检测 跑偏判定 报警输出 灰度帧 去噪图 边缘x坐标 报警信号 关键参数 图像分辨率:64×64 | 中心线x=32 | 允许偏移±8像素 | 梯度阈值=30 检测周期:~100ms(10FPS) | 报警条件:|edge_x - 32| > 8

编译与运行

在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的资源约束。