Add RUN precondition gate for 5-axis simulation
This commit is contained in:
@@ -0,0 +1,570 @@
|
||||
# 01 RUN 与 G-code 执行原理测试记录
|
||||
|
||||
生成时间:2026-06-22
|
||||
|
||||
## 1. 参考接续文件
|
||||
|
||||
本记录按 `textbak` 中的接续要求核对,不把 UI fixture、自增行号、JS-owned CNC 语义当作真实运行证明。
|
||||
|
||||
关键约束来自:
|
||||
|
||||
```text
|
||||
textbak/text2.txt
|
||||
- 数控/G-code/remap/tool/parameter/planner/kinematics/user-M 语义必须来自 LinuxCNC upstream 或 vendored LinuxCNC C/C++ source。
|
||||
- UI 已优先解析 run_step,fallback 到 canonical event。
|
||||
- 不引入 JS G-code parser 或 JS remap/tool/parameter semantics。
|
||||
|
||||
textbak/text40.txt
|
||||
- LinuxCNC 可加载 kinematics module 的独立 WASM ABI 已完成。
|
||||
- 下一步应转向 Web/M4/M5 simulation UI 接入 createLinuxCncKinematicsSdk() 输出,或推进 remap/planner/browser 集成验证。
|
||||
|
||||
textbak/text41.txt
|
||||
- Web/M4/M5 当前状态曾明确记录为 RUN/STEP/JOG/HOME 仍推进 fixture axis pose。
|
||||
- 目标是 RUN/STEP/JOG/HOME 消费 LinuxCNC kinematics frame contract。
|
||||
- program execution 如果仍是 fixture line playback,必须继续标记为 fixture/interpreter-not-connected。
|
||||
- remap/planner/browser full-process 不得因 kinematics 接入而自动 promotion。
|
||||
```
|
||||
|
||||
当前源码已经比 `text41.txt` 的早期基线多接入了 interpreter、kinematics、task/HAL runtime,但 `RUN` 的连续执行模型仍需要按 task/HAL feedback 口径复核。
|
||||
|
||||
## 2. 当前 G-code 加载过程
|
||||
|
||||
启动入口:
|
||||
|
||||
```text
|
||||
app/src/main.js:17-23
|
||||
```
|
||||
|
||||
页面启动时创建 store、挂载 gmoccapy UI,并异步附加:
|
||||
|
||||
```text
|
||||
1. LinuxCNC INI config
|
||||
2. LinuxCNC kinematics runtime
|
||||
3. LinuxCNC interpreter runtime
|
||||
4. LinuxCNC task/HAL runtime
|
||||
5. machine file staging
|
||||
```
|
||||
|
||||
默认程序加载:
|
||||
|
||||
```text
|
||||
app/src/main.js:103-124
|
||||
```
|
||||
|
||||
`ensureDefaultLinuxCncProgramPreview()` 在 interpreter 与 machine files staged 后选择默认 LinuxCNC 5-axis source,然后 dispatch:
|
||||
|
||||
```text
|
||||
LOAD_LINUXCNC_GCODE_SOURCE
|
||||
```
|
||||
|
||||
选择 vendored G-code 后,store 的处理链是:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:744-792
|
||||
```
|
||||
|
||||
实际步骤:
|
||||
|
||||
```text
|
||||
1. 从 machineFileStaging.save.files 中找到 sourceRel 对应的 G-code 文本。
|
||||
2. selectMachineFileProgram(...) 生成该 G-code 对应的 machine-file plan。
|
||||
3. buildLoadedProgram(...) 将文本拆成 programLines,设置 activeProgram、programStartLine=1、activeLine=1。
|
||||
4. 设置 programSource=linuxcnc-vendored-5axis-gcode。
|
||||
5. 如果 task/HAL runtime 已加载,initializeTaskHalSession({ openProgram: true })。
|
||||
6. 如果 interpreter runtime 已加载,dispatch RUN_INTERPRETER_PROGRAM。
|
||||
```
|
||||
|
||||
本地 operator 打开文件时走同一个 `buildLoadedProgram(...)`:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:1033-1057
|
||||
```
|
||||
|
||||
G-code 文本显示在 UI:
|
||||
|
||||
```text
|
||||
app/src/ui/gmoccapy-shell.js:193-228
|
||||
```
|
||||
|
||||
这里使用 `state.programLines` 逐行渲染,`state.activeLine` 对应的行加 `.active`,同时显示:
|
||||
|
||||
```text
|
||||
Current line ${state.activeLine}
|
||||
${state.activeLine} / ${programEndLine}
|
||||
```
|
||||
|
||||
所以“能否看到 G-code 程序”和“是否逐行显示当前行”取决于 `programLines` 与 `activeLine` 是否被同一执行反馈链正确更新。
|
||||
|
||||
## 3. interpreter 解释与 preview 过程
|
||||
|
||||
`RUN_INTERPRETER_PROGRAM` 不是机床运行按钮,它是在加载程序后调用 LinuxCNC interpreter runtime,生成 canonical motion / summary / timing 基础数据:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:468-508
|
||||
```
|
||||
|
||||
解释完成后:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:509-555
|
||||
```
|
||||
|
||||
当前实现会:
|
||||
|
||||
```text
|
||||
1. 保存 programExecution。
|
||||
2. buildTimingForState(...) 构建 programExecutionTiming。
|
||||
3. 设置 programExecutionSourceMode=execution.sourceMode。
|
||||
4. 设置 programExecutionMotionIndex=0、programExecutionSampleIndex=0。
|
||||
5. 根据 firstMotion 更新 activeLine、axisPose、kinsType、rtcpState。
|
||||
6. 创建 firstFeedback,并更新 feed.currentVelocity。
|
||||
```
|
||||
|
||||
需要注意:这里的 `axisPoseFromCanonicalMotion(firstMotion, ...)` 来自 canonical motion 事件,是预览/初始反馈,不等价于运行态 task/HAL 连续反馈。
|
||||
|
||||
## 4. timing 与速度来源
|
||||
|
||||
`buildTimingForState(...)` 的优先级:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:2369-2379
|
||||
```
|
||||
|
||||
如果 `execution.plannerTiming.plannerRuntimeReady === true`,使用 plannerTiming;否则调用:
|
||||
|
||||
```text
|
||||
buildProgramExecutionTiming(...)
|
||||
```
|
||||
|
||||
该 timing fallback 的语义边界明确是估算:
|
||||
|
||||
```text
|
||||
app/src/runtime/execution-timing.js:50-53
|
||||
semanticBoundary: linuxcnc_canonical_motion_timing_estimate_not_planner_queue
|
||||
sourceBasis: LinuxCNC canonical motion events plus INI/profile velocity limits and feed overrides
|
||||
```
|
||||
|
||||
fallback timing 的速度计算逻辑:
|
||||
|
||||
```text
|
||||
app/src/runtime/execution-timing.js:75-123
|
||||
```
|
||||
|
||||
它按 canonical motion 段计算:
|
||||
|
||||
```text
|
||||
1. rapid 使用 maxLinearVelocity * rapidOverride。
|
||||
2. feed 使用 feedRate * feedOverride。
|
||||
3. linearSeconds = linearDistance / linearVelocity。
|
||||
4. angularSeconds = angularDistance / angularVelocity。
|
||||
5. durationSeconds = max(linearSeconds, angularSeconds)。
|
||||
```
|
||||
|
||||
这不是 LinuxCNC task/motion planner queue 的真实 run_step 推进。除非 `plannerTiming` 已 ready,否则“实际时间”和“实际进给速度”只能说是 canonical-based estimate。
|
||||
|
||||
## 5. RUN 按钮当前执行原理
|
||||
|
||||
`RUN` action 入口:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:1059-1100
|
||||
```
|
||||
|
||||
分两条路径。
|
||||
|
||||
### 5.1 task/HAL runtime loaded 路径
|
||||
|
||||
如果 `state.taskHalRuntime?.loaded` 为 true,`RUN` 执行:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:1066-1072
|
||||
```
|
||||
|
||||
发送命令:
|
||||
|
||||
```text
|
||||
EMC_TASK_SET_STATE ON
|
||||
EMC_TASK_SET_MODE AUTO
|
||||
EMC_TASK_PLAN_RUN line = activeLine - 1
|
||||
```
|
||||
|
||||
然后调用:
|
||||
|
||||
```text
|
||||
runTaskHalCommandSequence(..., { taskCycles: 5 })
|
||||
```
|
||||
|
||||
`runTaskHalCommandSequence` 的实现:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:1572-1604
|
||||
```
|
||||
|
||||
当前真实顺序是:
|
||||
|
||||
```text
|
||||
1. 标记 taskHalExecutionPending=true。
|
||||
2. 如未初始化 task/HAL session,则 initializeTaskHalSession/openProgram。
|
||||
3. 逐个 sendCommand(command)。
|
||||
4. 调用 taskHalRuntime.runCycles({ taskCycles: 5 })。
|
||||
5. 调用 taskHalRuntime.readStatus()。
|
||||
6. dispatch TASK_HAL_STATUS_APPLIED。
|
||||
```
|
||||
|
||||
结论:
|
||||
|
||||
```text
|
||||
当前 RUN 是“发送 task/HAL 命令 -> 主动推进固定 cycles -> 拉取一次 status -> 应用到 UI”。
|
||||
源码中没有看到 task/HAL worker 在程序运行期间主动持续 postMessage status 的订阅/推送通道。
|
||||
```
|
||||
|
||||
### 5.2 task/HAL runtime missing fallback
|
||||
|
||||
如果 task/HAL runtime 未加载,`RUN` 走:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:1074-1098
|
||||
```
|
||||
|
||||
即:
|
||||
|
||||
```text
|
||||
nextProgramRuntimeSamplePlayback(state, 5)
|
||||
```
|
||||
|
||||
这个 fallback 按 sampleIndex 或 motionIndex 一次跳 5 步,更新 activeLine / axisPose / feed / runtimeFeedback。
|
||||
|
||||
语义边界在 feedback 中标记为:
|
||||
|
||||
```text
|
||||
linuxcnc-tp-runtime-sample
|
||||
linuxcnc_tp_run_cycle_feedback_without_hardware
|
||||
```
|
||||
|
||||
或在没有 sample 时退回:
|
||||
|
||||
```text
|
||||
linuxcnc-canonical-motion
|
||||
linuxcnc_canonical_motion_feedback_without_tp_sample
|
||||
```
|
||||
|
||||
这条路径不能当作真实 task/HAL 运行过程。
|
||||
|
||||
## 6. task/HAL feedback 如何映射到 UI 状态
|
||||
|
||||
task/HAL runtime 包装:
|
||||
|
||||
```text
|
||||
app/src/runtime/linuxcnc-task-hal-runtime.js:96-114
|
||||
```
|
||||
|
||||
暴露的是:
|
||||
|
||||
```text
|
||||
sendCommand(command)
|
||||
runCycles(options)
|
||||
readStatus()
|
||||
```
|
||||
|
||||
worker client:
|
||||
|
||||
```text
|
||||
app/src/runtime/linuxcnc-task-hal-worker-client.js:14-28
|
||||
```
|
||||
|
||||
worker 本体:
|
||||
|
||||
```text
|
||||
app/src/runtime/linuxcnc-task-hal-worker.js:5-17
|
||||
app/src/runtime/linuxcnc-task-hal-worker.js:19-53
|
||||
```
|
||||
|
||||
worker 当前是 request/response 模型:
|
||||
|
||||
```text
|
||||
主线程 postMessage({ id, type, payload })
|
||||
worker 执行 handleMessage(type, payload)
|
||||
worker postMessage({ id, ok, result })
|
||||
```
|
||||
|
||||
没有看到类似:
|
||||
|
||||
```text
|
||||
subscribeStatus
|
||||
onStatus
|
||||
while running post feedback
|
||||
```
|
||||
|
||||
因此,当前 task/HAL feedback 不是“运行时持续推送”,而是 UI/store 调用 `readStatus()` 得到的一次快照。
|
||||
|
||||
状态归一化:
|
||||
|
||||
```text
|
||||
app/src/runtime/linuxcnc-task-hal-runtime.js:155-199
|
||||
```
|
||||
|
||||
`normalizeTaskHalStatus()` 从 motion/HAL pins 生成:
|
||||
|
||||
```text
|
||||
ui.taskState
|
||||
ui.taskMode
|
||||
ui.interpState
|
||||
ui.taskCycle
|
||||
ui.servoCycle
|
||||
ui.motionQueueDepth
|
||||
ui.activeLine
|
||||
ui.switchkinsType
|
||||
ui.axisPose
|
||||
ui.currentVelocity
|
||||
```
|
||||
|
||||
应用到 store:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:1776-1835
|
||||
```
|
||||
|
||||
`applyTaskHalStatusPatch(...)` 将 status 映射为:
|
||||
|
||||
```text
|
||||
activeLine = programStartLine + ui.activeLine - 1
|
||||
axisPose = resolveTaskHalAxisPose(...)
|
||||
kinsType = resolveTaskHalKinsType(...)
|
||||
rtcpState = rtcpStateFromKinsType(kinsType)
|
||||
runState = 根据 interpState / paused / aborted / complete 推导
|
||||
feed.currentVelocity = ui.currentVelocity
|
||||
programRuntimeFeedback = createTaskHalRuntimeFeedback(...)
|
||||
```
|
||||
|
||||
runtime feedback 字段:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:1925-1948
|
||||
```
|
||||
|
||||
包括:
|
||||
|
||||
```text
|
||||
sourceMode=linuxcnc-task-motion-hal-wasm
|
||||
sampleIndex=ui.servoCycle
|
||||
motionIndex=ui.activeLine - 1
|
||||
line=activeLine
|
||||
timeSeconds=ui.taskCycle * 0.01
|
||||
axisPose
|
||||
currentVelocityMmPerMin
|
||||
requestedVelocityMmPerMin
|
||||
distanceToGo
|
||||
queueDepth
|
||||
cycle
|
||||
taskCycle
|
||||
```
|
||||
|
||||
这里的问题是:如果 `readStatus()` 不持续发生,这些字段不会按真实执行时间继续变化。
|
||||
|
||||
## 7. 本地快照观察
|
||||
|
||||
说明:本轮浏览器采集脚本在用户中断前已写出完整 JSON 快照,作为辅助证据。正式结论仍以源码追踪为主。
|
||||
|
||||
辅助证据文件:
|
||||
|
||||
```text
|
||||
web-rtcp-5axis-sim-plan/working_run/run-feedback-evidence/run-feedback-local.json
|
||||
web-rtcp-5axis-sim-plan/working_run/run-feedback-evidence/run-feedback-local.png
|
||||
```
|
||||
|
||||
快照摘要:
|
||||
|
||||
| 快照 | runState | activeLine | servoCycle | velocity | axisPose |
|
||||
| --- | --- | ---: | ---: | ---: | --- |
|
||||
| loaded-default | idle | 1 | 0 | 0 | X0 Y0 Z0 A0 B0 C0 |
|
||||
| after-power | idle | 1 | 10 | 0 | X0 Y0 Z0 A0 B0 C0 |
|
||||
| after-home | idle | 1 | 10 | 0 | X43 Y-32.15 Z-11.306 A0 B0 C0 |
|
||||
| after-auto | idle | 1 | 20 | 0 | X0 Y0 Z0 A0 B0 C0 |
|
||||
| after-run-idle | running | 5 | 70 | 3600 | X0 Y0 Z5 A0 B0 C0 |
|
||||
| run-plus-0.5s-no-command | running | 5 | 70 | 3600 | X0 Y0 Z5 A0 B0 C0 |
|
||||
| run-plus-2.0s-no-command | running | 5 | 70 | 3600 | X0 Y0 Z5 A0 B0 C0 |
|
||||
| run-plus-5.0s-no-command | running | 5 | 70 | 3600 | X0 Y0 Z5 A0 B0 C0 |
|
||||
|
||||
观察结论:
|
||||
|
||||
```text
|
||||
1. 点击 RUN 后,状态从 line 1 推进到 line 5,servoCycle 从 20 推进到 70。
|
||||
2. 后续 0.5s / 2.0s / 5.0s 没有再次调用命令时,activeLine、servoCycle、axisPose、velocity 均保持不变。
|
||||
3. 这与源码中的 runCycles({ taskCycles: 5 }) + readStatus() 一次相符。
|
||||
4. 这不是连续 task/HAL feedback 推送模型。
|
||||
```
|
||||
|
||||
## 8. 发现的问题
|
||||
|
||||
### P1. RUN 没有持续消费 task/HAL feedback
|
||||
|
||||
期望:
|
||||
|
||||
```text
|
||||
G-code 程序执行时,task/HAL/motion runtime 持续产生状态;
|
||||
UI/store 持续消费这些状态;
|
||||
当前行、轴值、速度、DTG、程序时间来自同一个 feedback source。
|
||||
```
|
||||
|
||||
当前:
|
||||
|
||||
```text
|
||||
RUN 只主动推进固定 taskCycles=5,然后 readStatus 一次。
|
||||
没有看到 worker 主动推送 status。
|
||||
没有看到 store 中存在运行期间持续 readStatus/readEvents 的执行循环。
|
||||
```
|
||||
|
||||
影响:
|
||||
|
||||
```text
|
||||
RUN 后页面可能停在某个 status snapshot。
|
||||
用户看到 runState=running,但 activeLine、轴值、速度不会随真实时间继续推进。
|
||||
```
|
||||
|
||||
### P1. 轴值存在状态回退/覆盖风险
|
||||
|
||||
快照中可见:
|
||||
|
||||
```text
|
||||
after-home: X43 Y-32.15 Z-11.306
|
||||
after-auto: X0 Y0 Z0
|
||||
```
|
||||
|
||||
源码位置:
|
||||
|
||||
```text
|
||||
app/src/state/store.js:1874-1901
|
||||
```
|
||||
|
||||
`resolveTaskHalAxisPose()` 对 `ui.axisPoseFrame === "work"` 直接合并 task/HAL axisPose,因此 task/HAL status 中的 0 位姿可覆盖 HOME 后的 fixture/work pose。
|
||||
|
||||
这解释了“现实的轴值都不对”的一类现象:UI 显示值可能来自 task/HAL local/status 快照,而不是实际期望的机床/工件坐标连续反馈。
|
||||
|
||||
### P2. 程序时间和速度可能是 estimate 或单点 status
|
||||
|
||||
fallback timing 明确是:
|
||||
|
||||
```text
|
||||
linuxcnc_canonical_motion_timing_estimate_not_planner_queue
|
||||
```
|
||||
|
||||
task/HAL feedback 中的时间:
|
||||
|
||||
```text
|
||||
timeSeconds = ui.taskCycle * 0.01
|
||||
```
|
||||
|
||||
如果 taskCycle 不推进,程序时间也不推进。快照中 `taskCycle=0`,但 velocity 已为 3600,说明当前 runtime feedback 的时间/速度字段并不构成可靠连续执行轨迹。
|
||||
|
||||
### P2. “逐行执行过程”目前只显示当前 activeLine,不显示执行历史
|
||||
|
||||
UI 已显示:
|
||||
|
||||
```text
|
||||
programLines
|
||||
activeLine
|
||||
gcode-row.active
|
||||
progress
|
||||
```
|
||||
|
||||
但没有看到 execution log / visited line history / per-feedback transcript。
|
||||
|
||||
因此用户能看到程序文本和当前行,但看不到完整“一行一行执行过程”的历史记录。
|
||||
|
||||
## 9. 正确的 RUN 执行模型建议
|
||||
|
||||
按你提出的标准,正确模型不应靠前端定时器自造轨迹,而应由 task/HAL/motion runtime 产出状态。
|
||||
|
||||
建议目标模型:
|
||||
|
||||
```text
|
||||
1. RUN 只发送 LinuxCNC task command:
|
||||
EMC_TASK_SET_STATE ON
|
||||
EMC_TASK_SET_MODE AUTO
|
||||
EMC_TASK_PLAN_RUN
|
||||
|
||||
2. task/HAL runtime 在程序执行期间持续 run task/motion/servo cycles。
|
||||
|
||||
3. 每个 cycle 或每批 cycle 产生 LinuxCNC-owned feedback:
|
||||
activeLine
|
||||
statement/source line
|
||||
axisPose
|
||||
jointPose
|
||||
currentVelocity
|
||||
requestedVelocity
|
||||
distanceToGo / DTG
|
||||
queueDepth
|
||||
interpState
|
||||
cycle / taskCycle / servoCycle
|
||||
switchkinsType / RTCP state
|
||||
|
||||
4. worker 将 feedback 推送给 main thread,或 main thread 通过明确的 runtime pump 读取。
|
||||
|
||||
5. store 只消费 feedback,不自行按 motionIndex/sampleIndex 推进真实运行态。
|
||||
|
||||
6. UI 渲染:
|
||||
- G-code 当前行高亮来自 feedback.line;
|
||||
- DRO 轴值来自 feedback.axisPose 或 kinematics frame;
|
||||
- 速度来自 feedback.currentVelocity;
|
||||
- 程序时间来自 feedback.timeSeconds;
|
||||
- 执行历史记录追加每次 feedback。
|
||||
```
|
||||
|
||||
注意:这里的“pump”可以在 worker 内部完成,也可以由 main thread 调用 runtime pump,但语义必须是 LinuxCNC task/HAL/motion cycles 产生反馈,而不是 UI 自己按 wall clock 或固定 index 插值。
|
||||
|
||||
## 10. 后续测试建议
|
||||
|
||||
建议在 `working_run` 后续补一个严格测试脚本,断言以下行为:
|
||||
|
||||
```text
|
||||
1. 加载一个短 G-code:
|
||||
G90 G21
|
||||
G0 X0 Y0 Z5
|
||||
G1 X10 F600
|
||||
G1 Y10 F300
|
||||
M30
|
||||
|
||||
2. RUN 后采集至少 5 个 feedback tick。
|
||||
|
||||
3. 断言每个 tick 的 sourceMode 都是 linuxcnc-task-motion-hal-wasm。
|
||||
|
||||
4. 断言 activeLine 按 feedback 推进,而不是固定跳到 line 5 后停止。
|
||||
|
||||
5. 断言 servoCycle/taskCycle 单调递增。
|
||||
|
||||
6. 断言 axisPose 与当前 G-code motion 目标/插补位置一致。
|
||||
|
||||
7. 断言 currentVelocity 与当前运动段 F 值/override/task status 对齐。
|
||||
|
||||
8. 断言 UI `.gcode-row.active`、DRO、runtime feedback 文本和 store state 使用同一个 feedback snapshot。
|
||||
|
||||
9. 断言执行历史中能看到逐条 line/tick 记录。
|
||||
```
|
||||
|
||||
## 11. 本轮验证命令
|
||||
|
||||
已运行:
|
||||
|
||||
```bash
|
||||
npm --prefix web-rtcp-5axis-sim-plan/app run build
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
```text
|
||||
gmoccapy_static_build=ok
|
||||
```
|
||||
|
||||
浏览器采集脚本在用户中断前已产生完整快照 JSON,未作为正式 smoke 通过声明;本报告只把它作为辅助观察。
|
||||
|
||||
## 12. 总结
|
||||
|
||||
当前 `web-rtcp-5axis-sim-plan` 的 G-code 程序加载、文本显示、interpreter canonical motion、task/HAL 命令发送和 status 映射链路已经存在。
|
||||
|
||||
但当前 `RUN` 的核心行为仍是:
|
||||
|
||||
```text
|
||||
发送命令 -> runCycles 固定 5 个 task cycles -> readStatus 一次 -> 更新 UI 一次
|
||||
```
|
||||
|
||||
它没有形成“G-code 执行期间 task/HAL feedback 持续推送/持续消费”的运行态闭环。因此,按实际时间和进给速度连续执行、真实轴值连续更新、逐行执行过程可见,这三项目前都不能判定为满足。
|
||||
@@ -0,0 +1,565 @@
|
||||
# 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
|
||||
```
|
||||
@@ -0,0 +1,311 @@
|
||||
# 03 RUN 第一步完成记录与下一步建议
|
||||
|
||||
生成时间:2026-06-22
|
||||
|
||||
## 1. 本轮完成范围
|
||||
|
||||
本轮只完成 `02-run-preconditions-test-and-implementation-steps.md` 中的第一步和第二步:
|
||||
|
||||
```text
|
||||
Step 1: 增加 validateRunPreconditions(state)
|
||||
Step 2: RUN action 先调用前置检查
|
||||
```
|
||||
|
||||
本轮没有实现连续 feedback pump。也没有把 `RUN` 宣称为完整实时运行模型。
|
||||
|
||||
## 2. 已完成改动
|
||||
|
||||
### 2.1 RUN 前置条件 gate
|
||||
|
||||
新增源码:
|
||||
|
||||
```text
|
||||
app/src/state/store.js
|
||||
export function validateRunPreconditions(...)
|
||||
```
|
||||
|
||||
校验内容:
|
||||
|
||||
```text
|
||||
1. profile 必须是 xyzac-trt 或 xyzbc-trt。
|
||||
2. LinuxCNC INI 必须已加载并 validation.ready=true。
|
||||
3. profile.iniPath 必须与已加载 INI path 一致。
|
||||
4. profile TRAJ coordinates 必须与 INI coordinates 一致。
|
||||
5. profile.kinematicsModuleId 必须与 INI [KINS] 推导结果一致。
|
||||
6. LinuxCNC kinematics runtime 必须 loaded。
|
||||
7. kinematics runtime moduleId 必须匹配当前 profile。
|
||||
8. RTCP frame 必须来自 source-derived-kinematics-wasm。
|
||||
9. machine files 必须 staged。
|
||||
10. 必须已选择 LinuxCNC source-directory G-code。
|
||||
11. task/HAL runtime 必须 ready。
|
||||
12. requireTaskHalSession=true 时,taskHalSession.programPath 必须匹配当前 selected G-code。
|
||||
```
|
||||
|
||||
关键结果:
|
||||
|
||||
```text
|
||||
当 taskHalRuntime 已加载时,RUN 不再直接发送 EMC_TASK_PLAN_RUN。
|
||||
RUN 会先校验 INI/profile/kinematics/machine-file/task-HAL 上下文。
|
||||
前置条件不满足时,只给 operatorMessage,不进入 fixture playback。
|
||||
```
|
||||
|
||||
### 2.2 RUN 使用真实 machine-file session
|
||||
|
||||
新增内部流程:
|
||||
|
||||
```text
|
||||
runValidatedTaskHalProgramRun()
|
||||
```
|
||||
|
||||
执行顺序:
|
||||
|
||||
```text
|
||||
1. validateRunPreconditions(..., requireTaskHalSession=false)
|
||||
2. 如 taskHalSession 缺失或 programPath 不匹配,initializeTaskHalSession({ openProgram: true })
|
||||
3. validateRunPreconditions(..., requireTaskHalSession=true)
|
||||
4. 发送:
|
||||
EMC_TASK_SET_STATE ON
|
||||
EMC_TASK_SET_MODE AUTO
|
||||
EMC_TASK_PLAN_RUN line = activeLine - programStartLine
|
||||
5. runTaskHalCommandSequence(..., allowFixtureSession=false)
|
||||
```
|
||||
|
||||
这一步解决的是“RUN 之前先确定明确 INI、机床类型和五轴运动学算法”,不是连续执行问题。
|
||||
|
||||
### 2.3 新增测试
|
||||
|
||||
新增:
|
||||
|
||||
```text
|
||||
tests/node/verify_run_preconditions.mjs
|
||||
```
|
||||
|
||||
覆盖:
|
||||
|
||||
```text
|
||||
1. xyzac-trt.ini 解析:
|
||||
MACHINE=sim-xyzac-trt-kins (switchkins)
|
||||
COORDINATES=XYZAC
|
||||
KINEMATICS=xyzac-trt-kins
|
||||
kinematicsModuleId=xyzac-trt
|
||||
|
||||
2. xyzbc-trt.ini 解析:
|
||||
MACHINE=sim-xyzbc-trt-kins (switchkins)
|
||||
COORDINATES=XYZBC
|
||||
KINEMATICS=xyzbc-trt-kins
|
||||
kinematicsModuleId=xyzbc-trt
|
||||
|
||||
3. applyIniConfigToProfile() 后 profile 与 INI 保持一致。
|
||||
4. createLinuxCncKinematicsRuntime() 可按 moduleId 加载对应 WASM。
|
||||
5. stageProfileMachineFiles() 和 buildTaskHalSessionFromMachineFiles() 能形成同一 machine-file 上下文。
|
||||
6. validateRunPreconditions() 能阻断未加载 INI 的初始状态。
|
||||
7. validateRunPreconditions() 能在 INI/kinematics/staged G-code ready 时通过非 task-HAL session 预检。
|
||||
8. task/HAL runtime 缺失时返回明确阻断消息。
|
||||
```
|
||||
|
||||
`app/package.json` 的 `smoke:node` 已加入:
|
||||
|
||||
```text
|
||||
node ../tests/node/verify_run_preconditions.mjs
|
||||
```
|
||||
|
||||
### 2.4 调整 task/HAL smoke
|
||||
|
||||
更新:
|
||||
|
||||
```text
|
||||
tests/node/verify_linuxcnc_task_hal_runtime.mjs
|
||||
```
|
||||
|
||||
调整点:
|
||||
|
||||
```text
|
||||
1. 不再用内联 fixture G-code 直接测试真实 RUN。
|
||||
2. 加载 xyzac-trt INI。
|
||||
3. 加载 xyzac-trt kinematics runtime。
|
||||
4. stage machine files。
|
||||
5. LOAD_LINUXCNC_GCODE_SOURCE 选择:
|
||||
configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc
|
||||
6. 等待 taskHalSession.programPath 指向该 G-code。
|
||||
7. 再执行 POWER/HOME/AUTO/RUN。
|
||||
```
|
||||
|
||||
这样 task/HAL RUN smoke 与新的 RUN 前置条件一致。
|
||||
|
||||
## 3. 已运行验证
|
||||
|
||||
通过:
|
||||
|
||||
```bash
|
||||
node web-rtcp-5axis-sim-plan/tests/node/verify_run_preconditions.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
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```text
|
||||
run_preconditions_ini_profile_smoke=ok
|
||||
run_preconditions_kinematics_smoke=ok
|
||||
run_preconditions_machine_file_smoke=ok
|
||||
|
||||
linuxcnc_task_hal_runtime_smoke=ok
|
||||
task_hal_machine_file_smoke=ok
|
||||
switchkins_remap_hal_sync_smoke=ok
|
||||
browser_task_hal_worker_smoke=ok
|
||||
|
||||
gmoccapy_static_build=ok
|
||||
```
|
||||
|
||||
部分通过后失败:
|
||||
|
||||
```bash
|
||||
npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node
|
||||
```
|
||||
|
||||
该命令已通过本轮新增和相关测试:
|
||||
|
||||
```text
|
||||
linuxcnc_kinematics_runtime_smoke=ok
|
||||
linuxcnc_interpreter_runtime_smoke=ok
|
||||
linuxcnc_ini_runtime_smoke=ok
|
||||
run_preconditions_ini_profile_smoke=ok
|
||||
run_preconditions_kinematics_smoke=ok
|
||||
run_preconditions_machine_file_smoke=ok
|
||||
linuxcnc_task_hal_runtime_smoke=ok
|
||||
task_hal_machine_file_smoke=ok
|
||||
switchkins_remap_hal_sync_smoke=ok
|
||||
browser_task_hal_worker_smoke=ok
|
||||
```
|
||||
|
||||
随后在既有 native audit 停止:
|
||||
|
||||
```text
|
||||
wasm-port/tests/native/verify_task_hal_phase0.sh failed with status 1
|
||||
```
|
||||
|
||||
直接运行该脚本确认失败点是:
|
||||
|
||||
```text
|
||||
wasm-port/tools/verify_task_hal_source_manifest.sh
|
||||
```
|
||||
|
||||
日志:
|
||||
|
||||
```text
|
||||
task_hal_source_manifest_ready=0
|
||||
task_hal_reference_source_ready=0
|
||||
task_hal_missing_reference_source_count=20
|
||||
```
|
||||
|
||||
说明:该失败来自外部 reference source `../linuxcnc` 缺失 task/HAL manifest 需要的 20 个文件,不是本轮 RUN 前置条件改动造成。
|
||||
|
||||
## 4. 当前 RUN 状态
|
||||
|
||||
现在 `RUN` 的第一道边界已经收紧:
|
||||
|
||||
```text
|
||||
没有明确 INI -> 不 RUN
|
||||
profile/INI 坐标不一致 -> 不 RUN
|
||||
kinematics module 不一致 -> 不 RUN
|
||||
kinematics frame 未 ready -> 不 RUN
|
||||
machine files 未 staged -> 不 RUN
|
||||
没有 LinuxCNC source G-code -> 不 RUN
|
||||
task/HAL runtime 未 ready -> 不 RUN
|
||||
taskHalSession.programPath 不匹配当前 G-code -> 不 RUN
|
||||
```
|
||||
|
||||
但当前 `RUN` 仍然是:
|
||||
|
||||
```text
|
||||
发送 task command
|
||||
-> runCycles({ taskCycles: 5 })
|
||||
-> readStatus() 一次
|
||||
-> TASK_HAL_STATUS_APPLIED 一次
|
||||
```
|
||||
|
||||
所以 `01-run-gcode-execution-principle-and-test.md` 中指出的连续 feedback 问题仍未解决。
|
||||
|
||||
## 5. 下一步工作建议
|
||||
|
||||
下一步应实现 `02` 文件中的 Step 3 和 Step 4:
|
||||
|
||||
```text
|
||||
Step 3: 拆分 task command 与执行 pump
|
||||
Step 4: 增加 RUN pump 状态
|
||||
```
|
||||
|
||||
建议最小实现范围:
|
||||
|
||||
```text
|
||||
1. 在 store state 增加 taskHalRunPump:
|
||||
active
|
||||
sequence
|
||||
profileId
|
||||
iniPath
|
||||
kinematicsModuleId
|
||||
tickCount
|
||||
lastStatusAt
|
||||
lastError
|
||||
|
||||
2. 增加 programRuntimeFeedbackHistory,最多保留 100 条。
|
||||
|
||||
3. RUN 发送 EMC_TASK_PLAN_RUN 后,不只 runCycles 5 次。
|
||||
改为启动 pump:
|
||||
runCycles({ taskCycles: batchSize })
|
||||
readStatus()
|
||||
dispatch TASK_HAL_STATUS_APPLIED
|
||||
append feedback history
|
||||
根据 interpState / task.nextProgramLine / openedLineCount / paused / aborted 停止。
|
||||
|
||||
4. STOP/ABORT 必须停止 pump。
|
||||
|
||||
5. PAUSE 停止或降频 pump,并保留 paused status。
|
||||
|
||||
6. RESUME 重新启动 pump。
|
||||
|
||||
7. STEP 在 task/HAL runtime loaded 时不走 fixture sample playback,
|
||||
而是推进一个明确 task cycle batch 并 readStatus 一次。
|
||||
```
|
||||
|
||||
下一步测试建议:
|
||||
|
||||
```text
|
||||
1. 新增 tests/node/verify_run_feedback_pump.mjs。
|
||||
2. 使用 xyzac_switchkins_test_1.ngc。
|
||||
3. RUN 后采集至少 8 个 feedback tick。
|
||||
4. 断言 taskCycle 或 servoCycle 单调递增。
|
||||
5. 断言 activeLine 不停留在 RUN 后第一帧。
|
||||
6. 断言每个 tick 的 sourceMode 都是 linuxcnc-task-motion-hal-wasm。
|
||||
7. 断言 programRuntimeFeedbackHistory 至少包含 3 条。
|
||||
8. 断言 STOP 后 pump.active=false。
|
||||
```
|
||||
|
||||
浏览器测试建议:
|
||||
|
||||
```text
|
||||
扩展 qa/web-rtcp-5axis-site-test/capture-toolpath-preview-cases.mjs
|
||||
新增 07-run-preconditions-and-feedback case。
|
||||
采集 RUN 后 0.2s / 0.5s / 1.0s / 2.0s 的 state。
|
||||
断言 activeLine、DRO、runtime feedback、canvas RTCP 状态来自同一 feedback snapshot。
|
||||
```
|
||||
|
||||
## 6. 重要边界
|
||||
|
||||
下一步实现 pump 时仍需保持:
|
||||
|
||||
```text
|
||||
不引入 JS G-code parser。
|
||||
不在 UI 里自增 activeLine。
|
||||
不在 UI 里自造 axisPose。
|
||||
不把 canonical timing estimate 当作真实 task/HAL runtime。
|
||||
不把 fixture playback 标记为 fullLinuxCncProgramExecutionReady。
|
||||
```
|
||||
|
||||
RUN 的真实推进必须来自:
|
||||
|
||||
```text
|
||||
taskHalRuntime.runCycles()
|
||||
taskHalRuntime.readStatus()
|
||||
TASK_HAL_STATUS_APPLIED
|
||||
```
|
||||
54
web-rtcp-5axis-sim-plan/working_run/README.md
Normal file
54
web-rtcp-5axis-sim-plan/working_run/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# working_run 运行功能测试与原理记录
|
||||
|
||||
生成时间:2026-06-22
|
||||
|
||||
本目录记录 `web-rtcp-5axis-sim-plan` 本地项目中 G-code 程序加载、解释、`RUN` 执行链路、task/HAL feedback 消费方式,以及当前测试发现的问题。
|
||||
|
||||
## 文件清单
|
||||
|
||||
| 文件 | 用途 |
|
||||
| --- | --- |
|
||||
| `01-run-gcode-execution-principle-and-test.md` | G-code 具体执行过程、`RUN` 执行原理、源码证据、测试观察和问题结论 |
|
||||
| `02-run-preconditions-test-and-implementation-steps.md` | `RUN` 前置条件、INI/机床/五轴运动学确认流程、详细测试用例和编写 `RUN` 程序步骤 |
|
||||
| `03-run-step1-preconditions-complete-next-steps.md` | 本轮已完成的 `RUN` 前置条件 gate、验证结果和下一步接续建议 |
|
||||
|
||||
## 结论摘要
|
||||
|
||||
`RUN` 不应作为第一步实现。正确顺序必须是:
|
||||
|
||||
```text
|
||||
1. 先确定明确的 LinuxCNC INI 文件。
|
||||
2. 由 INI/profile 确定机床类型、坐标轴、joint 配置、HAL/remap/tool-table 资产。
|
||||
3. 由 INI 的 [KINS] KINEMATICS 确定五轴运动学算法和 switchkins 映射。
|
||||
4. 验证对应 LinuxCNC kinematics WASM 已加载,并能产生 source-derived frame。
|
||||
5. 之后才进入 RUN:打开同一 INI 上下文下的 G-code,发送 task command,持续消费 task/HAL/motion feedback。
|
||||
```
|
||||
|
||||
当前项目明确支持的五轴机床上下文是:
|
||||
|
||||
| profile | INI | 机床类型 | 坐标 | 运动学 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `xyzac-trt` | `configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini` | table rotary tilting | `XYZAC` | `xyzac-trt-kins sparm=identityfirst` |
|
||||
| `xyzbc-trt` | `configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini` | table rotary tilting | `XYZBC` | `xyzbc-trt-kins sparm=identityfirst` |
|
||||
|
||||
当前实现已经能显示 G-code 程序文本、当前行、高亮行、DRO、runtime feedback 和 task/HAL 状态。
|
||||
|
||||
但按 `textbak` 接续文件的边界要求,当前 `RUN` 还不是连续的 task/HAL feedback 推送执行模型:
|
||||
|
||||
```text
|
||||
RUN 点击后:
|
||||
1. UI 发送 EMC_TASK_SET_STATE / EMC_TASK_SET_MODE / EMC_TASK_PLAN_RUN;
|
||||
2. store 调用 taskHalRuntime.runCycles({ taskCycles: 5 });
|
||||
3. 随后 readStatus() 一次;
|
||||
4. TASK_HAL_STATUS_APPLIED 将这一次 status 映射到 activeLine / axisPose / velocity / feedback;
|
||||
5. 没有看到 worker 主动持续 postMessage 推送 status;
|
||||
6. 如果没有再次调用 runCycles/readStatus,状态不会继续随真实时间推进。
|
||||
```
|
||||
|
||||
因此,当前问题重点不是“前端是否需要定时器”,而是:
|
||||
|
||||
```text
|
||||
task/HAL runtime 是否能在 G-code 执行期间持续产出状态;
|
||||
UI/store 是否持续消费这些 LinuxCNC-owned 状态;
|
||||
轴值、当前行、速度、DTG、程序时间是否都来自同一条 task/HAL/motion feedback 链。
|
||||
```
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 198 KiB |
Reference in New Issue
Block a user