Files
cnc_wams/web-rtcp-5axis-xyzbc-trt-sim-plan/working/20-20260707-AXIS按钮LinuxCNC真实C++对标实施步骤.md
2026-07-07 18:45:26 -04:00

295 lines
12 KiB
Markdown
Raw 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.
# 2026-07-07 AXIS 按钮 LinuxCNC 真实 C++ 对标实施步骤
## 1. 实施原则
本文件由 `19-20260707-AXIS按钮LinuxCNC-task-motion状态机制源码分析.md` 拆分而来,目标是把源码分析转成可执行的工程步骤。后续实现不能以 `compare 60/60 pass` 作为功能完成依据;`60/60 pass` 只能说明当前 compare 规则没有发现问题。真实合格标准必须是Web 项目的按钮、状态、Task/HAL/WASM、evidence 和 UI 行为逐项符合 LinuxCNC C++ task/motion/homing 的真实实现。
权威基线:
- LinuxCNC 源码:`/home/mes123456/cnc_wams/linuxcnc`
- 目标项目:`/home/mes123456/cnc_wams/web-rtcp-5axis-xyzbc-trt-sim-plan`
- 核心 C++ 对标文件:
- `linuxcnc/src/emc/task/emctaskmain.cc`
- `linuxcnc/src/emc/task/emctask.cc`
- `linuxcnc/src/emc/task/taskintf.cc`
- `linuxcnc/src/emc/motion/command.c`
- `linuxcnc/src/emc/motion/control.c`
- `linuxcnc/src/emc/motion/homing.c`
- `linuxcnc/src/emc/nml_intf/emc.hh`
- `linuxcnc/src/emc/nml_intf/emc_nml.hh`
## 2. 实施输出物
必须形成以下输出物:
| 输出物 | 目标 |
|---|---|
| C++ 行为映射表 | 每个按钮对应 LinuxCNC 源码入口、NML 命令、task 处理、motion 处理、状态字段 |
| Web 状态字段表 | `machine.taskState/mode/interpState/...` 与 LinuxCNC `EMC_STAT` 字段一一对应 |
| Task/HAL/WASM 命令 ABI | `EMC_TASK_SET_STATE``EMC_TASK_SET_MODE``EMC_JOINT_HOME``EMC_TASK_PLAN_RUN/PAUSE/RESUME/STEP` 的 JSON 输入输出 |
| 硬门禁测试 | 不允许只靠 UI disabled必须验证底层 task runtime 拒绝非法命令 |
| 真实程序执行证据 | 用真实 G-code、真实 line/motion id、真实状态流证明 Run/Pause/Step/Home 行为 |
| compare 增强规则 | compare 不只检查字段存在和误差,还检查 C++ 状态机不可变规则 |
## 3. 阶段 1固定 LinuxCNC C++ 源码事实
### 3.1 建立源码事实清单
实施步骤:
1. 在工作文档中建立 `按钮 -> AXIS Python -> emcmodule -> NML -> emctaskmain -> emctask/taskintf -> motion` 的链路表。
2. 每条链路必须标注具体源码文件和函数名。
3. 每条链路必须标注输入命令、先决条件、状态变更、错误路径。
必须覆盖:
- 急停:`axis.py estop_clicked()``EMC_TASK_SET_STATE``emcTaskSetState(ESTOP/ESTOP_RESET)`
- 上电/下电:`axis.py onoff_clicked()``emcTaskSetState(ON/OFF)``EMCMOT_ENABLE/DISABLE`
- Home`home_all_joints()``home_joint()``EMC_JOINT_HOME``EMCMOT_JOINT_HOME``homing.c`
- Run`task_run()``EMC_TASK_PLAN_RUN``all_homed()``programStartLine``interpState=READING`
- Pause/Resume`task_pause()``task_pauseresume()``EMC_TASK_PLAN_PAUSE/RESUME``EMCMOT_PAUSE/RESUME`
- Step`task_step()``EMC_TASK_PLAN_STEP``stepping``single_stepping``EMCMOT_STEP`、motion id 变化后再暂停。
完成标准:
- 任一 Web 状态或测试断言都能追溯到 LinuxCNC C++ 源码。
- 没有“按前端习惯推测”的状态规则。
### 3.2 建立状态字段对应关系
实施步骤:
1. 对照 `EMC_STAT.task``motion.traj``motion.joint[]` 建立 Web 字段映射。
2. 区分 task 层暂停和 motion 层暂停。
3. 区分 task state 命令请求和最终发布状态。
必须字段:
```js
machine: {
taskState: "estop" | "estop-reset" | "on",
mode: "manual" | "auto" | "mdi",
interpState: "idle" | "reading" | "paused" | "waiting",
interpResumeState: "idle" | "reading" | "waiting",
execState: "done" | "waiting-for-motion" | "waiting-for-io" | "waiting-for-motion-and-io" | "error",
taskPaused: boolean,
motionPaused: boolean,
singleStepping: boolean,
motionStepping: boolean,
motionEnabled: boolean,
homing: boolean,
homed: boolean[],
allHomed: boolean,
noForceHoming: boolean,
resumeInhibit: boolean,
currentLine: number,
readLine: number,
motionLine: number
}
```
完成标准:
- `taskState` 不再只从 `powerOn` 派生,而是符合 LinuxCNC “IO estop + motion enabled” 语义。
- `paused` 不再是单字段,必须拆成 `interpState/taskPaused/motionPaused`
- `Step` 不再只用 `sampleIndex + 1` 表示,必须能表达 `singleStepping/motionStepping/motion id`
## 4. 阶段 2实现 Task/HAL/WASM 真实状态机
### 4.1 实现 NML 命令 ABI
实施文件:
- `wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_task_hal_wasm.cpp`
- `wasm-port/runtime/sdk/src/linuxcnc-task-hal.js`
- `web-rtcp-5axis-xyzbc-trt-sim-plan/app/src/runtime/linuxcnc-task-hal-runtime.js`
实施步骤:
1. 统一 JSON 命令名称为 LinuxCNC NML 名称。
2. 每条命令返回 command accepted/rejected、operator error、状态快照。
3. 非法命令必须在 runtime 层拒绝,不能只靠 UI gate。
命令要求:
| 命令 | 必须实现的 C++ 语义 |
|---|---|
| `EMC_TASK_SET_STATE ESTOP` | abort motion/task/io/spindledisable motion清 pause/stepvolatile home 处理 |
| `EMC_TASK_SET_STATE ESTOP_RESET` | IO estop offmachine offabort/synch |
| `EMC_TASK_SET_STATE ON` | motion enable只有 enable 成功后最终 state 才是 on |
| `EMC_TASK_SET_STATE OFF` | abort、disable、清运行、清 pause/step、volatile unhome |
| `EMC_TASK_SET_MODE MANUAL` | AUTO 非 idle 时拒绝或必须按 LinuxCNC abort/close/synch 语义处理 |
| `EMC_TASK_SET_MODE AUTO/MDI` | motion coord mode、abort、plan synch |
| `EMC_JOINT_HOME` | 只在 on/manual/free/idle/非 homing/homing-inhibit=false 时启动 |
| `EMC_TASK_PLAN_RUN` | on/auto/idle/homed/program open/motion plan loaded |
| `EMC_TASK_PLAN_PAUSE` | 保存 `interpResumeState`task paused + motion paused |
| `EMC_TASK_PLAN_RESUME` | 恢复 `interpResumeState`,清 single stepping |
| `EMC_TASK_PLAN_STEP` | idle step 等价 run 后 pausepaused step 放行到下一个 motion id |
完成标准:
- Runtime 层能在无 UI 的 Node 测试中复现所有先决条件和状态变化。
- 任一非法命令都有明确错误消息,且状态保持不被破坏。
### 4.2 实现 Home 状态机
实施步骤:
1. 增加 per-joint `homed[]``homing[]``homeState[]`
2. Home All 使用 `joint=-1`
3. Home 过程至少记录 `HOME_START -> HOME_FINISHED/HOME_IDLE` 的可观测状态。
4. 正在 homing 时再次 Home 必须拒绝。
5. 下电/急停只清 LinuxCNC 语义中应清的 home 状态;若当前 Web 无 volatile home 配置,必须显式记录简化边界。
完成标准:
- Home All 后所有 active joints `homed[] = true`
- Home 期间 Run、Step、Jog、再次 Home 都被拒绝。
- Evidence 能看到 homing 瞬态,不允许直接静默从 unhomed 跳到 homed 而无事件记录。
### 4.3 实现 Pause/Resume/Step 真实 motion 语义
实施步骤:
1. Pause 时冻结执行位置、active line、tcp pose、tool axis、feed velocity。
2. Resume 恢复 `interpResumeState`,不是固定写 `reading`
3. Step 从 idle 开始时:先进入 run再立即 pause。
4. Step 从 paused 开始时:只放行到下一个 `motionId/currentLine` 后再次 pause。
5. Abort、ESTOP、OFF、Resume 都必须清理 `singleStepping/motionStepping`
完成标准:
- 暂停期间 50ms 多帧采样位置完全冻结。
- Step 后 active line 或 motion id 按 LinuxCNC 语义变化,不能只看 sample index。
- Resume 后速度和执行状态恢复,且暂停锁消失。
## 5. 阶段 3收敛 Web 状态与 UI 门禁
实施文件:
- `app/src/state/linuxcnc-task-policy.js`
- `app/src/state/store.js`
- `app/src/ui/axis-shell.js`
- `app/src/ui/gmoccapy-shell.js`
实施步骤:
1. `linuxcnc-task-policy.js` 作为唯一按钮门禁入口。
2. UI 组件只读取 policy不再各自写 LinuxCNC 状态判断。
3. `store.js` 的每个 action 都映射到 LinuxCNC NML 命令或明确的 UI 辅助流程。
4. Task/HAL runtime 存在时,前端可先进入预期状态,但最终必须以 status 回写覆盖。
按钮 gate 要求:
| 按钮 | Web gate 必须等价的 LinuxCNC 条件 |
|---|---|
| ESTOP | 始终可触发 |
| RESET ESTOP | 当前 taskState=estop |
| POWER ON | taskState=estop-reset |
| POWER OFF | taskState=on |
| HOME | taskState=on、mode=manual、interpState=idle、非 homing |
| RUN | taskState=on、mode=auto、interpState=idle、allHomed 或 noForceHoming、programOpen |
| PAUSE | taskState=on、mode=auto、interpState=reading/waiting |
| PAUSE_RESUME | taskState=on、mode=auto/mdipaused 走 resume非 idle 走 pause |
| STEP | taskState=on、mode=auto、programOpen、已 homed 或 noForceHoming、resumeInhibit=false |
完成标准:
- UI 按钮禁用状态、operator message、runtime 拒绝状态三者一致。
- UI 显示状态必须能追溯到 task/HAL status而不是只看本地 `runState`
## 6. 阶段 4重构 evidence 与 compare
### 6.1 evidence 必须采真实功能
实施步骤:
1. Native evidence 采集 LinuxCNC 真实 `task.state/mode/interpState/execState/currentLine/readLine/motionLine`
2. Native evidence 采集 motion `enabled/paused/stepping/queue/motion id/homing/homed[]`
3. Web evidence 输出同名字段。
4. 每个按钮输出 action 前、命令接受/拒绝、action 后、下一周期状态。
必须新增 evidence 段:
```json
{
"taskMotionStateTrace": [],
"buttonCommandTrace": [],
"homingTrace": [],
"pauseFreezeTrace": [],
"stepMotionIdTrace": [],
"illegalCommandTrace": [],
"cppParityAssertions": []
}
```
完成标准:
- 证据能说明“为什么允许/拒绝”,而不是只说明最终 pass。
- 每个 pass 都有对应 LinuxCNC C++ 规则名称。
### 6.2 compare 必须从表面 pass 升级为硬规则
现有 `60/60 pass` 只能保留为兼容摘要。必须增加真实功能硬检查:
| 新检查 | 失败条件 |
|---|---|
| `cppTaskStateMachineParity` | Web 状态转移不符合 `emcTaskSetState()` 或 task update 推导 |
| `cppModeGateParity` | AUTO 非 idle 可切出或 MDI/AUTO gate 不符合 C++ |
| `cppHomingParity` | Home 无 homing 瞬态、非法 Home 未拒绝、homed[] 错误 |
| `cppRunGateParity` | 未 home 可 Run、非 idle 可 Run、无 program 可 Run |
| `cppPauseResumeParity` | pause 未冻结、resume 未恢复 `interpResumeState` |
| `cppStepParity` | Step 不是 motion id/line 语义,只推进 sample |
| `illegalCommandParity` | UI 禁用但 runtime 接受非法命令,或 runtime 拒绝但 UI 显示允许 |
| `realProgramExecutionParity` | 真实 G-code 执行 line/motion/path/status 与 native 不一致 |
完成标准:
- compare 输出 `surfaceSummary``functionalSummary` 两部分。
- 只有 `functionalSummary.failCount=0` 才能称为真实通过。
- `surfaceSummary 60/60 pass``functionalSummary` 失败时,结论必须是失败。
## 7. 阶段 5测试实现顺序
建议顺序:
1. 先补 Task/HAL runtime 的无 UI 状态矩阵测试。
2. 再补 store/action 状态测试。
3. 再补 UI gate 测试。
4. 再补 native/Web evidence 字段。
5. 最后补 compare functional checks。
对应测试文件建议:
| 测试文件 | 目标 |
|---|---|
| `wasm-port/tests/wasm/node/verify_task_state_matrix.mjs` | C++ task state/mode/run/pause/step/home gate |
| `wasm-port/tests/wasm/node/verify_task_hal_wasm.mjs` | WASM command ABI 和 status 字段 |
| `app/tests/node/verify_linuxcnc_task_policy.mjs` 或现有同类测试 | Web policy gate |
| `tests/node/verify_rtcp_store.mjs` | store action 状态写入 |
| `tests/node/verify_run_preconditions.mjs` | Run/Home/Power/ESTOP 前置 |
| `tests/browser/xyzbc_trt_browser_smoke.html` | UI 按钮状态与实际流程 |
| `tools/collect-native-xyzbc-trt-evidence.py` | native C++ 行为证据 |
| `tools/collect-web-xyzbc-trt-evidence.mjs` | Web 同名证据 |
| `tools/compare-xyzbc-trt-evidence.mjs` | functionalSummary 硬检查 |
## 8. 完成判定
实施完成必须同时满足:
1. C++ 源码规则已映射到文档和测试断言。
2. Task/HAL runtime 无 UI 情况下能拒绝非法命令。
3. Web UI gate、store 状态、runtime status 三者一致。
4. Native/Web evidence 包含真实状态流、非法命令、Home、Run、Pause、Step。
5. compare 输出功能级硬检查,且功能级检查通过。
6. 真实 G-code 程序执行过程中active line、motion id、path、pose、task/motion 状态与 LinuxCNC 对齐。
明确禁止把以下结果单独作为完成依据:
- `compare 60/60 pass`
- 页面截图看起来正常
- UI 按钮样式 active/disabled 正常
- 单个 smoke 测试通过
- Web 本地 `runState` 看起来合理