# `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。