观测控制 本页只读过程数据缓存,不连接、不重启、不停 PDO 循环
未开始
链路 —
AL —
热改周期走 /api/motor/period(循环每拍重读的变量,全程喂狗不断流,随时可调、可反复调)。
低于 1ms 档后端自动用自旋节拍,会占满一个 CPU 核;从站固件修好前别低于 1ms —— 实测
0.25 / 0.125ms 档 GD32 顶到 99.5%,CAN 到帧率 λ 从 4000/s 塌到 149/s(瓶颈在从站不在主站,
只看主站达成率会整条看漏)。
刷新率 实测 = Δcycles/Δt;名义 = 1000/period_ms 仅作对照,两者差值就是软件调度开销
单电机状态刷新
—Hz
slot_period_ms —
CAN 到帧率 λ
—/s
Δglobal_seq (u32)
真丢帧
—帧/拍
主站 seq 空洞 · 从站 OVF(抽样单拍值)
从站 CPU 负载
—
load_perm · age —
撕裂 / 重入
—
rx_torn / pdo_reentry
本页请求耗时
—ms
本页→代理→native 最慢一个请求的往返(≠节拍耗时)
判读:达成率 < 100% = 节拍被软件拖住;λ ÷ 实测Hz = 每拍到达几帧 CAN(当前 1ms 档实测 6 帧/拍)。
drop 不判好坏:它是段 1/段 3 那个"最近一帧"单格被未取先覆的次数,
而单格每拍只能发布 1 帧;且自增点在 STATUS 过滤之前(ethercat_can_bridge.cpp:398
对 :435),所以每拍到的 6 帧全算进来 → 恒等于 λ − 实测Hz,零独立信息量。
这些帧并没有丢:STATUS 由段 2 按槽常驻上报,其余进段 4 覆盖窗口(实测 lost/OVF 均 0)。
drop 哪天才有权报警:让只走单格的帧(版本/节点应答)承担可靠投递时。
真丢帧逐层看:① CAN 控制器 err/TEC/REC;② CAN 软件 RX 队列满(深度 16)的
rx_drop_count —— 只在 ESP32 /can/feedback 有,过程数据里没有;
③ 段 4 覆盖窗口 主站侧按 seq 空洞算的 rx_batch.lost(step/2−1,
发布值恒为偶数,按 step−1 会把每帧虚报成丢 1 个);④ 段 4 从站侧未取先覆
rx_batch.pending(= OVF,与 ③ 是两个独立仪表,正常应当同步增长);
⑤ CAN 取帧撕裂 rx_torn。③④ 是本页 10Hz 抽样看到的单拍值,只能当下界。
撕裂 / 重入是饱和计数(到 65535 停),封顶时只能报下界。
实时曲线 滚动 90s · 紫 = 实测 PDO Hz(左轴) · 青 = 单拍 p50 µs(右轴)
总线与从站 /api/status · /api/native/health · state.head
窗口自适应:win_bases 是当前收缩出的接收窗口基址数,
单槽刷新 = period_ms × win_bases.length;开机首圈先扫全表(6 拍)。
桥接计数 state.bridge · 桥全局,无按通道拆分 / 无 TEC·REC
过程数据里没有逐通道 TEC/REC —— 没有的就显示 —,
不编 0 让"总线正常"和"没这个数据"长得一模一样。
收到的东西 ① 电机状态槽 state.motors[] · 48B STATUS 解码(DBC Motor_CAN_FD v0.74)
逐槽原始 hex(48B 全长,16B 一行、多列排)
—
「速度参考」= RT_Velocity,是内部斜坡参考值而非实测转速,
不能拿去回答"三轴实际是否同步"。InitStatus 显示 — 表示这条链路没送
B32-35 —— 补 0 会把"无数据"显示成"初始化正常"。
收到的东西 ② 批量接收区 rxraw.parsed(与下面槽表同一拍快照)· 段 4 覆盖窗口去重后的事件流
本拍新帧 / seq 空洞 / 从站 OVF —
本页帧样本 —
覆盖窗口 5 槽原样(从站每拍整块拷出,写游标绕圈覆盖 —— 槽下标 ≠ 到达顺序,seq 才是顺序)。
末列「本拍新上报」:是 = 这一拍第一次见到这帧,主站把它交给上层;否 = 它是上一拍就交过的旧帧
(窗口只留"最近 5 帧",一帧会连续几拍都躺在里面,但不会被重复上报)。
按子码汇总(每 sub 一行的采样次数 / 最近载荷)
同一 ID + 同一载荷出现两次不是重复显示:主站已按每槽 seq 去重,同一帧不会报第二次。
实测 120 个窗口快照里「同 ID 且 seq 相同」0 次、「同 ID 但 seq 不同」240 次 —— 那是两帧真的各到达一次,
只是电机空闲时 CONFIG 回报的 24B 逐字节相同,肉眼看一模一样。看下面槽表的 seq 列即可分辨。
"前面像少了一帧"也不是丢帧:① 主站每拍只把 seq 比上次大的槽交给上层,上一拍已经交过的帧
仍躺在窗口里(就是末列的"否"),但不会再进上面的表;② 页面 10Hz 采样、PDO 1kHz,两次采样之间约
100 拍的窗口内容已被覆盖,看不见(所以"样本数"只占全量约 0.8%,全量看 λ 那张卡)。
本表能看到的丢帧判据只有两个:seq 空洞(主站侧)与 OVF(从站侧),
上面 pill 里实时显示,实测同为 0;本表看不到的还有三层 —— CAN 控制器 err/TEC/REC、
GD32 软件 RX 队列满丢(深度 16,只在 ESP32 /can/feedback 有)、CAN 取帧撕裂
rx_torn。逐层对账跑 scripts/can_bridge_reconcile.py。
长帧(CONFIG 24B / 版本应答)在 8B 短快照里会被截断,所以后端另开 state.xrx 长帧槽,
逐字节的真凭实据在下面第 ③ 区的原始窗口里。
收到的东西 ③ 原始接收窗口 + 长帧 + 逐拍环 /api/motor/rxraw · state.xrx · /api/motor/dbg(全为只读缓存拷贝)
layout:win=1.6.15 定长覆盖窗口 / slim=变长 / old=旧布局,解析器必须按 layout 选,
否则拿变长游标解定长窗口会整片错位。
xrx 长帧完整载荷(kv 里那行是截断的,这里不截)
—
逐拍环未开启。开启后实测每次约 160KB(后端 RING=2048 拍),
只在需要看抖动分布时开,别常年挂着 —— 仪表本身也是负载。
覆盖窗口原始字节 —— 按 44B/槽分组:头 12B(ch dlc flags pad ‖ id LE ‖ seq LE)+ 数据 32B(两行)
—