Files
linuxcncWebWASM/doc-rtcp/xyzac-trt-control-panel-web-wasm-design.md

530 lines
24 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `xyzac-trt.ini` 控制面板、数据流、控制约束与 Web/WASM 设计基础
更新时间:2026-08-25
本文专门分析:
```text
linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini
```
目标不是复刻一个静态 AXIS 外观,而是为 Web/WASM 控制台建立可验证的功能、数据、控制和权限模型。所有“按钮是否可点”的结论都必须来自 LinuxCNC authoritative task/motion/HAL 状态;React/浏览器只能投影状态并发出带 gate 的命令。
相关运行入口和基础说明:
- [`run-5axis-rtcp.sh`](../run-5axis-rtcp.sh)
- [`5axis-rtcp-shortcut.md`](5axis-rtcp-shortcut.md)
- [`gmoccapy-control-panel-data-control-flow.md`](gmoccapy-control-panel-data-control-flow.md)
- [`5axis-rtcp-running.png`](5axis-rtcp-running.png)
## 1. 案例边界
### 1.1 入口配置
`xyzac-trt.ini` 的关键配置如下:
| INI 段 | 字段 | 功能 |
|---|---|---|
| `[EMC]` | `MACHINE = sim-xyzac-trt-kins (switchkins)` | 案例名称和 switchkins 语义 |
| `[DISPLAY]` | `DISPLAY = axis` | 主控制面板是 AXIS/Tk,不是 GMOCCAPY |
| `[DISPLAY]` | `OPEN_FILE = ./demos/xyzac_switchkins.ngc` | 启动后预置的 G-code 文件 |
| `[DISPLAY]` | `PYVCP = ./xyzac-trt.xml` | 右侧 SWITCHKINS/vismach-clear 面板 |
| `[DISPLAY]` | `JOG_AXES = XYZC` | 手动点动显示 X/Y/Z/C;A 仍属于五轴运动学 |
| `[DISPLAY]` | `PROGRAM_PREFIX = ../../nc_files` | 默认程序搜索目录 |
| `[DISPLAY]` | `POSITION_OFFSET = RELATIVE` | DRO 默认显示相对坐标 |
| `[DISPLAY]` | `POSITION_FEEDBACK = ACTUAL` | DRO 使用 actual position |
| `[RS274NGC]` | `SUBROUTINE_PATH = ./remap_subs` | M428/M429/M430 和 helix 子程序路径 |
| `[RS274NGC]` | `HAL_PIN_VARS = 1` | 允许 remap 访问 HAL pin |
| `[RS274NGC]` | `REMAP = M428/M429/M430` | kinematics 状态切换入口 |
| `[RS274NGC]` | `PARAMETER_FILE = xyzac.var` | RS274 参数持久化 |
| `[KINS]` | `KINEMATICS = xyzac-trt-kins sparm=identityfirst` | 5 关节 XYZAC,0=identity,1=TRT,2=userk |
| `[KINS]` | `JOINTS = 5` | X/Y/Z/A/C 五个 joint |
| `[HAL]` | `HALFILE = LIB:basic_sim.tcl` | 生成仿真 motion/HAL/模拟设备 |
| `[HAL]` | `POSTGUI_HALFILE = switchkins_postgui.hal` | GUI 创建后连接 PyVCP 控件 |
| `[HAL]` | `motion.analog-out-03 => motion.switchkins-type` | remap 写入 switchkins 的控制通道 |
| `[HAL]` | `loadusr -W xyzac-trt-gui` | 独立 Vismach 五轴模型进程 |
| `[TRAJ]` | `COORDINATES = XYZAC` | 解释器和轨迹规划的笛卡尔坐标集合 |
| `[EMCIO]` | `TOOL_TABLE = xyzac-trt.tbl` | 工具长度/直径等数据 |
### 1.2 三个界面实体
```text
AXIS 主窗口
├── Tk 菜单、工具栏、Manual Control、MDI、Preview、DRO、G-code view
├── PyVCP xyzac-trt.xml(右侧 SWITCHKINS 面板)
└── AXIS 内部 Python/Tk command + linuxcnc.stat 状态轮询
xyzac-trt-gui 进程
└── Python vismach 模型,仅消费 HAL joint feedback/tool-offset/offset
LinuxCNC runtime
├── linuxcncsvr / NML
├── milltask / RS274NGC interpreter
├── motmod / TP / switchkins / xyzac-trt-kins
└── HAL / simulated home / spindle / tool-change / PyVCP pins
```
AXIS 是控制和状态投影者,PyVCP 是 HAL 控件,Vismach 是可视化消费者;三者都不是独立的运动 authority。
## 2. 启动与初始化数据流
```text
run-5axis-rtcp.sh
│
▼
/usr/bin/linuxcnc -r xyzac-trt.ini
│
├── 读取 [DISPLAY]/[TASK]/[HAL]/[KINS]/[TRAJ]
├── 启动 linuxcncsvr
├── 启动 milltask
├── 运行 basic_sim.tcl 生成 HAL
├── loadusr xyzac-trt-gui
├── 执行 switchkins_postgui.hal
└── 启动 /usr/bin/axis -ini xyzac-trt.ini
│
├── open_file_guts(OPEN_FILE)
├── 创建 Tk/AXIS widgets
├── 读取 linuxcnc.stat
└── 周期刷新 DRO/preview/gates
```
### 2.1 AXIS 初始化的责任
主要来源:
```text
linuxcnc/src/emc/usr_intf/axis/scripts/axis.py
```
核心职责:
1. 解析 INI 和显示选项。
2. 初始化 `linuxcnc.command()`、`linuxcnc.stat()` 和 HAL component。
3. 根据 `COORDINATES=XYZAC` 建立 axis/joint 映射。
4. 读取 `OPEN_FILE`,通过 `open_file_guts()` 和 `c.program_open()` 载入程序。
5. 读取 G-code,运行 canon/preview 生成程序轨迹。
6. 周期 `s.poll()`,将 position、joint position、homed、limit、tool、G/M code、task/interpreter state 投影到 Tk 变量。
7. 根据 `running()`、`manual_ok()`、`all_homed()` 和 task/motion 状态决定按钮是否响应。
### 2.2 Vismach 初始化的责任
`linuxcnc/src/hal/user_comps/vismach/xyzac-trt-gui.py` 创建 HAL component:
```text
xyzac-trt-gui.table-x HAL_FLOAT IN
xyzac-trt-gui.saddle-y HAL_FLOAT IN
xyzac-trt-gui.spindle-z HAL_FLOAT IN
xyzac-trt-gui.tilt-a HAL_FLOAT IN
xyzac-trt-gui.rotate-c HAL_FLOAT IN
xyzac-trt-gui.y-offset HAL_FLOAT IN
xyzac-trt-gui.z-offset HAL_FLOAT IN
xyzac-trt-gui.tool-offset HAL_FLOAT IN
```
模型通过 `HalTranslate`/`HalRotate` 将这些输入转换为 OpenGL 模型姿态。它不发 `program_run`、`jog`、`home` 或 kinematics 命令。
## 3. AXIS 主控制面板功能
### 3.1 顶部菜单和工具栏
AXIS/Tk 主面板通常提供:
| 类别 | 典型动作 | LinuxCNC command/效果 |
|---|---|---|
| 文件 | Open | `program_open(path)`,更新 loaded file 和 preview |
| AUTO 按钮组 | `hbtb_auto` / `btn_load` | AXIS 的 Open/Load 文件入口;只在程序未运行时打开文件选择器 |
| 文件 | Reload | 重新读取当前文件;运行中拒绝 |
| 文件 | Recent files | 偏好文件保存最近路径,最多 10 项 |
| 文件 | Edit | 调用 `EDITOR`/外部编辑器;不改变 runtime authority |
| 程序 | Run | `c.mode(MODE_AUTO)` + `c.auto(AUTO_RUN, start_line)` |
| 程序 | Step | `c.auto(AUTO_STEP)` |
| 程序 | Pause | `c.auto(AUTO_PAUSE)` |
| 程序 | Resume | `c.auto(AUTO_RESUME)` |
| 程序 | Stop | `c.abort()`,同时设置 GUI abort 状态 |
| 程序 | Run from line | 设置 first line 后再 AUTO_RUN,风险高于普通 Run |
| 机床 | Power | `c.state(STATE_ON/OFF)` |
| 机床 | E-stop | `c.state(STATE_ESTOP/STATE_ESTOP_RESET)` 或硬件链路 |
| 机床 | Home/Unhome | `c.home(joint)` / `c.unhome(joint)` |
| 机床 | Spindle | `c.spindle(...)` 或 MDI/halui |
| 机床 | Feed/rapid/spindle override | `c.feedrate()`/`c.maxvel()` 或相应 HAL/command |
| 辅助 | HAL show/tooleditor | 外部工具或 tool data action |
| 视图 | Perspective/X/Y/Z/clear plot | 只改变 view/preview,不改变运动状态 |
菜单图标不是 authority。每个动作必须以 command result 和下一次 status snapshot 确认。
### 3.2 Manual Control
Manual 页包含:
- X/Y/Z/A/C 轴选择;`JOG_AXES=XYZC` 会影响默认可点动轴列表。
- Continuous/incremental jog 选择。
- jog speed、angular jog speed。
- Home All、单轴 Home、Unhome。
- Touch Off、Tool Touch Off。
- feed/rapid/spindle override。
- spindle start/stop/reverse。
AXIS 的 `manual_ok()` 条件:
```text
task_state == STATE_ON
并且当前没有 AUTO/MDI 正在运行
并且 interp_state == INTERP_IDLE
或当前为 MDI 且 queued_mdi_commands < max_queued_mdi_commands
```
`jog_on()` 还要满足当前 tab 是 manual、轴/joint 映射有效、没有 active limit 阻止动作。Web/WASM 应把这些结果作为 gate reason 返回,不仅仅把 HTML button 设为 disabled。
### 3.3 MDI
MDI 入口通过 `ensure_mdi()`:
1. 检查 `manual_ok()`。
2. 关闭 teleop 或切换到合适 motion mode。
3. `c.mode(MODE_MDI)`。
4. 用户输入字符串后调用 `c.mdi(command)`。
5. interpreter 执行后由 `stat.interp_state`、`queued_mdi_commands`、位置和错误通道反馈。
MDI 不是任意字符串的本地脚本执行器。Web/WASM 必须保留 G-code parser、能力边界、长度限制、错误码和 operation id。
### 3.4 Preview/DRO/G-code view
AXIS 周期更新同时刷新:
- `stat.actual_position` / `joint_actual_position` → DRO。
- `stat.g5x_offset` / `g92_offset` / `rotation_xy` / `tool_offset` → 坐标投影。
- `stat.gcodes` / `stat.mcodes` / `settings` → G-code 信息。
- canon/preview → 静态程序路径。
- `motion_line` / `running_line` → 当前行高亮。
- `joint.pos-fb` → Vismach 模型。
静态 preview 和 realtime/live plot 必须分开建模;Web 端不能用 JS 重新解析一份程序来代替 WASM canonical motion。
## 4. `xyzac-trt.xml` SWITCHKINS 面板
### 4.1 控件定义
PyVCP XML 定义:
| 控件文本 | HAL pin | 目标 |
|---|---|---|
| `IDENTITY` | `pyvcp.type0-button` | 触发 `halui.mdi-command-00` → M429 |
| `TCP:XYZAC` | `pyvcp.type1-button` | 触发 `halui.mdi-command-01` → M428 |
| `userk` | `pyvcp.type2-button` | 触发 `halui.mdi-command-02` → M430 |
| 多标签 | `kinstype.is-0/1/2` | 显示当前 switchkins type |
| `vismach-clear` | `pyvcp.vismach-clear` | 连接 `vismach.plotclear` |
`switchkins_postgui.hal` 将按钮连接到 HALUI MDI command:
```text
pyvcp.type0-button → halui.mdi-command-00
pyvcp.type1-button → halui.mdi-command-01
pyvcp.type2-button → halui.mdi-command-02
```
这意味着浏览器端的“TCP:XYZAC”按钮不能直接写 `motion.switchkins-type`,应走同等的受控 command/remap 路径,并等待确认状态。
### 4.2 switchkins 状态模型
```text
type 0 / M429 → identity
type 1 / M428 → xyzac TRT TCP/RTCP
type 2 / M430 → userk
```
`xyzac-trt-kins.c` 在 `sparm=identityfirst` 下将 type 0 绑定 identity,type 1 绑定 `trtKinematicsSetup + xyzacKinematicsForward/Inverse`,type 2 绑定 userk。配置注释和实现必须同时读取,不能只依据面板标签。
## 5. 五轴 RTCP 控制流
### 5.1 M428/M429 remap
`428remap.ngc` 的关键操作:
```text
验证 motion.switchkins-type HAL pin 存在
M68 E3 Q1 写 motion.analog-out-03 = 1
M66 E0 L0 同步等待
读取 motion.switchkins-type,必须等于 1
```
`429remap.ngc` 相同,但写入 `Q0`。失败时输出 debug STOP 并结束子程序;Web/WASM 需要把这些失败变成稳定的错误码,而不是只显示“按钮没有反应”。
### 5.2 典型 helix 数据流
`helix_ac.ngc` 的典型顺序:
```text
M429 identity
G0 / G10 L20 机床坐标定位和设置工作偏置
M428 XYZAC TRT / TCP
G0 A... C... 改变刀轴姿态
G2 ... 在 RTCP 运动学下插补
M429 切回 identity
G0 ... 安全返回
M428 如后续仍需 TCP
```
这里的关键不是“同时有 A/C 数字”,而是同一轨迹块由 XYZAC inverse kinematics 将 TCP pose 转换为五个 joint 命令。姿态变化可能导致 X/Y/Z 补偿变化;因此前端必须同时展示笛卡尔 pose、joint positions、active kinematics mode 和 tool offset。
### 5.3 Vismach 数据流
```text
joint.0.pos-fb → table-x → HalTranslate
joint.1.pos-fb → saddle-y → HalTranslate
joint.2.pos-fb → spindle-z → HalTranslate
joint.3.pos-fb → tilt-a → HalRotate(A)
joint.4.pos-fb → rotate-c → HalRotate(C)
motion.tooloffset.z → tool-offset → HalTranslate(tool)
y/z-offset → rotary geometry placement
```
Vismach 只读 HAL input。Web/WASM 的 Three.js adapter 应消费 authoritative `visual.pose`/`joints`/`toolpath`,而不是在 React 中根据 A/C 自行推算补偿。
## 6. 按钮互相制约条件
下表是 AXIS/LinuxCNC 语义的最小可执行门控。`running` 表示 AUTO 或 MDI 且 `interp_state != INTERP_IDLE`。
| 按钮/动作 | 必须满足 | 典型阻塞原因 |
|---|---|---|
| E-stop | 始终可用 | transport/session 不可用 |
| Power ON/OFF | 非 ESTOP;不在禁止转换状态 | `ESTOP_ACTIVE` |
| Reset | machine ON、非 running、无 active limit | `LIMIT_ACTIVE` / `INTERP_RUNNING` |
| Manual jog | `STATE_ON`、MANUAL、非 running、未 fault | `MACHINE_OFF` / `MODE_REQUIRED` |
| Home all | `manual_ok()`;必要时确认重复 homing | `NOT_ON` / `RUNNING` |
| 单轴 Home | `manual_ok()`;非 identity 时通常必须 joint mode;重复坐标字母禁用单轴 home | `JOINT_MODE_REQUIRED` |
| MDI | machine ON;队列未满;idle 或当前 MDI | `MDI_QUEUE_FULL` / `INTERP_RUNNING` |
| Open file | 解释器 idle;AXIS `open_file_guts` 临时切 MANUAL 后恢复原 mode | `INTERP_RUNNING` |
| Load program | machine ON、idle | `MACHINE_OFF` |
| Reload | idle 且已有 loaded file | `TASKFILE_MISSING` |
| Run | machine ON、idle、已有程序 | `TASKFILE_MISSING` / `INTERP_RUNNING` |
| Run from line | Run 条件 + 有明确 highlight line | `HIGHLIGHT_MISSING` |
| Step | machine ON 且有程序;进入 AUTO | `TASKFILE_MISSING` |
| Pause | machine ON 且 interpreter READING/WAITING | `PAUSE_STATE_GATE` |
| Resume | machine ON 且 interpreter PAUSED | `RESUME_STATE_GATE` |
| Stop/Abort | machine ON 且 running;abort 可以强制恢复状态 | `STOP_STATE_GATE` |
| Touch Off | manual_ok、MANUAL、允许的 motion mode | `JOINT_MODE_REQUIRED` |
| Tool Touch Off | Touch Off 条件 + 有当前工具 | `TOOL_MISSING` |
| TCP:XYZAC/M428 | remap HAL pin 存在、HAL net 正确、当前程序允许切换 | `MISSING_HAL_PIN` / `WRONG_SWITCHKINS_TYPE` |
| Identity/M429 | 同上,切换后必须确认 type=0 | `WRONG_SWITCHKINS_TYPE` |
| Vismach clear | 只清显示 plot,不改变 task/motion | 不应改变机床状态 |
### 6.1 重要状态互斥
```text
ESTOP → 禁止所有运动、模式、MDI、RTCP 切换
OFF → 可以复位/上电,禁止 Run/Jog/Home/MDI
ON + 未 homed → 允许 Manual/Home,禁止 AUTO/MDI(除非配置 NO_FORCE_HOMING)
RUNNING → 禁止 Open/Reload/Edit/MDI/Jog/Home;允许 Pause/Stop/状态观察
PAUSED → 允许 Resume/Stop;禁止 MDI/Jog/重新加载
RTCP type switch → 应在 interpreter idle、安全位置、无活动轨迹时执行
```
## 7. 当前 Web/WASM 的对应实现
### 7.1 已存在的通用契约
当前 Web 代码已经提供可复用基础:
| 文件 | 作用 |
|---|---|
| `web/app/axis-contract.mjs` | `AXIS_COMMANDS`、状态归一化、纯 gate 函数 |
| `web/app/axis-operation-controller.mjs` | operation id、gate 检查、command trace、错误保留 |
| `web/react/src/protocol.ts` | `MessageEnvelope`、`SimSnapshotV1`、`PanelSnapshotV1`、`AxisStateView` |
| `web/react/src/store.ts` | Worker message → authoritative snapshot/projected UI state |
| `web/react/src/worker-client.ts` | Dedicated Worker transport、seq、session/context、错误处理 |
| `web/react/src/visual-workflow.ts` | AXIS/GMOCCAPY/Vismach 的 visual source 分类 |
现有 `AXIS_COMMANDS` 已覆盖 `PROGRAM_LOAD/RUN/STEP/PAUSE/RESUME/ABORT/RESTART`、`MDI_EXECUTE`、`JOG_START/STOP`、`HOME`、`ESTOP`、`RESET`、override、spindle、coolant、tool 和 probe。
### 7.2 `xyzac-trt` 需要的新增协议字段
建议在现有 `PanelSnapshotV1` 上 additive 扩展,不破坏 `sim_task.v1`:
```json
{
"configuration": {
"case_path": "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini",
"coordinates": ["X", "Y", "Z", "A", "C"],
"kinematics": "xyzac-trt-kins",
"topology": "table-tilting-A/table-rotary-C",
"joint_count": 5,
"program_prefix": "../../nc_files"
},
"kinematics": {
"family": "switchkins",
"active_type": 1,
"active_name": "xyzac-trt",
"available": [
{"type": 0, "name": "identity", "command": "M429"},
{"type": 1, "name": "xyzac-trt", "command": "M428"},
{"type": 2, "name": "userk", "command": "M430"}
],
"transition": "idle_only"
},
"motion": {
"axes": {"x": 0, "y": 0, "z": 10, "a": 0, "c": 0},
"joints": [0, 0, 10, 0, 0],
"tool_offset": {"z": 0},
"rotation_center": {"x": 0, "y": 0, "z": 0},
"axis_offsets": {"y": 20, "z": 10}
}
}
```
字段的 authoritative 来源必须来自 WASM kinematics/motion snapshot 或受控 native oracle;不能由 A/C slider 在浏览器中自行补偿。
### 7.3 命令映射建议
| Web action | protocol command | xyzac 行为 |
|---|---|---|
| `PROGRAM_LOAD` | `PROGRAM_LOAD` | 载入程序、canonical preview、重置 active segment |
| `PROGRAM_RUN` | `PROGRAM_RUN` | 进入 AUTO,固定 tick 推进 interpreter/TP |
| `PROGRAM_PAUSE` | `PROGRAM_PAUSE` | 保留当前 segment/kinematics type |
| `PROGRAM_RESUME` | `PROGRAM_RESUME` | 继续同一 program state |
| `PROGRAM_ABORT` | `PROGRAM_ABORT` | 停止并返回稳定 STOPPED/IDLE |
| `MDI_EXECUTE` | `MDI_EXECUTE` | 用于 `M428`/`M429`/`M430`,必须有 idle gate |
| `KINEMATICS_SELECT` | 建议新增 | payload `{type:0\|1\|2}`,内部走 remap/受控 HAL,不直接写 pin |
| `JOG_START` | `JOG_START` | 仅允许合法 axis/joint;XYZAC 的 A/C 速度单位独立校验 |
| `HOME` | `HOME` | 返回每个 joint homed 状态和错误 |
| `VISMACH_CLEAR` | `VISUAL_CLEAR` | 只清可视化轨迹,不清 task/motion/program |
### 7.3.1 当前 Web 实现的五轴缺口
现有通用 AXIS contract 已有大量三轴/通用动作,但对本案例仍有明确缺口,不能把“按钮存在”当成已实现:
| 缺口 | 当前状态 | 五轴实现要求 |
|---|---|---|
| `KINEMATICS_SELECT` | `AXIS_COMMANDS` 尚未定义 | 新增受 gate 的 type 0/1/2 命令,禁止前端直接写 HAL |
| `POWER` | `axisGate()` 有 `power` 分支,但 `AXIS_COMMANDS` 没有对应 action | 补齐 command map 和 Worker handler,保持 OFF/ESTOP 语义 |
| `VISUAL_CLEAR` | 原生 PyVCP 有 `vismach-clear`,通用 Web command 尚未固定 | 作为 visual-only command,不能改 program/motion hash |
| A/C jog | 当前 React 示例轴选择主要是 X/Y/Z | 增加 A/C angular units、limits、jog speed 和 joint/teleop gate |
| XYZAC pose | `PanelSnapshotV1.visual.pose` 目前是通用 Record | 增加明确 `a/c`、joint vector、kinematics type 和 tool-offset 字段 |
| rotation centers | 当前通用 snapshot 没有 TRT rotation-point 完整字段 | 将 x/y/z rotation point、y/z offset 纳入 configuration/authoritative |
| switchkins recovery | 通用 recovery 有 task/program,但没有 active kinematics mode | checkpoint 必须保存 type、remap transition、source line、joint/pose hash |
### 7.4 Worker snapshot 到 React
```text
WASM/native runtime
└── task + interpreter + motion + joints + kinematics + HAL + devices
│
▼
protocol.v1 STATE_SNAPSHOT / COMMAND_RESULT
│
▼
store.ts projection()
├── axis_state
├── gates
├── task/program
├── motion.axes / motion.joints
├── authoritative.planner / authoritative.kinematics
└── visual.pose / visual.toolpath
│
▼
React DRO / controls / Three.js Vismach
```
React 控件的 `disabled` 只是 projection;真正 gate 必须在 Worker/runtime 再检查一次。`AxisOperationController` 已提供 operation id、拒绝原因和 trace 结构,五轴切换应复用此机制。
## 8. Web/WASM 不应直接照搬的部分
| 原生机制 | Web/WASM 处理 |
|---|---|
| Tk widget/菜单 | React button/menu/keyboard command,但保留 source control id 和 tooltip 语义 |
| LinuxCNC NML | Dedicated Worker protocol envelope + session/seq/operation_id |
| HAL pin `motion.switchkins-type` | Worker-owned runtime capability;浏览器不能任意写 HAL pin |
| `loadusr -W xyzac-trt-gui` | Worker/Three.js Vismach adapter;visual-only,不是 authority |
| `OPEN_FILE` | Worker workspace resolver + exact path/resource closure |
| `G-code preview` | WASM canonical interpreter/TP segments;不能用 JS preview 冒充 |
| `linuxcnc.stat()` polling | fixed-tick STATE_SNAPSHOT/EVENT,带 state_hash |
| M428/M429 remap | WASM remap/interpreter capability,记录切换、错误和首个 divergent tick |
| POSIX realtime/HAL hardware | SIM-DEVICE 或 REAL-EXCLUDED,不能静默当成 Web 等价 |
## 9. 推荐的 Web 端组件拆分
```text
XyzacTrtCaseResolver
├── exact ini/hal/remap/resource resolver
└── startup diagnostics
XyzacTrtControlStore
├── axis_state / task / interp / homed / limits
├── kinematics.active_type
├── gates and gate reasons
└── command trace
XyzacTrtOperationController
├── PROGRAM_LOAD/RUN/PAUSE/RESUME/ABORT
├── MDI M428/M429/M430
├── JOG/HOME/override
└── transition checks: idle, no fault, valid capability
XyzacTrtPanel
├── mode/task controls
├── XYZAC DRO and joint view
├── TCP/identity/userk segmented control
├── gate-aware MDI/run/jog/home buttons
└── alarms and diagnostics
XyzacTrtVismach
├── pose/joints/toolpath from authoritative snapshot
├── A/C table rotation
├── tool-offset rendering
└── canvas/WebGL pixel/interaction checks
```
## 10. 验收和测试矩阵
### 正常流程
1. 加载 `xyzac_switchkins.ngc`。
2. 验证 `XYZAC` 五个轴和五个 joints 出现在 snapshot。
3. 验证 preview segment/source line/hash。
4. `M429` → active type 0。
5. `M428` → active type 1,等待确认后再允许 TCP 轨迹。
6. 运行包含 A/C 变化的 helix;比较 Cartesian pose、joint positions、tool offset。
7. `M429` 安全返回;验证 no duplicate segment/no stale active segment。
### 边界和拒绝
| 测试 | 期望 |
|---|---|
| ESTOP 时 M428 | blocked,不改变 kinematics type |
| interpreter running 时 M428 | blocked 或排队策略明确,不能隐式切换 |
| 缺 `HAL_PIN_VARS=1` | remap 错误码 `M428:Missing...`,保留证据 |
| 缺 `motion.switchkins-type` net | `WRONG_SWITCHKINS_TYPE`/source diagnostic |
| A/C 超限 | limit/fault snapshot,禁止继续运动 |
| tool offset 非有限值 | fail closed,不能送入 kinematics |
| pause 后 resume | segment、kinematics type、state hash 连续 |
| abort 后 reload | program/task/preview 清理顺序确定 |
| Worker restart | checkpoint 恢复 kinematics type、program line、joint/pose hash |
| Vismach clear | 只清 visual layer,task/program/state_hash 不变 |
### 必须保存的证据
- context id、case path、INI/HAL/remap source hash。
- command envelope、operation id、gate result、command result。
- 每个固定 tick 的 task/interp/motion/kinematics state hash。
- Cartesian pose、XYZAC joint vector、tool offset、active segment/source line。
- 首个 divergent tick、错误码、资源缺失分类。
- native/WASM/Worker 对照结果;不以单一截图替代。
## 11. 已知限制
- 当前 `xyzac-trt.ini` 是 AXIS + PyVCP + 独立 Vismach 的 LinuxCNC 原生案例;Web/WASM 尚未声明其完整五轴 RTCP parity 已完成。
- 当前环境使用 POSIX non-realtime;不提供实时硬件周期、延迟和驱动证明。
- `xyzac-trt-gui` 只可视化 joint feedback/tool offset;它不是 canonical motion authority。
- 官方 kinematics oracle 缺失时,native/WASM 结果只能作为实现证据,不能伪称官方 golden。
- `xyzac-trt` 配置中的 `x-rot-point/y-rot-point/z-rot-point` 在示例中固定为 0,且注释说明当前 Vismach GUI 不支持通过 GUI 调整;Web 端必须把它作为配置/能力字段,而不是随意暴露可写 slider。
## 12. 后续实现顺序
1. 建立 exact-path `xyzac-trt.ini` resolver 和 resource graph。
2. 在 Worker/WASM 建立 additive `kinematics` snapshot 与 `KINEMATICS_SELECT` command。
3. 将 M428/M429/M430 的 remap 行为接入固定 tick interpreter,先做拒绝和错误边界。
4. 将 XYZAC Cartesian/joint/tool-offset canonical snapshot 接到 Three.js Vismach adapter。
5. 实现 gate matrix:ESTOP/OFF/ON/HOME/IDLE/RUNNING/PAUSED/limit/fault。
6. 完成 program load/run/pause/resume/abort/restart + RTCP switch recovery 测试。
7. 运行 native/Worker/browser 三方对照,并记录首个差异 tick。
8. 只有 source/resource/oracle/recovery/浏览器边界均有证据后,才可提升为 selected-case verified;不能从一个 AXIS 截图直接宣称全 LinuxCNC 五轴 parity。