title: 我给物联网系统加上了「眼睛」—— i.MX6ULL AI火灾检测 + 多传感器融合(开源更新) date: 2026-06-30 categories: 嵌入式开发 tags: [i.MX6ULL, YOLOv8, AI, 火灾检测, 嵌入式AI, 物联网, 开源]
项目地址(全部开源):https://github.com/wuqiZhu/IoTDualCtrl(13,000+ 行 C/C++)
简介
本文基于 i.MX6ULL 嵌入式 Linux 开发板,实现一套融合 YOLOv8 AI 视觉、8 类传感器加权评分的火灾预警系统,包含完整端云 MQTT 链路、状态机设计、容错机制与全流程踩坑复盘,全部代码开源。
一、这次更新了什么
上次分享了基于 i.MX6ULL 的五层物联网架构,这次给它加上了「眼睛」——AI视觉火灾检测。
上次:传感器 → HAL → RPC → MQTT → 云端 → 钉钉 这次: + AI摄像头 → YOLOv8 → 融合评分 → 状态机
核心新增:
| 功能 | 说明 |
|---|---|
| AI火灾检测 | YOLOv8n + ONNX Runtime,每10秒自动拍照推理 |
| 多传感器融合评分 | 8类信号加权投票,不依赖单一传感器 |
| 状态机 | SAFE→MONITOR→ALERT→COOLDOWN |
| 时序滤波 | 滑动窗口5帧中2帧通过才触发 |
| 深度学习训练 | D-Fire数据集训练YOLOv8n,导出ONNX部署 |
| 腾讯云推理服务 | Flask + ONNX Runtime,systemd托管 |
二、为什么要给物联网加AI
从烟雾传感器说起
传统烟雾传感器有一个固有问题——只能等烟飘到了才报警。仓库火灾往往是先有明火(几秒到几十秒),然后才有烟。烟雾传感器发现时,火可能已经烧起来了。
时间线: t=0 电线短路,产生火花 t=5 周围可燃物被点燃(明火) t=30 产生大量烟雾 t=60 烟雾飘到传感器位置 → 报警!← 晚了1分钟
AI视觉检测可以在明火阶段就发现火情,比烟雾传感器提前几十秒到几分钟。
为什么不只靠AI
AI也有自己的问题——误报。墙上的反光、窗外的阳光、甚至是飞过的虫子,都有可能被模型误判为火焰。
AI单独:该报的报了,不该报的也报了 ← 这不行 传感器单独:有些场景报不了,报的时候已经太晚了 ← 也不行
所以需要两者融合——AI负责早期发现,传感器负责确认,互相补位。
三、多传感器融合评分(核心设计)
3.1 设计思想
不依赖任何单个传感器,所有信号加权投票:
烟雾传感器报警 → +40分 AI看到明火 → +30分 温度快速上升 → +20分 湿度骤降 → +10分 ...... 总分 ≥ 60 → 告警
这样就不会出现"AI误报就发钉钉"或者"烟雾传感器坏了就不报警"的问题。
3.2 信号权重表
| 信号 | 权重 | 触发条件 | 动态修正 |
|---|---|---|---|
| 烟雾传感器 | 40分 | GPIO读到0(报警) | 深夜×1.5 |
| AI检测到fire | 30分 | conf>0.30 | 深夜×1.5 |
| 温度上升速率 | 20分 | ≥2°C且>3°C/分钟 | 夏季减半 |
| 温度>45°C | 15分 | 绝对温度 | 夏季减半 |
| 温度批量偏高 | 2分/°C | 高于历史平均5°C | 上限20 |
| 湿度骤降 | 10分 | 降幅>30%/分钟 | - |
| 光敏(夜间突亮) | 10分 | 暗→亮 | 夜间 |
| 光敏(白天变暗) | 5分 | 持续黑暗 | 白天 |
| PIR有人(配合报警) | 5分 | +烟雾/AI同时 | - |
| 并发倍率 | ×1.5 | ≥2个高权重信号 | 同时触发 |
深夜0-6点所有权重×1.5,因为夜间无人值守,更警惕是合理的。
3.3 一个实际的例子
昨天测试时的一个真实场景——打火机测试:
第1次AI拍照:没看到火 → 不触发 第2次AI拍照:看到火 conf=0.46 → +30分 → 进入MONITOR 第3次AI拍照:看到火 conf=0.32 → +30分 → 总分 30×0.95+30 = 58 → 还差2分 第4次AI拍照:看到火 conf=0.30 → +30分 总分 58×0.95+30 = 85 → ALERT → 钉钉
从点火到告警,约30秒。
如果打火机同时靠近烟雾传感器,两个信号并发触发:
烟雾+40 + AI+30 = 70 并发倍率 ×1.5 = 105 → 一次达到ALERT
3.4 衰减规则
每5秒:累积分 × 0.95 连续60秒无新信号:清零
这样短暂的事件(比如一个人走过被AI误判)不会长期影响分数,持续的事件(真火)可以稳定积累。
3.5 状态机
有可疑信号 评分≥60 30秒后 30秒后 SAFE ───────────→ MONITOR ───────────→ ALERT ──────────→ COOLDOWN ──────────→ SAFE ↑ │ │ └── 60秒无确认 ───┘ └── 恢复正常 ──────────────────────┘
| 状态 | 行为 |
|---|---|
| SAFE | 正常监控,不做任何操作 |
| MONITOR | 关注但不告警,记录数据 |
| ALERT | 发钉钉 + 开风扇 + 拍照上传 |
| COOLDOWN | 冷却,防止重复告警 |
四、AI模型的选型与训练
4.1 模型选择
YOLOv8n,参数量3.0M,模型仅6MB。选择它的原因:
| 因素 | 说明 |
|---|---|
| 轻量 | 3M参数,适合边缘部署 |
| 精度 | COCO mAP 37.3,足够火灾检测 |
| 生态 | ONNX导出方便,跨平台推理 |
| 速度 | CPU上~500ms/帧,满足10秒检测周期 |
4.2 数据集:D-Fire
使用D-Fire公开数据集训练。选择它而非其他数据集的原因:
| 数据集 | 类别 | 特点 |
|---|---|---|
| D-Fire | fire + smoke | 只有2类,无干扰类别 |
| NEWFire2 | fire + smoke + other | other类干扰严重 |
| Roboflow通用 | 多种 | 场景不够聚焦 |
第一版用的 NEWFire2 有 "other" 类,模型把所有前景都标为 smoke,fire 类完全学不到。换 D-Fire 后问题解决。
D-Fire 包含约 21,000 张图像:
| 类别 | 标注框数 |
|---|---|
| fire | 14,692 |
| smoke | 11,865 |
4.3 训练过程
# 训练平台:AutoDL RTX 4090 # 训练时长:约2.5小时 from ultralytics import YOLO model = YOLO('yolov8n.pt') model.train( data='data.yaml', epochs=100, imgsz=640, batch=16, device=0 )验证结果:
fire: mAP50 = 66% smoke: mAP50 = 83.7%
4.4 ONNX导出与部署
model.export(format='onnx', imgsz=640)
导出后部署到腾讯云,使用 ONNX Runtime CPU推理:
session = ort.InferenceSession('fire_model.onnx') outputs = session.run(None, {input_name: preprocess(img)})Flask服务 + systemd托管,故障自动重启。
五、解决了哪些问题
5.1 模型误报(最头疼的问题)
现象:什么都没发生,AI却检测到smoke conf=0.53,加了30分。
分析:摄像头画面左侧有个固定物体被模型误认成烟雾,20分钟内误报了7次。
解决:
置信度阈值从0.15提高到0.30,过滤低置信度误报
AI未检出时立即清零,不留60秒残留
滑动窗口5帧中2帧通过才触发,单帧误报不影响
改之前:conf=0.18 → AI加30分 → 可能误报 改之后:conf=0.18 < 0.30 → 忽略 conf=0.35 > 0.30 → AI加30分 → 但需要第二帧确认
5.2 温度噪声
现象:DHT11精度±1°C,27→28°C的正常波动被算成"温度上升6.7°C/分钟",加了20分。
解决:最低变化量≥2°C才算,排除DHT11噪声。
5.3 风扇跟评分打架
现象:ALERT状态强制开风扇,紧接着温度控制检测到<30°C又关掉,1秒内跳3次。
解决:ALERT和COOLDOWN状态下不执行温度关风扇逻辑,风扇保持运行。
5.4 评分算完了没人用
现象:融合评分算了一堆分数,但烟雾传感器该告警还是直接告警,评分是个玩具。
解决:评分直接决定是否进入ALERT状态,不再让传感器直接触发告警。
5.5 板子时间不对
现象:板子用的是UTC时间,深夜权重判定不准,PIR半夜不加分。
解决:设置时区为Asia/Shanghai,写入/etc/profile永久生效。
六、哪些做得还不够(坦诚说)
说完了做到的,也该说说没做到的:
| 问题 | 原因 | 如果能重来 |
|---|---|---|
| 对小火焰识别不稳定 | D-Fire数据集大火场景多,小火苗样本少 | 采集仓库场景数据微调 |
| AI推理在云端 | i.MX6ULL没有NPU | 换RK3588等带NPU的板子 |
| 温湿度精度差 | DHT11 ±1°C | 换成SHT30 |
| 单摄像头 | 只能管一个角度 | 支持多路RTSP |
| 光敏/湿度通道不完善 | 改动量大,优先级低 | 加基线学习 |
| 无数据闭环 | 误报/漏报无法反馈 | Web加反馈按钮 |
这些不是没想过,是做不完。一个人做项目总得有取舍,我把优先级给了最核心的检测链路。
七、项目结构(更新后)
lesson5/rpc_server/ RPC服务 + HTTP管理 + 摄像头驱动 lesson6/ MQTT桥接 + AI检测 + 融合评分 ├── mqtt_bridge.cpp 主程序(~1900行,4线程) ├── config.c/h 配置管理 ├── rpc_client.cpp RPC通信 └── *.c 看门狗、日志、OTA等 cloud/ 云端服务 ├── mqtt_to_influxdb.py MQTT→InfluxDB + 钉钉 └── fire_server.py AI推理服务 ← 新增 config.json 配置文件(阈值、权重等)
八、一点感想
这个项目从5月开始,到今天刚好两个月。
第一个月搭了IoT五层架构——从HAL到RPC到MQTT到云端Grafana。那时候觉得"传感器采集+上云"已经是个完整的项目了。
第二个月加了AI——训练模型、搭推理服务、写融合评分、调参、降误报。才发现前面说"完整"说早了。
最大的收获不是技术,是学会取舍。两个月里想加的东西很多:多摄像头、本地NPU推理、数据闭环。但一个人做项目,时间和精力就那么多,必须选最核心的先做。
代码全部开源,GitHub 13,000+ 行 C/C++,ARM开发板上跑通。
如果对你有帮助,GitHub 点个 Star ⭐
项目地址:https://github.com/wuqiZhu/IoTDualCtrl
九、工程实现深度问答
1. 怎么解决火焰传感器误告警的问题?
答:单一火焰传感器容易受强光、打火机短暂火光干扰,我采用了多维度加权判定策略:火焰传感器信号占40分、温度上升速率占20分、图像火焰识别占30分、环境湿度负向加权。总分≥60分才触发正式告警,同时加入时间衰减机制:每5秒分数衰减5%,60秒无新触发信号直接清零。夜间环境光线稳定时,传感器权重上调;白天强光环境下,视觉识别权重提升,从根源降低误报率。
2. 网络断开后,告警数据会不会丢失?
答:不会丢失。本地实现了环形缓冲区缓存机制,最多可存储100条告警数据,断网期间所有传感器数据、告警日志都写入缓存;网络恢复后自动按时间顺序补传,保证数据完整性。图片上传做了双通道降级:优先HTTP直传,失败则自动转为MQTT Base64分片传输,30秒超时仍失败则保留本地旧图兜底,下次网络恢复重传。
3. 开发中遇到过最棘手的bug是什么?
答:继电器频繁异常跳变。最初逻辑是烟雾触发开风扇、温度达标关风扇,两个条件独立运行,导致1秒内继电器反复吸合3次。排查两天定位到根源:风扇关闭计时变量初始值为0,判断条件`当前时间 >= 关闭时间`永远成立。最终修复了三层保护:烟雾告警期间屏蔽温度控制逻辑、温度未降到安全值不关闭风扇、定时器到期强制重置标志位,彻底解决了继电器抖动问题。
4. V4L2采集图像有没有遇到问题?
答:遇到过首帧黑屏、帧延迟两个主要问题。首帧黑屏是因为摄像头启动需要曝光时间,解决方案是丢弃前3帧数据,从第4帧开始正式采集;帧延迟通过内存映射(mmap)方式采集、双缓冲队列轮换处理,保证告警抓拍的实时性,从触发到图片上传完成控制在2秒以内。
作者:朱相波 | 长春大学旅游学院 物联网工程 大三求职方向:嵌入式软件 / Linux 应用开发