核查日期:2026-09-09。范围:现有红外/辅助餐盘识别输出、重量语义、历史关闭功能。未修改业务或控制项目、未执行 pull/commit/push。
用户已确认硬件使用扫码器扫描二维码;下文
rfidData/rfidLen为原SDK字段名,不代表RFID硬件。
冻结对象
- 代码目录:
/Users/jack/code/010-cpt/008-zhct/zhctproject/android/ZhctWeightingTableYoukate - origin:
https://codeup.aliyun.com/60069db88deaa14d9e02b875/zhct/device/restaurant/billedBygram/ZhctWeightingTableYoukate.git - 分支:
master - HEAD:
2f759f9415b46a7166215fa670d5b4fafeef615e - 读取时工作区干净。
- SDK 字节码复用前轮目录:
/tmp/scan-interruption-audit-20260909/sdk/,不重做已经完成的 SDK 缺陷审计。
1. 当前应用拿不到独立的红外/物体在位结果
确定的源码事实:
app/src/main/java/com/cpt/zhct/weighting/hardware/AuxiliaryTrayRecognitionController.java:8定义 OPEN 指令3E5343414E30363031303035813C,:13定义 CLOSE 指令3E5343414E30363030303035803C。:21的 configure 仅转发 sendCommand,并把返回值包装成结果。app/src/main/java/com/cpt/zhct/weighting/hardware/YoukateHardwareManager.java:125的 sendCommand 只核验已初始化/有输出流,然后在:136write、:137flush,:138返回成功;没有等待硬件 ACK、配置回读或实时在位查询。app/src/main/java/com/cpt/zhct/weighting/activity/SetActivity.java:928发配置;:939根据发送成功保存 LAST_INFRARED_OPEN_TIME/CLOSE_TIME。:945使用“命令已发送”文案,未宣称实际生效。app/src/main/java/com/cpt/zhct/weighting/widget/InfraredControlDialog.java:20明确只展示本应用最近成功发送命令的时间;该弹框不观察物体。- SDK
PC681ScaleManager$ScaleData的公开字段只有 netWeight、grossWeight、各自符号、isOverload、isZero、isTare、isStable、temperature、rfidLen、rfidData。没有 infraredPresent/objectPresent、扫码新鲜度、扫描序列号、独立红外时间戳等字段。可复查/tmp/scan-interruption-audit-20260909/sdk/com.jocat.device.utils.PC681ScaleManager$ScaleData.javap.txt:2。 YoukateHardwareManager.java:268接收 ScaleData,在:276归并成稳定/不稳定/超重,:283取净重,:288向页面回调onWeightData(state, weight, cleanScanCode(rfidData))。:329的业务监听只有这三项,无第二个物理在位观测。app/src/main/java/com/cpt/zhct/weighting/activity/HomeActivity.java:1963的 trayPresent 由mA02TrayClaimCodePresent || scanCode非空 || mCurrentCode非空得到,是码/会话推断,不是红外或重量在位结果。不能把变量名 trayPresent 当成独立传感器证据。
因此:现有“红外感应设置”证明系统具备红外配置命令入口,不能证明 App 已具备独立红外在位接口。下层是否把红外结果与扫码结果合并成 rfidData、具体如何保留/清空旧码、开关掉电是否保持,在本次可见应用和 SDK 字段中均无法确认,必须向板卡厂家索要协议/固件流程或抓波形与串口同步验证。
2. 历史确实有“关闭辅助识别”的开发,但不等于现场已关闭
确定的历史代码事实:
- commit
055401d1ad17cb3fa9dcb2d78be1919a23d70019(2026-07-29)题为#VWCG-1140 设置-高级设置中,增加“去掉红外感应”的功能。 - 此版本
AuxiliaryTrayRecognitionController方法名为removeAuxiliaryTrayRecognition(),发送的 REMOVE_AUXILIARY_RECOGNITION_COMMAND 正是当前 CLOSE 指令。因此历史“去掉辅助餐盘识别”与当前“关闭红外感应”在 App 层使用相同协议字节。 - commit
8744bc8后改成打开和关闭均可操作;当前代码两者都有。 - 控制资料
work_android/ZhctWeightingTableYoukate/change_records/2026-07-29-remove-auxiliary-tray-recognition.md:7明示模块实际关闭效果、断电保持、新版本实机验收仍待完成;:66明示发送成功仅代表 write/flush。 work_android/ZhctWeightingTableYoukate/docs/2026-07-31-infrared-control-dialog-design.md:100明示本地时间不代表设备 ACK;:101明示不能据此推断当前硬件状态;:131模块生效仍待实机验收。
可提出的项目行动:核对故障机器的最近开/关发送日志,同时做真正的硬件在位回读/现场遮挡实验。不得仅依据存在 CLOSE 功能或某个本地时间戳就认定现场红外被关闭,更不能先归因为人为关闭。
3. 菜盆与夹子共用秤体;现有代码未做夹子补偿
用户已明确的物理事实(由主 Agent 转达):当前秤称菜盆,夹菜夹子放在菜盆内,夹子可能放回餐盆,也可能没放回。以下据此判断,不再推测称重对象。
确定的源码事实:
YoukateHardwareManager.java:283将 SDK 净重直接作为业务 weight,没有独立牌重/夹重通道。HomeActivity.java:466开始取餐时冻结mSinglePickStartValue = mCurrentWeight。app/src/main/java/com/cpt/zhct/weighting/fragment/dark/DarkPickOngoingWithPriceFragment.java:790与DarkPickOngoingNoPriceFragment.java:680都按singlePick = startValue - weight计算取餐量;若小于零则置零。app/src/main/java/com/cpt/zhct/weighting/antiescape/NoTrayPickDetector.java:19在无盘、打餐前、稳定情况下运行;:32重量增大就提高基准;:36以基准减当前重量是否达到阈值判断未放盘取餐,:41保存该减重。- README 描述“一台设备当前菜品”“重量变化计算取餐量”;
HomeActivity.java:1984将 weight 保存到DISH_TABLE_LAST_WEIGHT。 Constants.java:50虽定义“勺重”SPOON_WEIGHT(默认 20g),全仓 app/src/main 的引用只有 Constants 和 SetActivity 设置界面,未发现当前取餐或在位算法读它。:57的 20g 仅为软件默认值,不能当成现场夹子实测重量。SetActivity.java:676的设置完成分支调用MmkvUtils.getInstance().get(Constants.SPOON_WEIGHT, spoonDialog.getCurrentInputValue()),不是 put。MmkvUtils.java:66的 get 只 decode 配置,不保存。因此界面虽刷新用户输入,当前该设置分支不将勺重持久化。即使先修为 put,仍需显式接入算法及状态观测才构成补偿。DarkPickOngoingWithPriceFragment.java:845和DarkPickOngoingNoPriceFragment.java:708的重量回调只过滤启动前若干回调和小范围重量波动,然后更新显示。它们没有夹子状态输入,也没有使用 SPOON_WEIGHT。函数注释写“只显示稳定状态”,但此处没有判断入参 state 是否稳定,不能将该注释当作已有稳定值门禁的证据。
结论:现有代码用“菜盆载荷前后减重”计算取餐量,开始/结束时夹子状态不同会污染食物取走量。设置页有“餐勺重量”不能证明已有补偿。
在菜盆皮重恒定、无外力、无补菜且夹子全部由菜盆承重的简化条件下,令 D=食物取走重量、T=夹子实际重量,开始/结束夹子在菜盆内的状态 s0,s1∈{0,1}:
秤体减重 ΔW = D + (s0 − s1) × T
| 开始夹子状态 | 结束夹子状态 | 当前算法误差(截零之前) |
|---|---|---|
| 在盆里 | 在盆里 | 夹重相互抵消 |
| 不在盆里 | 不在盆里 | 夹重相互抵消 |
| 在盆里 | 不在盆里 | 多计 T |
| 不在盆里 | 在盆里 | 少计 T;D<T 时页面截为 0 |
数学反例:看到秤体减少 100g,既可能取菜 100g 且夹子两端同态,也可能取菜 70g 并拿走 30g 夹子;单一秤体读数无法唯一反推。即使已知 T,也仍须知道 s0、s1,不能每单固定减一次夹重。
优先硬件改造方向是让夹子有与菜盆秤机械隔离的固定放置架/回位点,使夹子重量不进入食物称重;若操作允许“回盆或不回”而不约束,则需独立观测夹子在盆/离盆,或验证能分辨动作的传感方式。夹子带菜、滴液、部分搭在盆边由外部承重、手触碰菜盆等会破坏固定 T 或二值状态的假设,仍需实机校准/异常判定。
夹子在位、码牌在位、菜盆重量是三件不同事情。不能设计“weight > 0 所以码牌还在”,也不能以“夹子已放回”断言客户或码牌已经离开。挪牌/拿牌可不改变菜盆重量;取菜、放夹子、补菜都会改变重量。现有重量可作为取餐事件证据,不能替代码牌身份/在位证据。
4. 对方案的直接约束(工程建议,非现有实现)
- 与厂家确认是否能直接输出独立的
presence、presence_valid、presence_timestamp、scan_result、scan_sequence、scan_timestamp、sensor_fault,而不是将状态全部折叠为有码/空码。若固件已掌握红外结果,优先评估解耦输出能否复用现有硬件。 - 在源码中的码/重量回调之外,建立“物体在位/身份/数据健康”三个独立维度;丢码但可靠在位仍为真时进入身份暂失,保留当前会话并尝试重读。
- 独立在位只证明区域有物体,不证明仍是同一张牌。A→B 的新身份须走换牌判定并收尾 A,不能因在位连续而把 B 的取餐记给 A。
- 在位区必须覆盖允许挪动的范围。如果红外只照一个点,移动出光点而仍在桌上依然会判离开;需用合适范围/多点/机械承托设计,而不是单纯延长阈值。
- 无法区分两个物理情况时应显示“暂无法确认/请重新放牌”,不能在信息不足时声称已经明确识别未拿走。不能用无限延迟离盘换取表面的不中断。
5. 最少的现场鉴别实验
应同步记录物理视频、原始串口字节、SDK 解码、App 会话、时间戳:
| 实验 | 固定其它条件 | 要确认的边界 |
|---|---|---|
| 只挪牌,不动菜盆/餐具 | 不取餐 | 码丢失时独立在位是否仍为真,允许移动区域是否被覆盖 |
| 完全拿走牌 | 不取餐,不碰称重载荷 | 真离开是否有独立信号;当前 weight 是否仍不变 |
| 只拿起/放回夹子 | 牌位置保持 | 实测夹重、湿/干/带菜差异、是否部分搭放分担载荷 |
| 相同已知菜量,夹子开始/结束四种组合 | 牌固定 | 多计/少计夹重与零截断,补偿或机械隔离是否有效 |
| 取菜与补菜 | 牌固定 | 减重/增重来源、稳定时长及外力干扰 |
| 挡码不挪牌 | 区域内实体持续在位 | 身份识读与在位能否解耦 |
| A 直接换 B,间隔很短 | 连续有物 | 能否正确分隔身份与取餐会话 |
| 打开/关闭红外分别重复前述动作 | 使用相同固件、安装位置 | 配置是否生效、红外是否改变合并码规则 |
只有这些实验与厂家接口契约能补全“当前硬件可直接复用还是需要加传感器”的证据。