Add AC/BC RTCP programs and 3D machine manager

This commit is contained in:
2026-09-20 12:31:12 +08:00
parent 1c1e5f9672
commit 8aab531b02
363 changed files with 53213 additions and 58 deletions

70
test_Rtcp/MANIFEST.md Normal file
View File

@@ -0,0 +1,70 @@
# RTCP G-code 文件清单
下面的路径均相对于 `test_Rtcp/programs/`。括号中的路径是对应的 LinuxCNC 源码相对路径。
## 1. TRT table rotary/tilting 主程序与测试:16 个
这些程序对应 `xyzac-trt-kins` 或 `xyzbc-trt-kins`。在 switchkins 配置中,`M428` 选择 TCP 运动学,`M429` 选择 identity 运动学。
### 主程序和运动学测试
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_2.ngc`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_3.ngc`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc`
### remap 与可调用子程序
- `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`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/centering.ngc`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/helix_ac.ngc`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/helix_bc.ngc`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/xyzac_switchkins_sub.ngc`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/xyzbc_switchkins_sub.ngc`
## 2. gmoccapy TRT 示例:5 个
该配置直接加载 `xyzac-trt-kins`,所以示例中不一定显式写 `M428`。
- `configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/boat-xyzac.ngc`
- `configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/boat-xyzbc.ngc`
- `configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/impeller-7bl-xyzac.ngc`
- `configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/test-xyzac.ngc`
- `configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/test-xyzbc.ngc`
## 3. XYZAB table dual rotary:3 个
- `configs/sim/axis/vismach/5axis/table-dual-rotary/demos/xyzab-tdr-demo.ngc`
- `configs/sim/axis/vismach/5axis/table-dual-rotary/remap_subs/428remap.ngc`
- `configs/sim/axis/vismach/5axis/table-dual-rotary/remap_subs/429remap.ngc`
`xyzab-tdr-demo.ngc` 使用 HAL 运动学变量建立 G54,加载刀长补偿后进入 TCP 模式,并同时改变 A/B 姿态。
## 4. XYZBCW Bridge Mill / 5axiskins:4 个
- `configs/sim/axis/vismach/5axis/bridgemill/5axisgui.ngc`
- `configs/sim/axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc`
- `configs/sim/axis/vismach/5axis/bridgemill/remap_subs/429remap.ngc`
- `configs/sim/axis/vismach/5axis/bridgemill/remap_subs/430remap.ngc`
`5axisgui.ngc` 是参数化的球面/钻孔演示,使用 `W` 轴沿刀具方向进给;对应的 `5axiskins` 通过 pivot length 和当前刀长实现 TCP。
## 5. Hexapod RTCP 支持 remap:3 个
- `configs/sim/axis/vismach/hexapod-sim/remap_subs/428remap.ngc`
- `configs/sim/axis/vismach/hexapod-sim/remap_subs/429remap.ngc`
- `configs/sim/axis/vismach/hexapod-sim/remap_subs/430remap.ngc`
该目录在当前源码中没有额外的 RTCP 主加工程序,但 `genhexkins.c` 明确说明 `genhexkins.tool-offset` 连接到 `motion.tooloffset.Z` 时实现 RTCP,因此保留其运动学切换 remap 作为支持性 G 代码。
## 6. 独立五轴动态刀长示例:1 个
- `nc_files/cone.ngc`
该程序标注为 simulated 5 axis machine,先在旋转轴回零状态下使用 `G43.1` 修改动态刀长,然后执行 B/C 旋转和 W 轴钻削。它没有绑定到当前某个五轴 INI,因此应作为算法参考程序使用。

60
test_Rtcp/README.md Normal file
View File

@@ -0,0 +1,60 @@
# LinuxCNC RTCP G-code collection
本目录收集了当前仓库 `linuxcnc/` 源码树中与 RTCP/TCP 五轴运动学直接相关的 G 代码程序。
源码版本:
- LinuxCNC 子仓库:`239dcf4`(`git -C linuxcnc log -1 --oneline`)
- 原始文件根目录:`linuxcnc/`
- 复制目录:`test_Rtcp/programs/`
- 文件数量:32 个 `.ngc`
- 复制方式:保留相对于 `linuxcnc/` 的原始路径;已用 `cmp` 检查复制文件与源码文件一致
## 目录
`programs/` 下的路径去掉了源码根目录前缀。例如:
```text
programs/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc
```
对应源码:
```text
linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc
```
完整清单见 [`MANIFEST.md`](MANIFEST.md),分析见 [`rtcp_analysis.md`](rtcp_analysis.md)。
## Web 控制面板适配
这 32 个文件现已接入 Web AXIS 控制面板的“RTCP 程序库”入口:
- 程序清单与兼容性元数据:`web/react/src/rtcp-program-manifest.json`
- 程序库界面:`web/react/src/RtcpProgramLibrary.tsx`
- 控制面板按机床配置自动分为 AC(XYZAC)和 BC(XYZBC):AC 默认显示 15 个相关文件、可直接加载 8 个主程序;BC 默认显示 9 个相关文件、可直接加载 3 个主程序。
- “全部 32 个源程序”范围保留跨机型查阅能力,但另一类机床程序不会作为当前机型可执行项。
- remap、O-code 子程序、Hexapod 支持文件及当前未移植机型的主程序可查看和下载,但不会被误当作当前机型的独立主程序执行。
- 所有可执行项仍通过统一的 `PROGRAM_LOAD` 事务进入 LinuxCNC WASM 解释器、运动学和刀路预览,没有在 React 中增加第二套 G-code 或 RTCP 实现。
适配过程中补齐了 LinuxCNC 兼容语义:`G93` 模式下的 `G0` 快移不要求 F 值,`M1` 在当前“可选停止关闭”边界下可被解释器接受。11 个 AC/BC 主程序均通过 WASM 预解析测试。
## 运行前提
这些程序多数不是脱离配置即可运行的独立 G 代码。RTCP 由 LinuxCNC 的 kinematics 组件执行,G 代码需要匹配的 INI、HAL 和 remap 子程序:
- TRT 配置:`configs/sim/axis/vismach/5axis/table-rotary-tilting/`
- 双旋转台配置:`configs/sim/axis/vismach/5axis/table-dual-rotary/`
- Bridge Mill 配置:`configs/sim/axis/vismach/5axis/bridgemill/`
- gmoccapy TRT 配置:`configs/sim/gmoccapy/non_trivial_kinematics/table-rotary-tilting/`
- Hexapod RTCP remap 配置:`configs/sim/axis/vismach/hexapod-sim/`
LinuxCNC 这一源码版本没有找到使用标准 `G43.4` 或 `G43.5` 字样的 RTCP 示例。主要实现路径是:
```text
G-code -> M428/M429 remap 或直接加载非平凡 kinematics
-> inverse kinematics
-> joint XYZ + rotary axes
```
`TCP` 在这些示例中表示 Tool Center Point;不要与网络通信中的 TCP 混淆。

View File

@@ -0,0 +1,53 @@
#<r> = 60 ; sphere radius
#<rdelta> = 5 ; safe distance
#<drilldepth> = -5
#<zstart> = 0
#<bctmax> = 8
#<cctmax> = 16
#<toolno> = 100
#<frate> = 1000
#<bct> = 0
#<cct> = 0
#<cdelta> = [360/#<cctmax>]
#<bdelta> = [90/#<bctmax>]
g49
t#<toolno>m6g43
g53 g0 x0y0z#<zstart>b0c0 w0
g10l20 p0 x0 y0 z[#<r>+#<rdelta>] b0 c0 w0
g0 z0
f#<frate>
o100 while [#<bct> lt #<bctmax>]
#<b> = [#<bct>*#<bdelta>]
#<rnow> = [[#<r>+#<rdelta>]*[cos[#<b>]]]
#<x> = [#<rnow>]
#<y> = 0
#<z> = [-#<rnow>]
g0 x#<x> y#<y>
m66e0l0 ; force sync
g0 z#<z>
g0b[-90+#<b>]
#<cct> = 0
o200 while [#<cct> lt #<cctmax>]
o210 if [[#<bct> mod 2] eq 0]
#<c> = [#<cct> * #<cdelta>]
o210 else
#<c> = [360 - [1+ #<cct>] * #<cdelta>]
o210 endif
#<x> = [#<rnow>*[cos[#<c>]]]
#<y> = [#<rnow>*[sin[#<c>]]]
g0 x#<x> y#<y> z#<z> c#<c>
f#<frate>
g1 w[ #<drilldepth> - #<rdelta>]
g0 w0
m66e0l0 ;force sync
#<cct> = [#<cct>+1]
o200 endwhile
#<bct> = [#<bct>+1]
o100 endwhile
g0x0y0z0b0c0w0
g53 g0 x0y0z0
m2

View File

@@ -0,0 +1,24 @@
;M428 by remap: select kinstype=0 genhexkins
o<428remap>sub
#<kinstype> = 0
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M428:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M428: Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<428remap>endsub

View File

@@ -0,0 +1,24 @@
;M429 by remap: select kinstype==1 Identity kinematics
o<429remap>sub
#<kinstype> = 1
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M429:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M429:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<429remap>endsub

View File

@@ -0,0 +1,24 @@
;M430 by remap: select kinstype==2 userk kins
o<430remap>sub
#<kinstype> = 2
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M30:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M430:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<430remap>endsub

View File

@@ -0,0 +1,49 @@
; -- RELOAD GCODE FOR PROPER TOOL-PATH PREVIEW --
g21 g90 g49 g54
; switch to identity mode
m429
; clear g54
g10 l2 p0 x0 y0 z0 a0 b0
; go to machine origin
g53 g0 x0 y0 z0 a0 b0
; set g54 for face center of rotary
g10 l20 p0 x-[#<_hal[xyzab_tdr_kins.x-rot-point]>+#<_hal[xyzab_tdr_kins.x-offset]>] y-#<_hal[xyzab_tdr_kins.x-rot-point]> z-[#<_hal[xyzab_tdr_kins.z-rot-point]>+#<_hal[xyzab_tdr_kins.z-offset]>] a0 b0
; load a tool
M61 Q2 G43 H2
; switch to tcp mode
m428
g0 b30
; go to face center of rotary a
g0 x0 y0 z0
; show basic tcp functionality
g0 x30 a180
g0 x0 a0
g0 b100
g0 y-50
g0 a90
g0 b120
g0 y0
g0 a0 b30
g0 x1
; start with square
f1000
g0 y-30 z-30
g1 z30
g1 a45
g1 y30
g1 a90 b45
g1 z-30
g1 a180 b100
g1 y30
g1 a90 b120
g1 y-30
g1 a0 b30
g0 x5
g1 y-30 z-30 a90
g1 z30 a45 b60
g1 y30 a90 b90
g1 z-30 a135 b120
g1 y-30 a0 b30
; go to machine origin
g53 g0 x0 y0 z0 a0 b0
m2

View File

@@ -0,0 +1,24 @@
;M428 by remap: kinstype==1 (xyzac,xyzbc) (note: sparm=identityfirst)
o<428remap>sub
#<kinstype> = 1 ; xyzac,xyzbc
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M428:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M428: Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<428remap>endsub

View File

@@ -0,0 +1,24 @@
;M429 by remap: kinstype==0 Identity kinematics
o<429remap>sub
#<kinstype> = 0
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M429:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M429:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<429remap>endsub

View File

@@ -0,0 +1,3 @@
; zmax zmin r frate n a b c dist
o<xyzac_switchkins_sub> call [10] [5] [10][1000][3][20][0][45][20]
m2

View File

@@ -0,0 +1,39 @@
; for debugging, use mdi to set global #<_switchkins_debug>=1
#<FRATE>=1000
M429
G0 X0 Y0 Z0 A0 C0
G0 C90 X10 Y0
G1 F#<FRATE> Z2
M428
G1 F#<FRATE> Z0
M429
G1 F#<FRATE> Z2
G0 C90 X0 Y10
G1 F#<FRATE> Z0
M428
G1 F#<FRATE> Z2
M429
G1 F#<FRATE> Z0
G0 C90 X10 Y30
G1 F#<FRATE> Z2
M428
G1 F#<FRATE> Z0
M429
G1 F#<FRATE> Z2
G0 C90 X30 Y10
G1 F#<FRATE> Z0
M428
G1 F#<FRATE> Z2
M429
G1 F#<FRATE> Z0
G0 X0 Y0 Z0 A0 C0
M2

View File

@@ -0,0 +1,49 @@
; for debugging, use mdi to set global #<_switchkins_debug>=1
#<FRATE>=1000
M429 ;Trivkins
G64 P0.01
S1500 M3
G0 X0 Y0 Z5 A0 C0
G1 F#<FRATE> Z0
G1 X20 Y0 F#<FRATE>
M428 ;XYZAC
G1 C90
G1 X20
G1 Y20
G1 X0
G1 Y0
G1 A20
G1 X-20
G1 Y-20
G1 X0
G1 Y0
(-------)
G1 C45
G1 X-15
G1 Y15
G1 X0
G1 Y0
G1 Y-15
G1 X15
G1 Y0
G1 X0
(-------)
G1 C90 X15
G1 C180 Y15
G1 C270 X0
G1 C360 Y0
G1 C0
G1 C-90 X-15
G1 C-180 Y-15
G1 C-270 X0
G1 C-360 Y0
G1 Z5
M429 ;Trivkins
G1 X0 Y0 Z1 A0 C0
M2

View File

@@ -0,0 +1,15 @@
;# enable optional stop for m1
m429 ;trivkins
G0 X0 Y0 Z0 A0 C0
G0 C90 X10 Y0
G1 F1000 Z2
(debug,A expect: 10 0 2) m1
(debug,B expect: 10 0 2) m1
m428 ;tcp
(debug,C expect: 0 -10 2) m1
g1f1000 z0
(debug,D expect: 0 -10 0) m1
(debug,E expect: 0 -10 0) m1
m429 ;trivkins
(debug,F expect: 10 0 0)
m2

View File

@@ -0,0 +1,3 @@
; zmax zmin r frate n a b c dist
o<xyzbc_switchkins_sub> call [10] [5] [10][1000][3][0][20][45][20]
m2

View File

@@ -0,0 +1,24 @@
;M428 by remap: kinstype==1 (xyzac,xyzbc) (note: sparm=identityfirst)
o<428remap>sub
#<kinstype> = 1 ; xyzac,xyzbc
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M428:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M428: Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<428remap>endsub

View File

@@ -0,0 +1,24 @@
;M429 by remap: kinstype==0 Identity kinematics
o<429remap>sub
#<kinstype> = 0
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M429:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M429:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<429remap>endsub

View File

@@ -0,0 +1,24 @@
;M430 by remap: kinstype==2 userk kins
o<430remap>sub
#<kinstype> = 2
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M430:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M430:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<430remap>endsub

View File

@@ -0,0 +1,42 @@
(info: tests for values of [xyz]-rot-point)
o<centering>sub
#<xstart> = #1 (=-2.5)
#<ystart> = #2 (=-2.5)
#<xlen> = #3 (= 5)
#<ylen> = #4 (= 5)
#<zfinal> = #5 (=60)
#<n> = #6 (=12)
#<f> = #7 (=1000 feed)
#<angle> = 0
#<delta_angle> = [360/#<n>]
o1 if [exists [#<_hal[xyzac-trt-kins.x-rot-point]>]]
(debug,x-rot-point=#<_hal[xyzac-trt-kins.x-rot-point]>)
(debug,y-rot-point=#<_hal[xyzac-trt-kins.y-rot-point]>)
(debug,z-rot-point=#<_hal[xyzac-trt-kins.z-rot-point]>)
o1 endif
o2 if [exists [#<_hal[xyzbc-trt-kins.x-rot-point]>]]
(debug,x-rot-point=#<_hal[xyzbc-trt-kins.x-rot-point]>)
(debug,y-rot-point=#<_hal[xyzbc-trt-kins.y-rot-point]>)
(debug,z-rot-point=#<_hal[xyzac-trt-kins.z-rot-point]>)
o2 endif
M429 ;Identity kinematics
g0 x#<xstart> y#<ystart> z0 c0
M428 ;tcp
g61
o10 while [#<angle> le 360]
g1 f#<f>
#<angle> = [#<angle> + #<delta_angle>]
g0 c#<angle>
g1 x[#<xstart> + #<xlen>]
g1 y[#<ystart> + #<ylen>]
g1 x[#<xstart> + 0 ]
g1 y[#<ystart> + 0 ]
o10 endwhile
M429 ;Identity kinematics
g0 x0 y0 z#<zfinal> c0
o<centering>endsub

View File

@@ -0,0 +1,22 @@
; helix using switchkins (xyzac) a,c angles
o<helix_ac>sub
#<zmax> = #1 (=10)
#<zmin> = #2 (= 5)
#<r> = #3 (=10)
#<frate> = #4 (=1000)
#<n> = #5 (=3)
#<a> = #6 (=45)
#<b> = #7 (=0 NA)
#<c> = #8 (=20)
M429 ;Identity kinematics
g0 x[#<_x> - #<r>] ;adjust for radius
g10l20p0 x0y0 z#<zmax> a0 c0 ;new g54
M428 ;XYZAC
g0a#<a>c#<c> ;exercise a,c
f#<frate> g2i#<r>z#<zmin> p#<n> ;helix
M429 ;Identity kinematics
g0 x0 y0 z#<zmax> a0 c0 ;return to start
g0 x[#<_x> + #<r>] ;adjust restore
M428 ;XYZAC
o<helix_ac>endsub

View File

@@ -0,0 +1,22 @@
; helix using switchkins (xyzbc) b,c angles
o<helix_bc>sub
#<zmax> = #1 (=10)
#<zmin> = #2 (= 5)
#<r> = #3 (=10)
#<frate> = #4 (=1000)
#<n> = #5 (=3)
#<a> = #6 (=0 NA)
#<b> = #7 (=45)
#<c> = #8 (=20)
M429 ;Identity kinematics
g0 x[#<_x> - #<r>] ;adjust for radius
g10l20p0 x0y0 z#<zmax> b0 c0 ;new g54
M428 ;XYZBC
g0b#<b>c#<c> ;exercise b,c
f#<frate> g2i#<r>z#<zmin> p#<n> ;helix
M429 ;Identity kinematics
g0 x0 y0 z#<zmax> b0 c0 ;return to start
g0 x[#<_x> + #<r>] ;adjust restore
M428 ;XYZBC
o<helix_bc>endsub

View File

@@ -0,0 +1,47 @@
; ngcgui-compatible subroutine
(info: helix in each quadrant at angles A,C)
o<xyzac_switchkins_sub>sub
#<zmax> = #1 (=10)
#<zmin> = #2 (= 5)
#<r> = #3 (=10 radius)
#<frate> = #4 (=1000 feedrate)
#<n> = #5 (=3 n circles)
#<a> = #6 (=30 A angle)
#<b> = #7 (=0 B angle NA)
#<c> = #8 (=45 C angle)
#<dist> = #9 (=20 distance)
; quadrant I
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> a0 c0 ;MACHINE coordinates
g10l20p0 x0y0 z#<zmax> a0 c0 ;new g54
g0 x+#<dist> y+#<dist> z#<zmax> ;move to pattern center position
o<helix_ac> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant II
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> a0 c0
g10l20p0 x0y0 z#<zmax> a0 c0
g0 x-#<dist> y+#<dist> z#<zmax>
o<helix_ac> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant III
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> a0 c0
g10l20p0 x0y0 z#<zmax> a0 c0
g0 x-#<dist> y-#<dist> z#<zmax>
o<helix_ac> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant IV
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> a0 c0
g10l20p0 x0y0 z#<zmax> a0 c0
g0 x+#<dist> y-#<dist> z#<zmax>
o<helix_ac> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
;final position
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> ;MACHINE coordinates
g10l20p0 x0y0 z#<zmax> ;new g54
o<xyzac_switchkins_sub>endsub

View File

@@ -0,0 +1,47 @@
; ngcgui-compatible subroutine
(info: helix in each quadrant at angles B,C)
o<xyzbc_switchkins_sub>sub
#<zmax> = #1 (=10)
#<zmin> = #2 (= 5)
#<r> = #3 (=10 radius)
#<frate> = #4 (=1000 feedrate)
#<n> = #5 (=3 n circles)
#<a> = #6 (=0 A angle NA)
#<b> = #7 (=30 B angle)
#<c> = #8 (=45 C angle)
#<dist> = #9 (=20 distance)
; quadrant I
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> b0 c0 ;MACHINE coordinates
g10l20p0 x0y0 z#<zmax> b0 c0 ;new g54
g0 x+#<dist> y+#<dist> z#<zmax> ;move to pattern center position
o<helix_bc> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant II
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> b0 c0
g10l20p0 x0y0 z#<zmax> b0 c0
g0 x-#<dist> y+#<dist> z#<zmax>
o<helix_bc> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant III
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> b0 c0
g10l20p0 x0y0 z#<zmax> b0 c0
g0 x-#<dist> y-#<dist> z#<zmax>
o<helix_bc> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
; quadrant IV
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> b0 c0
g10l20p0 x0y0 z#<zmax> b0 c0
g0 x+#<dist> y-#<dist> z#<zmax>
o<helix_bc> call [#<zmax>][#<zmin>][#<r>][#<frate>][#<n>][#<a>][#<b>][#<c>]
;final position
M429 ;Identity kinematics
g53 g0 x0y0 z#<zmax> ;MACHINE coordinates
g10l20p0 x0y0 z#<zmax> ;new g54
o<xyzbc_switchkins_sub>endsub

View File

@@ -0,0 +1,24 @@
;M428 by remap: select kinstype=0 genhexkins
o<428remap>sub
#<kinstype> = 0
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M428:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M428: Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<428remap>endsub

View File

@@ -0,0 +1,24 @@
;M429 by remap: select kinstype==1 Identity kinematics
o<429remap>sub
#<kinstype> = 1
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M429:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M429:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<429remap>endsub

View File

@@ -0,0 +1,24 @@
;M430 by remap: select kinstype==2 userk kins
o<430remap>sub
#<kinstype> = 2
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M30:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M430:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<430remap>endsub

View File

@@ -0,0 +1,47 @@
o<test-xyzac> sub
(test-xyzac-kins with offsets and tool change)
( 5 AXIS XYZAC MILLING )
#<a_angle> = #1 (=20)
#<c_angle> = #2 (=30)
#<xy_max> = #3 (=30)
#<z_max> = #4 (=10)
#<feedrate> = #5 (=200)
#<tool1> = #6 (=1 1st Tool)
#<tool2> = #7 (=2 2nd Tool)
#<speed1> = #8 (=500)
#<speed2> = #9 (=600)
; 'square with 2 rounded corners'
#<x_max> = #<xy_max>
#<y_max> = #<xy_max>
#<g3_j> = #<xy_max>
N40 G00 G17 G40 G90 G94 Z10
(first tool - no z-offset)
T#<tool1> M6
S#<speed1> M3
G00 A#<a_angle> C#<c_angle>
G43 H#<tool1> Z0
G01 X#<x_max> F#<feedrate>
G01 Y#<y_max>
G01 X0
G03 X-#<x_max> Y0 I0 J-#<g3_j>
G00 Z#<z_max>
G00 X0
M5
(next tool- with z-offset)
T#<tool2> M6
S#<speed2> M3
G00 A#<a_angle> C#<c_angle>
G43 H#<tool2> Z0
G01 X-#<x_max> F#<feedrate>
G01 Y-#<y_max>
G01 X0
G03 X#<x_max> Y0 I0 J#<g3_j>
G0 Z#<z_max>
G0 X0 Y0
M5
A0 C0
o<test-xyzac> endsub

View File

@@ -0,0 +1,47 @@
o<test-xyzbc> sub
(test-xyzbc-trt-kins with offsets and tool change)
( 5 AXIS XYZBC MILLING )
#<b_angle> = #1 (=20)
#<c_angle> = #2 (=30)
#<xy_max> = #3 (=30)
#<z_max> = #4 (=10)
#<feedrate> = #5 (=200)
#<tool1> = #6 (=1 1st Tool)
#<tool2> = #7 (=2 2nd Tool)
#<speed1> = #8 (=500)
#<speed2> = #9 (=600)
;'square with 2 rounded corners'
#<x_max> = #<xy_max>
#<y_max> = #<xy_max>
#<g3_j> = #<xy_max>
G00 G17 G40 G90 G94 Z10
(first tool - no z-offset)
T#<tool1> M6
S#<speed1> M3
G00 B#<b_angle> C#<c_angle>
G43 H#<tool1> Z0
G01 X#<x_max> F#<feedrate>
G01 Y#<y_max>
G01 X0
G03 X-#<x_max> Y0 I0 J-#<g3_j>
G00 Z#<z_max>
G00 X0
M5
(next tool- with z-offset)
T#<tool2> M6
S#<speed2> M3
G00 B#<b_angle> C#<c_angle>
G43 H#<tool2> Z0
G01 X-#<x_max> F#<feedrate>
G01 Y-#<y_max>
G01 X0
G03 X#<x_max> Y0 I0 J#<g3_j>
G0 Z#<z_max>
G0 X0 Y0
M5
B0 C0
o<test-xyzbc> endsub

View File

@@ -0,0 +1,42 @@
(for the simulated 5 axis machine)
g21 g90 g94 g28
o200 sub
g0 b0 c0 (tool length change must happen with b,c=0)
g91 g28 z0 (could also be done with tool change position)
g90
g43.1 z#1 (change tool length)
g0z0 (move Z to apply new length)
x-100 b-45 c-180
g1 z-100 f2000
#100=-180
o100 while [ #100 le 180 ]
g1 x[100*cos[#100]] y[100*sin[#100]] c#100
#100=[#100+10]
o100 endwhile
g0 z0
x0 y0 b0 c0
o200 endsub
(cut around the "cone" with different tool lengths)
o200 call [50]
o200 call [80]
g61
g0 x-100 b-45 c-180
#100=-180
o101 while [ #100 lt 180 ]
g0 x[150*cos[#100]] y[150*sin[#100]] z-100 c#100
g1 w100 f2000 (drill)
g0 w0
#100=[#100+45]
o101 endwhile
g28
g49
m2

192
test_Rtcp/rtcp_analysis.md Normal file
View File

@@ -0,0 +1,192 @@
# LinuxCNC RTCP G-code 特点分析
## 1. 实现方式
这套 LinuxCNC 源码没有把 RTCP 作为独立的 `G43.4/G43.5` 代码实现。源码中的 RTCP 是运动学层能力:
- `src/emc/kinematics/trtfuncs.c` 实现 XYZAC 和 XYZBC 的正逆运动学。
- `src/emc/kinematics/xyzac-trt-kins.c` 和 `xyzbc-trt-kins.c` 将对应运动学注册为 LinuxCNC kinematics。
- `src/emc/kinematics/5axiskins.c` 实现 XYZBCW Bridge Mill 的 pivot-length、刀长和 W 轴变换。
- `src/emc/kinematics/genhexkins.c` 的注释明确说明,`tool-offset` 连接到 `motion.tooloffset.Z` 时实现 RTCP。
因此,G 代码主要承担四件事:
1. 选择 TCP 或 identity 运动学。
2. 设置刀长补偿和工件坐标系。
3. 给出刀尖/工件坐标和刀具姿态。
4. 用同步的直线、圆弧和旋转轴运动验证逆运动学结果。
## 2. M428/M429/M430 的作用
在 TRT、TDR、Bridge Mill 和 Hexapod 的 switchkins 配置中,常见映射如下:
| 命令 | 作用 |
|---|---|
| `M428` | 选择非平凡 TCP/RTCP kinematics,通常通过 `M68 E3 Q1` 设置 `motion.switchkins-type=1`,然后用 `M66 E0 L0` 同步 |
| `M429` | 选择 identity/trivkins,通常设置 `motion.switchkins-type=0` |
| `M430` | 选择 userk,通常设置 `motion.switchkins-type=2`;它是扩展运动学入口,不等于 RTCP 本身 |
这几个 M 代码是 remap 出来的用户命令,不是 LinuxCNC 固定的通用 M 代码。使用前必须匹配 INI 中的 `REMAP`、`SUBROUTINE_PATH` 和 HAL 信号。例如 TRT 配置需要把 `motion.analog-out-03` 接到 `motion.switchkins-type`。
`428remap.ngc` 和 `429remap.ngc` 都会检查 `motion.switchkins-type` 是否存在,并在 task 模式下检查切换结果;缺少 `HAL_PIN_VARS` 或 HAL 网络时会输出 debug 信息并停止。这说明运动学切换被设计成有确认步骤的同步操作。
## 3. TRT 的 XYZAC 与 XYZBC
### XYZAC
`xyzac-trt` 表示:
- 直线轴:X、Y、Z
- 倾转轴:A
- 旋转轴:C
- 典型结构:A 倾转台上安装 C 旋转台
`trtfuncs.c` 的正逆变换会使用:
- C 轴旋转中心:`x-rot-point`、`y-rot-point`、`z-rot-point`
- A 轴相对于 C 轴的偏置:`y-offset`、`z-offset`
- 当前刀长:`tool-offset`
### XYZBC
`xyzbc-trt` 表示:
- 直线轴:X、Y、Z
- 倾转轴:B
- 旋转轴:C
- 典型结构:B 倾转台上安装 C 旋转台
它使用 `x-offset`、`z-offset` 描述 B/C 旋转组件之间的几何偏置,并同样使用旋转中心参数和当前刀长。
两种运动学的共同点是:G 代码给出的 XYZ 和旋转姿态被当作笛卡尔 pose,逆运动学再计算实际关节位置。RTCP 的核心效果是改变 A/B/C 姿态时,刀尖 TCP 的空间位置仍按程序要求保持。
## 4. 刀长和 TCP 偏置
典型写法包括:
```gcode
T1 M6
G43 H1 Z5.0
...
G49
```
或:
```gcode
G43.1 Z#1
...
G49
```
含义分别是:
- `G43 Hn`:使用刀具表中第 n 号刀的长度。
- `G43.1`:从当前 G 代码块的轴字设置动态刀长。
- `G49`:取消刀长补偿。
在 TRT 配置中,`motion.tooloffset.z` 通过 HAL 连接到 `xyzac-trt-kins.tool-offset` 或 `xyzbc-trt-kins.tool-offset`。这使得普通 G43/G43.1 的结果进入运动学变换,而不是只修改显示坐标。
`cone.ngc` 特别体现了动态刀长的使用:它先令 B/C 回到零位,再用 `G43.1 Z#1` 设置刀长,随后执行五轴旋转轨迹。这样可以避免切换刀长时旋转姿态带来的大幅关节变化。
## 5. 工件坐标系与旋转中心
RTCP 程序常见以下组合:
```gcode
G53 G0 X0 Y0 Z...
G10 L20 P0 X0 Y0 Z... A0 C0
G54
```
- `G53` 用于在机器坐标下安全定位。
- `G10 L20 P0` 根据当前姿态建立或重设工件坐标系。
- `G54` 激活工件坐标系。
`centering.ngc`、`helix_ac.ngc`、`helix_bc.ngc` 和 `xyzab-tdr-demo.ngc` 还读取 HAL 变量,例如旋转中心和机械偏置。这类程序不是只验证 G 代码语法,而是验证“配置中的旋转中心、偏置和程序坐标”是否保持一致。
## 6. 轨迹类型
### CAM 点列轨迹
`boat-xyzac.ngc`、`boat-xyzbc.ngc` 和 `impeller-7bl-xyzac.ngc` 是典型后处理器输出:
- 大量连续的 `G1` 线段。
- 同一段轨迹同时改变 X/Y/Z 与 A/C 或 B/C。
- `boat-xyzbc.ngc` 和 impeller 程序使用 `G93` 逆时间进给,并在安全移动时切回 `G94`。
- 通过高密度姿态点逼近船体、叶轮等复杂曲面。
- 文件规模较大,适合验证连续五轴轨迹和逆运动学稳定性,不适合作为最小功能测试。
### 运动学切换测试
`xyzac_switchkins_test_1.ngc`、`xyzac_switchkins_test_2.ngc`、`xyzac_switchkins_test_3.ngc` 的重点是对照:
- `M429` 下的 identity 坐标。
- `M428` 下的 TCP 坐标。
- C 轴旋转后,同一个 X/Y/Z 指令对应的实际关节变化。
- `(debug,...)` 输出的预期坐标。
- M1 可选停,用于人工检查切换前后的结果。
其中 `test_3` 直接写出切换前后的预期位置,例如 C=90 后进入 TCP 模式时,X/Y 位置会因旋转变换而改变。
### 螺旋和四象限测试
`helix_ac.ngc` 和 `helix_bc.ngc` 的主要模式是:
```gcode
M429
G10 L20 ...
M428
G0 A... C...
G2 I... Z... P...
M429
```
它们在 TCP 模式下执行带旋转姿态的螺旋,再回到 identity 模式进行安全返回。`xyzac_switchkins_sub.ngc` 和 `xyzbc_switchkins_sub.ngc` 将该动作扩展到四个象限,并用参数传入安全高度、半径、圈数、进给率、姿态角和象限间距。
### 旋转中心保持测试
`centering.ngc` 先输出 HAL 中的旋转中心,然后进入 TCP 模式,在 C 轴每个角度执行一个小方形轨迹。它用于观察工件坐标中心是否在 C 轴旋转过程中保持固定。
### 参数化 Bridge Mill 测试
`5axisgui.ngc` 使用 O 代码循环和三角函数:
- B 轴分层改变倾角。
- C 轴分段改变方位角。
- 根据角度计算球面上的 X/Y/Z 位置。
- 用 W 轴执行钻削和退刀。
- 使用 `G43` 将当前刀长送入 5axiskins 的 pivot length。
它更偏向运动学和可视化演示,代码结构比 CAM 输出更适合阅读和移植。
## 7. 这些程序的共同特点
1. RTCP 由 kinematics 完成,程序行本身通常仍是普通 `G0/G1/G2/G3` 加旋转轴字。
2. TCP 模式和 identity 模式经常交替出现,前者用于加工或姿态变换,后者用于机器坐标定位、建立偏置和安全返回。
3. 刀长不是单独的显示量,而是通过 `motion.tooloffset.z` 进入逆运动学。
4. 旋转中心、旋转组件偏置和工件坐标系是正确运行的必要条件;参数错误会直接表现为 TCP 漂移。
5. 连续五轴 CAM 程序经常使用 `G93`,因为 XYZ 直线运动和旋转轴运动必须在同一段时间内完成。
6. 许多程序明确使用 `G53`、高 Z 安全位置、`G49` 和姿态归零,说明五轴 RTCP 程序对切换点和刀长变化较敏感。
7. 大型船体和叶轮程序主要验证连续轨迹;小型 switchkins、helix、centering 程序主要验证几何和状态切换。
## 8. 筛选边界
以下内容没有放入本集合:
- 只出现普通 `G43/G49`、没有五轴非平凡运动学关联的通用铣削、车削和探测程序。
- SCARA、Puma、Melfa 等使用 `M428/M429` 进行运动学切换,但源码没有将其定义为 RTCP 的示例。
- millturn 的 `M428/M429`,其作用是铣削/车削运动学切换,不是 TCP/RTCP。
- 只有 `XYZAC` 或 `XYZBC` 文字、但配置使用 `trivkins` identity 的普通五轴坐标示例。
- `G43.1` 工具测量程序本身,除非同时包含五轴姿态和 RTCP 运动学上下文。
筛选依据来自源码中的配置和运动学实现,尤其是:
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/README`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.txt`
- `configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.txt`
- `configs/sim/axis/vismach/5axis/table-dual-rotary/README`
- `docs/src/motion/5-axis-kinematics.adoc`
- `src/emc/kinematics/trtfuncs.c`
- `src/emc/kinematics/5axiskins.c`
- `src/emc/kinematics/genhexkins.c`