Skip to content

feat(turret): per-slot calibration, backlash compensation, software homing, factory parameter set - #601

Open
veerwang wants to merge 4 commits into
Cephla-Lab:masterfrom
veerwang:pr-singlemotor
Open

feat(turret): per-slot calibration, backlash compensation, software homing, factory parameter set#601
veerwang wants to merge 4 commits into
Cephla-Lab:masterfrom
veerwang:pr-singlemotor

Conversation

@veerwang

Copy link
Copy Markdown
Contributor

Summary

Two commits improving the NiMotion 4-position objective turret controller:

1. Per-slot calibration and gear backlash compensation (6918f4f)

  • OBJECTIVE_TURRET_CALIBRATED_PULSES: per-slot calibrated absolute pulse targets (slot -> pulses from homing zero). Calibrated slots are used verbatim; others fall back to the theoretical (slot-1)*pulses_per_position + OBJECTIVE_TURRET_OFFSET_PULSES.
  • OBJECTIVE_TURRET_BACKLASH_DEG: when > 0, every slot change overshoots below the target and approaches from below, so the final approach direction is constant and gear backlash cancels out.
  • Both validated at init so a bad machine .ini fails fast; defaults keep behavior identical.

2. Software homing, DI1 origin switch, factory parameters (fffd0a5)

  • Software homing replaces the driver's built-in homing modes: velocity-mode sweep toward the sensor polling the DI level → decel-stop on trigger → back off until the switch releases → fine-step back to the trigger edge → SET_ZERO there. Repeatability ±5 pulses (hardware-measured 0); ends clamped at home with holding torque. Home timeout raised to 120 s.
  • DI1 permanently "origin switch" (3) — the previous scheme (DI1 temporarily remapped to negative limit + homing method 17) faults FF0E on current drive firmware whenever a normal move passes the sensor.
  • Factory parameter set auto-calibrated on connect: accel/decel 1000, max speed 200, min speed 16 (written before max — fixes a min/max write-order bug), motor currents sized so a fully loaded turret does not lose steps, microstep pinned to 16 (fail fast asking for a power cycle on mismatch).
  • modbus_rtu: new read_input_registers() batch read so the homing sweep sees DI + position + alarm in one frame per poll (the ~50-pulse sensor window must not be crossable between polls).

Deployment notes

  • First connect on a real unit rewrites speed/current/DI parameters and saves EEPROM (one-time).
  • Machines with per-slot calibration measured under the old driver-homing zero must re-measure (the zero reference moved slightly).

Test plan

  • 66 tests pass (tests/control/test_objective_turret_controller.py, tests/control/test_modbus_rtu.py): calibration/backlash targeting, software-homing edge/sweep/timeout paths, factory-param write order, microstep-mismatch fail-fast
  • Homing repeatability verified on hardware in the source project (0-pulse deviation between runs)
  • Bench test on production hardware: startup homing, slot-switching accuracy, slot re-calibration

🤖 Generated with Claude Code

veerwang and others added 2 commits July 20, 2026 09:41
Port two positioning features from the SingleMotor source project:

- OBJECTIVE_TURRET_CALIBRATED_PULSES: per-slot calibrated absolute pulse
  targets (slot 1..4 -> pulses from homing zero). A calibrated slot is
  used verbatim; uncalibrated slots fall back to the theoretical
  (slot-1)*pulses_per_position + OBJECTIVE_TURRET_OFFSET_PULSES.
- OBJECTIVE_TURRET_BACKLASH_DEG: gear backlash compensation (0..1 turret
  degrees). When > 0 every slot change overshoots below the target and
  approaches it from below, so the final approach direction is always
  the same and gear backlash cancels out.

Both are validated at init (slot range, integer pulses, deviation bound
of one slot vs theoretical, degree range) so a bad machine .ini fails
fast. Defaults keep behavior identical to before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… switch, factory params

Re-merge from the SingleMotor source project (2026-07-23..27 changes):

- Homing rewritten as software homing (sweep in velocity mode polling the DI
  level -> backoff -> fine-search -> SET_ZERO at the trigger edge), replacing
  the driver's built-in homing modes. Repeatability +/-5 pulses; ends clamped
  at home with holding torque. Default home timeout raised to 120s.
- DI1 is now permanently "origin switch" (3). The old scheme (DI1 temporarily
  mapped to negative limit + homing method 17) faults FF0E on the current
  firmware whenever a move passes the sensor; all homing-register calibration
  is removed.
- Factory parameter set ported and auto-calibrated on connect: accel/decel
  1000, max speed 200, min speed 16 (written before max — fixes the
  min/max write-order bug), currents overload 1.3A / idle 0.6A /
  accel+run+decel 0.95A, microstep forced to 16 (write + save + fail fast
  asking for a power cycle when it differs). Decel current is marked volatile
  (firmware drops the write) so it cannot trigger an EEPROM save every
  connect. Direction register written to RAM after the EEPROM save.
- modbus_rtu: add read_input_registers() batch read so the homing sweep gets
  DI + position + alarm in one frame per poll (the ~50-pulse sensor window
  must not be crossable between two polls).
- _def.py: fix the calibrated-pulses doc example (6640 deviates more than one
  slot and fails validation) and note that slots must be re-measured after
  upgrading from driver homing (the zero reference moved).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@veerwang veerwang closed this Jul 28, 2026
@veerwang veerwang reopened this Jul 28, 2026
veerwang and others added 2 commits July 28, 2026 16:22
…t in CI

All tests pass but the pytest process intermittently dies with exit code 139:
pyqtgraph's atexit cleanup sweeps every gc-tracked object while the Qt C++
side is already tearing down (seen on master too, e.g. runs for 52c6f58 and
f8fe36d). The sweep only matters for long-lived interactive sessions, so turn
it off for the test process.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ne-search accel, max speed 150

Port SingleMotor f366df9..4119c32 (manager-specified values):
- Homing: fine step 5->2 (repeatability +/-2), backoff 150->60, sweep
  50->60 Step/s with 20ms poll (52ms window crossing >= 2.6 polls),
  fine travel limit 400->200
- Fine search now temporarily lowers acceleration (0x005F) to 50 to
  soften the microstep approach to the trigger edge; restored after
- Max speed 200->150: the 0.95A current cap loses steps under load at 200
- Idle current 60->21 (displayed 0.69A); drop the decel-current (0x15)
  calibration and its volatile mechanism — the SDM42 drive has no such
  parameter (writes silently dropped, reads back 0)

SingleMotor's reconnect-polling fix (8ab21dc) is Qt-panel-specific and
does not apply to this synchronous controller.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@veerwang

Copy link
Copy Markdown
Contributor Author

Pushed fd6ee50, syncing the tuning work done on the SingleMotor bench project over 07-27/07-28 (all manager-specified values):

Homing parameter revisions

  • Fine-search step 5 → 2 pulses: home repeatability tightens from ±5 to ±2 pulses
  • Backoff step 150 → 60: worst-case overshoot past the trigger edge is ~49 pulses (29 stop distance + 20 detection lag), so a single backoff jog clears the sensor window; the loop remains as a fallback
  • Sweep speed 50 → 60 Step/s with the DI poll period shortened 25 → 20 ms — the anti-aliasing constraint still holds (~50-pulse window crossed in 52 ms ≥ 2.6 poll periods)
  • Fine-search travel limit 400 → 200 (backoff 60 + window 50 + margin)

New: temporarily lowered acceleration during fine search
home() now reads the original acceleration (0x005F), lowers it to 50 Step/s² for the fine-step approach to soften the microstep landing on the trigger edge, and restores it in the cleanup path alongside max speed. Covered by a new regression test.

Max speed 200 → 150 Step/s
The 0.95 A driver current cap leaves no torque margin at speed 200 and the loaded turret was observed losing steps. 150 × 16 microsteps = 2400 pulses/s ≈ 98°/s at the turret. Homing is unaffected (sweep 60 / jog 60 are well below).

Current parameters

  • Idle current 60 → 21 (displays as 0.69 A)
  • Dropped the decel-current (0x15) calibration and its "volatile" mechanism: the SDM42 drive has no such parameter — the firmware silently drops writes and always reads back 0

Not ported: SingleMotor's reconnect-polling fix is specific to its Qt status panel; this controller polls synchronously per move and doesn't have that failure mode.

These values are written on connect and persisted to EEPROM by the existing calibration path. Bench-verified on SingleMotor; re-verification on the turret hardware is still pending.

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