Initial BEC ophyd integration for the SmarGon goniometer via the smargopolo
RESTful API. Controls the virtual SCS axes (the server runs the kinematics; the
underlying q1..q6 stages are never commanded directly). Structure mirrors the
Canon CR-N300 device: an ophyd-free transport (real RestTransport over urllib +
in-memory FakeTransport) with threaded poll-to-tolerance positioners and a
PSIDeviceBase parent.
Scope / decisions:
- v1 movable axes: SHX SHY SHZ CHI PHI; OMEGA optional via has_omega (YAML).
- Referencing is a deliberate operator action (reference()); moves refuse unless
Mode.READY.
- Soft limits are user-set; smargopolo owns the coupled hardware limits. Both
fault paths handled: up-front PUT rejection fails the move immediately, and a
mid-move fault (mode -> 99 ERROR) aborts the in-flight move with the rosout
detail (SmarGon._raise_if_error).
- Move completion = readback within (user-set) tolerance, done on first
in-tolerance sample (robust to active position-hold dither).
Status: DRAFT. 27 unit tests pass against FakeTransport, but NOTHING has been
tested against a real smargopolo server or hardware. Do not commission as-is.
Open questions (to confirm with the smargopolo maintainer, W. Glettig):
- Stop semantics: no explicit stop endpoint; we abort by retargeting an axis to
its current readback ("Follow Target" halt). Confirm this is the intended way.
- Mid-move fault signalling: we rely on /mode -> 99 (ERROR) with the reason in
/readbackMCS rosout.msg. Confirm an out-of-range / coupled-limit violation
reliably drives this, so the abort path is dependable.
- Per-poll cost: the mid-move check adds a /readbackMCS GET alongside the
/readbackSCS position read (~20 req/s per moving axis at 0.1s). Revisit once we
know whether /readbackSCS also carries mode, or once the per-motor `state`
strings can give a truer moving/settled flag.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>