# 5axis-xyzbc-trt-sim 执行过程分析 本文分析当前 LinuxCNC 源码树中 `5axis-xyzbc-trt-sim` 对应的仿真配置。实际入口配置文件为: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini ``` 该配置是一个 `axis` GUI + `basic_sim.tcl` 仿真 HAL + `xyzbc-trt-kins` 可切换运动学 + PyVCP/halui 控制面板 + Vismach 三维模型的五轴转台仿真。 ## 1. 启动入口 如果从项目中已有快捷方式启动,入口文件是: ```text linuxcnc-rtcp-5axis-shortcuts/table-rotary-tilting/xyzbc-trt.desktop ``` 其中的执行命令为: ```bash /home/mes123456/linuxcnc-master/scripts/rip-environment linuxcnc /home/mes123456/linuxcnc-master/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini ``` `rip-environment` 负责设置 RIP 开发环境,然后调用 `linuxcnc` 脚本并传入 `xyzbc-trt.ini`。 `scripts/linuxcnc` 会读取 INI 中的关键段: - `[TASK] TASK = milltask` - `[HAL] HALUI = halui` - `[HAL] HALFILE = LIB:basic_sim.tcl` - `[DISPLAY] DISPLAY = axis` - `[KINS] KINEMATICS = xyzbc-trt-kins sparm=identityfirst` - `[TRAJ] COORDINATES = XYZBC` 总体启动顺序如下: 1. 启动 `linuxcncsvr`,创建和持有 NML 通道。 2. 启动 realtime/HAL。 3. 加载 `tpmod`、`homemod`。 4. 启动 `[TASK] TASK = milltask`。 5. 启动 `[HAL] HALUI = halui`。 6. 执行 `[HAL] HALFILE = LIB:basic_sim.tcl`。 7. 执行 INI 中所有 `[HAL] HALCMD = ...`。 8. 执行 `halcmd start`,启动实时线程。 9. 启动 `[DISPLAY] DISPLAY = axis`。 ## 2. INI 核心配置 目标配置文件: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini ``` 关键内容: ```ini [EMC] MACHINE = sim-xyzbc-trt-kins (switchkins) [DISPLAY] GEOMETRY = XYZB OPEN_FILE = ./demos/xyzbc_switchkins.ngc PYVCP = ./xyzbc-trt.xml JOG_AXES = XYZC DISPLAY = axis [RS274NGC] SUBROUTINE_PATH = ./remap_subs HAL_PIN_VARS = 1 REMAP = M428 modalgroup=10 ngc=428remap REMAP = M429 modalgroup=10 ngc=429remap REMAP = M430 modalgroup=10 ngc=430remap PARAMETER_FILE = xyzbc.var [KINS] KINEMATICS = xyzbc-trt-kins sparm=identityfirst JOINTS = 5 [TRAJ] COORDINATES = XYZBC LINEAR_UNITS = mm ANGULAR_UNITS = deg ``` `COORDINATES = XYZBC` 表示该配置使用 5 个坐标字母,对应 5 个 joint: - `joint.0` -> X - `joint.1` -> Y - `joint.2` -> Z - `joint.3` -> B - `joint.4` -> C `sparm=identityfirst` 是本配置的重要细节。它改变了 `xyzbc-trt-kins` 的默认类型顺序,使启动时的 `switchkins-type 0` 是 identity kinematics。 ## 3. basic_sim.tcl 建立仿真 HAL INI 中: ```ini [HAL] HALFILE = LIB:basic_sim.tcl ``` 对应文件: ```text lib/hallib/basic_sim.tcl lib/hallib/sim_lib.tcl ``` `basic_sim.tcl` 读取 INI 中的坐标、joint 数、servo period,然后调用 `core_sim`。 `core_sim` 位于 `lib/hallib/sim_lib.tcl`,主要完成: 1. 调用 `setup_kins` 加载 `[KINS] KINEMATICS` 指定的运动学模块。 2. 加载 `motmod`。 3. 将 `motion-command-handler` 和 `motion-controller` 加入 `servo-thread`。 4. 为每个 joint 创建 `pid`。 5. 为每个 joint 创建 `mux2`。 6. 将 `joint.N.motor-pos-cmd` 经由 `pid`、`mux2` 接回 `joint.N.motor-pos-fb`,形成理想伺服仿真闭环。 7. 加载仿真回零、仿真主轴、手动换刀等用户态/实时组件。 运行后可生成等效 HAL 文件: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt_cmds.hal ``` 其中关键 HAL 命令为: ```hal loadrt xyzbc-trt-kins sparm=identityfirst loadrt motmod base_period_nsec=0 servo_period_nsec=1000000 num_joints=5 loadrt pid names=J0_pid,J1_pid,J2_pid,J3_pid,J4_pid loadrt mux2 names=J0_mux,J1_mux,J2_mux,J3_mux,J4_mux addf motion-command-handler servo-thread addf motion-controller servo-thread ``` 每个 joint 的典型连接形态为: ```hal net J0:pos-cmd joint.0.motor-pos-cmd => J0_pid.command net J0:on-pos J0_pid.output => J0_mux.in1 net J0:pos-fb J0_mux.out => joint.0.motor-pos-fb ``` 这说明该仿真没有真实驱动器,反馈位置由仿真 HAL 直接产生。 ## 4. switchkins 初始化 运动学源码入口: ```text src/emc/kinematics/xyzbc-trt-kins.c src/emc/kinematics/switchkins.c src/emc/kinematics/trtfuncs.c ``` `xyzbc-trt-kins.c` 的 `switchkinsSetup()` 根据 `sparm` 配置三套运动学函数。 因为 INI 使用: ```ini KINEMATICS = xyzbc-trt-kins sparm=identityfirst ``` 所以实际类型顺序为: - `switchkins-type 0`:identity kinematics - `switchkins-type 1`:xyzbc TRT kinematics - `switchkins-type 2`:userk kinematics 如果没有 `identityfirst`,默认 type 0 才是 `xyzbc-trt-kins`。 `switchkins.c` 提供统一包装函数: - `kinematicsForward()` - `kinematicsInverse()` - `kinematicsSwitch()` - `kinematicsSwitchable()` 并创建状态 HAL pin: - `kinstype.is-0` - `kinstype.is-1` - `kinstype.is-2` 启动时 `switchkins_type = 0`,随后调用 `kinematicsSwitch(0)`,因此本配置启动后处于 identity kinematics。 ## 5. xyzbc TRT 几何参数 `trtKinematicsSetup()` 位于: ```text src/emc/kinematics/trtfuncs.c ``` 它为 TRT 运动学创建 HAL 输入: - `xyzbc-trt-kins.x-rot-point` - `xyzbc-trt-kins.y-rot-point` - `xyzbc-trt-kins.z-rot-point` - `xyzbc-trt-kins.x-offset` - `xyzbc-trt-kins.y-offset` - `xyzbc-trt-kins.z-offset` - `xyzbc-trt-kins.tool-offset` - `xyzbc-trt-kins.conventional-directions` INI 中对这些参数的设置和连接为: ```hal net :tool-offset motion.tooloffset.z net :tool-offset xyzbc-trt-kins.tool-offset xyzbc-trt-gui.tool-offset net :x-offset xyzbc-trt-kins.x-offset xyzbc-trt-gui.x-offset net :z-offset xyzbc-trt-kins.z-offset xyzbc-trt-gui.z-offset sets :x-offset -20 sets :z-offset -15 setp xyzbc-trt-kins.x-rot-point 0 setp xyzbc-trt-kins.y-rot-point 0 setp xyzbc-trt-kins.z-rot-point 0 setp xyzbc-trt-kins.conventional-directions 0 ``` 因此实际计算中: ```text dx = x-offset = -20 dz = z-offset + tool-offset ``` `tool-offset` 来自 `motion.tooloffset.z`,也就是 LinuxCNC 当前刀长补偿的 Z 分量。 ## 6. xyzbc 正/逆运动学 `xyzbcKinematicsForward()` 位于: ```text src/emc/kinematics/trtfuncs.c ``` 它从 joint 坐标计算当前笛卡尔位姿: ```text joints[X/Y/Z/B/C] -> EmcPose XYZBC ``` `xyzbcKinematicsInverse()` 从程序位姿计算 joint 目标: ```text EmcPose XYZBC -> joints[X/Y/Z/B/C] ``` 关键输入包括: - X/Y/Z/B/C 指令位姿 - B 轴角度 - C 轴角度 - `x-offset` - `z-offset` - `tool-offset` - 旋转中心 `x/y/z-rot-point` - `conventional-directions` 在 coordinated motion 中,motion 控制循环调用当前运动学的 inverse,将轨迹规划器输出的笛卡尔目标位置转换为 joint 目标。 路径为: ```text trajectory planner -> emcmotStatus->carte_pos_cmd -> kinematicsInverse() -> xyzbcKinematicsInverse() -> joint.N.coarse_pos -> joint.N.motor-pos-cmd -> 仿真 PID/mux -> joint.N.motor-pos-fb ``` 反馈/状态更新时则通过 forward: ```text joint feedback/cmd -> kinematicsForward() -> xyzbcKinematicsForward() -> 当前 XYZBC 位姿 ``` ## 7. Vismach 可视化模型 INI 中启动 Vismach: ```hal loadusr -W xyzbc-trt-gui ``` 对应文件: ```text bin/xyzbc-trt-gui src/hal/user_comps/vismach/xyzbc-trt-gui.py ``` `xyzbc-trt-gui.py` 创建 HAL 用户组件: ```python c = hal.component("xyzbc-trt-gui") ``` 并创建输入 pin: - `table-x` - `saddle-y` - `spindle-z` - `tilt-b` - `rotate-c` - `z-offset` - `x-offset` - `tool-offset` INI 中连接为: ```hal net :table-x joint.0.pos-fb xyzbc-trt-gui.table-x net :saddle-y joint.1.pos-fb xyzbc-trt-gui.saddle-y net :spindle-z joint.2.pos-fb xyzbc-trt-gui.spindle-z net :tilt-b joint.3.pos-fb xyzbc-trt-gui.tilt-b net :rotate-c joint.4.pos-fb xyzbc-trt-gui.rotate-c ``` 因此 Vismach 显示的是 joint 反馈,不是直接显示 G-code 坐标。 偏置和刀长补偿也传给 Vismach: ```hal net :tool-offset xyzbc-trt-kins.tool-offset xyzbc-trt-gui.tool-offset net :x-offset xyzbc-trt-kins.x-offset xyzbc-trt-gui.x-offset net :z-offset xyzbc-trt-kins.z-offset xyzbc-trt-gui.z-offset ``` 这样三维模型的几何位置和运动学计算使用同一组偏置。 ## 8. PyVCP 面板与按钮 AXIS 根据: ```ini [DISPLAY] PYVCP = ./xyzbc-trt.xml ``` 加载: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.xml ``` 该 XML 创建一个 `SWITCHKINS` 面板,包含: - 多状态标签:`0:IDENTITY`、`1: XYZBC`、`2: USERK` - 按钮 `IDENTITY` - 按钮 `TCP:XYZBC` - 按钮 `userk` - 按钮 `vismach-clear` AXIS 创建 PyVCP 组件后,再执行: ```ini [HAL] POSTGUI_HALFILE = switchkins_postgui.hal ``` 对应文件: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/switchkins_postgui.hal ``` 其中连接: ```hal net :kinstype.is-0 <= kinstype.is-0 => pyvcp.multilabel.0.legend0 net :kinstype.is-1 <= kinstype.is-1 => pyvcp.multilabel.0.legend1 net :kinstype.is-2 <= kinstype.is-2 => pyvcp.multilabel.0.legend2 net :type0-button <= pyvcp.type0-button => halui.mdi-command-00 net :type1-button <= pyvcp.type1-button => halui.mdi-command-01 net :type2-button <= pyvcp.type2-button => halui.mdi-command-02 ``` INI 中 `[HALUI]` 配置为: ```ini MDI_COMMAND = M429 MDI_COMMAND = M428 MDI_COMMAND = M430 ``` 所以按钮和运动学类型的实际关系是: - `IDENTITY` -> `halui.mdi-command-00` -> `M429` -> type 0 - `TCP:XYZBC` -> `halui.mdi-command-01` -> `M428` -> type 1 - `userk` -> `halui.mdi-command-02` -> `M430` -> type 2 ## 9. M428/M429/M430 切换链路 remap 子程序位于: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc ``` 由于本配置使用 `sparm=identityfirst`,实际映射为: - `M429`:`# = 0`,identity - `M428`:`# = 1`,xyzbc TRT - `M430`:`# = 2`,userk 以 `M428` 为例,`428remap.ngc` 中核心语句为: ```ngc # = 1 # = 3 M68 E# Q# M66 E0 L0 ``` 实际等价于: ```ngc M68 E3 Q1 M66 E0 L0 ``` `M68 E3 Q1` 设置 `motion.analog-out-03 = 1`。 INI 已连接: ```hal net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type ``` 因此完整切换路径为: ```text PyVCP button -> halui.mdi-command-01 -> M428 -> 428remap.ngc -> M68 E3 Q1 -> motion.analog-out-03 = 1 -> motion.switchkins-type = 1 -> motion servo thread 检测到变化 -> handle_kinematicsSwitch() -> kinematicsSwitch(1) -> 激活 xyzbc TRT kinematics ``` `M66 E0 L0` 用于强制解释器和 motion 同步,确保后续 G-code 在切换后的运动学类型下执行。 ## 10. motion 伺服周期中的 switchkins 处理 motion 控制循环位于: ```text src/emc/motion/control.c ``` 每个 servo cycle 中会执行: ```c read_homing_in_pins(ALL_JOINTS); handle_kinematicsSwitch(); process_inputs(); do_forward_kins(); ... get_pos_cmds(period); ... output_to_hal(); ``` `handle_kinematicsSwitch()` 的逻辑: 1. 如果当前运动学不可切换,直接返回。 2. 读取 `motion.switchkins-type`。 3. 如果值没变,直接返回。 4. 如果值变化,调用 `kinematicsSwitch(new_type)`。 5. 用当前 joint 位置做一次 forward kinematics。 6. 更新 `emcmotStatus->carte_pos_cmd`。 7. 更新 trajectory planner 当前位姿。 这一步很重要:切换运动学时,LinuxCNC 会用当前 joint 位置重新计算新的笛卡尔位置,避免轨迹规划器还停留在旧运动学解释下的位置。 ## 11. M68 到 motion analog output 的路径 `M68` 在解释器中被转换为设置 analog output 的 canonical command。 源码路径: ```text src/emc/rs274ngc/interp_convert.cc src/emc/task/emccanon.cc src/emc/task/taskintf.cc src/emc/motion/command.c ``` 核心过程: 1. `interp_convert.cc` 识别 `M68 E... Q...`。 2. 调用 `SET_AUX_OUTPUT_VALUE(index, value)`。 3. `emccanon.cc` 生成 `EMC_MOTION_SET_AOUT`。 4. task 层调用 `emcMotionSetAout()`。 5. motion 收到 `EMCMOT_SET_AOUT`。 6. `emcmotAioWrite(index, value)` 写入 `motion.analog-out-XX`。 本配置中 index 为 3,所以写入: ```text motion.analog-out-03 ``` 再通过 HAL net 传给: ```text motion.switchkins-type ``` ## 12. 演示 G-code 执行过程 AXIS 启动后自动打开: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc ``` 该文件内容很短: ```ngc o call [10] [5] [10][1000][3][0][20][45][20] m2 ``` 它调用: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/xyzbc_switchkins_sub.ngc ``` 参数含义: - `zmax = 10` - `zmin = 5` - `r = 10` - `frate = 1000` - `n = 3` - `a = 0` - `b = 20` - `c = 45` - `dist = 20` `xyzbc_switchkins_sub.ngc` 在四个象限重复类似流程: ```ngc M429 G53 G0 X0 Y0 Z# B0 C0 G10 L20 P0 X0 Y0 Z# B0 C0 G0 X... Y... Z# o call [...] ``` 也就是: 1. 用 `M429` 切到 identity。 2. 用 `G53` 在机床坐标中移动到安全位置。 3. 用 `G10 L20 P0` 重设当前工件坐标系。 4. 移动到当前象限的加工中心。 5. 调用 `helix_bc`。 `helix_bc.ngc` 的核心流程为: ```ngc M429 G0 X[#<_x> - #] G10 L20 P0 X0 Y0 Z# B0 C0 M428 G0 B# C# F# G2 I# Z# P# M429 G0 X0 Y0 Z# B0 C0 G0 X[#<_x> + #] M428 ``` 含义: 1. 先切回 identity,方便做直观的定位和坐标系设置。 2. 调整 X 到圆弧起点。 3. 重设 G54。 4. `M428` 切换到 xyzbc TRT 运动学。 5. 移动 B/C 到指定角度。 6. 执行带 Z 下降的 `G2 ... P#` 螺旋插补。 7. 切回 identity,回到安全位置。 8. 最后再次切到 xyzbc,保持显示/演示状态。 ## 13. 运行时数据流总览 启动阶段: ```text desktop/rip-environment -> scripts/linuxcnc -> linuxcncsvr -> realtime/HAL -> milltask -> halui -> basic_sim.tcl -> loadrt xyzbc-trt-kins sparm=identityfirst -> loadrt motmod num_joints=5 -> HALCMD loadusr -W xyzbc-trt-gui -> axis GUI -> PyVCP -> switchkins_postgui.hal ``` 切换运动学: ```text PyVCP button 或 G-code M428/M429/M430 -> remap ngc -> M68 E3 Q -> motion.analog-out-03 -> motion.switchkins-type -> handle_kinematicsSwitch() -> kinematicsSwitch(type) ``` 加工运动: ```text G-code XYZBC -> interpreter -> task -> trajectory planner -> emcmotStatus->carte_pos_cmd -> kinematicsInverse() -> xyzbcKinematicsInverse() 或 identityKinematicsInverse() -> joint.N.motor-pos-cmd -> pid/mux 仿真闭环 -> joint.N.motor-pos-fb -> Vismach 显示 ``` 反馈显示: ```text joint.N.pos-fb -> xyzbc-trt-gui table/saddle/spindle/tilt/rotate pins -> Vismach 三维模型 kinstype.is-N -> pyvcp.multilabel -> SWITCHKINS 面板显示当前类型 ``` ## 14. 关键结论 该仿真不是简单的五个独立轴显示程序,而是一个完整的 switchkins 示例: 1. 启动默认是 identity kinematics,因为 `sparm=identityfirst`。 2. `M429` 选择 identity,即 `switchkins-type 0`。 3. `M428` 选择 xyzbc TRT,即 `switchkins-type 1`。 4. `M430` 选择 userk,即 `switchkins-type 2`。 5. 运动学切换不是按钮直接写运动学模块,而是经过 `halui -> MDI -> remap -> M68 -> motion.analog-out-03 -> motion.switchkins-type`。 6. `xyzbcKinematicsInverse()` 是 RTCP/TCP 行为的核心,它根据 XYZBC 指令、B/C 角度、转台偏置和刀长补偿计算 joint 目标。 7. Vismach 使用 joint feedback 和同一组几何偏置显示机床模型,因此可视化结果跟运动学参数保持一致。 8. 演示程序通过 identity 与 xyzbc TRT 之间反复切换,展示了在普通机床坐标定位和五轴 TCP 加工之间切换的完整过程。 ## 15. 主要相关文件清单 配置入口: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini ``` HAL/GUI: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.xml configs/sim/axis/vismach/5axis/table-rotary-tilting/switchkins_postgui.hal configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt_cmds.hal src/hal/user_comps/vismach/xyzbc-trt-gui.py bin/xyzbc-trt-gui ``` G-code/remap: ```text configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/xyzbc_switchkins_sub.ngc configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/helix_bc.ngc configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc ``` 运动学源码: ```text src/emc/kinematics/xyzbc-trt-kins.c src/emc/kinematics/trtfuncs.c src/emc/kinematics/switchkins.c src/emc/kinematics/userkfuncs.c include/kinematics.h ``` motion/task/interpreter 相关: ```text src/emc/motion/motion.c src/emc/motion/control.c src/emc/motion/command.c src/emc/rs274ngc/interp_convert.cc src/emc/task/emccanon.cc src/emc/task/taskintf.cc ``` 启动脚本和 HAL 库: ```text scripts/linuxcnc scripts/rip-environment lib/hallib/basic_sim.tcl lib/hallib/sim_lib.tcl ``` ## 16. 与 LinuxCNC 数据系统核心原理的对应关系 `xyzbc-trt` 仿真可以看作 LinuxCNC 数据系统的一次完整穿透:从 INI 装配,到 NML 命令,到 task/interpreter,到 motion 实时共享内存,到 HAL pin/signal,再到 Vismach 显示。 ### 16.1 INI 是装配入口 `xyzbc-trt.ini` 决定系统启动时要加载的主要对象: ```ini [DISPLAY] DISPLAY = axis [DISPLAY] PYVCP = ./xyzbc-trt.xml [DISPLAY] OPEN_FILE = ./demos/xyzbc_switchkins.ngc [KINS] KINEMATICS = xyzbc-trt-kins sparm=identityfirst [KINS] JOINTS = 5 [TRAJ] COORDINATES = XYZBC [HAL] HALFILE = LIB:basic_sim.tcl [HAL] POSTGUI_HALFILE = switchkins_postgui.hal ``` INI 本身不做实时控制,它描述“系统应该如何装配”。真正的运行时数据交换由 NML、motion shared memory 和 HAL 完成。 ### 16.2 NML 负责 GUI/halui/task 命令与状态 当用户点击 PyVCP 按钮时,按钮并不直接写 `motion.switchkins-type`。实际路径是: ```text PyVCP button -> halui.mdi-command-N -> halui 通过 NML 发送 MDI 命令 -> milltask 接收命令 -> interpreter 执行 M428/M429/M430 remap ``` 这体现了 LinuxCNC 的基本原则:GUI 和 halui 表达操作意图,task 负责调度和合法性,motion 负责实时执行。 ### 16.3 Interpreter/Canonical 层把 M428 转成 motion 能执行的动作 `M428` 并不是 motion 原生命令,而是 remap 子程序: ```ngc M68 E3 Q1 M66 E0 L0 ``` 解释器把 `M68 E3 Q1` 转换为 canonical motion output command,最终由 task 发送给 motion: ```text M68 E3 Q1 -> SET_AUX_OUTPUT_VALUE(3, 1) -> EMC_MOTION_SET_AOUT -> emcMotionSetAout() -> usrmotWriteEmcmotCommand() -> realtime motion command shared memory ``` 这说明 G-code 的作用不是直接改 HAL,而是通过解释器和 task 进入 motion。 ### 16.4 Motion shared memory 是 task 和实时 motion 的边界 task 写入 `emcmot_command_t`,实时 motion 读取并执行。motion 每个 servo cycle 更新 `emcmot_status_t`,task 再把它汇总到 `EMC_STAT`。 在 `xyzbc-trt` 中,`M68 E3 Q1` 最终被 motion 执行为: ```text motion.analog-out-03 = 1 ``` 然后 HAL 连接把这个值传给: ```text motion.switchkins-type = 1 ``` ### 16.5 HAL 是实时信号网络 本配置最关键的 HAL net 是: ```hal net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type ``` 它的本质是让两个 HAL pin 共享同一个 signal 值: ```text writer: motion.analog-out-03 signal: :kinstype-select reader: motion.switchkins-type ``` servo-thread 中 `handle_kinematicsSwitch()` 读取 `motion.switchkins-type`,发现从 0 变成 1 后调用: ```text kinematicsSwitch(1) ``` 于是当前运动学从 identity 切换到 xyzbc TRT。 ### 16.6 Vismach 是 HAL 数据消费者 Vismach 模型不参与 NML,也不参与 motion command 调度。它作为 HAL 用户组件读取 pin: ```hal joint.0.pos-fb -> xyzbc-trt-gui.table-x joint.1.pos-fb -> xyzbc-trt-gui.saddle-y joint.2.pos-fb -> xyzbc-trt-gui.spindle-z joint.3.pos-fb -> xyzbc-trt-gui.tilt-b joint.4.pos-fb -> xyzbc-trt-gui.rotate-c ``` 因此 Vismach 显示的是 HAL 中的 joint feedback 快照,而不是直接读取 G-code 或 motion 内部轨迹队列。 ### 16.7 该配置的数据链总图 ```text INI 装配 -> basic_sim.tcl 加载 motion/k 等 HAL 模块 -> AXIS 创建 PyVCP -> PyVCP 按钮触发 halui MDI -> NML command 到 milltask -> interpreter 执行 M428/M429/M430 remap -> M68 变成 EMC_MOTION_SET_AOUT -> task 写 emcmot_command_t -> realtime motion 写 motion.analog-out-03 -> HAL net 传给 motion.switchkins-type -> servo-thread 切换 kinematics -> inverse kinematics 生成 joint 目标 -> 仿真 PID/mux 生成 joint feedback -> Vismach 读取 HAL feedback 显示机床 -> motion status 汇总到 EMC_STAT -> AXIS/halui 显示状态 ``` 详细通用原理见: ```text 项目分析/LinuxCNC数据系统核心原理.md ```