ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于Nordic BLE SoC的洗手液监测器:低功耗智能卫生方案

基于Nordic BLE SoC的洗手液监测器:低功耗智能卫生方案 洗手液监测器基于 Nordic BLE SoC 的智能卫生方案实操记录疫情期间大家应该都见过这类场景医院走廊、商场入口、学校食堂门口摆放着一瓶瓶洗手液但到底有多少人真的用了用了多久有没有按时补充这些问题靠人眼盯是不现实的。我最近做了一个基于 Nordic Semiconductor BLE SoC 的洗手液监测器专门回答这三个问题而且整个设备用的是纽扣电池一颗可以跑一年以上。这篇文章把整个项目的思路、硬件选型、固件开发、数据链路和踩坑记录都梳理一遍给打算做类似 BLE 低功耗传感节点的朋友一个可复用的参考。这个项目本质上是一个 BLE 信标 接近感应的组合体通过红外反射传感器检测人手伸向洗手液瓶的动作利用 Nordic 的 BLE SoC 把事件广播出去再由网关汇总数据上传云端。它的核心价值不是“检测有没有洗手液”而是“统计洗手行为发生的频率和时刻”这就引出了一串技术点低功耗状态机怎么设计、广播包怎么编码、数据在网关侧怎么去重、电池续航怎么压进“年”这个量级。如果你正打算做智能楼宇、智慧医疗、资产管理类的 BLE 节点这篇文章会很有参考价值。它不涉及复杂的云端平台所有代码逻辑都围绕“传感器采集 BLE 上报 低功耗”硬件成本控制在 30 元左右适合小批量原型验证也适合直接升级成量产方案。1. 先搞清楚核心问题监测器到底该做什么1.1 手卫生依从性这个老大难问题医疗领域有个很出名的统计医院内感染HAI的发生率大约在 5% 到 10%而正确的手卫生行为能显著降低这个比例。但“正确洗手”做不到实时监督护士站可以盯着走廊里的洗手液机没人盯。早年的方案是人工巡查每天记录洗手液消耗量这个办法数据滞后、精度低、还费人力。所以这类监测器的核心需求其实是两个维度行为事件维度有人在某个时间点按压或靠近了洗手液机这是一个离散事件。设备状态维度洗手液是否快用完了是否需要补充。这两个维度决定了硬件必须要有感知能力和通信能力。感知靠传感器通信靠无线。在 WiFi、Zigbee、BLE 这几个选项里BLE 因为功耗低、手机直接能扫到、网关成本低成了最合理的选择。1.2 为什么选 Nordic 的 BLE SoC而不是 ESP32 或 nRF24L01MCU项目初期我对比过三套方案这个环节值得展开说说因为很多人会纠结“用 ESP32 不也能做吗”。确实能但要看场景。ESP32 性能强、WiFi/BLE 双模、开发简单可它的功耗在物联网场景里就是个灾难深度睡眠还要 10 微安以上WiFi 连接时峰值电流能到几百毫安。对于一节纽扣电池供电、要跑一年的设备这个功耗完全不可接受。第二套方案是 STM32 nRF24L01 这种经典的 2.4G 射频组合。它的问题在于协议栈是私有的手机没法直接连接需要额外配一个专用网关而且整体物料成本并不低还要自己处理协议封装。最终选了 Nordic 的单芯片方案nRF52 系列把 Cortex-M4F 内核、BLE 协议栈、射频前端集成在一颗芯片里。J-Link 直接调试协议栈由 Nordic 官方维护开发时不用关心链路层的时序专注业务逻辑就好。开发板加芯片的成本在量产级别可以做到 20 元以内几乎不可能找到更低功耗的成熟方案。1.3 单节点到系统端到端的链路设计整个系统分为三层感知层若干个洗手液监测节点每个节点是一个 nRF52 设备跑 BLE 广播模式。汇聚层一个 BLE 网关我用的是 nRF52840 dongle 配合树莓派也可以用手机扫描周围节点的广播包解析后通过 WiFi/4G 上传。应用层云端接收数据做清洗、统计和可视化。这里的关键设计决策是节点不进连接、不配对只做单向广播。这样节点的功耗可以被压到极低同时省去连接管理的复杂度。代价是广播是单向的没法远程改配置但对于这种一次部署不再改参的设备来说完全够用。真需要升级固件时可以用 Nordic 的 DFU 机制通过网关下发改固件但那是另一套工程后面单独说。2. 硬件设计要点传感器、SoC 与供电方案2.1 传感器选型对射式还是反射式检测人手伸向洗手液瓶的动作可选方案有这几种方案原理优点缺点红外反射传感器发射红外光物体反射后由接收管检测成本低、功耗可控距离近10cm以内、易受环境光干扰对射式红外发射管和接收管分两侧物体经过时遮挡光路检测距离远、判定准确需要安装支架结构复杂超声波测距通过飞行时间算距离变化距离远、不受颜色影响体积大、功耗高、成本高于红外电容感应感应人手接近引起的电容变化无需开孔、美观对安装环境敏感标定麻烦在洗手液机这个场景里人手距瓶身喷嘴一般在 5cm 以内而且我们只需要检测“有没有手而不是测量精确距离”所以红外反射式传感器是性价比最高的选择。硬件上用一颗 IR LED 一颗光电二极管或者直接买集成的反射式传感器模块比如 RPR-0521RS 这类自带环境光补偿的 I2C 传感器代码写起来更省心还能顺带利用它的 ALS环境光通道来做光照补偿。2.2 主芯片选型nRF52810 还是 nRF52832Nordic 的 nRF52 系列里最常用的是 nRF52810、nRF52832 和 nRF52840。它们之间的差别主要在 Flash/RAM 大小、IO 数量、是否支持 NFC/长距离。我这个项目用的是 nRF52832实际上如果你只需要一个简单的传感器节点nRF52810 就行它价格更低功耗特性和 52832 基本一致。选 52832 的原因是我想在初期调测试代码时留有足够空间而且 52832 支持 S132 协议栈全功能 BLE 外设后续如果想把节点改成可连接的温湿度计或者血糖仪这类双向设备引脚和外设资源不用重新设计。不过这里有个坑需要提醒nRF52810 不支持 S132只能用 S112它只支持外设模式且连接数少。如果你的产品规划里明确只要广播和单连接那 52810 没问题但想留扩展余地建议直接从 52832 起步开发调试少受平台限制。2.3 供电设计一节 CR2032 跑一年的关键参数整个设备只有两种供电方案可选锂电池升压 DCDC或者一次性纽扣电池。从成本、体积、可靠性角度看CR2032 最合适3V 电压直接喂给 nRF52 的 VDD不需要额外的 LDO。这样电路极简也少一个静态功耗源。要估算续航先列出各状态的电流消耗深度睡眠System OFF 模式nRF52832 典型 0.3 µA连电池自放电都比它大。传感器检测周期每 1 秒唤醒一次读取 ADC/GPIO每次耗时约 2ms电流约 5 mA等效平均电流约 10 µA。BLE 广播每 500ms 广播一次每次约 3 个广播包广播时峰值电流约 5.5 mA单次广播占用 2.25ms等效平均电流约 25 µA。如果每 5 秒检测一次手部事件每次事件触发后广播 10 个包那么平均电流可以做到 50 µA 以下。一颗 CR2032 的额定容量大约 220 mAh可用容量按 70% 算实际容量受自放电和脉冲放电影响降额必须考虑折合可用容量 150 mAh也就是 150 mAh / 0.05 mA 3000 小时约 125 天。等等这个算出来才 4 个月问题出在广播间隔和唤醒检测频率上。实际项目的优化方案是平时每 2 秒唤醒采集一次传感器数据广播间隔放到 1 秒。另外触发事件后不是连续广播 10 包而是发完 3 包立刻回到睡眠。这样平均电流可以控制在 25 µA 左右续航大约 250 天接近一年。如果你能接受事件上报延迟 2 秒把广播间隔进一步拉长到 2 秒平均电流可以压到 15 µA 以下续航超过 400 天。这里要强调一个理解上的误区BLE 广播的功耗并不由发射功率主导而是由“唤醒次数 × 单次唤醒时长”主导。一个广播包大概只有 300 µs 的射频开启时间但协议栈要预热、要准备数据整个流程大约 2 到 4 ms。所以算法上尽量减少唤醒次数比调低发射功率更有效。2.4 硬件布局的几个实际问题硬件上走过的弯路不少挑三个最有价值的说一说。第一红外发射管和接收管之间的光学隔离。因为发射管功率较大如果两者正面相对安装接收端会被发射端直射的红外光直接打饱和极端情况下会造成持续误触发。解决办法是在安装结构里加一个不透明的隔板物理隔离发射和接收光路。第二传感器朝向。洗手液瓶大多是圆柱或者方瓶传感器要安装在瓶身侧面的支架上朝向人手伸过来的方向。如果朝上装会检测到天花板或灯光反射造成误触发如果朝下装又会检测到台面。需要在现场做一次“空场景测试”记录 5 分钟的原始 ADC 值波动范围作为判定阈值的设计依据。第三蓝牙天线的净空区。很多新手画的 PCB 上天线底下走了地线或者铺了铜导致辐射效率大幅下降。nRF52 参考设计里天线下方的 PCB 需要净空这个区域不能有走线和铜皮。近场调试可能看不出问题但到了现场隔着 5 米就收不到广播包了。3. 固件开发广播、传感器读取与低功耗状态机3.1 广播包设计与编码节点采用非连接广播Non-connectable Advertising这样手机和网关都能收到数据同时不允许任何设备连接避免了多设备连接占满连接槽位的问题。广播包的内容设计如下字段长度内容说明Flags1 字节0x06LE General Discoverable BR/EDR Not SupportedManufacturer Specific Data6-8 字节厂商 ID 设备类型 电池电压 事件计数Local Name可变“HWSAN-{设备ID}”方便开发时识别设备其中事件计数是关键字段。网关需要用它来做去重判断。如果一个节点在一次洗手动作中广播了 3 个相同包网关收到 3 次但事件计数没变就只上报一次。计数到 255 回绕网关侧需要容忍这种回绕。广播间隔的选择直接影响功耗和上报实时性。事件触发时我会临时切换到 100ms 高速广播持续 1 秒这样网关能在 1 秒内收到至少 5 个包。空闲时广播间隔是 1 秒只广播电池电压和设备状态方便维护巡检。这里用到一个 nRF52 的特性可以动态修改广播参数不需要重新初始化协议栈。3.2 红外传感器的读取与判定算法传感器读取的核心是避免误判。原始 ADC 值在无人状态下也不是完全稳定的环境光变化、洗手液瓶的材质反光、空调出风口的气流扰动都会造成波动。我采用的判定逻辑是每 2 秒读取一次传感器 ADC 值记为raw。每次读完后与上次值做差得到delta。如果delta大于设定的阈值比如基线值的 30%则判定为“检测到事件”进入事件确认状态。连续 3 次检测都超过阈值才真正触发事件并进入广播状态。这种“连续确认”机制可以过滤掉单次随机波动造成的误触发。但要注意连续确认的代价是事件检测延迟增加了最多 4 秒。如果你要求更快的响应比如检测到人手后马上播放提示音就得缩短确认次数或者加长检测间隔。另外一个细节红外传感器的使用时间长了发射管的光强会衰减接收管的灵敏度也会下降。设计时应在固件里留一个电容电压校准参数的存储位置每次更换电池时通过 BLE 广播电池电压网关侧如果看到电压异常低可以提醒维护人员更换电池顺便校准传感器阈值。3.3 低功耗状态机从“永远在跑”改成“该睡就睡”整个固件的核心是一个只有四个状态的状态机INIT上电初始化配置 GPIO、传感器、协议栈。MEASURE唤醒采集传感器 ADC 值判断是否有人手接近。EVENT确认触发事件发送广播包。SLEEP进入 System ON 睡眠模式等待 RTC 唤醒。状态之间的切换完全由定时器和 ADC 比较结果驱动。System ON 睡眠模式下内核停止运行外设中的 RTC 和 GPIO 唤醒功能仍然工作电流在微安级别。实现上要注意的坑nRF52 的 UART、SPI、TWI 等外设在进入睡眠前必须全部 deinit否则它们会持续耗电。另外定时器的分辨率要选够。我用的是 RTC132.768 kHz 晶振精度比内部 RC 振荡器好而且 RTC 的定时时间不受芯片温度影响这直接避免了“冬天走得快、夏天走得慢”这种问题。3.4 DFU 升级能力没它你会哭虽然节点是纯广播模式没有连接但总会有“改一下阈值”“修一个 bug”的需求。之前我吃过亏一批设备部署到现场后发现问题只能全部拆回来升级又费时间又尴尬。后来给节点加了 DFU 支持。nRF52 的 DFU 流程是设备先以 DFU 模式广播网关或者手机连接后把新的固件包通过 BLE 发给设备设备写进内部 Flash然后跳转重启。但广播模式的节点要进入 DFU 模式得有一个触发机制。我的做法是在传感器检测到连续 5 次异常比如 ADC 值持续超上限判断为“维护人员故意触发了特殊的维护动作”然后节点进入 DFU 广播模式持续一分钟等待连接。虽然这个机制不太优雅但在不拆壳的情况下已经是最实用的方案了。4. 网关、云端与前端可视化4.1 网关选型能收到广播就行但别太乐观节点的数据通过 BLE 广播出来就必须有设备在听。网关的硬件选型有几个层次手机适合开发和演示装个 Nordic nRF Connect 或者自己写个 Android App扫描广播包把数据转发到云端。树莓派 BLE USB Dongle适合小规模部署便宜灵活可以用 Python 或 Node.js 写扫描脚本。专用 BLE 网关适合大规模部署比如 Nordic 的 nRF52840 Dongle 配合 Zephyr 做多协议处理或者市面上成熟的 LoRa/BLE 网关产品支持以太网/PoE 供电部署方便。我的测试环境用树莓派 4B nRF52840 Dongle。树莓派通过 USB 连接 dongle运行一个 bluez 编写扫描程序抓取广播包后解析出厂商数据字段再通过 MQTT 发给本地 Broker。实际测试中发现一个问题BLE 广播的信道只有 37/38/39 三个当环境里蓝牙设备很多时广播冲突概率很高网关收到丢包率可能达到 30%。解决办法是在发送端做冗余每个事件连发 3 个广播包时间上稍微错开这样即使某两个包冲突剩下的也能被网关收到。这个简单策略能把实际丢包率降到 5% 以下。4.2 数据链路从原始广播包到结构化事件网关收到原始广播包需要做这几件事检查广播包类型过滤非目标设备通过厂商 ID 和本地名称前缀。解析出设备 ID、事件计数、电池电压、传感器状态字段。用“设备 ID 事件计数”作为去重键避免同一事件重复上报。打上时间戳网关本地时间建议做 NTP 同步推送到 MQTT。MQTT 主题按层级设计比如hw_sanitizer/{device_id}/event和hw_sanitizer/{device_id}/telemetry。事件主题里放一次洗手动作的触发时间和计数值遥测主题里放周期性的电池电压、设备状态。这样下游的数据消费者比如一个 Node-RED 流程可以单独订阅事件流而不用接收所有遥测包。云端我用了简单的 MariaDB 做存储然后接 Grafana 做展示。Grafana 可以直接查数据库绘出每个洗手点位的日使用量曲线、每个点位的电池剩余趋势。这个链路最大的好处是每个环节都通用不会绑定某一家云厂商。4.3 可视化要看什么这决定了你数据的意义数据可视化不是做一堆花哨图表就完事。我在设计 dashboard 时确立了三个核心视图日使用量柱状图每个洗手液点位一天被触发的次数按小时聚合用于发现高峰低谷。设备健康度列表每个节点的电池电压、最近一次心跳时间、信号 RSSI 均值用于主动维护。依从率趋势图如果有多个点位比如手术室入口、走廊、护士站可以按“实际触发次数 / 理论期望次数”算依从率。这个比例比原始次数更能说明问题。后端的分析脚本用 Python 写定期从数据库拉数据计算阈值和趋势把异常设备自动标记出来。这部分不复杂但很实用。5. 我踩过的坑与调试心得5.1 传感器误触发的排查到底是谁在碰它项目上线后不到一周就有一个点位出现了异常高的使用量一天触发了两千多次。排查过程让我印象很深。先看原始数据报事件计数的增长速度和触发时刻完全不像是人手操作几乎是均匀分布。这就排除了人手的行为特征。然后看传感器 ADC 值发现空闲状态下的基线在早晨和傍晚有大幅波动。那两天恰好是阴天转晴环境光变化剧烈红外传感器受到阳光中红外成分的干扰误触发了。解决方法是利用传感器内置的环境光通道当环境光强度超过某个阈值时动态抬高判定阈值。同时增加一个低通滤波对 ADC 值做滑动平均减小瞬时噪声的影响。调完后的效果非常明显一天的误触发次数从两千降到了个位数。这里得到的教训是做检测类产品尤其是户外或者窗口位置考虑环境光变化是一个必修课不能只在实验室里测。5.2 电池续航与功耗实测和理论差的不是一星半点理论算过能跑一年但实测续航只到了 7 个月左右差了快一半。用 Nordic 的在线功耗分析工具 PPK2 抓电流曲线后发现两个问题。第一个问题是 TWII2C总线在每次读取后没有完全释放。传感器模块是 I2C 接口的每次读完寄存器如果 SDA 线保持在高电平外设不会完全关断会导致大约 5 µA 的额外电流。解决办法是在读取完最后一位后发送一个 STOP 条件并拉低 SDA等待一个短暂延时然后切换到 GPIO 输入模式并上拉彻底释放总线。第二个问题是广播包数量比预想的多。我在事件触发后设置了“连发 10 包”但没考虑到协议栈在后台还会自动补发一些 ACK 包或者重试包。后来优化策略把广播间隔改成一包一发模式事件确认后发 3 包就停。改完之后实测电流曲线干净了很多。实际功耗测试中我建议每个使用 nRF52 系列的朋友都搞一个 PPK2 或者至少用万用表串联测平均电流。否则你根本不知道系统里到底哪里在漏电。5.3 信号覆盖问题的处理一个网关到底能管多少点位在一个 200 平米的开放空间里一个网关能覆盖 20 个左右的洗手液节点但问题不在于覆盖半径而在于并发冲突。多个节点同时广播时由于广播信道只有 3 个信道拥塞导致丢包率上升。特别是早晚高峰食堂门口有 6 个节点同时触发网关收到的事件往往不足 60%。缓解方案有两条路一是从发送端降低广播时长每个事件从发 3 包减到发 2 包发包间隔从 100ms 改成 80ms减少在信道上的占用时间二是从网关端增加扫描窗口在 Linux 上用 Wireshark 抓包分析确认冲突发生在哪些信道然后调整发射功率尽量减小节点间的相互干扰。实际效果最好的方式还是将洗手液点位分组每组错开广播时刻。比如 A 组奇数秒广播B 组偶数秒广播通过固件里设置一个 500ms 相位偏移来实现。这个优化没有增加任何硬件成本但显著提升了并发场景下的接收成功概率。5.4 洗手液对 PCB 的腐蚀问题别小看那一层水雾最后说一个不太起眼但容易踩的坑。洗手液机的周围尤其是出液口附近湿度长期偏高而且洗手液泡沫可能会溅到 PCB 表面。如果 PCB 不做三防漆处理一段时间后可能出现短路或腐蚀。第一次打样没有做三防结果一个月后一张板子就出问题了。拆下后发现传感器引脚之间有明显白色残留物。解决办法很简单PCB 出厂时加一道三防漆工艺成本几乎可以忽略但稳定性和寿命显著提升。如果条件不允许用三防漆也要在结构设计时让 PCB 垂直安装避免水平朝上减少液体在板面积聚。传感器的窗口要用密封垫圈和机壳贴合防止水汽从缝隙渗入。6. 项目复盘与可复用的经验动手做这个项目之前我其实对 BLE 广播的具体功耗数字并没有太准确的把握很多数据是边做边测出来的。但做完之后整个链路里哪些地方是重点、哪些地方可以放手思路就很清晰了。传感器方案的选择要跟着“检测什么”走不要求功能多只求稳定。Nordic 的 BLE SoC 在低功耗和开发效率之间取得了很好的平衡官方提供的 SDK 和协议栈文档质量很高只要你按参考设计画板基本没有射频翻车的问题。广播模式的节点虽然没有握手环节但正因为无连接部署和维护极其简单。这适合大量一次性部署的传感器场景。功耗设计要贯穿软硬件始终任何一个角落的漏电都会侵蚀你的电池寿命。如果后续要做类似的 BLE 传感节点我的建议是先定功耗预算再做功能。先画一个电流分配表把每个模块的静态电流、唤醒电流和唤醒时间列出来乘上使用频率算出总平均电流再决定电池容量和传感器方案。这个习惯能避免很多后期返工。洗手液监测器只是一个很小的应用。同样的硬件架构换个传感器就能做门磁、占用检测、资产追踪、冷链监测核心逻辑都是“超低功耗 BLE 广播 网关汇聚 云端分析”。这个架构的通用性在我实测中验证得相当扎实以后有新项目也打算继续沿用。
返回列表