Skip to content

Pr turret - #609

Open
veerwang wants to merge 5 commits into
Cephla-Lab:masterfrom
veerwang:pr-turret
Open

Pr turret#609
veerwang wants to merge 5 commits into
Cephla-Lab:masterfrom
veerwang:pr-turret

Conversation

@veerwang

Copy link
Copy Markdown
Contributor

Summary

Ports the turret-controller changes from pr-singlemotor onto this branch, as 5 commits:

  1. Per-slot calibration + gear backlash compensation (3c0400c)
    • Per-slot absolute pulse targets (OBJECTIVE_TURRET_CALIBRATED_PULSES), fall back to theoretical positions
    • Backlash compensation: approach every slot change from below to cancel gear backlash
  2. Re-port SingleMotor logic (14fc708): software homing (sweep → backoff → fine-search → set zero), DI1 origin switch, factory params auto-calibrated on connect
  3. Sync SingleMotor tuning (c03564e): fine-step 2, backoff 60, max speed 150, etc.
  4. Motor direction inversion (8e10165): OBJECTIVE_TURRET_DIRECTION_INVERTED
  5. Origin-switch DI polarity inversion (3dd9060): OBJECTIVE_TURRET_DI_INVERT

Files changed

  • software/control/_def.py / objective_turret_controller.py / microscope.py / modbus_rtu.py / tests/control/test_objective_turret_controller.py

Notes

  • Toggling direction/DI inversion requires re-homing and re-measuring calibrated slots
  • Turret controller tests: 74 passed (simulation, no hardware)

veerwang and others added 5 commits August 12, 2026 15:38
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>
…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>
…db6c

Some turret motor models are wired with the opposite phase order, so the
same commands spin the other way. Add OBJECTIVE_TURRET_DIRECTION_INVERTED
(per-machine .ini, default False = behavior unchanged):

- Inversion applied only at the register boundary: absolute-move targets,
  jog signs, homing-sweep direction bit, and position readbacks; slot
  mapping / calibration / backlash / homing logic stay in logical
  coordinates untouched
- Init direction-register (0x0052) expected value follows the flag
  (inverted expects 0), still RAM-only after the EEPROM save
- microscope.py passes the flag via turret_kwargs; the simulation twin
  accepts it for constructor parity
- 12 new tests incl. a default-off regression guard; theoretical-target
  assertions pass explicit offset/calibration to stay independent of
  machine .ini values loaded into _def

After toggling on an existing machine, re-home and re-measure the
calibrated slots (the physical zero moves with the sweep direction).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ngleMotor 8874934

New objective changers sense the origin switch on the opposite logic level
(homing direction flipped, jerky). Add a per-machine software option that
inverts the DI1 trigger verdict during software homing / distance search.

- _def.py: OBJECTIVE_TURRET_DI_INVERT (default False = old logic)
- objective_turret_controller.py: di_invert ctor kwarg (def fallback + bool
  validation, same pattern as direction_inverted); the verdict flips in
  _read_status_snapshot so the sweep/backoff/fine state machine, direction
  logic and calibration stay in the same logical frame
- microscope.py: pass di_invert through turret_kwargs
- tests: 6 di_invert tests (inside/outside window homing, backoff direction
  unchanged, def fallback, non-bool raises, sim accepts kwarg); 74 passed
  in a CI-equivalent env. Note: toggling requires re-homing — the fine-search
  edge (physical zero) sits on the other side of the sensor window.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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