Skip to content

motion: axis_sync_teleop_tp_to_carte_pos resets velocity/acceleration#3933

Open
is-primary-dev wants to merge 1 commit intoLinuxCNC:masterfrom
is-primary-dev:fix-teleop-tp-velocity-reset
Open

motion: axis_sync_teleop_tp_to_carte_pos resets velocity/acceleration#3933
is-primary-dev wants to merge 1 commit intoLinuxCNC:masterfrom
is-primary-dev:fix-teleop-tp-velocity-reset

Conversation

@is-primary-dev
Copy link
Copy Markdown

Without this, residual teleop_tp.curr_vel from an aborted jog can survive the FREE -> TELEOP transition. axis_sync_teleop_tp_to_carte_pos is called in two places: enabling motion from DISABLED, and entering teleop mode (e.g. after homing finishes). Both semantically represent the joint being at rest at the current cartesian position — leaving the trajectory planner's velocity and acceleration at stale non-zero values causes the first simple_tp_update_normal call after the sync to integrate one cycle of motion, drifting curr_pos away from the synced position.

Reproduction on a XYZZ machine where Z homes at MAX_LIMIT:

  1. Home all
  2. Jog Z in the minus direction
  3. Release the jog key (axis_jog_abort(immediate=0) runs, leaving teleop_tp.curr_vel partially decayed but non-zero)
  4. Re-home all (homing runs in FREE mode, does not touch teleop_tp)
  5. Motion mode transitions FREE -> TELEOP on homing completion
  6. axis_sync_teleop_tp_to_carte_pos sets curr_pos to the current (correct) cartesian position but leaves curr_vel non-zero
  7. The first axis_calc_motion -> simple_tp_update_normal call integrates one cycle of motion, drifting curr_pos away
  8. Result: homed Z lands offset from HOME by distance equal to the area under the velocity decay curve, not at HOME exactly

Two-line fix matching the function's documented intent.

Without this, residual teleop_tp.curr_vel from an aborted jog can
survive the FREE -> TELEOP transition. axis_sync_teleop_tp_to_carte_pos
is called in two places: enabling motion from DISABLED, and entering
teleop mode (e.g. after homing finishes). Both semantically represent
the joint being at rest at the current cartesian position — leaving
the trajectory planner's velocity and acceleration at stale non-zero
values causes the first simple_tp_update_normal call after the sync
to integrate one cycle of motion, drifting curr_pos away from the
synced position.

Reproduction on a XYZZ machine where Z homes at MAX_LIMIT:
  1. Home all
  2. Jog Z in the minus direction
  3. Release the jog key (axis_jog_abort(immediate=0) runs, leaving
     teleop_tp.curr_vel partially decayed but non-zero)
  4. Re-home all (homing runs in FREE mode, does not touch teleop_tp)
  5. Motion mode transitions FREE -> TELEOP on homing completion
  6. axis_sync_teleop_tp_to_carte_pos sets curr_pos to the current
     (correct) cartesian position but leaves curr_vel non-zero
  7. The first axis_calc_motion -> simple_tp_update_normal call
     integrates one cycle of motion, drifting curr_pos away
  8. Result: homed Z lands offset from HOME by distance equal to the
     area under the velocity decay curve, not at HOME exactly

Two-line fix matching the function's documented intent.
@is-primary-dev
Copy link
Copy Markdown
Author

Summary

axis_sync_teleop_tp_to_carte_pos updates teleop_tp.curr_pos and pos_cmd
from the cartesian command but does not reset curr_vel or curr_acc.
Both callers (enabling motion from DISABLED, and entering teleop mode via
set_operating_mode) semantically mean "joint at rest at this cartesian
position" — stale velocity from a prior aborted jog leaks through the
mode transition and causes the first post-sync simple_tp_update_normal
call to drift curr_pos away from the synced value.

Observable symptom

On a XYZZ machine where Z homes at MAX_LIMIT:

  1. Home all
  2. Jog Z in the minus direction
  3. Release the jog key — axis_jog_abort(immediate=0) runs, leaving
    teleop_tp.curr_vel at a partially-decayed non-zero value
  4. Re-home all — homing runs in FREE mode and does not touch teleop_tp
  5. Motion mode transitions FREE → TELEOP on homing completion
  6. axis_sync_teleop_tp_to_carte_pos sets curr_pos to the (correct)
    post-homing cartesian position but leaves curr_vel non-zero
  7. The first subsequent axis_calc_motion → simple_tp_update_normal
    call integrates one cycle of motion, drifting curr_pos
  8. Re-homed Z lands offset from HOME by the area under the velocity
    decay curve, not at HOME exactly

Fix

Two-line change in src/emc/motion/axis.c: reset curr_vel and
curr_acc to 0 in axis_sync_teleop_tp_to_carte_pos. Matches the
function's documented intent — both callers represent "joint at rest
at this position."

Testing

Reproduced and verified on a simulated XYZZ machine with HOME=500 for
the Z axes. Before the fix, re-homed Z landed 1-3 mm below HOME=500
with a deterministic relationship to the jog-settle timing. After the
fix, re-home consistently lands at exactly HOME with 0 mm spread over
5 cycles of jog-and-re-home.

Locally compiled against current upstream/master with the exact CI
invocation (./autogen.sh && ./configure --disable-check-runtime-deps && make -O -j<n>); build succeeded with no new warnings.

is-primary-dev pushed a commit to is-primary-dev/linuxcnc that referenced this pull request Apr 13, 2026
…router

Codifies the rule that this fork must stay composable with upstream
LinuxCNC pulls. Operator-flagged after Phase 4b: any modification to
upstream-authored files creates merge conflict surface on every
git pull upstream master, and creating new human docs at linuxcnc
root (DEVELOPMENT.md, TESTING.md, BUILD.md) overlaps with upstream's
README.md and scripts/ docs.

New 'Upstream composability' section enumerates:
- Don't modify upstream-authored files (README, src/, configs/, etc.)
- Don't create new human docs at linuxcnc root
- Fork-only additions go in fork-only files (AGENTS.md, CLAUDE.md,
  MEMORY.md, memory/, TODO.md, .claude/settings.json, agent-helpers/)
- If unsure whether a file is upstream-owned, ask the operator

To make room for the new rule (would have pushed AGENTS.md over the
180-line budget), trimmed the Upstream PR prep section from ~60 lines
verbatim to ~14 lines: command block + brief 'what the script does'
paragraph + router to memory/reference_upstream_pr_workflow.md, which
Phase 4c will populate with the full procedure, prerequisites, and
workflow notes (worktree rationale, message handling, build flags,
travis-install-build-deps prohibition, worked example PR LinuxCNC#3933).

The plan said 'preserve verbatim' for the Upstream PR prep section —
the routing-to-memory approach preserves the load-bearing content,
just lazy-loaded instead of always-loaded. The summary in AGENTS.md
covers the must-know facts (use the wrapper, never the script
directly, worktree not switch -c, dynamically-resolved author).

Net change: 181 → 146 lines (-35). Well under the 180 budget, with
plenty of headroom for future rules.

Leak grep clean across AGENTS.md and memory/reference_fork_setup.md.
is-primary-dev pushed a commit to is-primary-dev/linuxcnc that referenced this pull request Apr 13, 2026
Phase 4c of the distributed-singing-stonebraker plan: copy fork-specific
auto-memory entries into in-repo memory/, build the MEMORY.md index,
create a TODO.md peer file, and apply the public-fork scrub to all
new content as a single batched review.

Auto-memory originals are NOT touched in this commit. Phase 5 handles
their deletion after end-to-end verification.

New files:
- MEMORY.md — pure index of 7 memory entries (1 line per entry)
- TODO.md — empty-state placeholder for now (no fork-specific pending
  items at migration time)
- memory/feedback_public_fork.md — public fork hygiene rule
- memory/reference_halcompile_workflow.md — compile-and-symlink pattern
  for sudo-once unattended .comp recompiles, plus halcompile naming
  gotcha and 'variable' keyword usage
- memory/reference_runtime_latest.md — RUNTIME=latest vs release semantics
- memory/reference_teleop_velocity_bug.md — upstream PR LinuxCNC#3933 context
- memory/reference_test_timings.md — healthy sim suite baselines
- memory/reference_upstream_pr_workflow.md — full upstream PR procedure,
  prerequisites, worktree rationale, build-flag CI parity, worked
  example PR LinuxCNC#3933

reference_fork_setup.md was already created in Phase 4b (when the
One-Time Setup section was extracted from AGENTS.md). MEMORY.md
indexes all 7 entries including that one.

Public-fork scrub (batched, applied at copy time):
- memory/feedback_public_fork.md: replaced 'lab/agent-helpers/setup-rt-machine.sh'
  example with a generic '<private-repo>/path/to/script.sh' placeholder.
  Also updated 'agents.md, memory.md' to 'AGENTS.md, MEMORY.md' to match
  the new file naming.
- memory/reference_teleop_velocity_bug.md: replaced 'Committed on
  cncmill1/z-home-redesign branch' with the public commit/PR identifiers
  (fork master commit f40e8e6, upstream PR LinuxCNC#3933) — the public facts
  preserve the lesson without leaking the private branch name.
- memory/reference_upstream_pr_workflow.md: dropped the dead-end
  reference to 'lab/cncmill1/memory/parked-linuxcnc-upstream-teleop-pr.md'
  (the parking doc is in the private lab repo and not visible to
  standalone linuxcnc sessions; the procedure detail in this file is
  sufficient on its own).
- memory/reference_halcompile_workflow.md: heavy rewrite to remove
  cncmill1-specific framing. Removed 6 references to cncmill1, dropped
  the example components list (sim_lin_enc.comp, latch_pos.comp), and
  removed the relative path to '../../is-dev/lab/cncmill1/src/DEVELOPMENT.md'
  (private path leak). The technical content (halcompile compile vs
  install, symlink pattern, Makefile target structure, naming gotcha,
  variable keyword) is generalized to apply to any downstream LinuxCNC
  project.

Final leak grep clean: zero matches for cncmill1, lab/, ~/is-dev,
/home/igor, /Users/, igorpopov, or other private-path patterns across
AGENTS.md, CLAUDE.md, MEMORY.md, TODO.md, and memory/*.md.

NOT touched (per Upstream composability rule landed in the previous
commit):
- README.md (upstream-owned)
- src/, configs/, scripts/, debian/, docs/, lib/, tcl/, python/
  (upstream-owned trees)
- No new human docs created at linuxcnc root (no DEVELOPMENT.md,
  TESTING.md, BUILD.md). Fork-specific dev notes live in memory/
  reference entries, lazy-loaded.

TODO.md discoverability: indexed in MEMORY.md (no entry needed since
TODO.md is a peer file, not a memory entry) and discoverable via
direct file listing. No README cross-link because README.md is
upstream-owned.

Linuxcnc fork side of the migration is now complete pending the
batched public-fork final review and Phase 5 auto-memory deletion.
is-primary-dev pushed a commit to is-primary-dev/linuxcnc that referenced this pull request Apr 13, 2026
…text reorganization

Mirror of the lab repo's reorganization for the linuxcnc fork:

- CLAUDE.md auto-loads via the documented @AGENTS.md import. Standalone
  linuxcnc sessions get the fork's AGENTS.md inlined automatically;
  no bootstrap rituals.
- Renamed agents.md → AGENTS.md.
- Trimmed AGENTS.md from 264 → 146 lines. Added Public fork warning
  (don't leak private project context), Upstream composability rule
  (don't modify upstream-authored files, don't create new human docs
  at root that overlap with upstream README/scripts), Safe Action
  Protocol, Session startup checklist, File ownership matrix, Memory
  routing, Git conventions, and a compact Build/Run/Test/Clean section.
  The Upstream PR prep section was trimmed from ~60 lines to ~14
  lines (summary + router to memory/reference_upstream_pr_workflow.md
  for the full procedure).
- Created in-repo MEMORY.md (pure index) and TODO.md (peer file) at
  fork root.
- Migrated 5 fork-relevant entries into linuxcnc/memory/:
  feedback_public_fork.md (with the new 'grep is necessary but not
  sufficient' contextual-leak lesson), reference_fork_setup.md
  (8-step setup procedure extracted from AGENTS.md One-Time Setup),
  reference_teleop_velocity_bug.md (upstream PR LinuxCNC#3933 context),
  reference_upstream_pr_workflow.md (full upstream contribution
  procedure).
- Three Phase 4c entries (reference_runtime_latest.md,
  reference_test_timings.md, reference_halcompile_workflow.md) were
  initially copied here, then removed in follow-up commits when the
  operator caught that they describe private project work that uses
  the fork rather than fork-side knowledge. The straddle rule put
  them in the private repo's memory/ instead. Their delete-overlay
  commits stay in branch history; the file content is no longer in
  the fork tree.
- Disabled harness auto-memory via .claude/settings.json:autoMemoryEnabled=false
  with a gitignore exception so the setting reaches every cloner.
- Deleted the legacy lowercase memory.md (consolidated into AGENTS.md
  rules and Gotchas/Environment sections).
- README.md and other upstream-authored files NOT touched, per the
  Upstream composability rule.

8 commits, all on session branch distributed-singing-stonebraker.
Multiple public-fork hygiene passes applied during the migration —
final tree is leak-free per both literal-path grep and contextual
human review.
is-primary-dev added a commit to is-primary-dev/linuxcnc that referenced this pull request Apr 13, 2026
Fork-specific additions to LinuxCNC/linuxcnc maintained as a single
commit on top of upstream master (parent: same upstream commit as
the open PR branch fix-teleop-tp-velocity-reset, so both fork master
and the PR branch share a common ancestor).

History squashed 2026-04-13 to remove ~37 commits of fork-specific
churn that's no longer relevant after the distributed agent context
migration. Catching the fork up to the latest upstream/master is a
separate operation that happens after this squash.

What's added beyond upstream:

- agent-helpers/ — Claude Code agent tooling: safe-agent-action.sh
  wrapper (build/test/git/halcmd passthrough with master/main gates),
  install-hooks.sh, setup-dev-env.sh (NOPASSWD sudoers for setuid
  restore), upstream-pr-prep.sh (cherry-pick + worktree-based PR
  workflow with dynamic gh-api-user author resolution), README.md
- CLAUDE.md -> @AGENTS.md import chain (auto-loaded by Claude Code at
  session start; lazy descendants via documented memory loading)
- AGENTS.md (~146 lines): public-fork warning, upstream composability
  rule, Safe Action Protocol, Session startup checklist, File
  ownership matrix, Memory routing, Git conventions, Build/Run/Test
  reference, Upstream PR prep summary
- MEMORY.md — pure index of in-repo memory entries
- memory/ — in-repo agent memory (lazy-loaded, fork-side only):
  feedback_public_fork.md (public-fork hygiene rule + 'grep is
  necessary but not sufficient' lesson),
  reference_fork_setup.md (8-step setup procedure for a fresh
  clone — Debian, debian/control, build/runtime deps, configure,
  agent-helpers hooks, setuid, RT tuning),
  reference_teleop_velocity_bug.md (upstream PR LinuxCNC#3933 context),
  reference_upstream_pr_workflow.md (full upstream PR procedure)
- TODO.md — placeholder for fork-specific deferred work
- .claude/settings.json — disables harness auto-memory; allowed
  command patterns for agent operations
- .gitignore additions for .claude/ with !/.claude/settings.json
  exception so the project setting reaches every cloner
- src/emc/motion/axis.c — the same patch as upstream PR LinuxCNC#3933
  (axis_sync_teleop_tp_to_carte_pos resets curr_vel/curr_acc).
  The PR branch fix-teleop-tp-velocity-reset based on
  upstream/master is preserved separately for the upstream PR.

Based on upstream commit: a2a929c
Prior fork master before squash: 586186a
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