From 0475d2ff596236e7f1df4a8351ff3a5676aabdb0 Mon Sep 17 00:00:00 2001 From: You Yan Date: Wed, 17 Jun 2026 23:21:44 -0700 Subject: [PATCH] fix(filter-wheel): reset W/W2 range to full after home (rotary axis); v1.4 Intermittent: the filter-wheel home reports success but the post-home offset move (absolute +102 usteps) is rejected with CMD_EXECUTION_ERROR. Root cause: the home anchors its coordinate frame from the limit-switch PRESS latch (X_LATCH_RD) but detects "home found" on the switch RELEASE, leaving xmin = L - C (L = press-latch position, C = release position). tmc4361A_moveTo is the sole reject gate (x_pos < xmin), so the abort means xmin > 102, which happens whenever a home reaches release without a fresh, correctly-ordered in-cycle press (stale/mis-ordered latch). Depends on the wheel's resting state, hence intermittent. Fix at the right altitude: the [xmin,xmax] range check is linear-stage infrastructure (physical end-stops, SET_LIM, moveToExtreme). The filter wheel is rotary with no travel end-stop. finalize_homing_w/_w2 now reset xmin/xmax to full int32 range after anchoring home, so a latch-derived xmin can never reject a valid rotary move -- every entry path. Safe: W/W2 xmin/xmax are written only in check_homing_w/w2 and consumed only by the moveTo gate (check_limits clamps X/Y/Z only; SET_LIM targets the stage). FIRMWARE_VERSION 1.3 -> 1.4. Co-Authored-By: Claude Opus 4.8 (1M context) --- firmware/controller/src/constants.h | 5 ++++- firmware/controller/src/operations.cpp | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/firmware/controller/src/constants.h b/firmware/controller/src/constants.h index 771ba06e0..d6b8a5b26 100644 --- a/firmware/controller/src/constants.h +++ b/firmware/controller/src/constants.h @@ -12,8 +12,11 @@ // Version 1.2 = CMD_EXECUTION_ERROR reported on failed moves + MOVETO_W2 command // Version 1.3 = strobe ISR latches illumination source at start (race fix when // channel switched during live HW-triggered acquisition) +// Version 1.4 = filter-wheel (W/W2) home resets xmin/xmax to full range (rotary +// axis has no travel end-stop); fixes intermittent post-home +// MOVETO_W CMD_EXECUTION_ERROR (home left xmin = L - C > offset) #define FIRMWARE_VERSION_MAJOR 1 -#define FIRMWARE_VERSION_MINOR 3 +#define FIRMWARE_VERSION_MINOR 4 #include "def/def_v1.h" diff --git a/firmware/controller/src/operations.cpp b/firmware/controller/src/operations.cpp index fdf3f611a..28785d860 100644 --- a/firmware/controller/src/operations.cpp +++ b/firmware/controller/src/operations.cpp @@ -375,6 +375,17 @@ void finalize_homing_w() tmc4361A_write_encoder(&tmc4361[w], 0); if (stage_PID_enabled[w]) tmc4361A_set_PID(&tmc4361[w], PID_BPG0); + // The filter wheel is ROTARY (no travel end-stop) -- the linear-stage + // [xmin,xmax] range gate in tmc4361A_moveTo does not apply to it. Homing + // leaves xmin = L - C (L = press-latch position, C = release-detect + // position); a stale/mis-ordered latch makes xmin exceed the small absolute + // post-home offset target, so MOVETO_W is wrongly rejected with + // CMD_EXECUTION_ERROR. Reset to full range so valid rotary moves are never + // range-rejected. Safe: W xmin/xmax are written only in check_homing_w and + // consumed only by the moveTo range check (check_limits acts on X/Y/Z only, + // stopping them on a limit-switch event, and never touches W/W2). + tmc4361[w].xmin = INT32_MIN; + tmc4361[w].xmax = INT32_MAX; } W_pos = 0; is_homing_W = false; @@ -393,6 +404,9 @@ void finalize_homing_w2() tmc4361A_write_encoder(&tmc4361[w2], 0); if (stage_PID_enabled[w2]) tmc4361A_set_PID(&tmc4361[w2], PID_BPG0); + // Rotary wheel: no travel end-stop -> full range (see finalize_homing_w). + tmc4361[w2].xmin = INT32_MIN; + tmc4361[w2].xmax = INT32_MAX; } W2_pos = 0; is_homing_W2 = false;