295 lines
12 KiB
Markdown
295 lines
12 KiB
Markdown
# 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/spindle,disable motion,清 pause/step,volatile home 处理 |
|
||
| `EMC_TASK_SET_STATE ESTOP_RESET` | IO estop off,machine off,abort/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 后 pause;paused 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/mdi,paused 走 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` 看起来合理
|
||
|