资讯动态

基于Arduino UNO Q与边缘AI的智能空气质量监测系统实战

发布时间:2026/10/9 2:18:18 来源:尧图企业网站定制
1. 这个项目到底在解决什么问题空气质量这件事说大不大说小不小。你每天待的室内环境PM2.5、温湿度、二氧化碳浓度这些指标其实一直在悄悄影响你的注意力和身体状态。但市面上大多数家用空气检测仪的问题在于它们只给你一个数字不告诉你这个数字意味着什么更不会结合你当前的身体状况给出建议。Atmosis 这个项目的出发点就是补上这一环——用边缘端的传感器采集环境数据在本地跑轻量级 AI 模型做环境态势判断再通过云端大模型生成个性化的健康建议。整个系统的核心链路是这样的Arduino UNO Q 作为主控板负责传感器数据采集和本地推理Edge Impulse 用来训练和部署环境分类模型Arduino IDE 和 Arduino App Lab 负责固件开发和调试Google AI Studio 则承担健康建议的生成任务。这套组合的好处是环境判断在本地完成响应快、隐私好健康建议走云端语言表达自然、知识面广。适合谁来参考这篇内容如果你手上有 Arduino UNO Q 或者类似的开发板想做一个带 AI 能力的物联网项目这篇可以直接抄作业。如果你只是想了解边缘 AI 和环境监测怎么结合也能从架构设计和参数选择的部分拿到有用的思路。我默认你有基本的 Arduino 使用经验知道怎么烧录固件、怎么看串口输出但不需要你懂机器学习。2. 系统架构与核心选型逻辑2.1 为什么选 Arduino UNO Q 而不是普通 UNOArduino UNO Q 和经典 UNO 最大的区别在于它搭载了双核处理器——一个 Cortex-M33 负责实时控制一个 Cortex-A53 跑 Linux 系统。这个架构对 Atmosis 来说非常关键因为环境数据的采集需要硬实时响应而 AI 推理和网络通信需要操作系统支持。如果只用经典 UNO你连一个像样的神经网络都跑不起来更别说同时处理传感器和网络请求了。具体来说M33 核负责以固定频率读取传感器数据保证采样间隔稳定A53 核跑 Linux在上面部署 Edge Impulse 导出的推理引擎同时管理 Wi-Fi 连接和 HTTP 请求。两个核之间通过共享内存通信M33 把传感器数据写进去A53 读出来做推理。这种分工的好处是即使推理任务偶尔卡顿也不会影响传感器采样的时序精度。2.2 Edge Impulse 在项目中扮演什么角色Edge Impulse 是一个面向嵌入式设备的机器学习平台它的核心价值在于把模型训练和部署的流程标准化了。对于 Atmosis 来说我用它做了一件具体的事训练一个环境状态分类模型。输入是 PM2.5、温度、湿度、CO2 浓度四个维度的时序数据输出是四个类别——优良、轻度污染、中度污染、重度污染。为什么不用回归模型直接预测 AQI 数值因为回归模型对传感器噪声非常敏感而且边缘设备上的计算资源有限分类模型的计算量更小、鲁棒性更好。实测下来一个三层全连接网络参数量控制在 8KB 以内在 UNO Q 的 A53 核上单次推理耗时不到 15ms完全满足实时性要求。2.3 Google AI Studio 的接入方式健康建议的生成走的是 Google AI Studio 的 Gemini API。这里有一个设计决策需要解释为什么不在本地生成建议因为本地模型的语言生成能力有限而且健康建议涉及医学常识需要模型有足够的泛化能力。Gemini 在这方面的表现足够好而且 API 调用成本很低一次请求的 token 消耗在 200 以内。接入方式很简单A53 核上的 Python 脚本通过 HTTPS 把环境分类结果和原始传感器数据发给 Gemini APIprompt 里带上用户的健康档案比如是否有哮喘、过敏史Gemini 返回一段自然语言建议。整个往返延迟在 1.5 秒左右对于健康建议这种非实时场景完全可以接受。3. 硬件搭建与传感器选型3.1 传感器清单与参数对比Atmosis 用到了四类传感器选型的时候我对比了不少方案下面这张表是我最终确定的配置和选型理由传感器类型型号接口精度选型理由PM2.5PMS5003UART±10μg/m³激光散射原理数据稳定串口输出直接可用温湿度SHT31I2C±0.3°C / ±2%RH精度高响应快I2C 接线简单CO2SCD40I2C±50ppm光声原理免校准周期长适合长期部署气压BMP280I2C±0.12hPa辅助判断通风状态价格便宜PMS5003 用 UART 而不是 I2C 是因为它的数据包格式是固定的 32 字节串口读取最方便。SHT31 和 SCD40 共用 I2C 总线地址不冲突SHT31 是 0x44SCD40 是 0x62。BMP280 地址是 0x76也挂在同一条总线上。3.2 接线注意事项UNO Q 的引脚定义和经典 UNO 不完全一样接线前一定要看官方引脚图。我踩过的坑是UNO Q 的 3.3V 输出电流有限PMS5003 的峰值电流能到 100mA直接供电会导致电压跌落传感器数据异常。解决办法是给 PMS5003 单独供 5V用电平转换模块把它的 TX 降到 3.3V 再接到 UNO Q 的 RX。I2C 总线上拉电阻的问题也需要注意。UNO Q 内部已经有 4.7kΩ 的上拉电阻如果你外接的传感器模块上也带了上拉电阻并联之后阻值会降到 2.35kΩ 左右虽然大多数情况下还能工作但波形质量会下降。我的做法是把传感器模块上的上拉电阻焊掉只用 UNO Q 内部的。3.3 供电方案整个系统的功耗实测下来传感器部分大约 150mAUNO Q 本体在跑推理的时候大约 300mA峰值能到 500mA。如果用 USB 供电建议用 5V/2A 的适配器不要用电脑的 USB 口因为电脑 USB 口的电流限制通常是 500mA带不动。如果要长期部署可以考虑用 18650 电池加升压模块但要注意 PMS5003 的激光风扇对电压波动很敏感升压模块的输出纹波要控制在 50mV 以内。我试过用 MT3608 升压模块纹波太大后来换成了 TPS61088问题解决。4. 数据采集与本地推理实现4.1 传感器数据读取的代码结构M33 核上的固件用 Arduino IDE 开发核心逻辑是定时器中断触发数据采集。下面是我实际使用的代码框架#include Wire.h #include Adafruit_SHT31.h #include SparkFun_SCD4x_Arduino_Library.h Adafruit_SHT31 sht31 Adafruit_SHT31(); SCD4x scd40; struct SensorData { float pm25; float temperature; float humidity; float co2; float pressure; }; SensorData currentData; void setup() { Serial.begin(115200); Wire.begin(); sht31.begin(0x44); scd40.begin(); // 配置定时器每2秒触发一次采集 Timer.setInterval(2000, sampleSensors); } void sampleSensors() { currentData.temperature sht31.readTemperature(); currentData.humidity sht31.readHumidity(); if (scd40.readMeasurement()) { currentData.co2 scd40.getCO2(); } // PMS5003 数据通过串口读取 currentData.pm25 readPMS5003(); // 写入共享内存供 A53 核读取 writeToSharedMemory(currentData); }采样间隔选 2 秒是有讲究的。SCD40 的测量周期最快是 5 秒一次但它的数据手册里写了连续测量模式下内部会自动更新你读到的永远是最新值。PMS5003 的推荐采样间隔是 1 秒以上2 秒完全够用。SHT31 的转换时间只有 15ms不是瓶颈。4.2 Edge Impulse 模型训练流程模型训练在 Edge Impulse 的网页端完成流程分四步数据采集我用 UNO Q 连续采集了 72 小时的环境数据覆盖了白天、夜晚、开窗、关窗、做饭、打扫等不同场景。总共收集了大约 13 万条数据点按 8:2 划分训练集和测试集。特征工程原始数据是四维时序我加了一个滑动窗口窗口大小 30 个采样点即 60 秒步长 10 个采样点。每个窗口计算均值、方差、最大值、最小值四个统计量最终特征维度是 16 维。这样做的好处是降低了数据维度同时保留了时序变化信息。模型选择Edge Impulse 提供了几种预置架构我选了 1D 卷积神经网络因为它在时序数据上的表现比全连接网络好而且参数量可控。具体配置是两个卷积层卷积核大小 3通道数 16 和 32一个全局平均池化层一个全连接层64 个神经元输出层 4 个类别。量化与部署训练完成后用 Edge Impulse 的 EON Compiler 做 int8 量化模型大小从 45KB 压缩到 11KB推理速度提升约 2.3 倍。导出的 C 库直接集成到 A53 核的 Python 脚本里通过 ctypes 调用。4.3 本地推理的性能实测在 UNO Q 的 A53 核上我用 Python 的 time 模块测了 1000 次推理的耗时指标数值平均推理耗时12.3ms最大推理耗时18.7ms最小推理耗时9.8ms内存占用约 2.1MBCPU 占用单核约 15%这个性能完全满足需求。推理结果通过共享内存回传给 M33 核M33 核根据分类结果决定是否触发云端请求。如果连续 5 次推理都是优良就不发请求节省 API 调用次数。5. 云端健康建议生成与系统集成5.1 Gemini API 的调用细节A53 核上的 Python 脚本负责调用 Gemini API。我用的模型是 gemini-1.5-flash因为它的响应速度快、成本低对于健康建议这种场景足够用。调用代码如下import google.generativeai as genai genai.configure(api_keyYOUR_API_KEY) def get_health_advice(env_data, user_profile): prompt f 当前环境数据 - PM2.5: {env_data[pm25]} μg/m³ - 温度: {env_data[temperature]} °C - 湿度: {env_data[humidity]} % - CO2: {env_data[co2]} ppm - 环境等级: {env_data[level]} 用户健康档案 - 哮喘: {user_profile[asthma]} - 过敏史: {user_profile[allergy]} - 年龄: {user_profile[age]} 请用一句话给出当前环境下最需要注意的健康建议不超过50字。 model genai.GenerativeModel(gemini-1.5-flash) response model.generate_content(prompt) return response.textPrompt 的设计有几个要点第一把环境数据和用户档案都结构化传入避免模型瞎猜第二限制输出长度在 50 字以内因为最终要显示在 UNO Q 的小屏幕上第三明确要求最需要注意的建议避免模型给出泛泛而谈的内容。5.2 系统集成中的坑集成过程中遇到的最大问题是网络稳定性。UNO Q 的 Wi-Fi 模块在 Linux 下的驱动不太成熟偶尔会断连。我的解决办法是加了一个心跳检测机制每 30 秒 ping 一次网关如果连续 3 次失败就重启网络接口。这个逻辑用 Python 的 subprocess 调用系统命令实现虽然粗暴但有效。另一个坑是 API 调用的超时处理。Gemini API 偶尔会响应很慢如果不设超时整个系统会卡住。我在 requests 库上设了 5 秒超时超时后返回一个本地缓存的建议保证用户体验不中断。5.3 数据存储与历史查询环境数据需要存下来供后续分析。我在 A53 核上跑了一个轻量级的 SQLite 数据库每 10 秒写入一条记录。表结构很简单CREATE TABLE env_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, pm25 REAL, temperature REAL, humidity REAL, co2 REAL, level TEXT );查询的时候用 Flask 起一个简单的 Web 服务提供 /history 接口返回最近 24 小时的数据。前端用 Chart.js 画趋势图整个页面不到 200 行代码。6. 常见问题与排查实录6.1 Arduino IDE 启动卡在等待界面的问题这个问题我遇到过两次一次是在 Windows 上一次是在 Mac 上。Windows 上的原因是杀毒软件拦截了 Arduino IDE 的串口驱动加载解决办法是把 Arduino IDE 的安装目录加入白名单。Mac 上的原因更隐蔽是系统权限问题需要在安全性与隐私里给 Arduino IDE 授予输入监控权限。如果你用的是 ESP32 开发板还需要注意离线包的安装。Arduino IDE 2.x 版本的离线包管理器和 1.x 不一样需要在首选项里手动指定离线包的路径。我建议直接用开发板管理器在线安装虽然慢一点但省心。6.2 传感器数据跳变的问题PMS5003 的数据偶尔会出现跳变比如 PM2.5 从 15 突然跳到 200 又跳回来。这个问题的根源是激光散射原理对气流敏感如果传感器附近有风扇或者空调出风口读数就会不稳定。解决办法是给传感器加一个防风罩或者用滑动平均滤波。我用的是 5 点滑动平均效果不错延迟也在可接受范围内。SCD40 的 CO2 读数在刚上电的时候会偏高这是它的自动校准机制在起作用。数据手册里建议上电后等待 3 分钟再读取我实测下来 2 分钟左右就稳定了。如果你等不了可以在代码里加一个启动延时。6.3 Edge Impulse 模型部署失败的问题Edge Impulse 导出的 C 库在 UNO Q 上编译失败最常见的原因是编译器版本不匹配。UNO Q 的 Linux 系统里默认的 GCC 版本是 11.2而 Edge Impulse 的库是用 GCC 9 编译的。解决办法是在 Edge Impulse 的项目设置里把目标平台改成Linux (ARMv8)重新导出。另一个问题是内存对齐。Edge Impulse 的推理引擎要求输入数据的地址是 4 字节对齐的如果你用 Python 的 array 模块传数据默认是 1 字节对齐会导致推理结果错误。我的做法是用 numpy 的 zeros 数组它默认就是 4 字节对齐。6.4 常见问题速查表问题现象可能原因排查方法解决方案Arduino IDE 卡在启动界面杀毒软件拦截 / 权限不足查看系统日志加白名单 / 授予权限PM2.5 读数跳变气流干扰用手挡住传感器看是否稳定加防风罩 / 滑动平均CO2 读数偏高自动校准未完成等待 3 分钟后重新读取加启动延时模型推理结果错误内存对齐问题检查输入数据地址用 numpy 数组Wi-Fi 断连驱动不稳定ping 网关测试加心跳检测API 调用超时网络延迟抓包分析设超时 本地缓存7. 实操心得与扩展思路7.1 关于采样频率的取舍我一开始把采样间隔设成了 500ms想着数据越多越好。结果发现两个问题一是 SD 卡写入速度跟不上二是 Edge Impulse 的训练数据量太大训练一次要等半小时。后来改成 2 秒数据量降到原来的四分之一模型精度只下降了 0.3 个百分点完全划算。这里有一个经验公式采样频率应该至少是环境变化特征频率的 2 倍。室内环境的变化周期通常在分钟级别2 秒的采样间隔对应的 Nyquist 频率是 0.25Hz远远覆盖了实际需求。7.2 关于模型更新的策略Edge Impulse 的模型不是训练一次就完事了。季节变化、传感器老化都会导致数据分布漂移。我的做法是每三个月重新采集一批数据用增量学习的方式更新模型。Edge Impulse 支持在已有模型的基础上继续训练不需要从头开始。如果你不想频繁更新模型可以在推理层加一个置信度阈值。当模型对某个样本的置信度低于 0.6 时就把这个样本标记为不确定上传到云端做人工标注。积累到一定数量后再统一更新模型。7.3 这个项目还能怎么扩展Atmosis 目前的形态是一个桌面级的环境监测站但它的架构可以扩展到更多场景。比如把 PMS5003 换成甲醛传感器就变成了装修污染监测加上一个继电器控制新风系统就变成了闭环的空气质量管理。软件层面Gemini API 的 prompt 可以做得更精细。比如根据用户的作息时间调整建议的语气——早上给鼓励式的建议晚上给放松式的建议。这些都不需要改硬件只改 prompt 就行。最后分享一个小技巧UNO Q 的 A53 核上可以跑 Docker我把整个 Python 环境打包成了容器镜像换设备的时候直接拉镜像就行省去了配环境的麻烦。镜像大小控制在 200MB 以内启动时间不到 10 秒。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑