Skip to content

feat(rs274ngc): MAX_UNWIND_TURNS auto rotary G0 rebase#3990

Draft
grandixximo wants to merge 1 commit intoLinuxCNC:masterfrom
grandixximo:auto-rotary-rebase
Draft

feat(rs274ngc): MAX_UNWIND_TURNS auto rotary G0 rebase#3990
grandixximo wants to merge 1 commit intoLinuxCNC:masterfrom
grandixximo:auto-rotary-rebase

Conversation

@grandixximo
Copy link
Copy Markdown

Draft for testing and feedback. Targets the rotational-cutting use case from #3902 where G1 must honor literal multi-turn absolute targets (helical winding, spiral carving) but a terminal G0 should not physically unwind.

Mechanism

New INI flag [AXIS_<L>] MAX_UNWIND_TURNS = N. On a G0 absolute move with the rotary word, if the user-frame delta exceeds N full turns, the interpreter shifts a per-axis hidden user-frame offset so the motor stays put while the user-frame position jumps to the programmed target. Subsequent absolute moves use the rebased frame.

The motion-side traj.position remains accumulated. Only an interp-only offset moves. Stepgens, encoders, and PID see no discontinuity, sidestepping the motor_offset injection problem @andypugh raised in #3902. G53 explicitly bypasses (literal machine coords). Incremental (G91) is unaffected.

Trace

[AXIS_A] MAX_UNWIND_TURNS = 10

state: AA=0, offset=0, user=0
G0 A0 X0 Y5 Z1     ; no trigger (|delta|=0)
G1 Y0
G1 X20 A28800      ; literal target = 28800, +28800 (80 turn cut)
                   ; AA=28800, offset=0, user=28800
G0 X0 A0           ; |delta_turns|=80 > 10, rebase: offset=28800
                   ; machine_target=28800, motor delta=0 (no unwind)
                   ; AA=28800, offset=28800, user=0

#5423/#5424/#5425 and _a/_b/_c named params report user-frame.

Trade-offs / caveats

  • Absolute machine-frame position drifts by one rebase per run. MAX_LIMIT eventually reached on very long runs. Trade is necessary because in-program joint rebase is not safely doable (per @andypugh's analysis).
  • Trivkins 1:1 axis-to-joint only. Coupled kinematics (5-axis TCP, gantry rotary) unsupported (not validated).
  • Run-from-line not handled (skipped blocks would not trigger rebases).
  • Offset persists across M2/M30 (clean display for back-to-back runs). The first G0 of the next program self-heals after re-home/estop/power-cycle because the unwind delta exceeds the threshold.
  • Mutex with WRAPPED_ROTARY, startup warning if both set.

Mapping to other controls

Closest precedent is Hurco M31 (explicit, programmer-placed). This implementation auto-triggers on G0 above a threshold; to my knowledge no commercial control automates this but the structural reasons (mostly TCP coupling) are addressable via the trivkins gate.

Status

Draft, seeking feedback and test results from @djdelorie's helical-carving setup before promoting. Build clean.

Adds a new INI flag, [AXIS_<L>] MAX_UNWIND_TURNS = N, that enables an
interp-side rebase on G0 absolute moves. When a G0 with a rotary word
would otherwise unwind more than N full turns from the current accumulated
position, the interpreter shifts a per-axis hidden user-frame offset so
the motor takes the shortest path to the target's angular position
(within +/- 180 degrees) while the user-frame position jumps to the
programmed target. Whole turns of unwind are absorbed by the offset; only
the sub-turn part is physical motion.

The motion-side traj.position remains accumulated. Only an interp-only
offset moves. Stepgens, encoders, and PID see no discontinuity. This
sidesteps the joint-side fake_position machinery (FREE-mode only, cannot
run during program execution) and the kin-chain validation that
machine-frame rebase would require.

Targeted use case: rotational cutting (helical winding, spiral carving)
where G1 must honor literal multi-turn absolute targets but a terminal G0
should not physically unwind. CAM output and existing G-code stay
unchanged. The terminal G0 takes a sub-turn realignment regardless of
accumulated history; subsequent absolute moves work in the rebased user
frame.

Side effects:
- #5423-#5425 and _a/_b/_c report user-frame values, matching the
  programmer's commanded value.
- Absolute machine-frame position drifts by one rebase increment per
  program run; soft limit MAX_LIMIT eventually reached on very long runs
  (configurable).
- Gated to non-coupled rotary axes (trivkins 1:1). Behavior under
  TCP/gantry/tilted-plane is unsupported.
- Mutually exclusive with WRAPPED_ROTARY; if both are set, the
  MAX_UNWIND_TURNS feature is disabled for that axis with a startup
  warning.
- G53 absolute machine-coord moves bypass the offset (G53 reaches
  literal machine position as documented).
- Incremental (G91) is unaffected.

Default: MAX_UNWIND_TURNS = 0 disables the feature. Existing INI files
unaffected.
@grandixximo grandixximo force-pushed the auto-rotary-rebase branch from 4684b5d to 54db0fe Compare May 1, 2026 06:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant