1051 lines
28 KiB
Markdown
1051 lines
28 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. INI definition contract
|
||
|
||
`RUN` 只能基于一个完整、可验证的 LinuxCNC INI 上下文启动。INI 不是展示信息,而是机床契约来源。`parseLinuxCncIni()` 和 `applyIniConfigToProfile()` 必须把下面字段转成结构化状态,RUN gate 只读取结构化状态,不在 RUN action 中重新猜测字符串。
|
||
|
||
### 3.1 必须存在的 INI sections
|
||
|
||
当前五轴 `xyzac-trt` / `xyzbc-trt` profile 至少要求这些 section:
|
||
|
||
| section | 是否必填 | RUN gate 用途 |
|
||
| --- | --- | --- |
|
||
| `[EMC]` | 必填 | 识别 machine name,确认是 switchkins 五轴 profile |
|
||
| `[DISPLAY]` | 必填 | 提供默认打开程序、程序目录、UI 坐标提示;不能作为运动学真值 |
|
||
| `[RS274NGC]` | 必填 | 提供 remap、subroutine path、HAL pin vars、parameter file |
|
||
| `[KINS]` | 必填 | 提供 kinematics module 和 joint 数,是 kinematics/runtime 匹配依据 |
|
||
| `[HAL]` | 必填 | 提供 HAL 文件、HALUI、POSTGUI_HALFILE、switchkins HALCMD |
|
||
| `[HALUI]` | 必填 | 提供 M428/M429/M430 operator command 顺序和语义提示 |
|
||
| `[TRAJ]` | 必填 | 提供 COORDINATES、单位、速度/加速度上限 |
|
||
| `[EMCMOT]` | 必填 | 提供 motmod、SERVO_PERIOD、COMM_TIMEOUT |
|
||
| `[TASK]` | 必填 | 提供 task module 和 CYCLE_TIME |
|
||
| `[EMCIO]` | 必填 | 提供 tool table |
|
||
| `[AXIS_*]` | 必填 | 提供各坐标轴 limit/velocity/acceleration |
|
||
| `[JOINT_*]` | 必填 | 提供 joint 类型、home、limit、home sequence |
|
||
|
||
不满足这些 section 时,INI readiness 必须是 not ready,RUN 必须阻断。
|
||
|
||
### 3.2 必填字段与 gate 用途
|
||
|
||
`[EMC]`:
|
||
|
||
```text
|
||
VERSION
|
||
MACHINE
|
||
```
|
||
|
||
要求:
|
||
|
||
```text
|
||
xyzac-trt: MACHINE = sim-xyzac-trt-kins (switchkins)
|
||
xyzbc-trt: MACHINE = sim-xyzbc-trt-kins (switchkins)
|
||
```
|
||
|
||
用途:
|
||
|
||
```text
|
||
1. 推导 profileId。
|
||
2. 确认当前 profile 是 switchkins 五轴仿真机床。
|
||
3. 作为 task/HAL session metadata,写入 feedback 证据。
|
||
```
|
||
|
||
`[DISPLAY]`:
|
||
|
||
```text
|
||
GEOMETRY
|
||
OPEN_FILE
|
||
JOG_AXES
|
||
DISPLAY
|
||
PROGRAM_PREFIX
|
||
POSITION_OFFSET
|
||
POSITION_FEEDBACK
|
||
MAX_LINEAR_VELOCITY
|
||
MAX_ANGULAR_VELOCITY
|
||
```
|
||
|
||
用途:
|
||
|
||
```text
|
||
1. OPEN_FILE 只能作为默认程序候选,RUN 实际程序必须来自 staged selected G-code。
|
||
2. PROGRAM_PREFIX 用于解析 machine-file staging 的相对路径。
|
||
3. GEOMETRY/JOG_AXES 用于 UI 呈现,不得覆盖 [TRAJ] COORDINATES。
|
||
```
|
||
|
||
`[RS274NGC]`:
|
||
|
||
```text
|
||
SUBROUTINE_PATH
|
||
HAL_PIN_VARS = 1
|
||
REMAP = M428 modalgroup=10 ngc=428remap
|
||
REMAP = M429 modalgroup=10 ngc=429remap
|
||
REMAP = M430 modalgroup=10 ngc=430remap
|
||
PARAMETER_FILE
|
||
```
|
||
|
||
用途:
|
||
|
||
```text
|
||
1. HAL_PIN_VARS=1 是 remap 子程序读取 motion.switchkins-type 的前提。
|
||
2. M428/M429/M430 remap 文件必须被 stage 到同一 machine context。
|
||
3. PARAMETER_FILE 必须随 profile 区分,不能 xyzac/xyzbc 混用。
|
||
```
|
||
|
||
`[KINS]`:
|
||
|
||
```text
|
||
KINEMATICS
|
||
JOINTS
|
||
```
|
||
|
||
要求:
|
||
|
||
```text
|
||
xyzac-trt: KINEMATICS = xyzac-trt-kins sparm=identityfirst
|
||
xyzbc-trt: KINEMATICS = xyzbc-trt-kins sparm=identityfirst
|
||
JOINTS = 5
|
||
```
|
||
|
||
用途:
|
||
|
||
```text
|
||
1. 从 KINEMATICS 推导 kinematicsModuleId。
|
||
2. 校验 kinematics WASM moduleId。
|
||
3. 校验 joint count 与 [JOINT_0]...[JOINT_4] 完整性。
|
||
4. sparm=identityfirst 决定 switchkins type 0 是 identity,不能按默认 kins 猜测。
|
||
```
|
||
|
||
`[HAL]`:
|
||
|
||
```text
|
||
HALUI = halui
|
||
HALFILE = LIB:basic_sim.tcl
|
||
POSTGUI_HALFILE = switchkins_postgui.hal
|
||
HALCMD = net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type
|
||
```
|
||
|
||
用途:
|
||
|
||
```text
|
||
1. HALUI 存在时,UI command 与 LinuxCNC halui 行为对齐。
|
||
2. HALFILE/POSTGUI_HALFILE 必须 stage,task/HAL runtime 才能构造同一机床上下文。
|
||
3. switchkins HALCMD 是 M428/M429/M430 影响 motion.switchkins-type 的证据。
|
||
```
|
||
|
||
`[HALUI]`:
|
||
|
||
```text
|
||
MDI_COMMAND = M429
|
||
MDI_COMMAND = M428
|
||
MDI_COMMAND = M430
|
||
```
|
||
|
||
用途:
|
||
|
||
```text
|
||
1. 记录 operator 命令入口。
|
||
2. 与 [RS274NGC] REMAP 和 [HAL] switchkins HALCMD 交叉校验。
|
||
3. 不直接作为 RUN 自动插入命令;RUN 程序内的 M428/M429/M430 由 interpreter/remap 处理。
|
||
```
|
||
|
||
`[TRAJ]`:
|
||
|
||
```text
|
||
COORDINATES
|
||
LINEAR_UNITS
|
||
ANGULAR_UNITS
|
||
DEFAULT_LINEAR_VELOCITY
|
||
MAX_LINEAR_VELOCITY
|
||
MAX_LINEAR_ACCELERATION
|
||
DEFAULT_LINEAR_ACCELERATION
|
||
```
|
||
|
||
要求:
|
||
|
||
```text
|
||
xyzac-trt: COORDINATES = XYZAC
|
||
xyzbc-trt: COORDINATES = XYZBC
|
||
LINEAR_UNITS = mm
|
||
ANGULAR_UNITS = deg
|
||
```
|
||
|
||
用途:
|
||
|
||
```text
|
||
1. COORDINATES 是 UI 轴、G-code 轴、runtime axisPose 的主契约。
|
||
2. 单位决定 DRO 和 velocity 显示,不能由前端默认值覆盖。
|
||
3. velocity/acceleration 是 planner/runtime limit 的来源。
|
||
```
|
||
|
||
`[EMCMOT]` 与 `[TASK]`:
|
||
|
||
```text
|
||
[EMCMOT]
|
||
EMCMOT = motmod
|
||
SERVO_PERIOD = 1000000
|
||
COMM_TIMEOUT = 1
|
||
|
||
[TASK]
|
||
TASK = milltask
|
||
CYCLE_TIME = 0.010
|
||
```
|
||
|
||
用途:
|
||
|
||
```text
|
||
1. SERVO_PERIOD 用于 taskHalStatusLoop 的 servo tick 语义。
|
||
2. CYCLE_TIME 用于 task cycle 语义和测试断言。
|
||
3. runtime readiness 必须能报告 task/motion/HAL 三者已按这些参数初始化。
|
||
```
|
||
|
||
`[EMCIO]`:
|
||
|
||
```text
|
||
TOOL_TABLE
|
||
```
|
||
|
||
用途:
|
||
|
||
```text
|
||
1. tool table 必须 stage 到 machine files。
|
||
2. G43/tool offset 相关状态不能用空表静默替代。
|
||
```
|
||
|
||
`[AXIS_*]`:
|
||
|
||
```text
|
||
MIN_LIMIT
|
||
MAX_LIMIT
|
||
MAX_VELOCITY
|
||
MAX_ACCELERATION
|
||
```
|
||
|
||
要求:
|
||
|
||
```text
|
||
xyzac-trt: [AXIS_X] [AXIS_Y] [AXIS_Z] [AXIS_A] [AXIS_C]
|
||
xyzbc-trt: [AXIS_X] [AXIS_Y] [AXIS_Z] [AXIS_B] [AXIS_C]
|
||
```
|
||
|
||
用途:
|
||
|
||
```text
|
||
1. 校验 profile coordinates 对应的 axis section 完整。
|
||
2. 约束 UI limit、DRO 范围、preview bounds。
|
||
3. 防止 xyzac/xyzbc 轴表混用。
|
||
```
|
||
|
||
`[JOINT_*]`:
|
||
|
||
```text
|
||
TYPE
|
||
HOME
|
||
MIN_LIMIT
|
||
MAX_LIMIT
|
||
MAX_VELOCITY
|
||
MAX_ACCELERATION
|
||
HOME_SEARCH_VEL
|
||
HOME_SEQUENCE
|
||
```
|
||
|
||
要求:
|
||
|
||
```text
|
||
JOINT_0..JOINT_4 必须完整。
|
||
JOINT_0..JOINT_2 TYPE = LINEAR。
|
||
xyzac-trt: JOINT_3/JOINT_4 分别对应 A/C rotary。
|
||
xyzbc-trt: JOINT_3/JOINT_4 分别对应 B/C rotary。
|
||
```
|
||
|
||
用途:
|
||
|
||
```text
|
||
1. 校验 [KINS] JOINTS=5 与 joint section 数量一致。
|
||
2. home/allHomed gate 的配置来源。
|
||
3. task/HAL runtime 初始化 joint status 的来源。
|
||
```
|
||
|
||
### 3.3 INI readiness 输出
|
||
|
||
`parseLinuxCncIni()` 应输出或间接形成这些结构化字段:
|
||
|
||
```js
|
||
{
|
||
profileId: "xyzac-trt",
|
||
iniPath: "configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini",
|
||
machineName: "sim-xyzac-trt-kins (switchkins)",
|
||
traj: {
|
||
coordinates: "XYZAC",
|
||
linearUnits: "mm",
|
||
angularUnits: "deg"
|
||
},
|
||
kinematics: {
|
||
name: "xyzac-trt-kins",
|
||
moduleId: "xyzac-trt",
|
||
switchkins: true,
|
||
identityFirst: true,
|
||
joints: 5
|
||
},
|
||
rs274ngc: {
|
||
halPinVars: true,
|
||
remaps: ["M428", "M429", "M430"],
|
||
subroutinePath: "./remap_subs",
|
||
parameterFile: "xyzac.var"
|
||
},
|
||
hal: {
|
||
halui: "halui",
|
||
halFiles: ["LIB:basic_sim.tcl"],
|
||
postguiHalFiles: ["switchkins_postgui.hal"],
|
||
switchkinsSignal: "motion.analog-out-03 => motion.switchkins-type"
|
||
},
|
||
emcmot: {
|
||
module: "motmod",
|
||
servoPeriodNs: 1000000
|
||
},
|
||
task: {
|
||
module: "milltask",
|
||
cycleTimeSeconds: 0.010
|
||
},
|
||
emcio: {
|
||
toolTable: "xyzac-trt.tbl"
|
||
},
|
||
axes: {
|
||
X: { minLimit: -200, maxLimit: 200 },
|
||
Y: { minLimit: -100, maxLimit: 100 },
|
||
Z: { minLimit: -120, maxLimit: 120 },
|
||
A: { minLimit: -100, maxLimit: 50 },
|
||
C: { minLimit: -36000, maxLimit: 36000 }
|
||
},
|
||
joints: [
|
||
{ index: 0, type: "LINEAR", axis: "X" },
|
||
{ index: 1, type: "LINEAR", axis: "Y" },
|
||
{ index: 2, type: "LINEAR", axis: "Z" },
|
||
{ index: 3, type: "ANGULAR", axis: "A" },
|
||
{ index: 4, type: "ANGULAR", axis: "C" }
|
||
],
|
||
validation: {
|
||
ready: true,
|
||
errors: []
|
||
}
|
||
}
|
||
```
|
||
|
||
`xyzbc-trt` 的输出必须只在 profileId、machineName、coordinates、kinematics module、parameter/tool table、rotary axis B/C 等字段上变化,不能沿用 xyzac 的 A/C axis contract。
|
||
|
||
### 3.4 INI contract 失败时的阻断
|
||
|
||
这些情况必须让 `state.iniConfigReadiness.ready=false`,并阻断 RUN:
|
||
|
||
```text
|
||
缺少 [EMC] MACHINE。
|
||
缺少 [TRAJ] COORDINATES。
|
||
COORDINATES 不是 XYZAC 或 XYZBC。
|
||
[KINS] KINEMATICS 不是 xyzac-trt-kins 或 xyzbc-trt-kins。
|
||
[KINS] JOINTS 不是 5。
|
||
缺少 M428/M429/M430 remap。
|
||
HAL_PIN_VARS 不是 1。
|
||
缺少 motion.analog-out-03 => motion.switchkins-type HALCMD。
|
||
缺少 [EMCMOT] SERVO_PERIOD。
|
||
缺少 [TASK] CYCLE_TIME。
|
||
缺少 TOOL_TABLE。
|
||
axis section 与 COORDINATES 不一致。
|
||
joint section 数量与 [KINS] JOINTS 不一致。
|
||
xyzac INI 指向 xyzbc tool table/parameter file,或反向混用。
|
||
```
|
||
|
||
阻断消息建议:
|
||
|
||
```text
|
||
run blocked: LinuxCNC INI contract invalid
|
||
run blocked: INI missing required section [KINS]
|
||
run blocked: INI coordinates do not match selected profile
|
||
run blocked: INI switchkins remap incomplete
|
||
run blocked: INI HAL switchkins signal missing
|
||
run blocked: INI joint/axis contract mismatch
|
||
```
|
||
|
||
### 3.5 与 RUN gate 的关系
|
||
|
||
INI contract 通过只是 RUN 的第一层 gate。RUN 仍必须继续检查:
|
||
|
||
```text
|
||
1. kinematics WASM 已按 INI [KINS] moduleId 加载。
|
||
2. machine files 已按同一个 INI stage。
|
||
3. task/HAL runtime 已按同一个 INI/session 初始化。
|
||
4. selected G-code 已通过 task plan open 打开。
|
||
5. task status 的 opened file 与 selected staged G-code 一致。
|
||
6. machine ON、AUTO、homed/no_force_homing 满足。
|
||
```
|
||
|
||
所以不能把 `parseLinuxCncIni().validation.ready=true` 等同于 `RUN` ready。
|
||
|
||
## 4. 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
|
||
state.taskHalSession.openProgram === true
|
||
state.taskHalStatus.task.file 或 openedProgram.path 指向同一个 staged G-code
|
||
state.taskHalStatus.task.state 是 ON
|
||
state.taskHalStatus.task.mode 是 AUTO,或 RUN 前可切换到 AUTO
|
||
state.taskHalStatus.motion.allHomed === true,或当前仿真 profile 明确 no_force_homing
|
||
```
|
||
|
||
如果任一项不满足,`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
|
||
run blocked: machine is not on
|
||
run blocked: machine is not homed
|
||
run blocked: task mode is not AUTO
|
||
```
|
||
|
||
## 5. LinuxCNC 源码对照结论
|
||
|
||
`RUN` 命令修改方向总体合适,但必须严格贴近 LinuxCNC 的 task 语义:
|
||
|
||
```text
|
||
RUN 不是前端 sample playback。
|
||
RUN 不是直接解析 G-code 后自增 activeLine。
|
||
RUN 是在已打开程序、机床可运行、AUTO 模式下发送 EMC_TASK_PLAN_RUN,
|
||
随后由 task 主循环持续 read/execute interpreter,并从 motion/HAL 状态读取反馈。
|
||
```
|
||
|
||
源码证据:
|
||
|
||
```text
|
||
/home/mes123456/cnc_wams/linuxcnc/src/emc/usr_intf/halui.cc:1096
|
||
sendProgramRun(int line)
|
||
- updateStatus()
|
||
- 如果 emcStatus->task.file 为空,直接返回 -1
|
||
- 保存 programStartLine
|
||
- 设置 EMC_TASK_PLAN_RUN.line
|
||
- sendAuto()
|
||
- emcCommandSend(EMC_TASK_PLAN_RUN)
|
||
|
||
/home/mes123456/cnc_wams/linuxcnc/src/emc/usr_intf/shcom.cc:750
|
||
sendProgramOpen(program)
|
||
- 发送 EMC_TASK_PLAN_OPEN
|
||
- 本地进程发送文件名
|
||
- remote process 通过 remote_buffer 分块发送文件内容
|
||
|
||
/home/mes123456/cnc_wams/linuxcnc/src/emc/usr_intf/shcom.cc:814
|
||
sendProgramRun(int line)
|
||
- status 为 AUTO update 时先 updateStatus()
|
||
- task.file 为空时尝试重新打开 lastProgramFile
|
||
- 再发送 EMC_TASK_PLAN_RUN
|
||
|
||
/home/mes123456/cnc_wams/linuxcnc/src/emc/task/emctaskmain.cc:2164
|
||
EMC_TASK_PLAN_OPEN
|
||
- 接收 remote 文件或打开本地文件
|
||
- 调用 emcTaskPlanOpen(open_msg->file)
|
||
- 成功后写入 emcStatus->task.file
|
||
|
||
/home/mes123456/cnc_wams/linuxcnc/src/emc/task/emctaskmain.cc:2318
|
||
EMC_TASK_PLAN_RUN
|
||
- 未 homed 且 no_force_homing=false 时拒绝运行
|
||
- 清 single stepping
|
||
- 必要时重新 emcTaskPlanOpen(emcStatus->task.file)
|
||
- 保存 programStartLine
|
||
- 设置 interpState=READING
|
||
- 清 task_paused
|
||
|
||
/home/mes123456/cnc_wams/linuxcnc/src/emc/task/emctaskmain.cc:2337
|
||
EMC_TASK_PLAN_PAUSE
|
||
- emcTrajPause()
|
||
- interpState=PAUSED
|
||
- task_paused=1
|
||
|
||
/home/mes123456/cnc_wams/linuxcnc/src/emc/task/emctaskmain.cc:2369
|
||
EMC_TASK_PLAN_RESUME
|
||
- emcTrajResume()
|
||
- 恢复 interpState
|
||
- 清 task_paused
|
||
|
||
/home/mes123456/cnc_wams/linuxcnc/src/emc/task/emctask.cc:543
|
||
emcTaskPlanOpen(file)
|
||
- 清 motionLine/currentLine/readLine
|
||
- interp.open(file)
|
||
- taskplanopen=1
|
||
|
||
/home/mes123456/cnc_wams/linuxcnc/src/emc/task/emctask.cc:566
|
||
emcTaskPlanRead()
|
||
- interp.read()
|
||
- 文件未打开时用 emcStatus->task.file 重新 open/read
|
||
```
|
||
|
||
对当前 web runtime 的约束:
|
||
|
||
```text
|
||
1. initializeTaskHalSession({ openProgram: true }) 必须等价于先完成 EMC_TASK_PLAN_OPEN。
|
||
2. RUN gate 必须确认 opened program 与当前 selected G-code 是同一个 staged machine-file。
|
||
3. RUN 发送 EMC_TASK_PLAN_RUN 后,UI 不能用 canonical timing 或 fixture sample 冒充 task 反馈。
|
||
4. 连续反馈必须来自 taskHalRuntime.runCycles/readStatus,且 status 的 task/motion/HAL 字段必须同源。
|
||
5. PAUSE/RESUME/ABORT 要按 LinuxCNC task command 修改状态循环,而不是只改前端 runState。
|
||
```
|
||
|
||
## 6. 详细测试计划
|
||
|
||
### 6.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
|
||
```
|
||
|
||
### 6.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。
|
||
|
||
### 6.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
|
||
```
|
||
|
||
### 6.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 不一致。
|
||
```
|
||
|
||
### 6.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
|
||
```
|
||
|
||
## 7. 编写 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。
|
||
8. 检查 task status 的 opened file 与当前 staged G-code 一致。
|
||
9. 检查 machine ON、AUTO mode、homed/no_force_homing。
|
||
```
|
||
|
||
返回结构:
|
||
|
||
```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 对齐
|
||
5. 如果 task mode 不是 AUTO,先发送 EMC_TASK_SET_MODE AUTO 并等待 status 确认
|
||
6. 如果 task state 不是 ON,先发送 EMC_TASK_SET_STATE ON 并等待 status 确认
|
||
```
|
||
|
||
未满足前置条件时,只设置 `operatorMessage`,不推进任何 line/sample。
|
||
|
||
### Step 3: 拆分 task command 与 taskHalStatusLoop
|
||
|
||
`RUN` 应只发送 LinuxCNC task 命令:
|
||
|
||
```text
|
||
EMC_TASK_SET_STATE ON
|
||
EMC_TASK_SET_MODE AUTO
|
||
EMC_TASK_PLAN_RUN line = linuxcncStartLine
|
||
```
|
||
|
||
说明:
|
||
|
||
```text
|
||
linuxcncStartLine 应按 LinuxCNC 的 program run line 语义保存。
|
||
普通从头运行传 0。
|
||
run-from-line 才传明确 line,并需要单独处理 start line、previous modal state 和安全性。
|
||
不要用 UI activeLine 自行推导 programStartLine。
|
||
```
|
||
|
||
然后启动 `taskHalStatusLoop`:
|
||
|
||
```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 taskHalStatusLoop
|
||
```
|
||
|
||
说明:
|
||
|
||
```text
|
||
这里的 taskHalStatusLoop 可以在 store 主线程调度,也可以放到 worker 内部 postMessage 推送。
|
||
关键不是 timer 本身,而是每个 tick 都必须由 task/HAL/motion runtime 的 runCycles/readStatus 产生反馈。
|
||
```
|
||
|
||
### Step 4: 增加 RUN status loop 状态
|
||
|
||
建议 state 增加:
|
||
|
||
```js
|
||
taskHalStatusLoop: {
|
||
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 控制 taskHalStatusLoop
|
||
|
||
行为要求:
|
||
|
||
```text
|
||
STOP/ABORT:
|
||
send EMC_TASK_ABORT
|
||
stop taskHalStatusLoop
|
||
read final status
|
||
|
||
PAUSE:
|
||
send EMC_TASK_PLAN_PAUSE
|
||
taskHalStatusLoop 可停止或降频读取 paused status
|
||
runState=paused
|
||
|
||
RESUME:
|
||
send EMC_TASK_PLAN_RESUME
|
||
restart taskHalStatusLoop
|
||
|
||
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。
|
||
|
||
## 8. 开发验收命令
|
||
|
||
基础检查:
|
||
|
||
```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
|
||
node web-rtcp-5axis-sim-plan/tests/node/verify_run_feedback_loop.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
|
||
```
|
||
|
||
## 9. 完成标准
|
||
|
||
`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。
|
||
9. RUN 失败时能明确区分 INI/profile、open program、machine ON、AUTO、homed、runtime readiness 哪一项未满足。
|
||
```
|
||
|
||
未满足以上条件时,状态应继续标记为:
|
||
|
||
```text
|
||
fullLinuxCncProgramExecutionReady=false
|
||
hardwareDrive=false
|
||
hostRealtimeKernel=false
|
||
externalUserMProcessReady=false
|
||
```
|