Commit Graph
11 Commits
Author SHA1 Message Date
x01dcandClaude Sonnet 5 8cf95196b7 fix(ids-cameras): snap pixel clock to a supported value; pulse auto-gain
Pixel clock: get_pixel_clock_range()'s (min, max, increment) describes
a linear range, but IS_PIXELCLOCK_CMD_SET doesn't actually accept
every value in it -- confirmed on hardware, 49/60/73 MHz all failed on
camera 41. Added Camera.get_pixel_clock_list() (IS_PIXELCLOCK_CMD_GET_
NUMBER + _GET_LIST, the SDK's authoritative source for what's settable)
and IDSCamera.get_pixel_clock_list(); IDSCamera.set_pixel_clock() now
snaps to the nearest supported value before writing, instead of
passing the raw requested value straight to the driver.

Auto gain: HW testing found continuous auto-gain has nothing further
to adjust once correctly exposed, and takes gain out of manual
control. on_connected() now pulses auto_gain_enabled on then off
(_AUTO_GAIN_SETTLE_S = 0.5s in between, for the already-running
continuous capture to feed it a few frames), instead of leaving it
enabled like auto_exposure_enabled -- still does the one-time gain
correction, but leaves gain fixed under manual control afterward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYQTHuSxSaLCijvayoRkX5
2026-09-15 08:31:51 +02:00
x01dcandClaude Sonnet 5 9a999bed37 fix(ids-cameras): apply auto-exposure/gain defaults on connect; add pixel clock
auto_exposure_enabled/auto_gain_enabled default to True but were never
actually written to hardware at connect -- is_ResetToDefault() leaves
the sensor's auto-shutter/auto-gain off, so a fresh session ran
under-exposed until an operator happened to re-toggle the GUI switch
(which is what issued the enable call for the first time). Fixed by
round-tripping both through their subscribe callbacks in
on_connected(), same idiom as exposure_time.

Also adds pixel_clock/pixel_clock_min/pixel_clock_max Kind.config
signals, backed by the Camera.get_pixel_clock()/get_pixel_clock_range()/
set_pixel_clock() added earlier -- lowering the pixel clock raises the
achievable max exposure time, and changing it now re-derives
exposure_time_min/max from hardware automatically.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYQTHuSxSaLCijvayoRkX5
2026-09-15 08:31:50 +02:00
x01dc 8c1c322393 fix(ids-cameras): fix auto-gain/auto-exposure SDK call, add exposure-range query
is_SetAutoParameter's pval1/pval2 are double* (8 bytes); set_auto_gain()/
set_auto_shutter() were passing a c_int (4 bytes), so the driver read
garbage past the buffer and rejected it -- this is what raised
UEyeException (surfaced as ophyd's "Subscription value callback
exception") when toggling auto gain on real hardware. Fixed to pass
c_double, matching the SDK's documented signature.

Also wrap the three hardware-write subscribe callbacks in try/except so
a driver failure logs clearly from IDSCamera instead of only via
ophyd's generic subscription-exception message.

Adds Camera.get_exposure_range()/get_pixel_clock()/
get_pixel_clock_range()/set_pixel_clock() (the max exposure time is
bounded by the current pixel clock) and matching IDSCamera
exposure_time_min/max config signals + USER_ACCESS wrappers, seeded on
connect, so the GUI can bound its exposure control to real hardware
limits instead of a placeholder range.
2026-09-15 08:31:49 +02:00
x01dc e3323e521e feat(ids-cameras): add manual exposure / auto-gain control signals
Adds exposure_time/auto_exposure_enabled/auto_gain_enabled as
Kind.config Signals on IDSCamera (mirroring live_mode_enabled), with
USER_ACCESS wrappers and hardware seeding of exposure_time on connect.
Extends SimIDSCamera's backend to match, and adds unit test coverage.

Per docs/plans/ids-camera-manual-exposure.md.
2026-09-15 08:31:48 +02:00
wakonig_k 376e5b1661 fix(camera): stop live mode before disconnecting to prevent polling
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 1s
CI for csaxs_bec / test (push) Successful in 1m50s
2026-09-08 16:03:01 +02:00
x01dcandClaude Sonnet 5 e299775c44 feat(LamNI): measure camera live-mode FPS and smear-sweep capture FPS
CI for csaxs_bec / test (pull_request) Successful in 3m42s
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 1s
CI for csaxs_bec / test (push) Successful in 2m31s
Neither rate was previously measured anywhere, making it hard to tell a
real acquisition bottleneck from a display/overhead one.

- IDSCamera.get_live_fps() (new USER_ACCESS entry): rolling-buffer
  measurement of the live-mode push rate in _live_mode_loop(), readable as
  dev.cam_xeye.get_live_fps(). SimIDSCamera inherits it unchanged, so it
  works against the simulated deployment too.
- XrayEyeAlign._smear_sweep() now tracks timestamps of the first and most
  recent distinct frame it captures, storing the computed rate as
  self.last_smear_fps and printing it in the sweep-done summary line.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 10:35:38 +02:00
x01dcandClaude Sonnet 5 bcdfc12a88 fix(LamNI): decouple smear composite display from live acquisition channel
The "camera running" toggle (IDSCamera.live_mode_enabled) was flapping
on/off during the smear sweep, and on real hardware that's genuinely
slow (starting/stopping the live acquisition thread has real driver
overhead, unlike the simulator). Root cause: composite pushes shared
the same device_preview channel the live thread continuously publishes
to, so live_mode_enabled had to be toggled off around every push to
keep the composite from being instantly overwritten.

Give the composite its own channel instead:
- IDSCamera gains a smear_preview PreviewSignal (no rotation_90/
  transpose configured -- composite data is already display-oriented)
  and push_smear_preview(), mirroring push_preview_image() but fully
  decoupled from the live channel.
- XRayEye gains set_live_view_signal() to switch which camera signal
  the live Image view displays, defaulting to the normal channel for
  every fresh GUI instance; on_live_view_enabled() now uses whichever
  signal is currently selected instead of a hardcoded constant.
- _smear_sweep() switches the GUI to "smear_preview" for the sweep and
  pushes composite updates there -- live_mode_enabled is never touched
  at all (just ensured on at the start, exactly like _live_sweep()).
  The GUI is deliberately left on the composite after a successful
  sweep until the caller has collected the operator's click, then
  switched back to "image"; on KeyboardInterrupt it's switched back
  immediately.

This removes the resume_live/hold_display_s toggle-avoidance mechanism
added in def9bf4, which is no longer needed with a dedicated channel.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 16:08:01 +02:00
x01dcandClaude Sonnet 5 81f6d0ff1e fix(LamNI): freeze composite display, undo double rotation, speckle sim pattern
Real-HW-adjacent (sim) testing surfaced three issues with the smear
calibration aid:

1. The composite reverted to the plain rotating live view right before
   the click prompt. find_rotation_center_smear_experimental() called
   update_frame() after _smear_sweep(), which grabs a fresh raw live
   frame -- overwriting the composite it just built. Also,
   _push_smear_composite always resumed live mode, so even without that
   bug the composite would only stay visible for hold_display_s.
   Fixed: _push_smear_composite gained resume_live=False for the final
   push; _smear_sweep now takes keep_shutter_open and closes the
   shutter itself at the end, so the composite (not a fresh grab) stays
   frozen on screen for the click. The stray update_frame() call is
   removed.

2. The composite appeared rotated relative to the live view.
   get_last_image() frames already have num_rotation_90/transpose
   applied (PreviewSignal.put() applies it to whatever it stores), so
   composites built from those frames got the transform applied AGAIN
   by push_preview_image()'s own self.image.put() call. Fixed:
   push_preview_image() now undoes the transform first (reverse order,
   since transpose is applied last forward) so the net effect is a
   single transform, matching a live frame.

3. Feature request: the sim camera's rotation-coupled pattern was a
   single eccentric gaussian blob -- a better analog for the isolated/
   point-particle case than the extended/textured case this feature
   actually targets. Added generate_speckle_grains/
   make_speckle_test_pattern (sim_cameras.py): a fixed, seeded field of
   small gaussian "grains" at a range of radii, rotating rigidly
   together as the live angle changes -- producing several concentric
   arcs in the composite instead of one, much closer to a real textured
   sample. New sim_speckle_count/sim_speckle_seed config, defaults
   requiring no yaml changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 16:08:01 +02:00
wyzula_j be9938ddb7 fix(camera): unify the live mode on cameras 2026-03-11 16:09:39 +01:00
x01dc de22611941 refactor(ids_camera): old ids_camera deleted, ids_camera_new is now ids_camera 2025-10-23 14:39:59 +02:00
appel_c 9e45e927a0 test(ids-camera): add tests for the IDSCamera integration 2025-08-05 12:31:13 +02:00