2026-06-05 07:56:33 +08:00
2026-05-22 04:43:21 +08:00

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 FunctionsSTRAIGHT_FEEDARC_FEEDDWELLCHANGE_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 L2G10 L20G10 P0G54-G59.3 全部工件坐标系选择、G52G92/G92.1/G92.2/G92.3 的 G5X/G92/XY 旋转事件。
  • 已有探针事件回归语料LinuxCNC G38.2/G38.3/G38.4/G38.5 会输出独立 probe 事件,不再混作普通直线进给;probe.reserved 保留 LinuxCNC probe_type0=trip/error1=trip/no-error2=clear/error3=clear/no-error
  • 已有主轴方向状态回归语料,M3/M4/M5 会通过 set-spindle.reserved 输出 1=顺时针2=逆时针0=停止
  • 已有主轴速度模式回归语料,G96/G97 会通过 comment.reserved 临时输出 960=CSS970=constant RPMfeed 暂存 LinuxCNC SET_SPINDLE_MODE 的 mode/max-RPM 值。
  • 已有主轴定向回归语料,M19 R... P... Q... 会通过 comment.reserved 临时输出 1901=orient spindle1902=wait orient completefeed 暂存 R 角度,arcTurns 暂存 P 模式,dwellSeconds 暂存 Q 超时。
  • 已有主轴同步进给和螺纹回归语料,G33/G33.1/G76 会通过 comment.reserved 临时输出 3301=speed-feed sync start3302=velocity sync start3300=sync stopfeed 暂存每转进给量。
  • 已有车床直径/半径模式回归语料,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 override51=speed override52=adaptive feed53=feed holdfeed 暂存启用状态,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/on20/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/640feed 暂存 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 / elsewhilerepeatdo / whilebreakcontinue 控制流。
  • LinuxCNC Canon bridge 会把当前解释行号补到没有自带 lineno 的回调事件上,方便 Web 端诊断和源码高亮。
  • 下一步是继续替换源码级链接中残留的 Python、INI/HAL、文件系统和动态加载依赖并把 RTCP 内核接入 canon 事件流和机型配置。

本地测试

./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 配置选择:

{"backend":"linuxcnc-rs274"}

linuxcnc-rs274 是默认后端wasm 和 UI 默认通过 LinuxCNC RS274 源码路径解析;smoke 仅用于显式编译/选择的 legacy 联调路径。

网页面板右上角的 BACKEND 下拉框会把该配置传给 wasm/core。./build-wasm.sh 会生成 web/public/cnc_sim.jsweb/public/cnc_sim.wasm,随后运行 test-web-wasm-node-smoke.cjstest-web-wasm-browser-smoke.sh;这些 smoke 会验证 wasm 中的 LinuxCNC RS274 后端可在 Node 和 Chromium 浏览器中加载、可解析基础运动,并保留 M428/M429/M430 remap 触发的运动学切换事件。

RTCP 配置

RTCP 默认关闭。开启后,原有 rapidlinear-feedarc-feed 事件仍表示编程刀尖轨迹core 会额外发出 rtcp-pivot 事件,start/end 是按刀长和 A/B/C 姿态补偿后的枢轴/主轴点轨迹,centerx/y/z 暂存当前刀具向量。

{
  "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 pinx-rot-pointy-rot-pointz-rot-pointx-offsetz-offsetconventional-directions;刀长仍来自 toolLength / toolLengthsM430 使用 LinuxCNC userkfuncs.ckins_util.c identity 运动学路径。未支持或未知的 switchkins 类型不会回退到自研 RTCP 几何。

RTCP G 码控制已开始标准化:

  • G43.4 H...:开启 RTCPH 号进入事件,实际刀长优先从 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=IDENTITY1=XYZBC_TRT2=USERK_IDENTITY。这些 M 码对齐 LinuxCNC remap_subs/428remap.ngc429remap.ngc430remap.ngc,只设置 motion.switchkins-type,不隐式开启或关闭 RTCPRTCP 状态仍由 G43.4G43.5G49 控制。同一行中的 M428 M429 M430 会按出现顺序产生三个切换事件。

linuxcnc-rs274 native API backend 会在送入 LinuxCNC 解释器前拦截只包含这些切换 M 码的行,避免 LinuxCNC 去查找外部用户 M-code 文件。

坐标系事件

Canon bridge 已不再丢弃坐标系相关回调,会输出:

  • set-g5x-offset:来自 SET_G5X_OFFSETtool 字段存 G5X indexstart 存 XYZABCUVW offset。
  • set-g92-offset:来自 SET_G92_OFFSETstart 存 XYZABCUVW offset。
  • set-xy-rotation:来自 SET_XY_ROTATIONfeed 暂存旋转角度。

这些事件先保证 LinuxCNC Canon 层信息完整进入 Web/core。具体 G-codeG10G92、坐标旋转)是否触发这些回调,还要继续按 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 后端的配置为:

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 已构建的 librs274libtooldata

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.

Description
LinuxCNC-aligned CNC simulator
Readme 8.2 MiB
Languages
C++ 48.6%
Shell 40.1%
JavaScript 4.1%
C 4%
POV-Ray SDL 2%
Other 1.1%