site logo

Marico's space

LLM 没有鼻子,所以我们造了一个:Arduino UNO Q 上的 AI 嗅觉

Others 2026-10-21 11:28:59 9

前阵子折腾了一个有点离谱的项目:给大模型(LLM,即大型语言模型)装个鼻子。AI 能读、能写、能看、能听,但偏偏没有嗅觉——你问它冰箱里的牛奶是不是坏了,它只能老实说"闻不出来"。这不科学,毕竟我们每天靠鼻子来判断食物能不能吃。于是我们干脆自己造了一个。

LLMs have no nose. What if we built one?

▶ 演示视频 (3:11): youtu.be/n88pRiuib3U
▶ 代码 (MIT): github.com/PGASlab/app
▶ 没有硬件也能体验: live UNO Q simulation

做了什么

LLM 没有鼻子

AI 可以读、可以写、可以看、可以听。但你问它冰箱里那盒牛奶是不是坏了,它的诚实回答只能是"闻不出来"。嗅觉是我们每天用来判断食物能不能吃的那一感,AI 偏偏没有。

所以我们自己造了一个。

每个传感器都是一个小鼻子

Every sensor is a small nose: MQ-135, MQ-3 and MQ-2

鼻子的工作原理是不同受体对不同分子做出响应。PGAS 借鉴这个思路,用三个廉价的金属氧化物气体传感器来实现,每个针对不同类别的变质气体:

  • MQ-135 闻氨气和硫化物,也就是变质食物的"臭鸡蛋"味道
  • MQ-3 闻乙醇,这是细菌和酵母分解食物时产生的
  • MQ-2 闻范围更广的挥发性有机化合物

单独来看,它们就是随周围空气变化阻值的电阻。

组合起来就是一个大鼻子

Together, they make one big nose

接到 Arduino UNO Q 上,三个小鼻子合成为一个。UNO Q 的微控制器每秒采样所有三个传感器,Linux 那侧把读数与洁净空气对比,判断食物是否还能吃,然后行动:板载 LED 矩阵闪烁警告、发出警报、手机显示结论。不上云、不注册账号、不需要互联网,全部在用充电宝供电的板子上完成。

古人用银勺试毒,因为银碰到变质食物产生的硫化物会变黑。PGAS 就是现代版的银勺。我们为夜市摊位和小餐饮店设计的,在这些地方,卖变质食物是健康风险,而扔掉还能吃的食物是浪费。

副业场景。 国内夜市的很多摊位都是副业:白天上班、早上进货、晚上卖到深夜。没有食品检测实验室,只靠鼻子猜今天的牛奶还能不能用、昨天的剩菜还能不能吃。一批货出问题,小摊贩可能就丢了回头客。PGAS 是可以揣进口袋的第二个意见,用跟手机同一个充电宝供电。

演示

这里是一次真实的测试,用一盒变质牛奶,按步骤拍照记录。

1. 零件

All parts: Arduino UNO Q, breadboard, wires, power bank and three gas sensors

PGAS 需要的所有东西:

  • Arduino UNO Q(右下角):一个 STM32U585 微控制器加一个高通 QRB2210 运行 Debian Linux,集成 8×13 LED 矩阵
  • 三个气体传感器: MQ-135 检测氨气和硫化物,MQ-3(橙色那个)检测乙醇,MQ-2 检测多种挥发性化合物
  • 面包板 上每传感器一个 10 kΩ / 20 kΩ 分压电路,因为 UNO Q 的模拟引脚最高接受 3.3 V,而传感器输出最高 5 V
  • USB-C 充电宝。 没有连接笔记本电脑
  • 手机 连接同一个 Wi-Fi,网页由板子自己提供

2. 对照测试:附近无食物

Clean-air test:

先用无食物环境跑完整测试,确保 PGAS 不会误报。三个传感器的读数都保持在洁净空气基准(分别上升 +0.03 V、+0.02 V 和 +0.00 V),板子判定 新鲜 耗时 0.6 ms,LED 矩阵显示 ✓。

3. 可疑对象:一盒过期的牛奶

The spoiled milk bottle

Milk still inside the bottle

测试样本是一盒开封后放置变质的鲜奶。第二张照片证明里面确实还有奶。我们把它倒进小容器,方便逐个传感器对准测试。

4. 引导测试:逐个传感器进行

手机端点击 开始测试,页面会引导你一步步操作。每个传感器各 5 秒:1 秒在洁净空气中、1 秒移动到食物上方、3 秒测量。大圆倒计时和实时读数让你清楚知道进度。

Testing MQ-135 over the milk, countdown at 3

先测 MQ-135。 传感器放在牛奶上方,圆环倒计时。

MQ-135 and MQ-3 done, prompt to swap to MQ-2

然后 MQ-3。 传感器测完,页面提示你取出来准备下一个。这里 MQ-135 和 MQ-3 已打勾,轮到 MQ-2。

Pressing

按键确认 下一个传感器已在洁净空气中再按。PGAS 不会自己跳转,所以永远不会被催。

Testing MQ-2 over the milk, countdown at 2

最后 MQ-2。

5. 结论:不能吃、不能卖

Result:

PGAS 显示 食物已变质。MQ-3(乙醇)比自身洁净空气读数高出 +0.21 V,超过 0.20 V 阈值,所以板子判定牛奶为 不可销售,耗时仅 0.2 ms。MQ-135 上升 +0.02 V,MQ-2 上升 +0.05 V。乙醇是细菌和酵母发酵牛奶时产生的,所以 MQ-3 是我们预期反应最大的传感器。

弹窗用通俗语言写出结论:一个总判定加每个传感器的独立读数条。还会列出智能体的决策过程:

  • 感知: 3 个气体传感器,均高于洁净空气读数
  • 判断: UNO Q 离线判定为不可销售,耗时 0.2 ms
  • 行动: LED 矩阵报警(闪烁 ✕),警报已排队(Telegram 尚未配置)

6. 给好奇者:实时仪表盘

同一页面往下滚动,每个传感器都有速度表盘,显示当前电压、正常范围和实时图表。超过限值时,卡片变红闪烁。

MQ-3 in clean air: 0.37 V

MQ-3 在洁净空气中:0.37 V,在正常范围内。

MQ-3 over the spoiled milk: 0.70 V, card red

MQ-3 放在变质牛奶上方:0.70 V。 几乎翻倍,卡片变红。

MQ-3 30 seconds after leaving the milk: 0.38 V

移开 30 秒后:0.38 V,恢复到洁净空气值。传感器恢复很快,可以立即测试下一个食物。

MQ-3 洁净空气 变质牛奶上方 30 秒后
模块输出 0.37 V 0.70 V 0.38 V

代码

▶ github.com/PGASlab/app(MIT):Arduino sketch、Linux 应用、手机仪表盘、CI 自动测试,以及浏览器模拟的 UNO Q。

怎么做的

原理:感知 → 判断 → 行动

步骤 发生了什么 在哪运行
感知 MQ-135、MQ-3、MQ-2 以 1 Hz 采样,14 位 ADC,16 次平均 STM32U585 MCU(Arduino sketch)
判断 每个传感器与自身几秒前的洁净空气读数比较上升量。ONNX 模型将三个上升量转为变质概率,由安全规则兜底 QRB2210 Linux(Python,ONNX Runtime)
行动 LED 矩阵显示 ✓ 或闪烁 ✕,发送警报,手机显示结论 MCU + Linux

UNO Q 两部分通过 Arduino Bridge 通信:sketch 每秒调用 Bridge.notify("pgas_sample", …),Linux 用 Bridge.call("draw", …) 回传 LED 矩阵帧。手机页面通过官方 App Lab 的 arduino:web_ui 组件用 Socket.IO 提供服务,手机只需在同一个 Wi-Fi 或热点上。

每个传感器与自身几秒前的洁净空气读数比较,这才是 5 秒测试能工作的原因。MQ 传感器会随温度、湿度和预热漂移,绝对阈值不可靠,但几秒内的上升量是可靠的。

开源 AI:在板子上运行的模型

现在的判断来自一个小型机器学习模型,运行在 UNO Q 本地,不上云:

  • 模型: scikit-learn 的逻辑回归,导出为 ONNX,由板子 Linux 上的 ONNX Runtime 运行(pgas/bag_model.py)。模型文件仅 411 字节。
  • 输入: 三个上升量(MQ-135、MQ-3、MQ-2)。输出: 食物变质的概率。超过 80% 为不可销售,50%-80% 为正在变质。
  • 训练数据: 我们自己的真实测量:洁净空气对照(照片 2)、引导测试中的变质牛奶(照片 9)以及更早的一次变质牛奶测试。每个样本加上 ±0.01 V 的噪声(我们测量的传感器静止时的波动范围)。
  • 安全网: 三个样本是演示,不是经过验证的模型。所以板子也运行简单规则(最大上升量 ≥ 0.10 V 正在变质,≥ 0.20 V 不可销售),并取更严格的判定。食品安全工具绝不应该被只见过三个样本的模型说服撤销警告。

照片 2 和 9 的判定来自规则;我们之后用这些测试数据训练了模型,给出相同答案(洁净空气 7% 变质概率,牛奶 93%)。每增加一个新的带标签测试,模型就会更好:把上升量加到 SAMPLES 里,运行 python -m pgas.bag_model。仓库还有一个用 Qualcomm AI Hub 优化模型的脚本(pgas/aihub.py)。

硬件

器件 UNO Q 引脚 说明
MQ-135 A0 AO 通过 10 kΩ / 20 kΩ 分压(5 V → 引脚最大 3.33 V)
MQ-3(Waveshare) A1 同上分压
MQ-2 A2 同上分压
加热器 5 V 所有地线共接
电源 USB-C 5 V 充电宝供电,便携使用

在真实硬件上学到的

浏览器模拟把逻辑调对了,但真机上让我们学到更多:

  • Sketch 库。 Bridge 库需要在 sketch.yaml 中列出 MsgPack、DebugLog、ArxContainer 和 ArxTypeTraits。我们从板子上的 App Lab 示例复制了精确版本。
  • 我们用的 App Lab 版本没有 LLM 组件, 所以建议文本是规则生成的。
  • adb shell 设置了 Android 的 TMPDIR 在 UNO Q 上不存在,导致 arduino-app-cli 报错。我们的脚本会重置它。
  • 传感器读数比数据手册标称低。 我们的"传感器未插拔"检查误判了一个正常工作的 MQ-3,所以把下限调低到满量程的 0.25%。
  • 为复位做计划。 开发过程中板子偶尔重启,应用有时不能恢复。我们没完全定位原因(面包板接线松动是最大嫌疑),所以加了保活机制,一分钟内如果 PGAS 没运行就重启。
  • UX 对传感器项目也很重要。 第一次测试用罩子盖住食物花了 4 分钟。逐个传感器各 5 秒,手机引导,现在只需要约 15 秒加传感器切换时间。

为什么开放创新重要

街边小贩不可能依赖订阅服务、云 API 或手机信号。PGAS 用的全是开源的:Arduino App Lab 及其组件、Arduino sketch、Python、scikit-learn 和 ONNX Runtime 做板载推理,代码用 MIT 许可。任何人都可以按一个板子加三个传感器的成本复现、用自己的食物数据重新训练、换更好的模型,数据永远不会离开摊位。

奖项类别

最佳 Arduino 使用。

  • 它在板子上运行模型:ONNX 模型由板子上的 ONNX Runtime 在 UNO Q 离线判定
  • 它是一个能感知和行动的物理智能体:气体传感器输入,LED 矩阵报警和警报输出,判定在板子上毫秒内完成
  • 它用了 UNO Q 独特之处:MCU 和 Linux 通过 Bridge 协作、集成 LED 矩阵、App Lab 组件构建网页界面
  • 它用充电宝离线运行,可以在市场摊位使用

局限性

  • 一个变质样本加一个洁净空气对照是演示,不是准确性研究。模型见过三个真实样本,规则阈值是临时的,都需要更多食物类型来验证
  • MQ 传感器需要几分钟预热,且会随温度和湿度漂移
  • PGAS 是参考工具,不是食品安全认证。有疑问就别吃,去问专业人士

团队

  • k66
  • Alice
  • 29
  • Crystal
  • Cynthia
  • 用 Claude Code 做 AI 结对编程