划痕、裂纹、漏装、错装等缺陷很适合用机器视觉识别,但“模型能识别一张图片”和“系统能在产线上连续运行”是两件事。工业质检的成本往往分散在数据采集、样本标注、节拍控制、设备联动、异常处置和版本追溯中,而不只是模型训练。
真正的最后一公里,是把一次推理变成可重复、可审计、可回退的生产流程。RT-Thread 这类实时操作系统可以承担设备控制、任务调度和故障保护;视觉模型则可以运行在带 NPU/GPU 的边缘计算单元上。二者不必部署在同一颗芯片上,但必须形成清晰、稳定的接口。
不要从模型选型开始,先定义什么叫检得准
每一种工件、工艺和缺陷都有不同的判定边界。即使都是“划痕”,喷涂件、玻璃和金属件在长度、深度、方向以及可接受程度上也不一样。因此,项目启动时应先把业务标准转换为可计算的验收指标。
至少需要明确以下内容:
| 项目 | 需要回答的问题 |
|---|---|
| 缺陷分类 | 哪些必须拦截,哪些允许放行,哪些需要人工复核? |
| 漏检率 | 对关键缺陷最多允许漏掉多少? |
| 误检率 | 错误剔除会造成多少停线或材料损失? |
| 推理延迟 | 从触发拍照到输出结果,必须控制在多少毫秒内? |
| 环境范围 | 光照、温度、振动、工件速度变化到什么程度仍需正常工作? |
| 追溯信息 | 是否保存图片、工位、批次、模型版本和判定结果? |
准确率通常不是最重要的单一指标。假设 99.5% 的产品都是良品,一个始终输出“良品”的模型也能得到 99.5% 的准确率,却完全没有质检价值。关键缺陷应单独统计漏检率,并结合误检率、P95 延迟和人工复核比例一起验收。
数据集也不能只做随机切分。相邻时间拍摄的图片往往拥有相同光照、背景和工件批次,随机分配到训练集和测试集后,会产生看似很高的测试成绩。更稳妥的方式是按日期、产线、批次或供应商切分,并保留真实生产环境中的独立验收集。
把推理节点放进确定性的产线链路
一种可以实践的分层架构如下:
相机/光源
│ 触发与图像
▼
边缘计算单元(预处理、模型推理、置信度计算)
│ request_id + verdict + model_version + latency
▼
RT-Thread 控制节点(状态机、超时、队列、看门狗、I/O)
│
├── PLC/机械执行机构:放行、剔除、停线
└── 本地缓存/工厂系统:图片索引、批次、结果、告警
这套分工的重点不是限定硬件,而是隔离职责:模型负责给出判断,实时控制节点负责在规定时间内执行安全动作。即使推理运行在同一台设备上,也建议保留逻辑边界。
推理结果至少应包含:
request_id:关联触发信号、图片和工件;verdict:例如OK、DEFECT、REVIEW;defect_type:缺陷类别;confidence:用于复核分流,而不是直接代表真实概率;model_version:支持追溯和回滚;latency_ms:检查是否满足产线节拍;error_code:区分超时、图片损坏、模型不可用等异常。
控制逻辑不能把“没有收到结果”解释成“良品”。当消息队列已满、相机断连、推理超时或模型进程失效时,应进入预先约定的安全状态,例如转人工复核、暂停进料或停线告警。具体选择取决于漏检风险和停线成本。
用可执行的质量门禁阻止不合格模型上线
下面是一个可以直接运行的最小验收脚本。假设离线验收结果使用 CSV 保存,标签只有 OK 和 DEFECT。实际项目可以按缺陷类别扩展,并把阈值改成工厂确认过的标准。
将以下内容保存为 quality_gate.py:
#!/usr/bin/env python3
import argparse
import csv
import math
import sys
def ratio(numerator, denominator):
return numerator / denominator if denominator else 0.0
def percentile(values, p):
if not values:
return 0.0
values = sorted(values)
index = max(0, math.ceil(len(values) * p) - 1)
return values[index]
parser = argparse.ArgumentParser()
parser.add_argument('csv_file')
parser.add_argument('--max-fn-rate', type=float, default=0.02)
parser.add_argument('--max-fp-rate', type=float, default=0.03)
parser.add_argument('--max-p95-ms', type=float, default=120.0)
args = parser.parse_args()
with open(args.csv_file, newline='', encoding='utf-8') as file:
rows = list(csv.DictReader(file))
required = {'ground_truth', 'predicted', 'latency_ms', 'model_version'}
if not rows or not required.issubset(rows[0]):
sys.exit(f'CSV 缺少字段,必须包含: {sorted(required)}')
valid_labels = {'OK', 'DEFECT'}
for line, row in enumerate(rows, start=2):
if row['ground_truth'] not in valid_labels or row['predicted'] not in valid_labels:
sys.exit(f'第 {line} 行标签非法')
tp = sum(r['ground_truth'] == 'DEFECT' and r['predicted'] == 'DEFECT' for r in rows)
fn = sum(r['ground_truth'] == 'DEFECT' and r['predicted'] == 'OK' for r in rows)
fp = sum(r['ground_truth'] == 'OK' and r['predicted'] == 'DEFECT' for r in rows)
tn = sum(r['ground_truth'] == 'OK' and r['predicted'] == 'OK' for r in rows)
latencies = [float(r['latency_ms']) for r in rows]
versions = {r['model_version'] for r in rows}
fn_rate = ratio(fn, tp + fn)
fp_rate = ratio(fp, fp + tn)
p95_ms = percentile(latencies, 0.95)
print(f'samples={len(rows)} model_versions={sorted(versions)}')
print(f'TP={tp} FN={fn} FP={fp} TN={tn}')
print(f'false_negative_rate={fn_rate:.4%}')
print(f'false_positive_rate={fp_rate:.4%}')
print(f'p95_latency_ms={p95_ms:.2f}')
passed = (
len(versions) == 1
and fn_rate <= args.max_fn_rate
and fp_rate <= args.max_fp_rate
and p95_ms <= args.max_p95_ms
)
if not passed:
sys.exit('QUALITY GATE: FAILED')
print('QUALITY GATE: PASSED')
准备一份示例数据并执行:
cat > inspection_results.csv <<'CSV'
ground_truth,predicted,latency_ms,model_version
OK,OK,71.2,scratch-detector-1.4.0
DEFECT,DEFECT,84.5,scratch-detector-1.4.0
OK,OK,69.8,scratch-detector-1.4.0
DEFECT,DEFECT,91.3,scratch-detector-1.4.0
OK,DEFECT,78.6,scratch-detector-1.4.0
CSV
python3 quality_gate.py inspection_results.csv \
--max-fn-rate 0.02 \
--max-fp-rate 0.40 \
--max-p95-ms 120
示例为了使用少量数据,把误检率阈值放宽到了 40%,不能直接作为生产标准。实际验收集应覆盖不同批次、班次、光照、设备状态和典型缺陷,并由工艺与质量团队共同确定阈值。质量门禁可以接入 CI/CD:脚本返回非零退出码时,阻止模型包进入生产发布阶段。
上线之后,数据闭环比继续调参更重要
工业现场会不断产生训练阶段没有覆盖的变化:新供应商改变了材料纹理,相机支架发生轻微位移,灯具老化导致曝光变化,或者工艺改进改变了正常产品的外观。模型上线不是项目终点,而是新一轮数据采集的起点。
可以建立以下闭环:
- 将低置信度、人工改判和设备异常样本放入待复核队列;
- 优先标注模型意见与人工结论不一致的图片,而不是无差别保存全部图像;
- 为图片记录批次、工位、时间、相机参数和模型版本;
- 新模型先运行影子模式,只记录判断,不驱动剔除机构;
- 对比新旧模型在相同工件上的结果,通过门禁后再灰度切换;
- 保留上一版本模型和配置,确保现场可以快速回滚。
还应考虑存储和网络边界。生产图片可能包含产品设计或工艺信息,不宜默认上传到公网。网络中断时,控制链路必须继续工作;本地缓存达到上限后,应按风险策略删除旧良品图片、保留缺陷与异常记录,而不是阻塞实时任务。
落地前的检查清单
一个可上线的 AI 质检系统,至少应能回答这些问题:
- 缺陷标准是否由工艺、质量和算法团队共同确认?
- 测试集是否按批次或时间隔离,避免数据泄漏?
- 推理超时、相机断连和消息丢失时,RT-Thread 控制节点进入什么状态?
- 每次判定能否追溯到图片、工件、参数和模型版本?
- 新模型是否经过离线门禁、影子运行和小范围灰度?
- 是否存在无需联网的降级方案,以及可验证的回滚路径?
工业质检的竞争力并不只来自更复杂的网络结构。稳定的采集标准、可信的验收数据、确定性的实时控制和持续运行的数据闭环,才是把演示模型变成生产设备的关键。