一次 ClockSync 失败如何暴露时间戳语义
陈淮锐 · 项目时间:2026 年 7—8 月 · 网站收录 2026-09-17
GitHub · 0hello-bit/Robot_twin
本文回顾 2026 年 7—8 月的项目,包含后续整理与补充。实验数字和验证范围按原始项目记录陈述;文末仓库路径为记录索引。
MCU tick 有了,PC 接收时间有了,Q/T 往返数据也有了。看起来,时间线需要的东西已经挺齐。
排查 ClockSync 时,把代码和数据流逐一对上,问题才露出来:这些时间根本没在记同一类事情。有的记协议解析,有的记主机收到一批数据,有的才接近 payload 生成。数字再精确,记错了事件,后面照样会算偏。
时间戳对应的事件边界
| 名称 | 实际描述的边界 | 不能解释为 |
|---|---|---|
q_parse_done_tick |
STM32 解析完一个完整 Q 请求的本地 tick | UART 首字节到达、PC 发送时间或传感器采样时间 |
t_payload_generated_tick |
STM32 把 T payload 具体生成出来的本地 tick | 物理线缆发完、ESP SEND OK 或 PC 收到 T 的时间 |
pc_arrival_time |
PC 收到包含完整记录的接收批次时刻 | 最后一个字节到达、传感器采样时刻或 MCU 发送时刻 |
sensor_time |
传感器实际采样时的时间 | 当前项目里不能用普通 tick_ms 直接替代 |
ClockSync |
不同时间边界之间的映射和误差分析 | 已经完成的绝对物理时钟同步 |
这些名称对应不同事件,之间可能隔着几十毫秒。即使拟合残差很小,只要输入时间记在错误的事件上,得到的映射也不能用于所需的测量。
找到一处偏差:时间记早了
旧固件一开始 AT+CIPSEND,就把 mcu_tx_tick_ms 记下来了。可 ESP-01S 还没准备好,得等它回一个 >,固件才真正把 ClockSync payload 写入发送事务。中间这段等待,就这样被塞进了时间差里。
因此,旧时间戳实际更接近:
开始 AT+CIPSEND
-> 等待 ESP prompt
-> 生成并写入 T payload
翻保留下来的运行数据,这段准备和等待大约有 40 到 48 ms。难怪不能把它直接当网络时延,光在 payload 出来之前就已经等了一段。它也不全是 MCU 计算时间,能确认的是旧时间戳的位置不对。
延迟采样,还要处理事务与重试
采样要移到 payload 真正生成的位置,但还有重试和队列消费的问题。最后一起处理了这几步:
- 在开始事务前只 peek 一个待发送的 ClockSync 样本;
- 等 ESP prompt 到达之后,再生成当前 payload 和时间戳;
- 使用独立的 ClockSync 事务 tag,避免普通诊断帧误消费这个样本;
- 只有专用事务收到
SEND OK,才消费 pending 样本; ERROR、CLOSED、事务拒绝和超时都保留可重试的 pending 状态。
这样才说得清,哪次事务用了哪个时间样本,失败后还剩什么。顺便别把 SEND OK 看得太强:它是 ESP/AT 事务返回的结果,PC 到底收到没有,还得看 PC 那边。
时间有了,还要防止把两次请求拼到一起
只存几个整数还不够,后处理可能把不同 exchange、不同采集范围,甚至不同因果父节点的记录凑成一对。算出来未必报错,含义却已经错了。所以又加上 Clock Exchange identity 和这些检查:
- 一个事件必须属于正确的 capture scope;
- causal parent 必须来自同一个 exchange;
observed_boundary不能缺少观测时间,也不能声称存在未知的数据年龄;- legacy RTT 记录保留为回放证据,不混入新的正式因果拟合。
归属与因果关系不清楚的样本不能进入正式拟合,否则后续很难解释时间偏差来自哪一次通信。
MCU 查完,再看看 PC 这边
主机可以在现有的 sendall() 和 recv() 调用前后各读取一次单调时钟,从而得到一个 PC 应用调用区间:
应用调用开始 -> 应用调用返回
区间中点可以作为应用边界的代表时间,半区间宽度则是这次观察的不确定度。这个区间描述的是主机应用调用,不能直接解释成物理 TCP/Wi-Fi 链路的精确完成时间。
这一阶段的实现要求发送区间和接收区间都有效,才让样本进入正式因果拟合。区间缺了、顺序反了、不确定度说不清,就先拒绝,不能随手填一个“默认网络误差”把它凑齐。每次调用花多久,本来就不一样。
改了这么多,能说同步成功了吗
还不能。ClockSync 可以拟合出类似 pc_ns = a * tick_ms + b 的映射,但有一条拟合直线,离证明物理时钟同步还有距离。至少得继续回答:
- tick 对应的是哪个真实事件;
- 相机、IMU、MCU 和 PC 的边界是否覆盖了同一个物理过程;
- PC 应用区间能否约束网络观察的不确定性;
- 采集批次、重试、超时和丢包是否改变了样本分布;
- 在独立真实运行中,残差和不确定度是否稳定满足门限。
一次 UDP 黑盒探针曾经得到 16 次 timeout、0 次匹配和 1.0 的丢包比例。这个结果说明在那组条件下没有获得 ClockSync 样本,但不能单独归因于 UDP、+IPD 解析、Q 路由或固件发送路径中的某一个具体故障,也不能用它替代正式同步证据。
测试过了,硬件这一关还在
ClockSync 相关的离线修复经过了聚焦测试、Host C 测试、完整 Python 回归、编译检查和 Keil Target 1 构建检查。比如,延迟 payload 生成和专用事务 tag 的一轮离线记录包括 12 个聚焦测试通过、Host C test_cipsend_tx 和 test_twin_control_protocol 通过、完整 Python 回归 827 passed、5 skipped,以及 Keil 0 Error、0 Warning。
这些检查有用,至少代码约定和构建过了。但编译器不会替我烧录,更不会替我测真实时序。新固件在硬件上是不是按这个边界工作,仍然要单独采一轮。
时间语义修正之后,实机验证仍待完成
目前完成的是软件中的时间语义区分,以及已知 CIPSEND 起始时间偏差的修正。延迟 payload 采样、记录 PC 应用区间,预计能改善后续因果分析,但离线构建与回放还不能证明绝对时钟同步、物理线缆完成时间或实车控制所需的时间误差。
当时计划保留原始 evidence,用新边界进行一次经过授权的真实采集,再检查覆盖率、残差、不确定度和观测连续性。项目现已基本停止维护,这项实机验证尚未完成。
相关记录
- 上一篇:相机与 AprilTag 观测
- 下一篇:证据驱动迭代
GLOSSARY.md:时间、同步和证据术语docs/agent-context/handoffs/2026-08-11-causal-clock-apriltag-offline-reacceptance.md:payload 边界修复记录docs/superpowers/plans/2026-08-22-pc-causal-endpoint-uncertainty.md:PC 应用区间不确定度计划