diff --git a/docs/rt-link-verification-report.md b/docs/rt-link-verification-report.md new file mode 100644 index 0000000..c7b53b3 --- /dev/null +++ b/docs/rt-link-verification-report.md @@ -0,0 +1,287 @@ +# TwinCAT ↔ J1900 实时数据通讯验证报告(EL6695 桥接) + +> **版本**: 1.0 +> **日期**: 2026-08-12 +> **结论**: ✅ 全部通过(4kHz 3 小时 soak 零错误;8kHz RTT min 0.75ms / mean 1.04ms) +> **关联文档**: `8b-bridge-design.md`、`8b-verification-methodology.md`、`500us-latency-plan.md`、`jitter-analysis.md` + +--- + +## 1. 摘要 + +本报告覆盖 TwinCAT PC 与 J1900 嵌入式平台之间经 EL6695 EtherCAT 桥接的实时数据通讯验证, +包括数据完整性、长期稳定性、周期扩展(1kHz→8kHz)、双侧 DC-Synchron、RTT 延迟优化与 +断电恢复能力。 + +**核心结果**: + +| 验证项 | 结果 | +|---|---| +| 数据完整性(800B 载荷,双向交叉校验) | 3 小时 4537 万周期零错误 | +| 长期稳定性(4kHz soak 11400s) | bSync=True ×190 采样点,nMismatch delta=0 | +| J1900 侧自校验 | 33.6M 帧 payload mismatch=0,tx/rx err=0 | +| RTT(8kHz + tx_rx RT 提权) | min 0.75ms / mean 1.04ms / max 1.38ms | +| 单向延迟(推导) | 典型 0.3–0.5ms,最坏 ~0.6ms | +| 死链路检测 | lag 指标 + bSync 双重敏感(实测 5 秒内可检出) | +| DC-Synchron(双侧) | 从站侧固件 sync_mode=2 接受,180s 同步计数器全零 | +| 断电恢复 | TwinCAT 自恢复 Run;J1900 重建 /tmp 后 <2 分钟恢复全链路 | + +--- + +## 2. 系统架构与测试环境 + +### 2.1 硬件拓扑 + +``` +TwinCAT PC (Windows, TwinCAT 3.1.4026.24) + └─ EtherCAT 主站网卡 "以太网 2" (TwinCAT-Intel PCI, MAC 00-15-17-8A-B3-DA) + └─ EK1100 → EL2202 → EL1252 → EL2262 → EL2008 → EL6851-0010 → EL6022 + → EL6695 (桥接端子, 主站侧 X2) + └─ EL6695 从站侧 X1 ←直连→ J1900 eth1 +J1900 (Linux 6.6.135-rt74 PREEMPT_RT, Celeron J1900 4 核) +``` + +| 项 | 值 | +|---|---| +| TwinCAT AmsNetId | `169.254.176.217.1.1` | +| J1900 管理 IP | `192.168.68.100`(DHCP,曾漂移至 .101,MAC `00:e2:69:34:71:2c`) | +| SSH 跳板 | `tonycao@192.168.58.8` | +| EL6695 从站侧站址 | `0x1000` | +| J1900 内核 | 6.6.135-rt74(PREEMPT_RT,io_uring 可用) | + +### 2.2 软件与工程 + +| 项 | 位置 | +|---|---| +| TwinCAT 工程(800B 变体) | `C:\Users\tonycao\work\twincat3-auto-cli\TwinCAT_EL6695_Primary_800B\` | +| J1900 源码 | `C:\Users\tonycao\work\ethercat-linux`(Rust,ethercrab 0.7 本地 patch) | +| 构建目标 | `x86_64-unknown-linux-musl`(静态链接,零运行时依赖) | +| 关键 commits | `f0163d8`(800B) → `aabfe31`(DC-Synchron) → `cdb90c3`(800B 异步 FPWR) → `253f4b3`(J1900 DC) → `4083df0`(8kHz+RT 提权) | +| 配置备份 | tsproj `.bak-1k-dc` / `.bak-4k`;TcTTO `.bak-1k` / `.bak-4k` | + +### 2.3 载荷布局(800B) + +| 偏移 | 内容 | 方向 | +|---|---|---| +| `[0..7]` | 序列号:PLC 写 `tc_seq=nCycles`;J1900 回写 `f(tc_seq)=tc_seq*7+3` | 双向 | +| `[8..15]` | J1900 本地周期计数 | 上行 | +| `[16..799]` | 图案区:`(seq + i) mod 256`(J1900 原样回传) | 双向 | +| `[264..267]` | J1900 周期抖动 i32(统计区,不参与校验) | 上行 | +| `[268..271]` | J1900 payload mismatch 计数 | 上行 | +| `[272..279]` | 原始 tc_seq 保留(供 PLC 交叉验证) | 上行 | + +--- + +## 3. 验证方法学 + +### 3.1 数据完整性证明链 + +单向"收到数据"不能证明通讯正确。本方案用**双向交叉校验 + 数学变换**构成闭环证明: + +1. **PLC 侧写入**:`aOut1[i] = (nCycles + i) mod 256`(图案区),`aOut1[0..7] = tc_seq` +2. **J1900 侧处理**(证明"读取+计算+写回"三个动作真实发生): + - 校验收到图案 `[16..256)` 与 `tc_seq` 一致(不一致计入 `payload_mismatch`) + - 对序列号做不可由硬件桥接伪造的数学变换:`f(x) = x*7 + 3` + - 回写 `aIn1[0..7] = f(tc_seq)`,图案区原样回传,`[272..279]` 保留原始 tc_seq +3. **PLC 侧验证**: + - 从 `aIn1[0..7]` 反解 `nReturnedSeq = (x-3)/7`(整除性本身是一道校验) + - `bSync := 全部 aIn1[i] == (nReturnedSeq + i) mod 256`(768 字节逐字节) + +**设计要点**: +- `f(x)=7x+3` 保证回传数据不可能由桥接端子透传/环回伪造 +- 用 `nReturnedSeq`(回传帧自带的序号)而非本地 `nCycles` 做图案比对, + 使校验对传输滞后免疫——校验的是"回传帧内部自洽性" +- J1900 侧独立再做一遍正向校验,两侧互为佐证 + +### 3.2 新鲜度(liveness)证明 + +自洽性校验的盲区:回传通道冻结时数据仍自洽。对策: + +- **`nMatchLag = nCycles - nReturnedSeq`**(PLC 内每周期原子计算): + 回传帧的产生时刻距当前的周期数。通道健康时稳定在小范围; + 通道死亡时以任务频率无界增长 +- **实测死链路响应**:杀掉 J1900 ticker 后 5 秒内 lag 从 6 → 8.1 亿且以 4000/s 增长, + bSync 同步翻 False(EL6695 从站侧失联使输入映像清零) +- **反向验证**:重启 ticker 后 lag 立即回落至 4–6 周期 + +### 3.3 方法学盲区(如实声明) + +| 盲区 | 说明 | 缓解 | +|---|---|---| +| 桥转发冻结而两侧 ESC 保持 OP | aIn1 冻结时自洽校验仍通过,任何黑盒测试无法检出 | 概率极低;需侵入式手段 | +| J1900 侧图案校验仅覆盖 `[16..256)`(240/800 字节) | PLC 侧覆盖 768 字节,互补 | 可扩大 J1900 校验范围 | +| J1900 处理帧率低于发送帧率(设计性跳帧) | echo 恒为最新帧(lag 指标证明),无陈旧累积 | 见 5.4 | + +--- + +## 4. 指标详解 + +### 4.1 PLC 侧(GVL_Sync,ADS 可读) + +| 指标 | 类型 | 定义 | 意义与解读 | +|---|---|---|---| +| `nCycles` | ULINT | PLC 任务周期计数 | 任务存活与速率基准;速率 = Δ/Δt,偏离任务频率即异常 | +| `bSync` | BOOL | 当前周期 768 字节图案全部匹配 | **瞬时**正确性。单次 False 可能是瞬态;持续 False = 链路/配置故障 | +| `nMismatch` | DINT | 累计失配字节数(仅 diff>0 时累加) | **历史**错误总量。soak 中看 delta=0;注意 int32,错误率 3M/s 时约 11 分钟回绕 | +| `nReturnedSeq` | ULINT | 回传帧携带的原始序号(反解后) | 回传链路的"时间戳";与 nCycles 之差即 lag | +| `nMatchLag` | DINT | `nCycles - nReturnedSeq`,每周期原子更新 | **新鲜度核心指标**:回传 RTT 的周期数表示。健康值=小范围稳定;无界增长=回传通道死 | + +**ADS 采样注意**:`nCycles` 与 `nReturnedSeq` 分两次读取会产生撕裂(高速任务下可读出负 lag 假象); +必须直接读原子计算的 `nMatchLag`。 + +### 4.2 J1900 侧(ticker S 行遥测) + +| 字段 | 定义 | 异常含义 | +|---|---|---| +| `cyc` | J1900 处理循环计数 | 速率 = 实际处理能力上限的度量 | +| `raw` / `proc` | 收到的 tc_seq / 回写的 f(tc_seq) | 与 PLC 侧 nCycles 对账,验证双向一致 | +| `txe` / `rxe` | FPWR/FPRD 事务错误 | 持续增长 = 链路劣化或 ESC 掉态 | +| `late` | 异步 FPWR 响应未在下一周期收齐的次数 | 少量(<0.1%)正常;暴涨 = 总线拥塞或 RT 调度劣化 | +| `stale` | tc_seq 未变化(读到旧帧)占比 | spin 模式下少量正常(跳帧);100% = TwinCAT 侧停发 | +| `mono` | tc_seq 回退次数 | 非零 = 帧乱序/映像撕裂,严重异常 | +| `cerr` | J1900 内部计算自洽错误 | 必须恒为 0(软件自检) | +| `mism` | J1900 侧图案失配累计 | 必须冻结(delta=0) | +| `dcph` | EL6695 从站侧 DC 系统时间 mod 周期 | DC 时钟相位观测 | +| `dcdr` | DC 时钟相对 CLOCK_MONOTONIC 的累计漂移 | 无持续漂移补偿时有界 wander(实测 ±几十 ppm) | + +### 4.3 时延类统计(OnlineStats,结束报告) + +| 统计 | 定义 | 实测(3h soak, 4kHz spin) | +|---|---|---| +| `exec_time` | 单周期处理耗时(读→变换→写就绪) | p50=25µs, p99=44µs, max=300µs | +| `period_jitter` | spin 循环相邻 fresh 检测的间隔偏差 | p50=12µs, mean=88µs(受跳帧节奏支配,非调度抖动) | +| `fprd_rtt` / `fpwr_rtt` | 单次事务往返 | 800B FPRD ≈ 160µs(决定 spin 检测粒度) | + +### 4.4 RTT 分解模型(8kHz,125µs/周期) + +实测 RTT mean 1.04ms ≈ 8.3 周期,分解: + +| 环节 | 典型耗时 | 性质 | 可优化性 | +|---|---|---|---| +| TwinCAT 输出量化(任务边界→帧发出) | ~62µs(0–125) | 整周期 | 仅能提频 | +| 正向:线缆+EL6695 桥固件转发 | ~150µs | 连续 | 桥固件决定,不可控 | +| J1900 spin 检测(FPRD 轮询粒度 160µs) | ~125µs(0–250) | 量化 | 受 800B 事务往返物理下限约束 | +| J1900 处理 + 异步 FPWR 上线 | ~45µs | 连续 | 已优化至极限(24–25µs exec) | +| 回程:线缆+桥转发 | ~150µs | 连续 | 同上 | +| TwinCAT 输入量化(帧到达→任务读取) | ~62µs(0–125) | 整周期 | 仅能提频 | +| 整周期簿记(lag 按整周期计) | ~125–250µs | 量化 | — | + +**单向延迟推导**(TwinCAT→J1900,去掉回程三项):典型 **0.3–0.5ms**,最坏 ~0.6ms。 +适用设定值级控制、配方下发、同步基准传递;紧伺服闭环受限于完整 RTT(~1ms,闭环带宽 ~100Hz 量级)。 + +--- + +## 5. 测试结果 + +### 5.1 配置演进总表 + +| 阶段 | TwinCAT 任务 | J1900 模式 | 结果 | commit | +|---|---|---|---|---| +| 8B 原理验证 | 1kHz | ticker | 通过(XOR 逐字节证明) | `309aaba` | +| 800B + SM 精确匹配 | 1kHz | ticker | 5h 零错误(18M 周期) | `f0163d8` | +| TwinCAT 侧 DC-Synchron | 1kHz | ticker | 激活干净,90k 周期零错误 | `aabfe31` | +| spin-lock + 异步 FPWR | 4kHz | spin | J1900 2040/s,数据零错误 | `cdb90c3` | +| J1900 侧 DC-Synchron | 4kHz | spin+dc | 180s 同步计数器全零 | `253f4b3` | +| **3 小时 soak** | **4kHz** | **spin+dc** | **全绿(见 5.2)** | — | +| RTT 优化 | 8kHz | spin+dc+RT 提权 | RTT min 0.75ms / mean 1.04ms | `4083df0` | + +### 5.2 3 小时 soak(4kHz + spin + DC,2026-08-11 22:12 → 01:21) + +**PLC 侧**(ADS 每 60s 采样 ×190): + +| 指标 | 结果 | +|---|---| +| bSync | True ×190/190 | +| nMismatch delta | 0 ×190/190 | +| ADS 错误 | 0 | +| 任务速率 | 4000.9/s 恒定 | +| 总周期 | 45,370,909 | + +**J1900 侧**(`--duration 11400` 整): + +| 指标 | 结果 | +|---|---| +| 处理周期 | 33,711,687(~2957/s,74% 帧率,设计性跳帧) | +| payload 校验 | checked=33,598,819,mismatch=0 | +| tx_err / rx_err / comp_err | 0 / 0 / 0 | +| stale | 0.3%(跳帧读旧,正常) | +| late | 15,741(0.05%) | +| exec_time | p50=25µs,p99=44µs | +| DC 漂移 dcdr | 3.2h 累计 ~-9.8ms(≈-0.85ppm,有界 wander) | + +### 5.3 DC-Synchron 验证细节 + +| 发现 | 证据 | +|---|---| +| ethercrab init 已分发从站侧 DC 系统时间 | 0x0920 offset 非零、0x0930 漂移补偿激活、0x0910 以真实速率推进 | +| EL6695 从站侧 ESC SYNC 寄存器(0x0980+)ECAT 侧不可读 | FPRD WKC=0;写入 WKC=1(固件经 PDI 自管) | +| 正确启用路径是 CoE | `0x1C32/0x1C33:01 sync_mode=2` 写入被固件接受且回读保持 | +| DC 模式下运行无副作用 | 180s:sm_event_missed=0,cycle_exceeded=0,sync_error=0(SM2+SM3) | + +**未证实项**:SYNC0 脉冲全程实际激活状态(收尾计数器复读失败); +dcph 全范围游走表明 J1900 处理时序锁的是帧到达(spin)而非 SYNC0 网格。 +表述应为"DC 配置下数据通路无异常",而非"DC 对性能有贡献"。 + +### 5.4 RTT 优化实验矩阵 + +| 配置 | RTT min | RTT mean | RTT max | J1900 处理率 | 结论 | +|---|---|---|---|---|---| +| 4kHz AF_PACKET | 1.0ms | 1.45ms | 1.75ms | 2957/s (74%) | 基线 | +| 8kHz AF_PACKET | 0.75ms | 1.09ms | 1.5ms | ~4000/s (50%) | 两端量化减半生效 | +| 8kHz io_uring 后端 | 1.13ms | 1.42ms | 1.75ms | 2043/s | ❌ 阻塞式设计更差,弃用 | +| **8kHz + tx_rx RT 提权** | **0.75ms** | **1.04ms** | **1.38ms** | ~3100–4000/s | ✅ 当前最优 | + +**结论**:p50=1.0ms、min=0.75ms,"1ms 内"在最优/中位情形达成;mean 超出 4%。 +剩余耗时为结构性(桥固件转发、FPRD 检测粒度、两端量化), +16kHz 提频预期收益仅 ~60µs 且引入 TcTTO 整数 µs 取整、PLC exec 预算、EL6695 能力三重风险,不建议。 + +### 5.5 鲁棒性测试 + +| 场景 | 结果 | +|---|---| +| ticker 误退(默认 60s 时长) | PLC 侧 bSync→False、nMismatch 增长——故障可观测;`--duration 0` 为正确用法 | +| 死链路注入(杀 ticker) | lag 5s 内 6→8.1 亿,bSync=False;重启后 4–6 周期恢复 | +| 双实例抢网卡(误操作注入) | 错误计数(txe/rxe)立即暴露,err_streak 超限自动退出 | +| 整机断电重启 | TwinCAT 随 boot project 自恢复 Run+PLC Run(4kHz 配置保持);J1900 /tmp 清空需重建(脚本化 <2 分钟);DHCP 地址漂移 .101→.100 需 ARP 扫描定位 | + +--- + +## 6. 已知限制与残余风险 + +1. **J1900 处理帧率 < 发送帧率**(8kHz 时 ~50%):受 800B FPRD 事务往返 ~160µs 物理约束。 + echo 恒为最新帧(lag 指标证明),数据正确性不受影响,但每帧独立处理的场景不适用 +2. **无持续 DC 漂移补偿**:ethercrab 仅静态补偿,dcdr 以 ±几十 ppm wander。 + 事件驱动(spin)交换不受影响;若需 J1900 硬锁 DC 网格需加周期性 FRMW 补偿 +3. **TwinCAT 试用许可 7 天过期**:长期运行需周期性重新激活(过期症状:851 端口缺失、卡 Config 态) +4. **J1900 DHCP 地址漂移**:建议静态化或按 MAC 扫描定位(已备脚本化流程) +5. **方法学盲区**:桥转发冻结而 ESC 保持 OP 的失效模式黑盒不可检出(见 3.3) + +## 7. 结论与建议 + +**结论**:TwinCAT 4kHz(250µs)/8kHz(125µs) + EL6695 桥 + J1900 spin-lock + 双侧 DC-Synchron +配置下,800B 双向实时通讯经 3 小时 4500 万周期验证零数据错误; +RTT 达 min 0.75ms / p50 1.0ms / mean 1.04ms,单向延迟典型 0.3–0.5ms。 +数据完整性、新鲜度、故障可观测性、断电恢复均经实证。 + +**建议**: +1. 生产化时将图案区替换为真实过程数据(帧结构/序号校验/延迟特性已验证可直接复用) +2. soak 采样脚本已内置 lag 监控(`tc-ads-soak.ps1`),后续长测自动覆盖新鲜度 +3. 若需 mean RTT 严格 <1ms,评估 LRW 单帧交换(需 FMMU 配置,改动中等)前先量化收益 +4. J1900 管理口建议配置静态 IP,消除 DHCP 漂移运维成本 + +## 8. 附录:复现命令 + +```sh +# J1900 侧(经跳板) +ssh -J tonycao@192.168.58.8 root@192.168.68.100 +/tmp/el6695_rt_dc eth1 --duration 0 --cycle-us 125 --spin --dc # 8kHz 常驻 +/tmp/kill_el6695.sh # 停止全部实例 + +# TwinCAT 侧(非提权可读) +scripts\tc-ads-state.ps1 # 运行状态 +scripts\tc-ads-quick.ps1 # 速率 + bSync +scripts\tc-ads-lag.ps1 # nMatchLag 新鲜度采样 +scripts\tc-ads-mismatch-delta.ps1 # nMismatch 冻结检查 +scripts\tc-ads-soak.ps1 -Minutes N -LogFile X # 长测采样(WMI 方式后台启动) +scripts\tc-deploy-retry-800b.ps1 # 提权部署(构建+激活+重启) +```