news 2026/11/3 2:46:27

〖物流终端实战 03〗蓝牙电子秤底层协议解析:Notify 通知防抖、字节解析与稳定重量判定

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
〖物流终端实战 03〗蓝牙电子秤底层协议解析:Notify 通知防抖、字节解析与稳定重量判定

一、电子秤不是“读一个数”,是“处理一条高频数据流”

开发物流 App 对接蓝牙电子秤,最常见的误解是“连上之后读一次重量就行”。真实的电子秤工作在Notify(通知)模式:连接后使能特征值通知,秤以 10–50Hz 的频率持续推送字节数组,App 需要从这条高频数据流中解析出重量值,并判断“什么时候这个重量已经稳定”。

三个技术难点依次出现:字节怎么解析(协议是设备相关的)、数据怎么去抖(高频推送中夹杂噪声)、稳定怎么判定(什么时候可以把这个重量写入运单)。

二、字节解析:协议是设备相关的,与平台无关

电子秤的字节布局由厂商协议决定,常见结构是“帧头 + 重量数据 + 状态位 + 校验和”。一个典型的小端 16 位整数 + 比例因子的解析:

java

public BigDecimal parseWeight(byte[] data) { // 协议示例:data[0]=0x02(帧头), data[1..2]=重量(小端), data[3]=状态位 if (data.length < 4 || data[0] != 0x02) { return null; // 帧头不对,丢弃 } // 小端拼接:低字节在前,高字节在后 int raw = (data[1] & 0xFF) | ((data[2] & 0xFF) << 8); // 比例因子来自厂商协议:如 0.005 kg/单位 BigDecimal factor = new BigDecimal("0.005"); return BigDecimal.valueOf(raw).multiply(factor); }

三个必须遵守的约束:

第一,符号位处理。byte在 Java 中是带符号的,data[1]如果最高位是 1,直接toInt()会得到负数。必须& 0xFF转无符号。

第二,小端 vs 大端。不同厂商的字节序不同,解析前必须确认协议文档。小端是“低字节在前”,大端是“高字节在前”,拼反了重量会差几个数量级。

第三,解析在非主线程。10–50Hz 的推送在主线程解析会阻塞 UI,严重时 ANR。Android 用协程或 RxJava 的observeOn(Schedulers.io()),iOS 用后台队列,鸿蒙用 TaskPool。

三、去抖:滑动窗口 + 中值滤波,比“单点取平均”更稳

电子秤的推送数据中夹杂着噪声:包裹放上去的瞬间有冲击振荡,秤体轻微晃动会产生跳变。直接取“最近一个值”或“最近 N 个值的平均”都不够稳。

工程上更可靠的是滑动窗口中值滤波:维护一个长度为 N(如 5–7)的窗口,每次新数据进窗口、最旧数据出窗口,取窗口中位数作为当前重量。中位数对脉冲噪声(单点跳变)不敏感,比平均值更稳。

java

public class WeightFilter { private final Deque<BigDecimal> window = new ArrayDeque<>(); private final int size; public WeightFilter(int size) { this.size = size; } public BigDecimal push(BigDecimal weight) { window.addLast(weight); if (window.size() > size) window.removeFirst(); List<BigDecimal> sorted = new ArrayList<>(window); Collections.sort(sorted); return sorted.get(sorted.size() / 2); // 中位数 } }

窗口大小是权衡:窗口太小(3),滤波效果弱;窗口太大(15),响应延迟增加,包裹放上去后要等更久才显示稳定。工程上 5–7 是常见的平衡点,具体取决于秤的推送频率和作业节拍。

四、稳定判定:连续 N 次读数在容差内,才认为稳定

“重量稳定”不是“读数不变”——秤的精度限制决定了读数永远在小范围内波动。稳定的工程定义是:连续 N 次(如 5 次)的滤波后重量,两两之间的差值都在容差范围内(如 ±10g),且持续时间超过阈值(如 300ms)。

java

public class WeightStabilizer { private BigDecimal lastStable = null; private int consecutiveCount = 0; private static final int REQUIRED_COUNT = 5; private static final BigDecimal TOLERANCE = new BigDecimal("0.010"); // 10g public boolean isStable(BigDecimal current) { if (lastStable == null || current.subtract(lastStable).abs().compareTo(TOLERANCE) <= 0) { consecutiveCount++; lastStable = current; } else { consecutiveCount = 1; // 跳变,重新计数 lastStable = current; } return consecutiveCount >= REQUIRED_COUNT; } }

关键设计:稳定判定必须在滤波之后做,不能对原始数据直接判定。原始数据的噪声会让“连续 N 次在容差内”几乎永远不成立,或者频繁误判。

五、连接层的坑:使能通知不等于数据会来

5.1 使能通知必须写描述符

Android 端调用setCharacteristicNotification(char, true)只是“本地允许接收通知”,还必须写 CCCD 描述符(00002902-0000-1000-8000-00805f9b34fb)的ENABLE_NOTIFICATION_VALUE,秤才会真正开始推送。只调用前者不写描述符,秤不会发数据,表现为“连接成功但一直没读数”。

iOS 端setNotifyValue(true, for:)内部处理了描述符,但特征值必须同时具备.notify或.indicate属性,否则调用无效。

5.2 特征值筛选不能硬编码 UUID

不同电子秤的可通知特征值不同。正确做法是连接后遍历services和characteristics,按属性筛选:优先匹配已知的秤服务 UUID(如FFE0/FFE1、FFF0/FFF1),找不到时选第一个具备.notify或.indicate属性的特征值。

5.3 断连重连后必须重新使能通知

BLE 连接断开重连后,通知状态不会自动恢复。重连成功后必须重新写 CCCD 描述符使能通知,否则表现为“重连成功但没数据”。这是蓝牙电子秤最隐蔽的坑之一。

六、避坑指南

坑1:byte直接转int不& 0xFF。最高位为 1 时得到负数,重量解析错误。所有字节转整数必须做无符号处理。

坑2:对小端数据按大端拼接。重量差几个数量级。解析前确认协议字节序。

坑3:对原始数据直接做稳定判定。噪声导致永远不稳定或频繁误判。先滤波(滑动窗口中位数),再判定稳定。

坑4:只调用setCharacteristicNotification不写 CCCD。连接成功但没数据。使能通知必须写描述符。

坑5:断连重连后忘记重新使能通知。重连成功但没数据。重连成功后必须重新写 CCCD。

七、总结

蓝牙电子秤的工程核心是解析、去抖、稳定判定三层分离:字节解析处理帧头、字节序、符号位和比例因子;滑动窗口中值滤波去除脉冲噪声;连续 N 次读数在容差内的稳定判定给出可写入运单的重量。连接层三个必查项:使能通知必须写 CCCD、特征值按属性筛选不硬编码、断连重连后重新使能。秤的协议是设备相关的,但去抖和稳定判定的逻辑是平台无关的,应该收敛到共享层。

下一篇预告:电子秤解决了“重量怎么采”,但终端的高频操作还有一类——纯血鸿蒙 App 的长列表渲染与内存泄漏排查。明天聊 ArkTS 高阶性能优化。

> 本文作者:深圳+Eyf•半字节科技▪技术产品团队
> 物流、快递、快运作业管理系统,让每一票,都清晰可控。从任务分配到签收回传,一站式管理每个作业环节。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 2:45:59

小白程序员如何快速成长为高薪AI Engineer?

本文深入解析AI Engineer这一新兴岗位的内涵与市场需求&#xff0c;从岗位演变、技能要求到转型路径进行详细阐述。文章指出&#xff0c;AI Engineer的核心价值在于将现成的大模型转化为可靠的产品&#xff0c;而非模型训练。文章强调评测与集成的重要性&#xff0c;并提供了后…

作者头像 李华
网站建设 2026/11/3 2:44:21

OPRF应用之OPAQUE增强型口令认证密钥交换协议【4】

摘要本文是对RFC 9807所描述的增强型口令认证密钥交换协议OPAQUE的学习与梳理&#xff0c;包括&#xff1a;1&#xff09;协议整体执行流程、2&#xff09;注册方案和在线认证方案、3&#xff09;关键模块OPRF与3DH。文章保留了原标准的章节对应关系&#xff0c;方便对照RFC原文…

作者头像 李华
网站建设 2026/11/3 2:43:15

QML 字体度量与文本度量:FontMetrics 与 TextMetrics

目录一、文本排版中的基线概念二、FontMetrics&#xff1a;测量字体固有的尺寸属性三、TextMetrics&#xff1a;测量特定文本排版后的实际尺寸宽度与边界矩形属性的区别四、组件职责划分与适用场景对照五、关键开发注意事项与潜在缺陷拦截在进行界面排版和自定义控件设计时&…

作者头像 李华
网站建设 2026/11/3 2:41:03

WeVisOne-VL OCR定位指南:如何快速精准识别并定位图片中的任意文字

WeVisOne-VL OCR定位指南&#xff1a;如何快速精准识别并定位图片中的任意文字 WeVisOne-VL-2B 是腾讯微信视觉团队&#xff08;WeChat Vision&#xff09;开源的统一视觉感知模型&#xff0c;它不仅能看懂图片内容&#xff0c;还能对图中的任意文字进行 OCR 识别与精确定位&a…

作者头像 李华