结论:已完成浏览器侧真实加载验证,M428/M429/M430 的配置入口进一步从 LinuxCNC INI/HALFILE/REMAP 来源生成,native 与 source-link 验证通过。
201 lines
15 KiB
Markdown
201 lines
15 KiB
Markdown
# LinuxCNC Web/WASM CNC Simulator
|
||
|
||
本目录是把 LinuxCNC 面向浏览器仿真的改写入口。目标不是把完整 LinuxCNC 直接搬进浏览器,而是复用可移植的解释器、运动学和刀路算法,替换实时 HAL/NML/GUI 层,输出适合 Web Worker、Three.js/WebGPU 和后续碰撞/去料仿真的事件流。
|
||
|
||
## 关键判断
|
||
|
||
- 不能按“整套 LinuxCNC 编译为 wasm”做。LinuxCNC 包含实时线程、HAL、NML、动态模块、Python/Boost.Python remap、桌面 GUI 和 POSIX 依赖,这些都不是浏览器仿真核心。
|
||
- 可以先复用 `src/emc/rs274ngc` 解释器,接管 `canon.hh` 中的 Canonical Machining Functions,把 `STRAIGHT_FEED`、`ARC_FEED`、`DWELL`、`CHANGE_TOOL` 等调用记录为仿真事件。
|
||
- Fanuc、Siemens 等主流系统应作为“方言层”实现:先把宏变量、固定循环、坐标旋转、RTCP/TRAORI/CYCLE800 等控制器特性归一化为内部 IR,再交给同一个仿真内核。
|
||
- 浏览器端不做实时控制,只做可重复、可暂停、可回放的离线仿真,所以速度规划、前瞻、碰撞和去料可以使用非实时算法。
|
||
|
||
## 分层
|
||
|
||
1. `dialect`
|
||
- LinuxCNC RS274/NGC
|
||
- Fanuc Macro B / common milling and turning extensions
|
||
- Siemens 840D-style cycles and transforms
|
||
|
||
2. `interp`
|
||
- LinuxCNC interpreter compiled to wasm where possible
|
||
- Canon callback adapter records normalized motion/tool/state events
|
||
|
||
3. `sim-core`
|
||
- Units, modal state, work offsets, tool table
|
||
- Arc/NURBS segmentation
|
||
- 3/4/5-axis kinematics and RTCP
|
||
- Feed/time estimation and non-realtime lookahead
|
||
|
||
4. `verification`
|
||
- Golden G-code corpus
|
||
- Controller dialect compatibility matrix
|
||
- Numeric tolerance checks against LinuxCNC native output
|
||
|
||
5. `web`
|
||
- Web Worker wrapper around wasm
|
||
- Toolpath display
|
||
- Machine model, fixtures, stock, collision and material removal
|
||
|
||
## First milestone
|
||
|
||
The first useful target is:
|
||
|
||
- compile a small wasm module exposing `cnc_sim_*` C ABI;
|
||
- connect LinuxCNC RS274 interpreter to a Canon event sink;
|
||
- return a JSON event stream to TypeScript;
|
||
- render rapid/feed/arc events in the browser;
|
||
- compare the event stream against native LinuxCNC for a small test corpus.
|
||
|
||
## 当前进度
|
||
|
||
- 已有稳定 C ABI 和 Web 调用封装。
|
||
- 已有数控系统风格网页面板。
|
||
- 已有临时 smoke parser,用于在 LinuxCNC 后端接入前测试 UI 和 wasm 回调链路。
|
||
- 已有 native smoke test 和 JSON dump 工具。
|
||
- 已有 LinuxCNC `canon.hh` bridge,并已通过独立 smoke test。
|
||
- 已有 native `librs274` runner,可以让 LinuxCNC 解释器输出 `CncSimEvent`。
|
||
- 已有最小 LinuxCNC tooldata 初始化,native runner 和 API 后端都能覆盖 `T... M6` 换刀路径。
|
||
- 已有 LinuxCNC RS274 源码级链接 smoke:本项目直接编译 23 个解释器 core 源文件,不再通过 `librs274` 取得解释器主体。
|
||
- 已有五轴 RTCP 第一版几何内核,可根据编程刀尖点、A/B/C 姿态和刀长计算枢轴/主轴点补偿位置。
|
||
- 已有坐标系事件回归语料,覆盖 `G10 L2`、`G10 L20`、`G10 P0`、`G54`-`G59.3` 全部工件坐标系选择、`G52`、`G92/G92.1/G92.2/G92.3` 的 G5X/G92/XY 旋转事件。
|
||
- 已有探针事件回归语料,LinuxCNC `G38.2/G38.3/G38.4/G38.5` 会输出独立 `probe` 事件,不再混作普通直线进给;`probe.reserved` 保留 LinuxCNC `probe_type`:`0=trip/error`、`1=trip/no-error`、`2=clear/error`、`3=clear/no-error`。
|
||
- 已有主轴方向状态回归语料,`M3/M4/M5` 会通过 `set-spindle.reserved` 输出 `1=顺时针`、`2=逆时针`、`0=停止`。
|
||
- 已有主轴速度模式回归语料,`G96/G97` 会通过 `comment.reserved` 临时输出 `960=CSS`、`970=constant RPM`,`feed` 暂存 LinuxCNC `SET_SPINDLE_MODE` 的 mode/max-RPM 值。
|
||
- 已有主轴定向回归语料,`M19 R... P... Q...` 会通过 `comment.reserved` 临时输出 `1901=orient spindle`、`1902=wait orient complete`,`feed` 暂存 R 角度,`arcTurns` 暂存 P 模式,`dwellSeconds` 暂存 Q 超时。
|
||
- 已有主轴同步进给和螺纹回归语料,`G33/G33.1/G76` 会通过 `comment.reserved` 临时输出 `3301=speed-feed sync start`、`3302=velocity sync start`、`3300=sync stop`,`feed` 暂存每转进给量。
|
||
- 已有车床直径/半径模式回归语料,`G7/G8` 会切换 X 轴输入缩放,`G76` 会在直径模式下同步缩放线程几何参数。
|
||
- 已有 LinuxCNC 常用只读命名参数回归语料,`#<_absolute>`、`#<_incremental>`、`#<_metric>`、`#<_imperial>`、`#<_lathe_diameter_mode>`、`#<_lathe_radius_mode>` 能在 O-word 条件里直接读取当前模态状态。
|
||
- 已有覆盖控制回归语料,`M48/M49/M50/M51/M52/M53` 会通过 `comment.reserved` 临时输出 `50=feed override`、`51=speed override`、`52=adaptive feed`、`53=feed hold`,`feed` 暂存启用状态,`tool` 对 speed override 暂存 spindle 号。
|
||
- 已有 I/O M-code 回归语料,`M62/M63/M64/M65/M66/M67/M68` 会通过 `comment.reserved` 临时输出对应 M 码号,`tool` 暂存 P/E 通道号,`feed` 暂存输出值或 M66 等待模式,`arcTurns` 暂存 M66 输入类型,`dwellSeconds` 暂存 M66 超时。
|
||
- 已有 modal state 回归语料,`M70/M71/M72` 在 smoke parser 中支持主程序级保存、失效、恢复,`M73` 支持 O-word 子程序返回自动恢复;native/source 语料验证恢复后的距离模式、单位和 XY 平面运动。
|
||
- 已有注释事件行号回归语料,LinuxCNC `COMMENT` 事件会保留当前 G-code 行号。
|
||
- 已有当前刀号事件行号回归语料,LinuxCNC `M61 Q...` 会输出带行号的 `tool-change` 事件。
|
||
- 已有停止类事件回归语料,`M0/M1/M60` 会通过 `program-end.reserved` 输出 `1=程序停`、`2=可选停`、`3=托盘交换`。
|
||
- 已有冷却液状态回归语料,`M7/M8/M9` 会通过 `comment.reserved` 临时输出 `10/11=mist off/on`、`20/21=flood off/on`。
|
||
- 已有进给模式回归语料,`G93/G94/G95` 会通过 `comment.reserved` 临时输出 `93/94/95`,并通过 `set-feed` 记录 Canon feed mode 回调。
|
||
- 已有运动控制模式回归语料,`G61/G61.1/G64` 会通过 `comment.reserved` 临时输出 `611/612/640`,`feed` 暂存 G64 tolerance。
|
||
- smoke parser 已有固定循环第一版展开,覆盖 `G73` 高速啄钻、`G74/G84` 攻丝、`G81` 普通钻、`G82` 孔底暂停钻、`G83` 啄钻、`G85` 镗孔进给退刀、`G86` 镗孔停主轴快速退刀、`G87` 背镗、`G88` 手动退刀镗孔、`G89` 镗孔暂停后进给退刀,以及 `G80` 取消、`G98/G99` 返回模式和 `L` 重复次数;这些循环已按 LinuxCNC `G17/G18/G19` 平面映射进刀轴,`G87` 会按平面重映射 `I/J/K`。
|
||
- LinuxCNC native/source 对照已扩展到 `G82` 孔底暂停、`G83` 啄钻和 `G18/G19` 固定循环平面关键事件,覆盖 `G74/G84/G86/G87/G88` 非 XY 平面序列、孔底 dwell、啄钻深度序列、R 平面退刀、手动退刀停机和背镗偏置路径。
|
||
- smoke parser 已有 Fanuc 风格 `M98 P... L...` / `M99` 子程序调用第一版,支持同文件 `O...` 子程序块和重复调用展开;未知子程序、裸 `M99` 和过深嵌套会返回明确错误。
|
||
- smoke parser 已有 LinuxCNC 风格 O-word 子程序第一版,覆盖数字 `O100 ...` 和命名 `O<name> ...` 的 `sub` / `call [args]` / `return` / `endsub`,支持简单数字实参、`#1 = ...` 编号参数赋值、`#<name> = ...` 命名参数赋值、`X#1` / `X#<name>` 参数引用、`+ - * /` 可嵌套方括号表达式,以及 `ABS[]`、`SQRT[]`、`EXP[]`、`LN[]`、角度制 `SIN[]` / `COS[]` / `TAN[]` / `ASIN[]` / `ACOS[]`、LinuxCNC 双参数 `ATAN[]/[]`、`FIX[]` / `FUP[]` / `ROUND[]`,并拒绝和 `M98/M99` 风格混用。
|
||
- LinuxCNC native/source runner 已支持显式文件模式执行,O-word 子程序语料会通过 LinuxCNC 自身 `open/read/execute` 路径验证,而不是逐行模拟;native/source 回归现已同时覆盖数字 `O100` 和命名 `O<move_plus>` 子程序、实参传递、命名参数赋值、`return` 跳过体尾,以及 `if` / `elseif` / `else`、`while`、`repeat`、`do` / `while`、`break`、`continue` 控制流。
|
||
- LinuxCNC Canon bridge 会把当前解释行号补到没有自带 `lineno` 的回调事件上,方便 Web 端诊断和源码高亮。
|
||
- 下一步是继续替换源码级链接中残留的 Python、INI/HAL、文件系统和动态加载依赖,并把 RTCP 内核接入 canon 事件流和机型配置。
|
||
|
||
## 本地测试
|
||
|
||
```bash
|
||
./test-all-native.sh
|
||
```
|
||
|
||
当前 native 测试覆盖:
|
||
|
||
- smoke parser
|
||
- Canon event sink
|
||
- LinuxCNC Canon bridge
|
||
- 直接链接 LinuxCNC `librs274` 的 runner
|
||
- 通过 `cnc_sim_api` 选择 `linuxcnc-rs274` 后端
|
||
- LinuxCNC RS274 源文件语法探针和对象编译探针
|
||
- LinuxCNC RS274 源码级链接 smoke
|
||
- 五轴 RTCP 几何内核 smoke
|
||
- `M3` / `M4` / `M5` 主轴方向事件回归
|
||
- `M61 Q...` 当前刀号事件行号回归
|
||
- LinuxCNC 注释事件行号回归
|
||
- `M0` / `M1` / `M60` 停止类事件回归
|
||
- `M7` / `M8` / `M9` 冷却液状态回归
|
||
- `G93` / `G94` / `G95` 进给模式回归
|
||
- `G61` / `G61.1` / `G64` 运动控制模式回归
|
||
- smoke parser `G73` / `G74` / `G81` / `G82` / `G83` / `G84` / `G85` / `G86` / `G87` / `G88` / `G89` / `G80` / `G98` / `G99` / `L` 固定循环展开回归,以及 `G18/G19` 平面进刀轴和 `G87 I/J/K` 平面映射回归
|
||
- LinuxCNC native/source `G74` / `G82` / `G83` / `G84` / `G86` / `G87` / `G88` / `G18` / `G19` 固定循环对照回归
|
||
- smoke parser `M98 P... L...` / `M99` 子程序调用回归
|
||
- smoke parser LinuxCNC 风格 `O... sub/call/return/endsub` 子程序调用回归
|
||
- `G10 L2` / `G10 L20` / `G10 P0` / `G54`-`G59.3` / `G92.1` 坐标系事件回归
|
||
- `G38.3` 探针事件回归
|
||
|
||
## 后端选择
|
||
|
||
公共 API 使用同一个入口解析程序,后端通过 JSON 配置选择:
|
||
|
||
```json
|
||
{"backend":"linuxcnc-rs274"}
|
||
```
|
||
|
||
`linuxcnc-rs274` 是默认后端,wasm 和 UI 默认通过 LinuxCNC RS274 源码路径解析;`smoke` 仅用于显式编译/选择的 legacy 联调路径。
|
||
|
||
网页面板右上角的 `BACKEND` 下拉框会把该配置传给 wasm/core。`./build-wasm.sh` 会生成 `web/public/cnc_sim.js` 和 `web/public/cnc_sim.wasm`,随后运行 `test-web-wasm-node-smoke.cjs` 和 `test-web-wasm-browser-smoke.sh`;这些 smoke 会验证 wasm 中的 LinuxCNC RS274 后端可在 Node 和 Chromium 浏览器中加载、可解析基础运动,并保留 `M428/M429/M430` remap 触发的运动学切换事件。
|
||
|
||
## RTCP 配置
|
||
|
||
RTCP 默认关闭。开启后,原有 `rapid`、`linear-feed`、`arc-feed` 事件仍表示编程刀尖轨迹;core 会额外发出 `rtcp-pivot` 事件,`start`/`end` 是按刀长和 A/B/C 姿态补偿后的枢轴/主轴点轨迹,`center` 的 `x/y/z` 暂存当前刀具向量。
|
||
|
||
```json
|
||
{
|
||
"backend": "linuxcnc-rs274",
|
||
"rtcp": {
|
||
"enabled": true,
|
||
"toolLength": 100,
|
||
"toolLengths": {
|
||
"7": 125
|
||
}
|
||
},
|
||
"xyzbcTrt": {
|
||
"xRotPoint": 0,
|
||
"yRotPoint": 0,
|
||
"zRotPoint": 0,
|
||
"xOffset": -20,
|
||
"zOffset": -15,
|
||
"conventionalDirections": false
|
||
}
|
||
}
|
||
```
|
||
|
||
RTCP pivot 事件只在已知 LinuxCNC switchkins 类型下输出。`M428` 切换到 `XYZBC_TRT` 后,`xyzbcTrt` 对应 LinuxCNC `xyzbc-trt-kins` 的 HAL pin:`x-rot-point`、`y-rot-point`、`z-rot-point`、`x-offset`、`z-offset`、`conventional-directions`;刀长仍来自 `toolLength` / `toolLengths`。`M430` 使用 LinuxCNC `userkfuncs.c` 经 `kins_util.c` identity 运动学路径。未支持或未知的 switchkins 类型不会回退到自研 RTCP 几何。
|
||
|
||
RTCP G 码控制已开始标准化:
|
||
|
||
- `G43.4 H...`:开启 RTCP,`H` 号进入事件,实际刀长优先从 JSON 配置中的 `toolLengths` 按 H 号读取,未配置时回退到 `toolLength`。
|
||
- `G43.5 H...`:同样作为 RTCP 开启处理。
|
||
- `G49`:关闭 RTCP。
|
||
|
||
解析后会发出 `rtcp-state` 事件。事件中的 `feed` 表示 RTCP 状态:`0=关闭`、`1=开启`;`tool` 表示 H 号;`dwell_seconds` 暂存当前配置刀长。
|
||
|
||
## 运动学切换 M 码
|
||
|
||
core 已对原型中的运动学切换 M 码做标准化解析:
|
||
|
||
- `M429`:切换到三轴恒等运动学 `IDENTITY`。
|
||
- `M428`:切换到 LinuxCNC `xyzbc-trt-kins` 的 XYZBC TRT 运动学。
|
||
- `M430`:切换到 LinuxCNC 默认 `userk` 运动学;当前对齐 `userkfuncs.c` 的 identity 正/逆解。
|
||
|
||
解析后会发出 `kinematics-switch` 事件。事件中的 `reserved` 字段表示运动学类型:`0=IDENTITY`、`1=XYZBC_TRT`、`2=USERK_IDENTITY`。这些 M 码对齐 LinuxCNC `remap_subs/428remap.ngc`、`429remap.ngc`、`430remap.ngc`,只设置 `motion.switchkins-type`,不隐式开启或关闭 RTCP;RTCP 状态仍由 `G43.4`、`G43.5`、`G49` 控制。同一行中的 `M428 M429 M430` 会按出现顺序产生三个切换事件。
|
||
|
||
`linuxcnc-rs274` native API backend 会在送入 LinuxCNC 解释器前拦截只包含这些切换 M 码的行,避免 LinuxCNC 去查找外部用户 M-code 文件。
|
||
|
||
## 坐标系事件
|
||
|
||
Canon bridge 已不再丢弃坐标系相关回调,会输出:
|
||
|
||
- `set-g5x-offset`:来自 `SET_G5X_OFFSET`,`tool` 字段存 G5X index,`start` 存 XYZABCUVW offset。
|
||
- `set-g92-offset`:来自 `SET_G92_OFFSET`,`start` 存 XYZABCUVW offset。
|
||
- `set-xy-rotation`:来自 `SET_XY_ROTATION`,`feed` 暂存旋转角度。
|
||
|
||
这些事件先保证 LinuxCNC Canon 层信息完整进入 Web/core。具体 G-code(如 `G10`、`G92`、坐标旋转)是否触发这些回调,还要继续按 LinuxCNC 解释器参数路径逐项补回归语料。
|
||
目前已有多组回归语料:`tests/gcode/linuxcnc_coordinate_offsets.ngc` 覆盖 `G10 L2 P1 X... Y... Z... R...` 触发 `set-g5x-offset` / `set-xy-rotation`,以及 `G92.1` 触发 `set-g92-offset` 清零;`tests/gcode/linuxcnc_coordinate_l20.ngc` 覆盖 `G10 L20 P2` 按当前位置和目标工件坐标计算 G55 偏置;`tests/gcode/linuxcnc_coordinate_p0.ngc` 覆盖 `G10 L2 P0` 指向当前活动坐标系;`tests/gcode/linuxcnc_coordinate_select_all.ngc` 覆盖 `G54`-`G59.3` 选择时的 G5X index 和偏置载入。测试脚本会在坐标系语料之间重置参数文件,避免 LinuxCNC 持久参数互相污染。后续继续扩展持久参数文件读写策略和旋转叠加运动路径。
|
||
LinuxCNC 中部分 Canon 函数不携带行号参数,bridge 会在调用解释器 `read/execute` 前记录当前输入行,并用它填充这类事件的 `line` 字段。
|
||
|
||
## CMake native LinuxCNC 后端
|
||
|
||
手写测试脚本仍是当前主验证路径。如果使用 CMake,启用 native LinuxCNC 后端的配置为:
|
||
|
||
```bash
|
||
cmake -S core -B build/native-linuxcnc \
|
||
-DCNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND=ON \
|
||
-DCNC_SIM_LINUXCNC_ROOT=/home/cnc/桌面/cnc/linuxcnc
|
||
```
|
||
|
||
该选项是 native-only,会链接 LinuxCNC 已构建的 `librs274` 和 `libtooldata`。
|
||
|
||
## Legal note
|
||
|
||
LinuxCNC is GPL licensed. If this wasm module links LinuxCNC code, the combined simulator core must be distributed under GPL-compatible terms unless you replace that part with an independently written interpreter.
|