ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用UWB测距判断垃圾桶是否出门:从硬件到Home Assistant全流程

用UWB测距判断垃圾桶是否出门:从硬件到Home Assistant全流程 1. 垃圾桶是否拿出去这个需求比想象中难搞得多先说说我为什么要做 BinRange 这个项目。家里的垃圾桶平时放在车库内每周固定时间需要拿到院子门口的回收点。听起来很简单但问题在于智能家居系统需要知道垃圾桶到底是在屋里还是已经在门外。这个信息一旦缺失很多联动都做不了——比如晚上出门散步时顺手带垃圾系统得知道桶已经出去了不需要提醒如果桶在门外超过某个时间还没拿回来也应该给个提醒。最开始我试过各种旁门左道的方案在垃圾桶上贴加速度传感器来判断它是否被移动过结果发现挪车、扫地、甚至是猫碰一下都会触发用摄像头对着门口做识别又被傍晚逆光和夜间模式折磨得怀疑人生后来还试过简单的蓝牙信号强度定位稳定性差到完全没法用。最终让我下定决心换方案的是我发现 UWB超宽带无线电测距在短距离场景下的表现远超预期。UWB 通过测量无线电脉冲在两个设备之间的飞行时间来得到距离精度能做到厘米级而且不像蓝牙那样容易被多径反射干扰。关键是这套东西集成到 Home Assistant 里的路径并没有那么复杂。BinRange 这个名字就是 Bin垃圾桶 Range测距的合成词。如果你也在被判断某个物品是否离开了某个区域这类需求折磨这篇文章值得看完。我会把从硬件选型、数据接入、状态判定到踩坑排错的全过程都摊开讲最后还会给一个我正在用的完整配置和自动化示例。2. UWB 测距为什么适合做边界跨越判断而不是垃圾桶本身很多人一听UWB 判断垃圾桶是否拿出去下意识会想到给垃圾桶装 GPS 或者电子围栏。但实际用下来UWB 在这个场景里的核心优势不是定位而是测距。2.1 关键逻辑两个固定锚点之间的遮挡关系我的方案不是在追踪垃圾桶的位置而是在检测垃圾桶是否穿越了一个由两个 UWB 锚点定义的边界。具体做法是在屋内靠近大门的墙上放一个固定 UWB 基站Anchor A在屋外正对门口的屋檐下放另一个固定 UWB 基站Anchor B。垃圾桶上贴一个 UWB 标签Tag。系统持续测量标签到两个锚点的距离。当垃圾桶在屋里时标签到 A 的距离近、到 B 的距离远当垃圾桶被拿出门口这两组距离关系就会发生明确的翻转。这个设计规避了 UWB 在复杂环境下做高精度定位的所有麻烦。你不需要算出标签的具体坐标只需要判断距离关系的趋势变化。测距的可靠性远高于几米范围内做三角定位的可靠性尤其是在金属、墙体遮挡比较多的家居环境里。2.2 UWB 相比蓝牙 BLE 和 WiFi RSSI 的天然优势蓝牙和 WiFi 的测距本质上都是基于 RSSI接收信号强度反推距离。问题在于 RSSI 受环境影响太大一个从旁边走过的人、一扇被推开的金属门、甚至空气湿度变化都能让信号强度波动好几 dB换算成距离就是一两米的误差。用 RSSI 做垃圾桶是否在屋里这种需要在几米范围内明确判定的任务基本是不可靠的。UWB 测的是飞行时间ToF根据电磁波传播速度 F C × T 换算距离。它不依赖信号强度因此天然不受上述环境因素干扰。我实测在固定位置静止的垃圾桶UWB 测出来的距离值抖动通常在 ±5 cm 以内而同一场景蓝牙 RSSI 的等效距离抖动能达到 ±1 m。这个精度差异直接决定了能否用阈值法判状态。2.3 为什么不用 GPS 或电子围栏GPS 在室内根本没有信号垃圾桶在车库里的那段反而是关键期所以 GPS 直接出局。电子围栏更多依赖手机 App 和网络定位需要一个额外的随身设备不符合垃圾桶自己会说话的无感自动化初衷。UWB 标签是独立的功耗又可控是目前唯一一个能让我懒到不用做任何动作的技术方案。3. 硬件选型与组网从模块选型到供电方案先说结论再讲过程。我最终用的是 DWM3000 模块作为锚点和标签的核心通信协议走标准的 IEEE 802.15.4z UWB 帧通过串口连接到一个低功耗的 ESP32 控制器再把测距结果通过 WiFi 以 MQTT 协议上报给 Home Assistant。3.1 标签端贴在垃圾桶上电池供电是硬约束标签是贴在垃圾桶桶壁内侧的日晒雨淋都会经历最麻烦的是它必须用电池供电我不可能隔三差五给它换电池。标签端的核心功耗来自 UWB 测距时射频前端的脉冲收发。DWM3000 模块在测距模式下的峰值电流很高但每次测距只需要几毫秒关键是控制唤醒-测距-休眠的节奏。实测我的标签每隔 5 秒醒来测一次距两节 18650 电池并联供电理论上续航可以超过半年。需要注意的一点是频繁的测距会把电池电流需求拉得很高。在每次测距开始前我使用了一个大容量的钽电容作为瞬时储能缓冲避免直接从电池瞬间抽取大电流这能让电池的等效内阻影响降到最低电池寿命也更稳定。代码层面标签端用的是 Arduino 环境下基于 DWM3000 的 API。核心逻辑就是初始化天线参数进入低功耗模式定时器每 5 秒唤醒一次发起测距请求拿到距离值后通过串口交给 ESP32ESP32 组装成 JSON 消息发到 MQTT broker。// 标签端伪代码示意 #include dw3000.h void setup() { DW3000.begin(0x1000); // 初始化地址唯一标识 DW3000.setAntennaDelay(16450); // 天线校准具体值依模块而定 deepSleep(true); // 先睡下等定时唤醒 } void loop() { sleepUntil(5s); double distance; bool ok DW3000.ranging(0x2000 /* 锚点地址 */, distance); // 测距 if (ok) Serial.printf({\d\: %.2f}\n, distance); // 交给ESP32 deepSleep(true); }如果你不想自己搞硬件市面上也有现成的 UWB 标签和基站套件卖有些厂商甚至提供 MQTT 输出接口这样你可以跳过所有嵌入式开发部分直接进入 Home Assistant 集成。预算允许的话这是省时省心的最优解。3.2 锚点端一对双向测距的目标地址分配两个锚点一个部署在门内、一个在门外。每个锚点有一个全局唯一的短地址比如 0x1001 和 0x1002。标签向哪个地址发起测距请求得到的距离就是到哪个锚点的距离。所以一个完整的测距周期会产生两个距离值d_int到门内锚点和 d_ext到门外锚点。锚点那边不需要电池供电直接用 5V USB 电源。锚点本身只做透明转发收到标签的测距帧后回传确认帧同时把测到的飞行时间通过串口发给自己的控制器控制器再把数据发到 MQTT。3.3 室内外布线最容易翻车的地方室外锚点的防水非常重要。我一开始直接用小铁盒装裸板放在屋檐下结果一场雨就让它不稳定了。后来换成了带防水接头的工程塑料盒数据线和电源线都从盒底引入并用防水硅胶封口。凡是架在室外的电子设备不要抱有任何侥幸心理多花几十块的防水工程能省掉后面无数次的排查时间。另外两个锚点之间的直线距离不要拉得太长。UWB 虽然抗多径但越长的距离越容易受环境反射影响。我的门内门外锚点直线距离大约 5 m实测效果最好如果你家走廊很长可以考虑在中间增加一个中继锚点来缩短单跳距离。4. Home Assistant 集成链路从 MQTT 裸数据到垃圾桶已出门状态硬件上报只是第一步真正干活的部分是在 Home Assistant 里完成的。BinRange 的灵魂在于如何把两组连续的测距数据变成一个可靠的状态机。4.1 接入 MQTT 并生成基础传感器标签端每 5 秒上报一次MQTT topic 为binrange/tag1/distances消息内容大概是这样{id: tag1, anchor_a: 1.23, anchor_b: 4.78}在 Home Assistant 里我先用 MQTT 传感器把这几个值接进来mqtt: sensor: - name: BinRange 到门内锚点距离 unique_id: binrange_anchor_a state_topic: binrange/tag1/distances value_json: anchor_a unit_of_measurement: m device_class: distance availability_topic: binrange/tag1/status - name: BinRange 到门外锚点距离 unique_id: binrange_anchor_b state_topic: binrange/tag1/distances value_json: anchor_b unit_of_measurement: m device_class: distance这里有个细节MQTT 传感器的value_json字段会从 JSON 负载中提取对应键的值。如果标签端直接在 JSON 里把值算好HA 侧就省去了模板解析的开销。我建议将有效距离四舍五入到厘米避免小数点后面一堆尾巴徒增消息体积和存储压力。4.2 核心算法距离比值要比绝对距离可靠得多直接用 d_int 1.5 m 判断垃圾桶在屋里是不靠谱的。因为这个值会随垃圾桶在屋内的位置变化比如它靠墙一点还是靠门口一点d_int 的波动范围可能达到半米。我在 BinRange 里用的是距离比值法ratio d_int / (d_int d_ext)当垃圾桶在屋内时d_int 很小d_ext 很大ratio 会显著接近 0。当垃圾桶到了门外距离关系逆转ratio 会明显抬高。这个比值不受标签位置小范围挪动的影响也不需要去标定什么绝对位置坐标。用一个 template binary_sensor 把比值转换成最终的状态template: - binary_sensor: - name: 垃圾桶是否在门外 unique_id: binrange_trash_out state: {% set d_int states(sensor.binrange_anchor_a) | float %} {% set d_ext states(sensor.binrange_anchor_b) | float %} {% set ratio d_int / (d_int d_ext) %} {{ on if ratio 0.6 else off }} device_class: presence阈值 0.6 是我在实测中标定出来的。垃圾桶完全在屋里时ratio 大约在 0.15~0.25完全在门外时ratio 大约在 0.75~0.85。中间有非常宽的缓冲区这就是 UWB 精度带来的好处——你可以安心地设置阈值而不用整天跟误报做斗争。4.3 增加防抖与去毛刺逻辑就算 UWB 精度高也不能完全杜绝异常值。我遇到过的情况包括垃圾桶被猫撞动了一小段距离、人站在门外锚点旁边造成暂时的遮挡、极端天气导致个别报文丢包。所有这些都会让单个采样点的 ratio 瞬间跳动。解决办法是在 Home Assistant 里加一层状态防抖。不要直接用原始值而是用滑动窗口的中位数sensor: - platform: filter name: BinRange 门内距离滤波 entity_id: sensor.binrange_anchor_a filters: - filter: outlier window_size: 5 radius: 0.3 - filter: time_simple_moving_average window_size: 00:00:20outlier过滤器会在一个滑动窗口内剔除掉明显偏离中位数的异常点time_simple_moving_average再做一个 20 秒的简单移动平均把短时抖动彻底抹平。这样最终进入状态判定逻辑的数值就非常干净了。5. 自动化联动通知、记录与异常提醒状态传感器做出来只是第一步真正的价值在它触发的那些自动化。BinRange 给我的家庭自动化系统带来了好几个实打实的便利场景。5.1 出门提醒与忘记拿回来双保险最简单的自动化是当垃圾桶状态变化为门外时给手机推一条通知。这个通知刚好和傍晚扔垃圾的时间对上就能起到提醒你今天有垃圾要丢的作用。更有用的是一个反向提醒如果垃圾桶已经在门外连续待了超过 48 小时说明可能被遗忘了或者被收走之后没拿回来。用 Home Assistant 的duration写法可以这样automation: - alias: 垃圾桶在门外超48小时提醒 trigger: - platform: state entity_id: binary_sensor.binrange_trash_out to: on action: - wait_for_trigger: - trigger: time_pattern hours: /24 timeout: 48:00:00 - condition: state entity_id: binary_sensor.binrange_trash_out state: on - service: notify.mobile_app data: title: 垃圾桶还在外面 message: 桶已经在门口超过48小时了记得拿进来。5.2 和灯光/通知系统的联动我还做了一个垃圾桶在门外时打开门廊灯的自动化。夏季天黑得晚不明显但冬季傍晚扔垃圾的时候门外那个锚点附近如果没有灯光垃圾桶很容易放歪。现在只要状态变为 on门廊射灯就自动亮起持续 10 分钟后关闭。更进一步这个状态也可以作为垃圾桶已出门的输入与门锁联动。桶在门外是收运时间门外的安全等级会相对敏感一些此时人体传感器检测到门外有人活动时通知会附带更详细的情境信息。这些联动逻辑比较个人化但思路完全可以直接搬。5.3 历史趋势记录什么时候收垃圾、桶在外面待多久因为传感器数据是一路进 Home Assistant 的天然会写入历史数据库。我建了一个简单的history_stats传感器统计每周垃圾桶在门外累计时长用来反推收运车实际的到达时间范围。这个数据对计划什么时候把桶推出去最合适特别有帮助。sensor: - platform: history_stats name: 本周垃圾桶在外累计时长 entity_id: binary_sensor.binrange_trash_out state: on type: time start: {{ now().replace(hour0, minute0, second0) - timedelta(daysnow().weekday()) }} end: {{ now() }}看到这里你可能会发现所有这些自动化依赖的都是同一个稳定可靠的状态源。所以把传感器和状态判定做扎实是整个 BinRange 的关键而不是最后那些花哨的联动。6. 实测效果与踩坑记录UWB 不是神仙但够用最后说说真实使用效果和一堆踩过的坑。6.1 实际精度与稳定性数据我在完全不动垃圾桶的情况下连续采集了 72 小时数据。距离的静态抖动范围约为 ±4 cmratio 值波动在 ±0.02 以内。动态测试中我拎着垃圾桶从屋内走到门外状态翻转时间大约在 1~2 秒内完成没有出现来回跳变的情况。这个稳定性远超我之前尝试的蓝牙方案。6.2 最容易误判的场景是人拿着垃圾桶在门口停留有一个场景我一开始没考虑我拎着垃圾桶站在门口内侧还没完全走出去但人已经挡在了门内锚点前。这时候标签到门内锚点的距离可能保持不变很近而人本身是一个巨大的信号反射体会让测距值出现异常波动。解决方案是把测距周期从 5 秒降低到 2 秒同时把平均窗口缩短到 8 秒。这样系统能更快捕捉到人已走出门口之后的稳定状态。而如果人一直站在门口不动ratio 会落在中间区域0.45~0.6 之间我专门设置了一个unknown状态区间只有当 ratio 越过 0.6 才判定为outside避免在临界区域反复横跳。6.3 金属垃圾桶本身会反射 UWB 信号这个坑我调了两天才发现。垃圾桶的金属材质会带来强烈的信号反射导致标签到锚点的测距偶尔出现跳变。处理办法很简单标签不要直接贴在桶壁上中间垫一块 2mm 厚的塑料支架避免天线紧贴金属面。垫了几毫米的距离信号质量提升非常明显。6.4 电池电压下降会导致测距成功率降低UWB 测距对时钟同步要求极高电池电压下降会让标签的时钟频率发生细微漂移。我刚开始没在意直到用了两个月后发现偶尔测距失败才意识到电池快没电了。建议在标签端监控电池电压判定到低于 3.3V 时直接通过 MQTT 发一条低电量告警提前换电池不要等到测距失败才去排查。7. 扩展思路一套测距网络可以服务多个物品BinRange 做出来后我发现这套 UWB 基础设施其实可以复用到其他物体是否出门的场景。比如我的另外一个项目里用同一对锚点来检测拉杆箱是否还在储物间——出门旅行前拉出箱子时状态同样会翻转联动一个出门行李检查清单的自动化。技术上很简单每件物品只需要一个带唯一地址的 UWB 标签。锚点端按标签地址轮询即可标签之间用地址区分互不干扰。如果你想在其他 Home Assistant 项目里用类似的思路记住核心要点固定锚点定义边界、标签附着对象、距离比值判定状态、滤波处理保证稳定。这套方法论从垃圾桶是否拿出去扩展到宠物是否进屋工具是否归位都适用。BinRange 最后真正跑起来的时刻是我站在厨房垃圾桶旁边看手机Home Assistant 推送垃圾桶已出门的消息而我手上的桶还没走到门口。那一刻我知道这套系统不是在猜而是在真正地测量。
返回列表