在工业流水线质检、农业病虫害识别等边缘计算场景中,我们常常需要一种既经济实惠又能满足实时性要求的视觉检测方案。传统工控机+摄像头的组合虽然性能强大,但成本高昂且体积庞大。而基于STM32与OpenMV的协同方案,能以不到百元的硬件成本实现轻量级目标检测功能。
这个方案的核心设计理念是"各司其职":OpenMV负责图像采集和轻量化模型推理,STM32作为主控单元处理逻辑控制和设备交互。两者通过UART串口通信,形成一个完整的嵌入式视觉系统。我曾在一个农产品分拣项目中实测,这套系统在检测小目标时帧率能达到8-10FPS,完全满足大多数边缘场景的实时性需求。
OpenMV选型建议:
注意:务必选择带镜头模组的套装,单独购买主板可能无法直接使用
STM32主控选择:
外设搭配技巧:
code复制OpenMV Cam STM32
UART3_TX ---- PA10(RX)
UART3_RX ---- PA9(TX)
GND -------- GND
STM32外设连接:
OLED: PB6(SCL), PB7(SDA)
蜂鸣器: PA0
LED指示灯: PA1
python复制# 在OpenMV IDE的终端执行
import upip
upip.install('tensorflow')
upip.install('ulab')
推荐使用STM32CubeIDE:
python复制# 训练命令示例
python train.py \
--weights yolov7-tiny.pt \
--data custom_data.yaml \
--batch-size 16 \
--img-size 224 224 \ # 必须为32的倍数
--device 0 \
--epochs 100 \
--quant \ # 启用训练后量化
--hyp data/hyp.scratch.tiny.yaml
参数选择依据:
bash复制python export.py --weights best.pt --img-size 224 --include onnx
bash复制tflite_convert \
--output_file=yolov7-tiny-int8.tflite \
--saved_model_dir=./ \
--inference_type=QUANTIZED_UINT8 \
--mean_values=128 \
--std_dev_values=127 \
--default_ranges_min=0 \
--default_ranges_max=255
踩坑记录:OpenMV对TFLite模型有严格限制,输入输出tensor必须为int8/uint8格式,浮点模型无法运行
python复制import tf, image, time
# 初始化模型
net = tf.load("yolov7-tiny-int8.tflite", load_to_fb=True)
labels = ['class1', 'class2', 'class3'] # 替换为实际类别
def detect(img):
# 预处理
img = img.resize(224, 224)
img = img.to_grayscale(copy=False)
# 推理
outputs = net.classify(img)
# 后处理
boxes = []
for i, score in enumerate(outputs[0]['output']):
if score > 0.5: # 置信度阈值
y, x, h, w = outputs[0]['output_1'][i]
boxes.append((x-w/2, y-h/2, x+w/2, y+h/2, labels[i], score))
return boxes
load_to_fb=True将模型加载到帧缓冲区copy=False)pyb.freq()降低主频machine.sleep()在空闲时休眠采用简单的ASCII协议便于调试:
code复制# 检测结果格式
[class],[x],[y],[w],[h],[score]\n
# 示例
2,120,80,40,60,0.82\n
1,200,150,30,50,0.76\n
c复制// 串口中断服务函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
static char rx_buffer[64];
static uint8_t idx = 0;
if(rx_char == '\n') {
rx_buffer[idx] = '\0';
parse_detection(rx_buffer); // 解析检测结果
idx = 0;
} else {
rx_buffer[idx++] = rx_char;
}
HAL_UART_Receive_IT(huart, &rx_char, 1);
}
c复制// STM32逻辑示例
if(detected_class == TARGET_CLASS) {
counter++;
if(counter % 100 == 0) {
OLED_ShowNumber(0, 0, counter);
Buzzer_Beep(100); // 每100个提示一次
}
}
python复制# OpenMV端实现
for obj in detections:
if obj[4] == 'locust' and obj[5] > 0.7:
uart.write("ALARM,1\n") # 触发STM32报警
break
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| OpenMV无法加载模型 | 模型格式不兼容 | 检查是否为int8量化的TFLite模型 |
| 检测结果错乱 | 输入尺寸不匹配 | 确保训练和推理的img-size一致 |
| 串口通信丢失 | 波特率不匹配 | 检查两端均为115200bps |
| 帧率过低 | 图像预处理耗时 | 改用灰度图像减少计算量 |
| STM32无法解析数据 | 协议格式错误 | 添加数据校验和帧尾标识 |
在实际部署中,我发现最大的性能瓶颈往往是图像传输而非模型推理。通过将检测区域ROI缩小到目标可能出现的位置,可以显著提升系统响应速度。例如在一个PCB缺陷检测项目中,将检测区域限制在板卡边缘后,帧率从5FPS提升到了15FPS。