Skip to content

gcode: fix ROTATION_ENABLE 2nd-axis offset double-applied on rotated G54 moves#984

Merged
terjeio merged 1 commit into
grblHAL:masterfrom
stevenrwood:fix/g54-rotation-second-axis-double-offset
Jul 18, 2026
Merged

gcode: fix ROTATION_ENABLE 2nd-axis offset double-applied on rotated G54 moves#984
terjeio merged 1 commit into
grblHAL:masterfrom
stevenrwood:fix/g54-rotation-second-axis-double-offset

Conversation

@stevenrwood

Copy link
Copy Markdown
Contributor

Bug

In the both-rotation-axes branch of gc_execute_block() (the ROTATION_ENABLE
G53/rotation handling added around the same time as #977), the second rotation-plane
axis index is derived like this:

} else {
    idx_0 = ffs(r_around.mask) - 1;
    bit_false(r_around.mask, bit(idx));   // <-- stale outer-loop `idx`, not `idx_0`
    idx_1 = ffs(r_around.mask) - 1;
}

bit_false clears using the outer loop's idx instead of the just-computed idx_0.
When idx != idx_0, idx_1 (the second rotation-plane axis) comes out wrong, so in
the final offset-application loop that axis is no longer recognized as a rotation
axis and its WCS (G54) offset gets applied a second time. Net effect: a rotated G54
move that has both axes of the active plane in the same block targets
work_offset + 2x on the second axis instead of the correct position, which reliably
produces a false soft-limit trip (ALARM:2) once that lands outside travel.

Reproduced on hardware (Teensy 4.1 / grblHAL_Teensy4): only triggers with a nonzero
WCS rotation (G54 with $ rotation set) plus a full-plane move (both X and Y words
present, e.g. G54 G0 X10 Y10).

Fix

Clear bit(idx_0) instead of the stale bit(idx) — one line.

Testing

Verified on real hardware: rotated G54 XY moves land at the correct target and no
longer false-trip the soft limit.

…G54 XY moves

In the both-rotation-axes branch, bit_false(r_around.mask, bit(idx)) used the stale
outer loop variable idx instead of idx_0. When idx != idx_0, idx_1 (the second
rotation-plane axis) came out wrong, so in the final offset loop that axis was not
recognized as a rotation axis and its WCS offset was applied a second time. Result:
a rotated G54 move with both X and Y present targeted (work + 2x offset) on the second
axis -> false soft-limit (Alarm:2). Reproduced on hardware; only a nonzero WCS rotation
+ a full-plane G54 move triggers it. Fix: clear bit(idx_0).

Upstream grblHAL bug - PR-worthy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread gcode.c
} else {
idx_0 = ffs(r_around.mask) - 1;
bit_false(r_around.mask, bit(idx));
bit_false(r_around.mask, bit(idx_0)); // clear the FIRST rotation axis to find the second (was bit(idx) - a stale loop var, which mis-set idx_1 -> the second axis's WCS offset got applied twice -> false soft-limit on rotated G54 XY moves)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll strip this comment when committing to my upstream repo - it is not needed here.

@terjeio
terjeio merged commit 70ae0c1 into grblHAL:master Jul 18, 2026
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.

2 participants