566 lines
14 KiB
Markdown
566 lines
14 KiB
Markdown
# 02 RUN 前置条件、详细测试与编写步骤
|
||
|
||
生成时间:2026-06-22
|
||
|
||
## 1. 核心原则
|
||
|
||
`RUN` 不是孤立按钮逻辑。对五轴机床,必须先确定 LinuxCNC 机床上下文,再执行程序。
|
||
|
||
正确顺序是:
|
||
|
||
```text
|
||
明确 INI 文件
|
||
-> 确定机床类型、坐标轴、joint、HAL、remap、tool-table
|
||
-> 确定五轴运动学算法和 switchkins 映射
|
||
-> 验证 kinematics WASM 和 task/HAL runtime 已处在同一机床上下文
|
||
-> 加载并打开 G-code
|
||
-> RUN 发送 LinuxCNC task command
|
||
-> 持续 runCycles/readStatus 或 worker push feedback
|
||
-> UI 只消费 task/HAL/motion feedback
|
||
```
|
||
|
||
不能先写一个通用 `RUN`,再猜测当前机床是什么。否则 `activeLine`、DRO、RTCP、A/B/C 旋转轴、TCP 补偿和 switchkins 状态都可能来自不同来源。
|
||
|
||
## 2. 必须先确认的机床上下文
|
||
|
||
当前项目内可作为 `RUN` 上下文的五轴 profile 只有两个:
|
||
|
||
| profile | LinuxCNC INI | 机床类型 | 坐标 | kinematics module |
|
||
| --- | --- | --- | --- | --- |
|
||
| `xyzac-trt` | `configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini` | table rotary tilting | `XYZAC` | `xyzac-trt` |
|
||
| `xyzbc-trt` | `configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini` | table rotary tilting | `XYZBC` | `xyzbc-trt` |
|
||
|
||
源码落点:
|
||
|
||
```text
|
||
app/src/profiles/index.js
|
||
app/src/profiles/xyzac-trt.js
|
||
app/src/profiles/xyzbc-trt.js
|
||
app/src/runtime/linuxcnc-ini-runtime.js
|
||
app/src/runtime/linuxcnc-kinematics-runtime.js
|
||
wasm-port/runtime/sdk/src/linuxcnc-kinematics.js
|
||
```
|
||
|
||
### 2.1 `xyzac-trt`
|
||
|
||
必须确认:
|
||
|
||
```text
|
||
profile id: xyzac-trt
|
||
INI: configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini
|
||
[EMC] MACHINE: sim-xyzac-trt-kins (switchkins)
|
||
[TRAJ] COORDINATES: XYZAC
|
||
[KINS] KINEMATICS: xyzac-trt-kins sparm=identityfirst
|
||
WASM module id: xyzac-trt
|
||
WASM file: linuxcnc_xyzac_trt_kinematics.wasm
|
||
LinuxCNC source: src/emc/kinematics/xyzac-trt-kins.c
|
||
shared source: src/emc/kinematics/trtfuncs.c
|
||
switchkins source: src/emc/kinematics/switchkins.c
|
||
```
|
||
|
||
switchkins 映射:
|
||
|
||
```text
|
||
M429 -> switchkins type 0 -> identity
|
||
M428 -> switchkins type 1 -> tcp-xyzac
|
||
M430 -> switchkins type 2 -> userk
|
||
HAL link: motion.analog-out-03 => motion.switchkins-type
|
||
```
|
||
|
||
### 2.2 `xyzbc-trt`
|
||
|
||
必须确认:
|
||
|
||
```text
|
||
profile id: xyzbc-trt
|
||
INI: configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini
|
||
[EMC] MACHINE: sim-xyzbc-trt-kins (switchkins)
|
||
[TRAJ] COORDINATES: XYZBC
|
||
[KINS] KINEMATICS: xyzbc-trt-kins sparm=identityfirst
|
||
WASM module id: xyzbc-trt
|
||
WASM file: linuxcnc_xyzbc_trt_kinematics.wasm
|
||
LinuxCNC source: src/emc/kinematics/xyzbc-trt-kins.c
|
||
shared source: src/emc/kinematics/trtfuncs.c
|
||
switchkins source: src/emc/kinematics/switchkins.c
|
||
```
|
||
|
||
switchkins 映射:
|
||
|
||
```text
|
||
M429 -> switchkins type 0 -> identity
|
||
M428 -> switchkins type 1 -> tcp-xyzbc
|
||
M430 -> switchkins type 2 -> userk
|
||
HAL link: motion.analog-out-03 => motion.switchkins-type
|
||
```
|
||
|
||
## 3. RUN 前置状态检查
|
||
|
||
`RUN` action 进入真正执行前,应要求这些状态全部明确:
|
||
|
||
```text
|
||
state.profile.id 是 xyzac-trt 或 xyzbc-trt
|
||
state.profile.iniPath 非空且已加载
|
||
state.iniConfigReadiness.loaded === true
|
||
state.iniConfigReadiness.ready === true
|
||
state.iniConfigReadiness.coordinates 与 profile.traj.coordinates 一致
|
||
state.profile.kinematicsModuleId 与 INI [KINS] KINEMATICS 推导结果一致
|
||
state.kinematicsRuntimeReadiness.loaded === true
|
||
state.kinematicsRuntimeReadiness.moduleId === state.profile.kinematicsModuleId
|
||
state.rtcpFrame.sourceMode === source-derived-kinematics-wasm
|
||
state.machineFileStaging.status === staged
|
||
state.taskHalRuntimeReadiness.taskRuntimeReady === true
|
||
state.taskHalRuntimeReadiness.motionRuntimeReady === true
|
||
state.taskHalRuntimeReadiness.halRuntimeReady === true
|
||
state.taskHalSession.programPath 指向当前选中的 G-code
|
||
```
|
||
|
||
如果任一项不满足,`RUN` 应返回明确 operatorMessage,不应进入 fixture line playback 后伪装成真实运行。
|
||
|
||
建议阻断消息:
|
||
|
||
```text
|
||
run blocked: LinuxCNC INI not loaded
|
||
run blocked: machine profile and INI coordinates mismatch
|
||
run blocked: LinuxCNC kinematics runtime not ready
|
||
run blocked: task/HAL runtime not ready
|
||
run blocked: no machine-file G-code opened for task/HAL session
|
||
```
|
||
|
||
## 4. 详细测试计划
|
||
|
||
### 4.1 INI/profile 解析测试
|
||
|
||
目标:证明 `RUN` 使用的不是手写机床参数,而是明确 LinuxCNC INI。
|
||
|
||
测试文件建议:
|
||
|
||
```text
|
||
tests/node/verify_run_preconditions.mjs
|
||
```
|
||
|
||
断言:
|
||
|
||
```text
|
||
1. 读取 xyzac-trt.ini,parseLinuxCncIni() 返回:
|
||
profileId=xyzac-trt
|
||
machineName=sim-xyzac-trt-kins (switchkins)
|
||
traj.coordinates=XYZAC
|
||
kinematics.name=xyzac-trt-kins
|
||
kinematicsModuleId=xyzac-trt
|
||
validation.ready=true
|
||
|
||
2. 读取 xyzbc-trt.ini,parseLinuxCncIni() 返回:
|
||
profileId=xyzbc-trt
|
||
machineName=sim-xyzbc-trt-kins (switchkins)
|
||
traj.coordinates=XYZBC
|
||
kinematics.name=xyzbc-trt-kins
|
||
kinematicsModuleId=xyzbc-trt
|
||
validation.ready=true
|
||
|
||
3. applyIniConfigToProfile() 后:
|
||
profile.traj.coordinates 与 INI 一致
|
||
profile.kinematicsModuleId 与 INI 推导结果一致
|
||
axisLimits 和 jointConfig 来自 INI
|
||
```
|
||
|
||
命令:
|
||
|
||
```bash
|
||
node web-rtcp-5axis-sim-plan/tests/node/verify_run_preconditions.mjs
|
||
```
|
||
|
||
通过标准:
|
||
|
||
```text
|
||
run_preconditions_ini_profile_smoke=ok
|
||
```
|
||
|
||
### 4.2 运动学模块确认测试
|
||
|
||
目标:证明当前机床的五轴运动学算法已经按 INI/profile 加载。
|
||
|
||
断言:
|
||
|
||
```text
|
||
1. createLinuxCncKinematicsRuntime({ moduleId: "xyzac-trt" }) 成功。
|
||
2. readiness.moduleId === "xyzac-trt"。
|
||
3. wasmFile === "linuxcnc_xyzac_trt_kinematics.wasm"。
|
||
4. frameForJoints([10,20,30,25,40]) 返回 moduleId=xyzac-trt。
|
||
5. switchKinematics(1) 后 switchkinsType=1,frame source 仍是 linuxcnc_kinematics_wasm_c_abi。
|
||
|
||
6. 对 xyzbc-trt 重复同样测试。
|
||
```
|
||
|
||
已有相关测试:
|
||
|
||
```bash
|
||
node web-rtcp-5axis-sim-plan/tests/node/verify_linuxcnc_kinematics_runtime.mjs
|
||
```
|
||
|
||
新增 RUN 前置测试应把这个结果纳入 `RUN` gate,而不是只作为独立 smoke。
|
||
|
||
### 4.3 machine-file staging 测试
|
||
|
||
目标:证明 `RUN` 打开的程序、INI、remap、tool table 是同一个 LinuxCNC 机床目录上下文。
|
||
|
||
断言:
|
||
|
||
```text
|
||
1. stageProfileMachineFiles(profile) 成功。
|
||
2. save.files 中包含:
|
||
- 当前 profile 的 INI
|
||
- 当前 profile 的 tool table
|
||
- remap_subs/428remap.ngc
|
||
- remap_subs/429remap.ngc
|
||
- remap_subs/430remap.ngc
|
||
- 当前 profile 的 demo G-code
|
||
3. buildTaskHalSessionFromMachineFiles() 生成:
|
||
profileId 与 state.profile.id 一致
|
||
iniPath 与 profile.iniPath 一致
|
||
programPath 指向当前 selectedGcodeSourceRel
|
||
```
|
||
|
||
已有相关测试:
|
||
|
||
```bash
|
||
node web-rtcp-5axis-sim-plan/tests/node/verify_machine_file_staging.mjs
|
||
```
|
||
|
||
### 4.4 RUN 连续 feedback 测试
|
||
|
||
目标:证明点击 `RUN` 后,不是只推进一次 `taskCycles=5`,而是持续从 task/HAL/motion 获取反馈。
|
||
|
||
测试程序:
|
||
|
||
```ngc
|
||
G90 G21
|
||
M429
|
||
G0 X0 Y0 Z5 A0 C0
|
||
M428
|
||
G1 X10 Y0 Z5 A10 C20 F600
|
||
G1 X10 Y10 Z0 A20 C30 F300
|
||
M429
|
||
G1 X0 Y0 Z5 A0 C0 F600
|
||
M30
|
||
```
|
||
|
||
对 `xyzbc-trt` 时把 A 轴替换为 B 轴:
|
||
|
||
```ngc
|
||
G90 G21
|
||
M429
|
||
G0 X0 Y0 Z5 B0 C0
|
||
M428
|
||
G1 X10 Y0 Z5 B10 C20 F600
|
||
G1 X10 Y10 Z0 B20 C30 F300
|
||
M429
|
||
G1 X0 Y0 Z5 B0 C0 F600
|
||
M30
|
||
```
|
||
|
||
采集至少 8 个 feedback tick,断言:
|
||
|
||
```text
|
||
1. 每个 tick 的 sourceMode 都是 linuxcnc-task-motion-hal-wasm。
|
||
2. taskCycle 或 servoCycle 单调递增。
|
||
3. activeLine 随 feedback 推进,不停留在 RUN 后第一帧。
|
||
4. axisPose 来自同一 tick 的 task/HAL status.ui.axisPose。
|
||
5. currentVelocityMmPerMin 来自同一 tick 的 motion currentVel。
|
||
6. M428 后 kinsType 切到 tcp-xyzac 或 tcp-xyzbc。
|
||
7. M429 后 kinsType 回到 identity。
|
||
8. UI 当前高亮行、DRO、runtime feedback 文本读取的是同一个 feedback snapshot。
|
||
9. 程序完成后 runState 变为 complete 或 idle,不继续显示 running。
|
||
```
|
||
|
||
失败判定:
|
||
|
||
```text
|
||
RUN 后 servoCycle 只增加一次,然后 0.5s/2s/5s 不变。
|
||
activeLine 固定在某一行不再推进。
|
||
axisPose 从 HOME 位姿被 task-local 0 值覆盖。
|
||
programRuntimeFeedback.sourceMode 不是 linuxcnc-task-motion-hal-wasm。
|
||
RTCP 状态与当前 G-code 的 M428/M429 不一致。
|
||
```
|
||
|
||
### 4.5 浏览器端测试
|
||
|
||
建议扩展:
|
||
|
||
```text
|
||
qa/web-rtcp-5axis-site-test/capture-toolpath-preview-cases.mjs
|
||
```
|
||
|
||
新增 case:
|
||
|
||
```text
|
||
07-run-preconditions-and-feedback
|
||
```
|
||
|
||
浏览器断言:
|
||
|
||
```text
|
||
1. 首屏等待 state.iniConfigReadiness.loaded === true。
|
||
2. 选择 xyzac-trt,确认 titlebar/profile/INI/kinematics module 都是 xyzac-trt。
|
||
3. 点击 POWER、HOME、AUTO。
|
||
4. 加载上述短 G-code。
|
||
5. 点击 RUN。
|
||
6. 采集 t=0.2s、0.5s、1.0s、2.0s、5.0s 状态。
|
||
7. 断言 task/servo cycle 单调递增。
|
||
8. 断言 UI `.gcode-row.active` 的 data-program-line 等于 state.activeLine。
|
||
9. 断言 DRO X/Y/Z/A/C 等于 state.programRuntimeFeedback.axisPose。
|
||
10. 断言 canvas dataset 的 RTCP 状态与 state.rtcpState 一致。
|
||
```
|
||
|
||
输出证据:
|
||
|
||
```text
|
||
qa/web-rtcp-5axis-site-test/output/run-preconditions-feedback.json
|
||
qa/web-rtcp-5axis-site-test/screenshots/run-preconditions-feedback/*.png
|
||
```
|
||
|
||
## 5. 编写 RUN 程序的实现步骤
|
||
|
||
### Step 1: 增加 `validateRunPreconditions(state)`
|
||
|
||
位置建议:
|
||
|
||
```text
|
||
app/src/state/store.js
|
||
```
|
||
|
||
职责:
|
||
|
||
```text
|
||
1. 检查 INI 已加载。
|
||
2. 检查 profile 与 INI 坐标一致。
|
||
3. 检查 profile.kinematicsModuleId 与 kinematics runtime moduleId 一致。
|
||
4. 检查 kinematics runtime ready。
|
||
5. 检查 task/HAL runtime ready。
|
||
6. 检查 machine file staging ready。
|
||
7. 检查 taskHalSession.programPath 指向当前 G-code。
|
||
```
|
||
|
||
返回结构:
|
||
|
||
```js
|
||
{
|
||
ok: true,
|
||
profileId: "xyzac-trt",
|
||
iniPath: ".../xyzac-trt.ini",
|
||
coordinates: "XYZAC",
|
||
kinematicsModuleId: "xyzac-trt"
|
||
}
|
||
```
|
||
|
||
失败时:
|
||
|
||
```js
|
||
{
|
||
ok: false,
|
||
operatorMessage: "run blocked: LinuxCNC INI not loaded"
|
||
}
|
||
```
|
||
|
||
### Step 2: `RUN` action 先调用前置检查
|
||
|
||
当前 `RUN` 不能直接进入:
|
||
|
||
```text
|
||
runTaskHalCommandSequence([...], { taskCycles: 5 })
|
||
```
|
||
|
||
应先:
|
||
|
||
```text
|
||
1. gateLinuxCncTaskAction(state, action)
|
||
2. validateRunPreconditions(state)
|
||
3. initializeTaskHalSession({ openProgram: true }) 如需要
|
||
4. 确认 readStatus() 的 openProgram/programPath 与 state.activeProgram 对齐
|
||
```
|
||
|
||
未满足前置条件时,只设置 `operatorMessage`,不推进任何 line/sample。
|
||
|
||
### Step 3: 拆分 task command 与执行 pump
|
||
|
||
`RUN` 应只发送 LinuxCNC task 命令:
|
||
|
||
```text
|
||
EMC_TASK_SET_STATE ON
|
||
EMC_TASK_SET_MODE AUTO
|
||
EMC_TASK_PLAN_RUN line = activeLine - programStartLine
|
||
```
|
||
|
||
然后启动 feedback pump:
|
||
|
||
```text
|
||
while running:
|
||
taskHalRuntime.runCycles({ taskCycles: batchSize })
|
||
status = taskHalRuntime.readStatus()
|
||
dispatch TASK_HAL_STATUS_APPLIED(status)
|
||
append feedback history
|
||
if complete/paused/aborted/stopped:
|
||
stop pump
|
||
```
|
||
|
||
说明:
|
||
|
||
```text
|
||
这里的 pump 可以在 store 主线程调度,也可以放到 worker 内部 postMessage 推送。
|
||
关键不是 timer 本身,而是每个 tick 都必须由 task/HAL/motion runtime 的 runCycles/readStatus 产生反馈。
|
||
```
|
||
|
||
### Step 4: 增加 RUN pump 状态
|
||
|
||
建议 state 增加:
|
||
|
||
```js
|
||
taskHalRunPump: {
|
||
active: false,
|
||
sequence: 0,
|
||
profileId: null,
|
||
iniPath: null,
|
||
kinematicsModuleId: null,
|
||
tickCount: 0,
|
||
lastStatusAt: null,
|
||
lastError: null
|
||
}
|
||
```
|
||
|
||
同时增加:
|
||
|
||
```js
|
||
programRuntimeFeedbackHistory: []
|
||
```
|
||
|
||
历史最多保留 100 到 500 条,避免浏览器长程序内存无限增长。
|
||
|
||
### Step 5: `TASK_HAL_STATUS_APPLIED` 只消费 status
|
||
|
||
`applyTaskHalStatusPatch()` 应继续负责:
|
||
|
||
```text
|
||
activeLine
|
||
axisPose
|
||
kinsType
|
||
rtcpState
|
||
runState
|
||
feed.currentVelocity
|
||
programRuntimeFeedback
|
||
```
|
||
|
||
但需要补充:
|
||
|
||
```text
|
||
1. programRuntimeFeedbackHistory append 当前 feedback。
|
||
2. 记录 feedback.profileId、iniPath、kinematicsModuleId。
|
||
3. 对 ui.axisPoseFrame 做严格处理,避免 task-local 0 值覆盖 HOME/work pose。
|
||
4. 运行态 axisPose、velocity、DTG、activeLine 必须来自同一个 status snapshot。
|
||
```
|
||
|
||
### Step 6: STOP/ABORT/PAUSE/RESUME 控制 pump
|
||
|
||
行为要求:
|
||
|
||
```text
|
||
STOP/ABORT:
|
||
send EMC_TASK_ABORT
|
||
stop pump
|
||
read final status
|
||
|
||
PAUSE:
|
||
send EMC_TASK_PLAN_PAUSE
|
||
pump 可停止或降频读取 paused status
|
||
runState=paused
|
||
|
||
RESUME:
|
||
send EMC_TASK_PLAN_RESUME
|
||
restart pump
|
||
|
||
STEP:
|
||
不走 fixture sample playback
|
||
发送/推进一个明确的 task cycle batch
|
||
readStatus 一次
|
||
runState=stepping 或 paused
|
||
```
|
||
|
||
### Step 7: UI 显示执行历史
|
||
|
||
在 `app/src/ui/gmoccapy-shell.js` 的 info/sidebar 区域增加:
|
||
|
||
```text
|
||
Last feedback:
|
||
sourceMode / sample / line / taskCycle / servoCycle / velocity / kinsType
|
||
|
||
Run history:
|
||
最近 10 条 line/tick
|
||
```
|
||
|
||
UI 只显示 `programRuntimeFeedbackHistory`,不自行推导行号或坐标。
|
||
|
||
### Step 8: 移除真实 RUN 的 fixture fallback 混淆
|
||
|
||
保留 fallback 可以用于开发,但必须明确标记:
|
||
|
||
```text
|
||
programExecutionSourceMode=fixture-line-playback
|
||
operatorMessage=LinuxCNC task/HAL unavailable; fixture playback only
|
||
fullLinuxCncProgramExecutionReady=false
|
||
```
|
||
|
||
在真实 `taskHalRuntime.loaded === true` 且前置条件失败时,不应退回 fixture playback。
|
||
|
||
## 6. 开发验收命令
|
||
|
||
基础检查:
|
||
|
||
```bash
|
||
node web-rtcp-5axis-sim-plan/tests/node/verify_run_preconditions.mjs
|
||
node web-rtcp-5axis-sim-plan/tests/node/verify_linuxcnc_kinematics_runtime.mjs
|
||
node web-rtcp-5axis-sim-plan/tests/node/verify_machine_file_staging.mjs
|
||
node web-rtcp-5axis-sim-plan/tests/node/verify_linuxcnc_task_hal_runtime.mjs
|
||
npm --prefix web-rtcp-5axis-sim-plan/app run build
|
||
```
|
||
|
||
完整 node smoke:
|
||
|
||
```bash
|
||
npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node
|
||
```
|
||
|
||
浏览器 smoke:
|
||
|
||
```bash
|
||
bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh
|
||
bash web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_dist_browser.sh
|
||
```
|
||
|
||
QA 证据采集:
|
||
|
||
```bash
|
||
node qa/web-rtcp-5axis-site-test/capture-toolpath-preview-cases.mjs
|
||
```
|
||
|
||
## 7. 完成标准
|
||
|
||
`RUN` 可以判定为完善,必须同时满足:
|
||
|
||
```text
|
||
1. 每次 RUN 都能追溯到明确 INI。
|
||
2. 每次 RUN 都能说明机床类型和坐标轴。
|
||
3. 每次 RUN 都能说明使用哪个 LinuxCNC 五轴 kinematics module。
|
||
4. M428/M429/M430 的 switchkins 状态来自 LinuxCNC remap/HAL/task feedback 链。
|
||
5. activeLine、DRO、速度、DTG、程序时间来自同一个 task/HAL/motion feedback snapshot。
|
||
6. RUN 后 taskCycle/servoCycle 随时间持续推进,直到 paused/stopped/complete。
|
||
7. UI 高亮行和执行历史能复现逐行执行过程。
|
||
8. fallback playback 不能冒充 LinuxCNC task/HAL runtime。
|
||
```
|
||
|
||
未满足以上条件时,状态应继续标记为:
|
||
|
||
```text
|
||
fullLinuxCncProgramExecutionReady=false
|
||
hardwareDrive=false
|
||
hostRealtimeKernel=false
|
||
externalUserMProcessReady=false
|
||
```
|