Expose each SCS axis as its own top-level BEC motor sharing a singleton
SmargopoloController per host:port, plus a thin `dev.smargon` coordinator for
whole-goniometer ops. Replaces the single-device-with-axis-subcomponents design.
Why: BEC's motor UX (dev.wm, umv, limits, GUI motor widgets) is keyed on
top-level devices. With sub-components, dev.wm showed `readback N/A` (it looks up
a key equal to the device name) and `limits [0,0]` (the client reads limits from
the root device's low/high_limit_travel signals). General, not a sim artifact.
- controller.py: SmargopoloController(OphydObject), singleton per (host,port,sim);
owns transport + lock + mode; referencing / move_scs / nudge / q1..q6 diagnostics.
Reachable as dev.<axis>.controller.<op>() (USER_ACCESS).
- positioner.py: SmargopoloMotor(Device, PositionerBase) -- top-level per-axis motor.
scs_axis field binds the (user-chosen) BEC name to the fixed SCS axis. Exposes
low/high_limit_travel signals and aliases readback to the device name, so dev.wm
shows real per-axis readback + limits (low==high => unbounded). egu auto from axis.
- smargon.py: SmarGon(PSIDeviceBase) reduced to a thin coordinator delegating to the
shared controller; keeps read-only mode/rosout signals.
- YAML: smargon.yaml + smargon_sim_session.yaml rewritten to per-axis entries
(sgx/sgy/sgz/sgchi/sgphi[/sgomega]) + coordinator. Names user-configurable; SCS
binding explicit via scs_axis.
- transport/ layer + fake unchanged. Tests rewritten: 29 pass vs FakeTransport
(singleton reset fixture; covers sharing, wm readback aliasing, limits, fault paths).
Still DRAFT / untested against hardware.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
resources_2/Smargon.py (the MX-lab SmarGonController) gives real per-axis SCS
limits and the server hostname convention. Update smargon.yaml:
- SHX/SHY [-2,2], SHZ [10,22] (home ~18, not centred on 0), CHI [0,65],
PHI [-180,180] (was placeholder [-2.5,2.5] for the SH axes; SHZ was wrong).
- host: note it must be the actual reachable server (ref used mxlab1-smargopolo).
- Note PHI is continuous and the reference client wraps to [-180,180) before
sending -- flagged as an open design question, not yet handled here.
Still DRAFT / untested against hardware.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>