I was out messing with this a bit. I was trying to determine how I could zero things so I could both cut and laser for the same gcode. There are 3 things in play here: router, laser, laser crosshair. I should technically be able to zero for any of them and use either the router or laser for the same positioning.
The answer is this zero script:
; Set active WCS to current position and derive all others
; Activate the appropriate WCS, jog to work origin, then run this
;
; WCS assignments:
; G54 (P1) = Router bit
; G55 (P2) = Laser crosshair
; G56 (P3) = Laser beam
; G57 (P4) = Pen tip (TBD)
; G58 (P5) = Drag knife (TBD)
; === Raw measurements - update these with measured values ===
#<_router_to_crosshair_x> = 23.4 ; crosshair X offset from router
#<_router_to_crosshair_y> = -77.7 ; crosshair Y offset from router
#<_crosshair_to_laser_x> = 14.57 ; laser X offset from crosshair
#<_crosshair_to_laser_y> = 7.75 ; laser Y offset from crosshair
; === Derived WCS offsets relative to P1 ===
#<_p1_x> = 0
#<_p1_y> = 0
#<_p2_x> = #<_router_to_crosshair_x>
#<_p2_y> = #<_router_to_crosshair_y>
#<_p3_x> = [#<_router_to_crosshair_x> + #<_crosshair_to_laser_x>]
#<_p3_y> = [#<_router_to_crosshair_y> + #<_crosshair_to_laser_y>]
#<_p4_x> = 0 ; Pen tip (TBD)
#<_p4_y> = 0
#<_p5_x> = 0 ; Drag knife (TBD)
#<_p5_y> = 0
; Capture current machine position and active WCS
#<mach_x> = #<_abs_x>
#<mach_y> = #<_abs_y>
#<wcs> = #5220
; Zero the active WCS here
G10 L2 P#<wcs> X#<mach_x> Y#<mach_y>
; Resolve active WCS offset into act_x/act_y
o100 if [#<wcs> EQ 1]
#<act_x> = #<_p1_x>
#<act_y> = #<_p1_y>
o100 elseif [#<wcs> EQ 2]
#<act_x> = #<_p2_x>
#<act_y> = #<_p2_y>
o100 elseif [#<wcs> EQ 3]
#<act_x> = #<_p3_x>
#<act_y> = #<_p3_y>
o100 elseif [#<wcs> EQ 4]
#<act_x> = #<_p4_x>
#<act_y> = #<_p4_y>
o100 elseif [#<wcs> EQ 5]
#<act_x> = #<_p5_x>
#<act_y> = #<_p5_y>
o100 endif
; Derive and set all WCS from active tool offset
G10 L2 P1 X[#<mach_x> - #<_p1_x> + #<act_x>] Y[#<mach_y> - #<_p1_y> + #<act_y>]
G10 L2 P2 X[#<mach_x> - #<_p2_x> + #<act_x>] Y[#<mach_y> - #<_p2_y> + #<act_y>]
G10 L2 P3 X[#<mach_x> - #<_p3_x> + #<act_x>] Y[#<mach_y> - #<_p3_y> + #<act_y>]
G10 L2 P4 X[#<mach_x> - #<_p4_x> + #<act_x>] Y[#<mach_y> - #<_p4_y> + #<act_y>]
G10 L2 P5 X[#<mach_x> - #<_p5_x> + #<act_x>] Y[#<mach_y> - #<_p5_y> + #<act_y>]
(print, Zeroed from WCS %d#<wcs> at %.3f#<mach_x> %.3f#<mach_y>)
This is setup such that the router is G54, the laser crosshair is G55, and the laser is G56. So, if you want to zero based on the crosshair, switch to G55, go to the zero position, and run this script. Similarly for the others in their respective WCS.
The result of this is that no matter what I zero in, G54 X0Y0 takes the router to the zero point, G55 X0Y0 takes the crosshair to the zero point, and G56 X0Y0 takes the laser to the zero point.
I got Claude to write that gcode for me with some direction.