ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RT-Thread工业质检AI实战:从方案选型到代码实现全解析

RT-Thread工业质检AI实战:从方案选型到代码实现全解析 RT-Thread应用创新大赛的赛题公布后“工业质检AI”这个题目在我加的开发者群里讨论度一直没降下来。我猜大家的心态都差不多——这题目把嵌入式开发和AI落地拉到了同一个赛道上听起来既高级又有点摸不着门。我仔细读了几遍命题说明又翻了不少往届作品结合自己做边缘视觉项目的经验这题其实没有想象中那么高不可攀。题目里那句“每个开发者都能做”不是客套话它的潜台词是你不一定非得会训练复杂的深度模型但你需要有能力把一套完整的检测链路跑起来。这篇文章我会从命题拆解、方案选型、代码实现到踩坑复盘完整讲一遍。不管你是学生、刚工作的嵌入式工程师还是半路转行边缘AI的开发者只要你手上有一块常见的开发板按这条路线走做出来的东西完全可以拿去参赛甚至可以放到真实产线上做一轮小规模验证。1. 命题背后到底在考什么理解工业质检AI的真实需求1.1 先搞明白工业现场要解决什么问题工业质检AI说白了就是把原来靠人眼做的外观检查、装配确认、尺寸判断这些事交给摄像头和算法去做。制造业里面这类需求遍地都是注塑件有没有缺料、PCB板上元件有没有漏焊、装配线上螺丝有没有少打一颗、包装环节有没有混入异物。这些场景有几个共同点检测对象高度重复产品形态固定检测标准明确而且绝大多数都是“有”和“没有”、“多”和“少”、“好”和“坏”的二分类问题。这种问题恰恰最适合用嵌入式设备配合摄像头来解决因为算法不需要理解复杂语义只需要在固定位置、固定光照下做稳定的像素级判断。人工质检最大的问题不是看不出来而是注意力没法长时间保持。有研究表明人在重复目检任务中20分钟后漏检率会明显上升。一条产线往往需要安排多名质检员轮换人力成本高漏检风险依然不可控。而一台固定的视觉检测设备可以不休息、不喝水、不聊天持续以同样标准工作这才是不良品拦截和价值创造的基础。1.2 RT-Thread在这类项目里到底扮演什么角色RT-Thread是国内开发者非常熟悉的开源物联网操作系统组件化程度高生态也活跃。它在这个命题里的角色有点像一个“总装车间”摄像头驱动是买来的零件图像缓存是临时库房算法是加工工位显示屏和网络上报是质检员的报告台。你把它们用一个系统组织起来让各自有序运转这就是RT-Thread的核心价值。很多初学者一看到“AI”两个字就紧张以为需要服务器、GPU、深度学习框架那一整套。但命题真正考察的是端侧部署能力也就是在一个资源有限的小系统里让视觉采集、推理计算和结果输出协同工作。RT-Thread的线程管理、设备驱动框架、信号量通信、文件系统、网络协议栈都是为这种场景准备的成熟积木。而且RT-Thread官方一直在推动AI扩展包社区里也有TinyMaix、nnom等轻量级神经网络推理库可以直接调用。这意味着你可以在MCU上用Keras训练一个很小的模型然后转换成C数组部署到板子上甚至不需要连接云端。这个技术路线已经非常成熟不是只有大厂才能玩。1.3 “每个开发者都能做”这句话的真实含义我见过不少开发者卡在第一步觉得自己没有算法背景做不了AI。其实命题真正的意思是你不需要从零发明模型你只需要学会使用工具。现有开源资料和预训练模型已经足够覆盖很多工业质检场景更难的部分在于系统集成——如何让摄像头稳定出图、如何保证检测实时性、如何在低资源设备上把整个流程跑通。话说回来也不是所有质检都必须上深度学习。很多规则明确的场景用传统图像处理就够了比如判断一个区域有没有物体、测量一个间距是否在范围内。深度学习适合的是缺陷形态不固定、难以用规则描述的场景。能根据实际问题选择合适的技术路线比套一个“AI模型”的壳子更显功力这在评委那里也是明显的加分项。2. 硬件与软件技术选型用最少成本搭出可用原型2.1 主控芯片MCU、MPU和NPU怎么选先给一张对比表把三类常见平台的定位说清楚。平台类型代表芯片可部署算法开发难度硬件成本适用阶段高性能MCUESP32-S3、STM32H750、瑞萨RA6M4轻量CNN几百KB以内、传统图像算法中低50~150元原型验证、小批量Linux MPURV1126、V853、STM32MP1ncnn、ONNX Runtime、RKNN 中等模型较高中150~400元复杂算法、中批量NPU平台RK3588、地平线X3较大模型、多路视频高高500元以上接近量产、多工位我的建议是如果是第一次做优先选高性能MCU。RT-Thread在MCU上的生态是最成熟的ESP32-S3和STM32H750这类芯片本身带FPU算轻量卷积和传统图像算法完全够用而且开发板和摄像头模块加起来一百多块钱就能搞定即使后面方案推倒重来试错成本也低。如果目标场景确实需要跑一个几百层的深度网络再考虑Linux MPU。RV1126这类芯片内部集成NPU能以较低功耗运行中等规模模型但开发环境配置复杂度会上一个台阶需要同时管理Linux系统、交叉编译链和NPU工具链对新手来说前期成本挺高。2.2 图像采集模块与光学环境摄像头选择上OV2640和OV5640是常见的低成本方案前者200万像素后者500万像素。MCU侧受内存和带宽限制最终参与运算的分辨率一般在QVGA320×240到VGA640×480之间所以5M像素更多是给裁剪取景留余地实际运算分辨率并不高。工业固定场景下我强烈建议选带全局快门的摄像头比如OV9281或OV2311。卷帘快门在拍摄运动物体时会产生果冻效应位置判断会变形。对螺栓、元件这类小目标果冻效应很容易让边缘特征偏移导致误判。预算允许就上全局快门这是现场稳定性的关键。光源是被很多人忽略的隐藏变量。固定光照环境下算法阈值可以设置得很窄检测稳定性非常高自然光环境一旦出现午后阳光偏移或者灯管频闪同样的阈值就会出现大量误检。我建议参赛方案里至少要配一个固定角度的LED补光灯成本几十块钱但能把整体可靠性提升一大截。哪怕是最普通的条形白光灯也比什么都不加好得多。2.3 软件栈怎么搭RT-Thread组件与AI扩展RT-Thread构建项目有两种主流方式RT-Thread Studio图形化建工程或者Env工具配合menuconfig配置。我个人的习惯是用Env配置完组件后再回到Studio或者VS Code写代码这样既保留了命令行的灵活性又享受了IDE的调试便利。一个典型的工业质检工程需要开启以下组件内核部分线程、信号量、事件集、软件定时器设备驱动摄像头驱动sensor框架、LCD显示驱动、GPIO/LED控制文件系统如果需要对图片落盘采样挂载LittleFS或FATFS网络组件如果做结果上报开启SAL套接字层和MQTT软件包AI相关软件包TinyMaix、nnom或LVGL用于界面展示这些组件在RT-Thread的包管理器里都有现成版本点选配置后编译系统会自动拉取源码不需要自己移植。真正需要你花时间的是设计检测逻辑和处理边界情况这比调试驱动更考验功力。3. 从零跑通一个“缺件检测”质检终端完整实操3.1 定义清晰可验收的检测目标我选一个特别容易被评委理解的场景做例子小型继电器底座上需要插三根金属端子产线偶尔出现缺一根或两根的不良品。摄像头垂直固定检测时底座位置由治具限定所以每次拍摄的角度基本一致。检测内容是判断三根端子是否都在位。结合实际端子是金属材质光线照射下亮度较高和黑色塑料底座对比度明显这样一个场景用传统图像处理就能做不需要神经网络。将这个思路做成最小闭环整个系统只需要四个模块图像采集、图像处理、结果判定、结果输出。3.2 开发环境与基础工程搭建我使用ESP32-S3开发板搭配OV2640摄像头模块来说明整个过程这套组合在RT-Thread社区的资料最全遇到问题也好搜。创建工程后用Env进入目录执行menuconfig然后做如下配置在Hardware Drivers Config中开启Camera设备驱动选择OV2640开启LCD设备选择对应的SPI或RGB屏驱动在Components中开启POSIX、信号量等基础组件在Software packages中选上TinyMaix即使第一版不用后面扩展比较方便如果计划用Wi-Fi上报结果开启Wi-Fi框架和MQTT包保存退出后执行scons -j8编译第一次编译需要下载大量软件包网络好时大约需要十分钟。把固件通过串口烧录进开发板打开串口终端能看到RT-Thread的启动logo和msh命令行。到这里基础环境就算跑通了。3.3 图像采集、预览与灰度化现在编写一个简单的线程来采集图片并显示到LCD上目标是把实时图像链路先打通。这部分是后面一切检测逻辑的前提如果图像链路不稳定后面做再多算法都是空中楼阁。#include rtthread.h #include rtdevice.h #define QC_IMAGE_W 320 #define QC_IMAGE_H 240 static rt_device_t cam_dev; static rt_device_t lcd_dev; static uint8_t *rgb_buf; static uint8_t *gray_buf; static int qc_camera_init(void) { cam_dev rt_device_find(cam0); if (!cam_dev) { rt_kprintf(camera not found!\n); return -RT_ERROR; } if (rt_device_open(cam_dev, RT_DEVICE_FLAG_RDONLY) ! RT_EOK) { rt_kprintf(camera open failed!\n); return -RT_ERROR; } /* 设置采集分辨率由驱动具体实现决定 */ rt_device_control(cam_dev, RT_SENSOR_CTRL_SET_RANGE, (void *)(QC_IMAGE_W * QC_IMAGE_H)); return RT_EOK; } static int qc_lcd_init(void) { lcd_dev rt_device_find(lcd); if (!lcd_dev) { rt_kprintf(lcd not found!\n); return -RT_ERROR; } if (rt_device_open(lcd_dev, RT_DEVICE_FLAG_RDONLY) ! RT_EOK) { rt_kprintf(lcd open failed!\n); return -RT_ERROR; } return RT_EOK; }RGB565转灰度是图像处理的第一步注意ESP32-S3的摄像头驱动默认输出RGB565格式每个像素占两个字节。灰度化要用整数运算避免浮点拖慢速度配比按感知亮度系数来static void qc_rgb565_to_gray(const uint8_t *rgb, uint8_t *gray, int w, int h) { int i, j; for (i 0; i h; i) { for (j 0; j w; j) { int idx (i * w j) * 2; int r rgb[idx] 0xF8; int g ((rgb[idx] 0x07) 5) | ((rgb[idx 1] 0xE0) 3); int b (rgb[idx 1] 0x1F) 3; gray[i * w j] (r * 299 g * 587 b * 114) / 1000; } } }这里把RGB各5到6位扩展到8位后再参与计算精度比直接用小位宽算好不少。虽然代码看起来多几行但对后续阈值判断有很大帮助不会因为色深不够导致边缘噪声放大。3.4 用“白色像素统计”实现第一版检测逻辑在本场景中三根金属端子在补光下呈现高亮底座是黑色塑料两者亮度差异非常大。检测逻辑就简化成统计图像中高亮像素的数量和位置分布与合格品模板做对比。先做一个简单的二值化函数把灰度图按阈值分成前景和背景static int qc_threshold(uint8_t *gray, int w, int h, int th) { int count 0; for (int i 0; i w * h; i) { if (gray[i] th) { gray[i] 255; count; } else { gray[i] 0; } } return count; }返回的count值就是高亮像素的总数。看起来很简单但实际项目里还必须考虑“位置”信息否则画面边缘出现一个反光点也会被误判为OK。更进一步的做法是把ROI区域切成几个子区域分别统计每个子区域的白色像素数。如果每个子区域的数量都在合格范围内才判定OK。主检测线程的框架是这样的static void qc_detect_thread_entry(void *param) { int ret 0; int area_w1 0, area_w2 0, area_w3 0; while (1) { /* 1. 抓取一帧 */ ret rt_device_read(cam_dev, 0, rgb_buf, QC_IMAGE_W * QC_IMAGE_H * 2); if (ret 0) { rt_thread_mdelay(100); continue; } /* 2. 转灰度并二值化 */ qc_rgb565_to_gray(rgb_buf, gray_buf, QC_IMAGE_W, QC_IMAGE_H); (void)qc_threshold(gray_buf, QC_IMAGE_W, QC_IMAGE_H, 150); /* 3. 分ROI统计高亮像素 */ area_w1 qc_count_roi(gray_buf, QC_IMAGE_W, QC_IMAGE_H, ROI_1); area_w2 qc_count_roi(gray_buf, QC_IMAGE_W, QC_IMAGE_H, ROI_2); area_w3 qc_count_roi(gray_buf, QC_IMAGE_W, QC_IMAGE_H, ROI_3); if (area_w1 OK_MIN || area_w1 OK_MAX || area_w2 OK_MIN || area_w2 OK_MAX || area_w3 OK_MIN || area_w3 OK_MAX) { rt_pin_write(PIN_LED_RED, PIN_HIGH); rt_pin_write(PIN_LED_GREEN, PIN_LOW); total_fail; rt_kprintf([QC] FAIL w1%d w2%d w3%d\n, area_w1, area_w2, area_w3); } else { rt_pin_write(PIN_LED_RED, PIN_LOW); rt_pin_write(PIN_LED_GREEN, PIN_HIGH); total_ok; rt_kprintf([QC] OK w1%d w2%d w3%d\n, area_w1, area_w2, area_w3); } /* 4. 在LCD上显示当前帧和结果便于演示 */ rt_device_write(lcd_dev, 0, rgb_buf, QC_IMAGE_W * QC_IMAGE_H * 2); qc_draw_result(total_ok, total_fail); rt_thread_mdelay(200); } }这里ROI需要预先通过取景确定。第一次跑起来后先把三个端子的坐标框出来分别定义ROI_1、ROI_2、ROI_3四个整数x、y、宽、高。然后在现场分别拍正常品、缺一个端子的不良品、缺两个端子的不良品各几十张统计高亮像素的范围把 OK_MIN 和 OK_MAX 标定出来。这一步叫“标定”是整个传统视觉方案里最耗时也最重要的工作。3.5 从“能检测”到“能用”结果展示和数据上报能判断OK/NG只是第一步。你得让这两个结果产生实际价值否则评委无法直观看到系统能力。最直接的输出是LED指示灯加蜂鸣器但这只适合现场演示。更加分的是把结果同步上报到上位机或者云端形成一条完整的数据流转链路。在RT-Thread里串口上报最简单直接rt_kprintf输出结构化日志就行后续可以用脚本解析统计误检率。如果有Wi-Fi模块可以通过MQTT把每一次检测结果发布到公共MQTT Broker比如EMQX或Mosquitto这样你在手机上打开一个轻量MQTT客户端就能实时看到检测记录。这个功能在答辩现场非常吸引眼球因为评委可以看到数据在实时流动。节点ID、产品批次号、检测时间、结果、各ROI统计值建议都塞进上报数据里。这看起来是小事但对数据追溯意义很大。做过产线项目的人都知道设备不联网、数据不归档出问题的时候根本没法回溯是哪一批工件开始出现偏差的。有了数据记录至少能画个趋势图出来。3.6 如果检测目标复杂怎么上轻量模型复用神经网络如果缺陷类型不固定比如划痕、脏污、形状异常传统阈值没法稳定描述这时候就可以把TinyMaix用起来。流程是用PC端收集几百张合格品和不合格品图片训练一个几层的卷积网络做二分类然后导出为C语言权重数组放到RT-Thread工程里通过TinyMaix的API加载并推理。TinyMaix在MCU上的资源占用可以做到几十KB级别。以ESP32-S3为例跑一个MobileNetV1量化模型大概需要几百毫秒实时性刚好够用。我建议的第一版方案仍然先用传统图像处理打通全链路模型推理作为扩展点。原因很简单神经网络模型训练、量化和调试的成本高而且掉坑了不好排查传统算法至少逻辑透明每一步都能打印出来检查对错。4. 答辩评审最看重的三个维度指标、稳定性、演示效果4.1 用数据说话检测率、误检率和耗时很多参赛作品演示的时候效果很好但评委一问“漏检率是多少”“误检率是多少”“单次检测耗时多少”就卡住了。这其实是最基本的工程化指标建议在方案文档和演示PPT里明确列出。实际测法很简单准备合格品20个故意制造缺件不良品20个让设备连续检测统计结果。漏检率就是不良品里被误判成合格品的比例误检率就是合格品里被误判成不良品的比例。再用rt_tick_get()在检测线程前后打时间戳算出单帧平均耗时。比如我这里用ESP32-S3QVGA分辨率传统算法单次耗时约12ms算上抓图和显示一帧总耗时约180ms基本每秒5帧左右。如果换成VGA分辨率算法耗时会翻倍但检测鲁棒性会好一些这个取舍要权衡。我在项目里固定用一组回归图片集来测版本更新每次改算法参数后跑一遍记录OK/NG判定是否和预期一致。这样能防止改一处好的地方导致另一个场景挂掉这是实战里攒下来的重要经验。4.2 稳定性测试连续运行与异常恢复工业设备讲究7×24小时稳定运行。虽然参赛原型不要求真跑一个月但至少要让评委看到你有这方面的思考。连续运行两小时记录系统有没有卡死、检测线程有没有异常退出、Wi-Fi有没有掉线重连。异常恢复也是一个值得展示的点人为拔掉摄像头连接、或者让画面中出现大面积遮挡让系统能检测到“无效帧”并给出提示而不是误判成OK或NG。这可以通过计算图像平均亮度来简单实现如果亮度异常低或异常高就直接标记为“环境异常”不参与产品判定。这个逻辑虽然简单但体现出来的工程意识比单纯一个算法demo强很多。4.3 演示脚本设计从开机到结论的完整流程有没有发现其实评委在你演示的3分钟里能记住的不是你的代码写得多么精妙而是系统能不能在他面前“演完一出完整的戏”。我习惯在演示前跑一遍固定动作流程。第一步把系统上电展示启动日志说明RT-Thread初始化了什么模块第二步放一个合格品到治具上屏幕显示OK绿色指示灯亮数据上报成功第三步换上一个缺件不良品屏幕显示NG红色指示灯亮蜂鸣器响上报数据第四步打开手机MQTT客户端或上位机看板展示历史检测记录和统计数据第五步拔掉摄像头展示系统进入异常提示状态恢复后能继续自动工作这套演示流程比任何PPT都更有说服力。它展示了从硬件到系统再到应用的完整闭环对应了命题里“工业质检AI”的完整意义。5. 我踩过的坑和排查方法工业质检开发笔记5.1 摄像头花屏、掉帧、颜色不对这三个问题在MCU摄像头项目里几乎无法避免处理方案不同花屏多半是DMA传输不稳定或者帧缓冲指针没有正确同步建议关闭Cache对帧缓存区域的缓冲或者检查是不是同时有多个线程读了同一块内存掉帧一般是因为图像采集线程卡在其他耗时操作上比如把灰度转换和显示都放在同一个高优先级线程里导致下一帧来时上一帧还没处理完。把图像采集单独放一个线程算法处理放另一个线程中间用消息队列传递“新帧可用”事件掉帧情况会缓解很多颜色不对优先检查RGB565的字节序有些驱动输出的是BGR565而不是RGB565光这一个问题就够折腾一下午如果显示出来的图像有条纹或者撕裂感通常是在访问帧缓存时机上出了问题。要么加互斥锁要么在DMA写完后用回调通知读取二选一就能解决。5.2 RT-Thread内存不足与线程栈溢出ESP32-S3内置SRAM约512KB听起来不少但摄像头帧缓冲、LCD显存、网络协议栈和TinyMaix的模型数组一加上来内存立刻紧张。K210、STM32H750这类平台更抓狂几百KB内存跑视觉应用非常局促。裁剪分辨率能跑QVGA就别用VGA模型输入能设96×96就别设224×224减少帧缓冲个数保存一份RGB和一份灰度缓冲即可不要为每层处理都复制一份线程栈设置在128KB范围内优先选最小可用值再用ps命令在msh里查看线程栈使用率发现接近或超过上限就调大不能想当然用free命令在msh里查看动态内存剩余量如果程序跑半小时内存持续下降多半是有内存泄漏需要检查哪个线程频繁申请但没有释放线程栈溢出比较隐蔽早期症状可能是运行几小时后莫名其妙重启或者某个变量值突然变掉。在RT-Thread的启动配置里开启栈溢出检测同时把系统重启日志保存起来排查会高效很多。5.3 检测算法因光照变化失效这个问题最折磨人。在室内灯光下阈值150调得很好拿到窗边变成140才能测准过一会太阳出来了130又不够。这是所有视觉检测项目的核心痛点解决方案按优先级分三层。第一层是物理上做固定遮光比如3D打印一个遮光罩盖在检测区域上让外部光线对内部的影响降到最低。第二层是软件上做自适应阈值计算图像直方图找到波峰波谷作为分界线替代固定阈值代价是每帧多花一些CPU时间。第三层才是上神经网络让模型自动学习光照不变特征。我的建议是前两层能解决的就不要急上第三层因为传统算法调试周期短、问题透明答辩时也能解释清楚。第三层适合作为“性能增强”章节展示体现方案的可扩展性。5.4 从原型到“现场可用”的最后一步很多同学做完了展示完了就觉得任务结束了。但我建议下一步思考一下如果这个设备要放到真实产线还需要做什么固定结构和防护罩怎么设计通信断线时本地缓存数据怎么处理设备重启后需要人工确认当前状态还是自动恢复需要什么权限的人才能调整检测参数这些思考即使只是写在参赛文档的建议章节也会让评委觉得你具备工程落地意识。参赛的价值并不仅在于获奖这段经历会强迫你把一个抽象概念落成一个可运行的实物中间踩的每一个坑都会变成你下一份工作、下一个项目里的判断力。我个人的体会是工业质检AI的赛题看着高但它真正考的不是AI算法本身而是你能否把一个光学成像、实时计算、结果输出串成一个闭环。最后分享一个我调试时的小习惯每次改完算法一定固定相机拍20张照片存下来作为回归集确保之前能检出的不会又漏掉。这个习惯帮我省了非常多时间不管做比赛还是后续做项目都值得保留。
返回列表