Skip to content

homing: wait HOME_DELAY before the final move - #4621

Closed
yurc wants to merge 3 commits into
LinuxCNC:2.9from
SyncTwin:synctwin/home-delay-final-move
Closed

yurc wants to merge 3 commits into
LinuxCNC:2.9from
SyncTwin:synctwin/home-delay-final-move

Conversation

@yurc

@yurc yurc commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Closed, not merged — see the discussion below. Description corrected after review.

In base_1joint_state_machine() every *_START state waits HOME_DELAY after the joint has stopped: the timer branch ends with break. In HOME_FINAL_MOVE_START that break is missing (since the 2022 state-machine rework), so pause_timer is incremented, immediately cleared, and the final move to HOME is planned without the pause. The developer state diagram (docs/src/code/homing.dot) still shows "after HOME_DELAY" on that edge.

HOME_DELAY is not an INI setting. It is the compile-time constant #define HOME_DELAY 0.100 in src/emc/motion/homing.c (line 54 on 2.9, 55 on master), i.e. 0.1 s.

How to see it: a sim config with a home switch and a non-zero HOME_OFFSET, e.g. trivkins, one joint, SERVO_PERIOD = 1000000, sim_home_switch at -2, HOME_SEARCH_VEL = -10, HOME_LATCH_VEL = -1, HOME_OFFSET = -1, HOME = 0, HOME_FINAL_VEL = 5. Record joint.0.home-state and joint.0.motor-pos-cmd every servo period with sampler (halsampler -t) while homing. On master f7ccc4f the joint spends 2 periods in HOME_FINAL_MOVE_START (state 20) before HOME_FINAL_MOVE_WAIT (21); with the break added it spends 102 periods (0.1 s = HOME_DELAY).

Adding the break alone breaks 15 tests that home joints back to back with HOME_ABSOLUTE_ENCODER or zero search/latch velocities: such a joint now waits 0.1 s and the next home request is dropped. Gating the delay on joints that actually moved fixes that, but that is new behavior, not a stable-branch fix, and we have no field measurement of a drive that needs the pause. The diagram is corrected separately in #4628.

yurc and others added 2 commits October 3, 2026 09:53
HOME_FINAL_MOVE_START is meant to wait HOME_DELAY after the joint has
stopped before it plans the move to HOME, like every other *_START
state. The 'break' after pause_timer++ was missing, so the timer was
incremented and immediately cleared, and the final move was planned in
the first servo period after the joint stopped.

Add the 'break'. Check the negative HOME_SEQUENCE sync before the delay,
not after it: otherwise a joint that is already waiting can time out
and latch sync_now while its partner has just arrived and is still in
its own delay, and the synchronized final moves would start up to
HOME_DELAY apart instead of within one servo period as now.
With the delay now honored in HOME_FINAL_MOVE_START, a joint homed in
place (HOME_SEARCH_VEL = HOME_LATCH_VEL = 0, or HOME_ABSOLUTE_ENCODER)
stayed in homing for HOME_DELAY although it never moved, so a home
request for the next joint issued right after it was dropped and
tests that home joints back to back (maxkins, matrixkins, kins-switch,
single-step, hard-limits, abort/*, interp/g28.2/*, ...) failed.

Wait only when the joint made a search or latch move: that is what the
delay lets settle. Homing in place finishes in the same servo cycle as
before.
@yurc

yurc commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

Reproduction in sim, and a correction plus a regression found while doing it.

Correction to the description: HOME_DELAY is not an INI key, it is the compile-time constant #define HOME_DELAY 0.100 (src/emc/motion/homing.c:54 on 2.9, :55 on master), so "HOME_DELAY = 2" in the description is wrong: the pause is 0.1 s.

Setup (master f7ccc4f vs. the same patch on master, Debian trixie, RIP uspace; the 2.9 hunk is identical): trivkins, one joint, SERVO_PERIOD = 1000000, sim_home_switch at -2, HOME_SEARCH_VEL = -10, HOME_LATCH_VEL = -1, HOME_OFFSET = -1, HOME = 0, HOME_FINAL_VEL = 5. sampler records joint.0.motor-pos-cmd and joint.0.home-state every servo period while joint.0.homing is true, read with halsampler -t.

entered HOME_FINAL_MOVE_START (20) entered HOME_FINAL_MOVE_WAIT (21) / first pos change time in state 20
before sample 891 893 2 periods (2 ms)
after sample 891 993 102 periods (0.102 s) = HOME_DELAY

Regression: with the patch as it is, 15 tests of scripts/runtests tests/ fail that pass without it: maxkins, matrixkins, kins-switch, kins-switch-unsolved, single-step, hard-limits, abort/on_abort_command-crazy-move, abort/stop-button-crazy-move, interp/subroutine-return, interp/mdi-oword-m66, mqtt and four more under interp/. They home joints back to back (for j in ...: c.home(j)) with HOME_ABSOLUTE_ENCODER = 1 or both vels zero. Such a joint never moves, but it now stays in homing for 0.1 s in HOME_FINAL_MOVE_START, so the next home request is dropped and the joints stay unhomed. That is probably also why rip-and-test did not complete here.

A follow-up commit applies the delay only to a joint that made a search or latch move (!(home_flags & HOME_ABSOLUTE_ENCODER) && (home_search_vel != 0 || home_latch_vel != 0)); homing in place finishes in the same servo cycle as before: SyncTwin/linuxcnc synctwin/home-delay-final-move-v2 (538d901, on top of this PR's commit). With it on master: the 15 tests pass, the full suite shows no failures except the display-dependent pyvcp/ui-smoke/* (same as unpatched master in that environment), and the measurement above still gives 102 periods. I have not built 2.9 itself; the cherry-pick applies cleanly.

HOME_FINAL_MOVE_START is meant to wait HOME_DELAY after the joint has
stopped before planning the final move, and the final moves of a
negative HOME_SEQUENCE pair must still start together. Check both in
sim by polling joint.N.home-state.

Fails on current master (final move starts 1-2 servo periods after the
stop); passes with "homing: wait HOME_DELAY before the final move".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QARseQ7Wp54ytTTisVrtvm
@grandixximo

Copy link
Copy Markdown
Contributor

Thanks for the careful measurement, the home-state table is convincing. Two things to fix though.

The issue body is wrong about HOME_DELAY. It is not an INI key, it is the compile-time #define HOME_DELAY 0.100 in src/emc/motion/homing.c, so the repro recipe ("set HOME_DELAY = 2 in axis_mm.ini") cannot work as written; an unknown key in a joint section is silently ignored. Your follow-up comment already notes this, but the body is what stays, please edit it.

Tested on master, targeted at 2.9. The PR bases on 2.9, but all numbers and the full test run come from master f7ccc4f, with 2.9 itself never built. For a released stable branch that is backwards: the bar there is regressions that hurt users, verified on that branch. And this patch does hurt users: your own run shows 15 previously-passing tests failing, because a joint that never moves (HOME_ABSOLUTE_ENCODER, zero search/latch velocities) now parks in HOME_FINAL_MOVE_START for 0.1 s and the next back-to-back home request gets dropped. The v2 gating commit repairs that, but at that point this is no longer a one-line "restore the missing break" bugfix, it is new conditional behavior that has never existed in any release.

Some history for context: the break was dropped in the 2022 state-machine rework (e5be0730d1, re-landed as becaf35c2f), first shipped in 2.9.0. The old behavior is documented only in the developer-manual state diagram (docs/src/code/homing.dot); the user homing docs never mention an inter-state delay. So "restore" here means re-adding 100 ms that nobody missed through four years of 2.9 releases, at the price of the regression your own testing found.

My suggestion: retarget at master with the v2 gating folded in, and treat "should the final move wait HOME_DELAY at all" as the design question it is, not a stable-branch bugfix.

@yurc

yurc commented Oct 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, Luca, for the review and the history. You're right on both points.

  • The description is fixed: HOME_DELAY is the compile-time 0.1 s constant, and the repro now uses the sampler measurement instead of the INI key that does not exist.
  • Targeting 2.9 with numbers from master was backwards, and with the regression it is not a stable-branch fix anyway.

I'm closing this. We found it by reading the code, not because a machine misbehaved, so we have nothing from the field that would justify new behavior in master either. The diagram that still says "after HOME_DELAY" is corrected in #4628 (docs only).

If we ever measure a drive that really needs a pause before the final move, we'll come back to master with the data, as a design proposal.

@yurc yurc closed this Oct 4, 2026
grandixximo pushed a commit that referenced this pull request Oct 4, 2026
Since the 2022 homing state-machine rework the HOME_FINAL_MOVE_START
state plans the final move as soon as the joint has stopped (and, for a
negative HOME_SEQUENCE, the other joints of the sequence are ready);
there is no HOME_DELAY pause before it (src/emc/motion/homing.c, the
timer branch of this state has no break). The diagram still showed
'after HOME_DELAY' on that edge. Describe the actual behavior; no code
change.

See #4621.
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