Feat/aerotech stages #351

Merged
holler merged 53 commits from feat/aerotech-stages into main 2026-11-03 11:44:23 +01:00
53 Commits
Author SHA1 Message Date
x12saandClaude Opus 5.5 12528a8f63 Merge origin/main into feat/aerotech-stages
CI for csaxs_bec / test (pull_request) Successful in 3m46s
CI for csaxs_bec / test (push) Successful in 3m36s
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 2s
Conflict in cSAXS.py: keep cSAXSDiagnostics(client) from main and the
csaxs.aerotech helper from this branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017NrH3poJsYBCTVq2Y9fuHZ
2026-11-03 11:40:08 +01:00
x12saandClaude Opus 5.5 cb1dbdb003 config(sastt): aerotech beamline setup in main.yaml, PandA config to legacy
main.yaml loads sastt_aerotech.yaml instead of ptycho_lamni.yaml. aeroz and
aerorot are commented out in sastt_aerotech.yaml (not used at the beamline now).
sastt_aerotech_panda.yaml (PandA test setup without beamline timing) moved to
legacy/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017NrH3poJsYBCTVq2Y9fuHZ
2026-11-03 11:37:12 +01:00
x12saandClaude Opus 5.5 353d6bbb01 fix(aerotech): park the PSO window once the line is triggered
CI for csaxs_bec / test (push) Successful in 3m47s
CI for csaxs_bec / test (pull_request) Successful in 3m38s
At the beamline (DDG1 trigger) every line started two bursts: the window was
switched to the next line when the axis passed trigger_high, just after the DDG1
cycle (as long as the travel trigger_low -> trigger_high), and the edge started a
second burst. MCS and detectors counted twice the frames, so their frames no
longer matched the captured positions (progress bar done at half the scan).

The window is now moved to a parking range beyond the line end as soon as the axis
has entered it, while DDG1 / PandA run the line and ignore edges; the next line's
window is set beyond the exposures as before, outside both windows. The per-line
MCS check also fails on more frames than the line has.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017NrH3poJsYBCTVq2Y9fuHZ
2026-11-03 11:21:00 +01:00
x12saandClaude Opus 5.5 b3bc8a27b2 docs(aerotech): beamline values in the generated cont grid examples
The scan server builds the Minimum/Full examples itself; ScanArgument(example=...)
now gives aerox / aeroy, a 3.5 x 3 mm field at 40 um and 20 ms. trigger_device
defaults to None (pandatrig with trigger_source="panda"), so the Full example no
longer shows pandatrig next to the default "ddg".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017NrH3poJsYBCTVq2Y9fuHZ
2026-11-03 11:20:59 +01:00
x01dcandClaude Opus 5.5 6e2eec9942 feat(aerotech): progress bar from the captured lines, statistics shown without MCS
CI for csaxs_bec / test (push) Successful in 3m32s
The IPython client prints client-info messages only from a scan's progress
display. With trigger_source="panda" or None the scan registered none, so the
end-of-scan statistics were sent but never shown (scan 8511). The position
capture now publishes a ProgressSignal (lines read / num_points) and the scan
uses it for the progress bar when there is no MCS card.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-30 11:19:07 +01:00
x01dcandClaude Opus 5.5 6b49f9eaa3 docs(smargon): monitor_interval in the config key list
CI for csaxs_bec / test (push) Successful in 3m33s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-30 10:52:23 +01:00
x01dcandClaude Opus 5.5 94d7890aee feat(smargon): readback monitor follows moves made outside BEC
CI for csaxs_bec / test (push) Successful in 3m38s
The motors only updated their readback at connect and during BEC moves, so a
move in the smargopolo web interface never reached BEC (a read returned the
stored value). The shared controller now polls /readbackSCS (all axes, one
request) every monitor_interval (motor config, default 0.5 s, 0 = off) and
publishes the axes that changed; it skips while BEC moves an axis, logs a
failure once, and stops when the last axis is destroyed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-30 10:52:17 +01:00
x01dcandClaude Opus 5.5 92be444069 config(sastt): SmarGon goniometer in sastt_aerotech_panda.yaml
CI for csaxs_bec / test (push) Successful in 3m31s
Coordinator + SHX/SHY/SHZ/CHI/PHI motors as in smargon.yaml (smargopolo REST
API, host tt-smargopolo, port 3000).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-30 09:42:40 +01:00
x01dcandClaude Opus 5.5 ffba9394eb fix(aerotech): PandA mimics the DDG1 shutter delay, shutter_delay reaches DDG1
CI for csaxs_bec / test (push) Successful in 3m47s
- PandA line trigger: shutter_delay (default 8 ms, as DDG1) between the line
  trigger and the first gate, get/set_shutter_to_open_delay like DDG1; the scan
  now reads it for trigger_source="panda" (was 0, so the test series ran with
  the first gate at the trigger, unlike the beamline)
- a shutter_delay scan argument with "ddg" only moved the trigger positions,
  DDG1 kept its own delay; it is now set on DDG1 before staging and restored
  in post_scan / on_exception
- docs: DDG1/DDG2 timing chain (exp_time = gate period, readout subtracted),
  note that the 2026-10-29 series ran without shutter delay

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-30 06:44:25 +01:00
x01dcandClaude Opus 5.5 171fc17cd2 docs(aerotech): measured comparison default vs minimal run-up, position plots
CI for csaxs_bec / test (push) Successful in 3m36s
Both series of 2026-10-29 (8486-8494 default, 8501-8509 minimal_run_up):
timing and positioning per case, why the saving is about half the shorter
travel (Y step no longer hidden in the run-out), the constant direction
offset after the velocity transient and the 20 mm/s oscillation, deviation
and zoom plots, and the split of the line period with the next levers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 16:15:18 +01:00
x01dcandClaude Opus 5.5 2c5ea7e6bf fix(csaxs): aerotech plot stops following once its window is closed
CI for csaxs_bec / test (push) Successful in 3m37s
A closed plot made every redraw fail with a warning for each line of each
scan. The first failure now stops following the scans (unsubscribes) with one
message to reopen the plot with csaxs.aerotech.plot().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 15:21:51 +01:00
x01dcandClaude Opus 5.5 8c19ed0807 fix(csaxs): aerotech plot shows markers only and reuses its plot
CI for csaxs_bec / test (push) Successful in 3m40s
- the column-wise connecting lines suggested a vertical fast axis; a NaN after
  every point now breaks the curve, so only the exposure markers are drawn (X
  stays finite and sorted for clip-to-view)
- a second plot() call added a second Waveform to the window (new() with the
  same object_name does not reuse it); the existing one is now looked up with
  widget_map() and cleared

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 15:16:44 +01:00
x01dcandClaude Opus 5.5 bff159095c docs(aerotech): live plot colours, stop_plot
CI for csaxs_bec / test (push) Successful in 3m37s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 15:08:09 +01:00
x01dcandClaude Opus 5.5 b7365eceb6 fix(csaxs): aerotech plot sends the positions itself, no downsampling artefacts
CI for csaxs_bec / test (push) Successful in 3m58s
The Waveform's async device curves switch on automatic "peak" downsampling and
clip-to-view above 1000 points; both assume X increasing along the curve, so a
snake scan (8494, 105651 points) showed a diamond pattern and paired markers.
csaxs.aerotech.plot() now reads the scan file (history) or follows the
aerocapture async stream of the running scan (live, from_start, redraw in a
worker thread at <= 2 Hz) and sends plain X/Y data: forward and backward lines
as two curves, points ordered by cell column, alternately up and down, so X
increases along each curve (clip-to-view works when zoomed) and the thin line
runs along the columns. csaxs.aerotech.stop_plot() stops following.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 15:08:00 +01:00
x01dcandClaude Opus 5.5 7fd40c69dc feat(csaxs): csaxs.aerotech.plot() shows the exposure centres Y vs X live
CI for csaxs_bec / test (push) Successful in 3m36s
Opens (or reuses) the GUI window "aerotech" with a Waveform of the async
aerocapture centres, enc2_centre vs enc6_centre, updated per line during
aerotech_cont_grid; scan_number=... shows a finished scan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 14:43:26 +01:00
x01dcandClaude Opus 5.5 b1fb215fa5 docs(aerotech): measured timing and positioning of the default series (scans 8486-8494)
CI for csaxs_bec / test (push) Successful in 3m40s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 14:40:53 +01:00
x01dcandClaude Opus 5.5 3c551ba38e feat(aerotech): minimal_run_up option, run-up only the ramp distance
CI for csaxs_bec / test (push) Successful in 3m39s
aerotech_cont_grid(..., minimal_run_up=True): run-up / run-out = v^2 / (2a),
without the 2x margin and settle_time, for analysis with unevenly spaced
(captured) positions; at least 0.01 so the fast axis never stops and reverses
at the edge of the next line's PSO window (0.25 um at 0.5 mm/s otherwise).
Shown in the statistics header and the limit message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 13:58:31 +01:00
x01dcandClaude Opus 5.5 c86e825e61 docs(aerotech): user page for the SAXS-TT stages, developer page on design and triggering
CI for csaxs_bec / test (push) Successful in 3m33s
User guide (SAXS / Aerotech stages): initialisation on the A3200 PC, config,
moves, aerotech_cont_grid with copy-paste examples for the planned fields of
view, run-up and soft limits, data written, timing / positioning section
(results of the 2026-10-29 series pending; overhead and uneven-positions
estimate defined). Developer guide: interface, moves, scan design and measured
choices, position capture, PandABox line trigger, pitfalls, commissioning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 13:53:54 +01:00
x01dcandClaude Opus 5.5 51ec4fcad8 fix(aerotech): readout_time in scan_info, statistics report the real line period
CI for csaxs_bec / test (push) Successful in 3m31s
- scan_info / data file recorded readout_time 0.0 although the gates and the
  centres used the trigger hardware's 0.2 ms; now the value the scan uses
- statistics: "line mean" was line start .. trigger checked (0.60 s for a
  0.78 s line in scan 8477) and "scan" ran from pre_scan only (10.0 s for a
  13.5 s file); now line period start to start incl. capture readout and step,
  with motion / readout split, and the total of the lines labelled as such

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 13:42:37 +01:00
x01dcandClaude Opus 5.5 96c30dbd3a fix(panda): ignored trigger edges logged per line as info, not as a growing warning
CI for csaxs_bec / test (push) Successful in 3m35s
wait_lines_done warned after every line with the total of ignored edges since
arm (20/10, 23/11, 26/13 ... in a 2026-10-29 scan), which read like an
escalating trigger error. These edges are harmless (encoder noise at the PSO
window entry while the line runs; lines and pulses are checked and raise on a
mismatch), so only the edges new since the last line are logged, at info level.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 13:31:10 +01:00
Mirko HollerandClaude Opus 5.5 723d13d8cc fix(aerotech): captured positions in the user coordinates of the BEC motors
CI for csaxs_bec / test (push) Successful in 3m38s
aerocapture published the latched positions (and centres) in controller coordinates;
with sign: -1 in the device config they had the opposite sign of the motor readback
and the scan statistics compared different frames. The capture device now looks up
the A3200Motor of each channel (same controller, same axis) on the device server and
applies its sign; without such a motor it keeps sign 1 and logs a warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-29 13:25:15 +01:00
x01dcandClaude Opus 5.5 06ce7b0751 fix(aerotech): scan checks raise alarms so the user sees the reason
CI for csaxs_bec / test (push) Successful in 3m34s
The scan worker only logs a ScanAbortion; the client then shows just "Scan ...
was interrupted" (seen 2026-10-29 with the run-up limit check). The checks of
aerotech_cont_grid now raise LimitError (limits), ValueError (parameters,
missing devices) and RuntimeError (missing line trigger), which the scan worker
turns into an alarm with the message, and still runs on_exception.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 13:12:45 +01:00
x01dcandClaude Opus 5.5 e57ae0ddc6 fix(aerotech): set_line_trigger_window in USER_ACCESS
CI for csaxs_bec / test (push) Successful in 4m2s
aerotech_cont_grid switches the PSO window per line through RPC, which only
exposes USER_ACCESS methods: the scan failed after the first line with
"'Positioner' object has no attribute 'set_line_trigger_window'".
New test: every method the scan calls on the fast axis, the capture device and
the PandA is in the device's USER_ACCESS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 13:09:48 +01:00
x01dcandClaude Opus 5.5 aa49276d8d fix(aerotech): calibrate returns string keys so the scan does not hang
CI for csaxs_bec / test (push) Successful in 3m36s
calibrate() returned {channel: offset} with integer keys. The scan server cannot
decode an RPC reply with integer map keys (msgpack strict_map_key), so the
calibrate status never completed and aerotech_cont_grid waited forever in
pre_scan. Now {"enc<channel>": offset}; new test round-trips the RPC return
values of the capture device through the BEC serializer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 12:59:53 +01:00
x01dcandClaude Opus 5.5 e79314c77f fix(panda): rename software_trigger to soft_line_trigger
CI for csaxs_bec / test (push) Successful in 3m34s
software_trigger is a DeviceBase name in BEC, so the device server refused to
load pandatrig ("User access method name {'software_trigger'} is protected").
New test: USER_ACCESS of the PandA and A3200 devices has no protected names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 12:50:36 +01:00
Mirko HollerandClaude Opus 5.5 58636421ad feat(aerotech): step axis moves during the run-out and turnaround of the fast axis
CI for csaxs_bec / test (push) Successful in 3m27s
As soon as the fast axis has left the exposure range (beyond the trigger position),
the PSO window of the next line is set and the step axis starts; the next line starts
when both have arrived. Saves ~0.15 s per line (2 mm/s, 0.8 mm: 1.07 -> 0.92 s per
line incl. step; 20 mm/s: 0.85 -> 0.65-0.73 s). settle_time stays 0.15 s: shorter
values at 20 mm/s gave -24 / +10 / +4.5 / -21 um backward - forward (0.08 / 0.04 /
0.02 / 0 s), a ~10 Hz oscillation after the ramp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-29 12:42:36 +01:00
Mirko HollerandClaude Opus 5.5 4d95cf755f fix(aerotech): move settles only after holding the tolerance for 0.1 s
After a hard stop (5 mm/s, 500 mm/s^2) X rings at ~10 Hz with ~20 um. The single
position error check caught a zero crossing (-0.19 um), the move was declared
settled 3.5 um off the target and failed (premove of a scan aborted). Now position
error and distance to the target must stay within the tolerance for
in_position_hold (0.1 s) without interruption.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-29 12:42:36 +01:00
Mirko HollerandClaude Opus 5.5 201e6406d2 feat(aerotech): exposure centres, readout gap compensation, positions always captured
CI for csaxs_bec / test (push) Successful in 3m27s
- readout time from the trigger hardware (DDG2 effective_readout_times()["ab"], PandA
  device config readout_time, default 0.2 ms), no scan argument; the trigger positions
  move inward by v * readout / 2 so the gates are centred in their cells and forward /
  backward lines have the same exposure centres
- aerotech_cont_grid always captures the positions (capture_positions removed):
  aerocapture publishes the captured gate starts (enc<ch>) and the exposure centres
  (enc<ch>_centre, + v * gate_width / 2 in the direction of motion)
- statistics at the end of the scan (sent to the client): centre - nominal cell centre
  per direction, backward - forward with slope and peak-peak, scan and line times
- aerox acceleration 500 mm/s^2 (1000 left a speed drift in the lines at 20 mm/s);
  aerocapture enabled, channels X and Y only

Hardware 2026-10-29 (PandA, 0.2 ms readout, 6 snake lines each), backward - forward:
2 mm/s +2.3 / +3.2 um, 0.5 mm/s -0.1 / -0.75 um, no slope; 20 mm/s -1.2 um,
slope -1.2 um/mm (was +24 um, 5 um/mm with 1000 mm/s^2 and no compensation).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-29 12:27:26 +01:00
Mirko HollerandClaude Opus 5.5 3aca5030a2 fix(aerotech): position capture latches the gate start (DATAACQ trigger 3)
CI for csaxs_bec / test (push) Successful in 3m31s
Measured with TTL gates on J12 at 2 mm/s: trigger 0 ("UINT1 rising" in the A3200
help) latched at the gate end (+17.2 um for a 10 ms gate, expected +20), trigger 3
at the gate start (-3.0 um). The Npaq UINT input is inverted compared with the help.
Default trigger_input is now 3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-29 12:08:34 +01:00
Mirko HollerandClaude Opus 5.5 28ba071d68 fix(panda): write layout and pulse fields only when they differ
A replayed PULSE train also came 1.3 s after an unchanged parameter write by a new
device instance (connect / configure_line), outside the 1 s quiet wait, and blocked
the first line trigger. Fields are now read first and written only if the PandA holds
a different value, so a reconnect on a configured PandA writes nothing; the quiet wait
after a real change is 2 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-29 12:08:34 +01:00
Mirko HollerandClaude Opus 5.5 972137b871 fix(aerotech): DDG1 trigger edge rising by default (opto output, measured)
CI for csaxs_bec / test (push) Successful in 3m25s
The PSO opto output (J7-6/7 sourcing from J7-25 +5 V) into a 50 Ohm input is high
inside the window in both directions (measured on the PandA TTLIN3, 2026-10-29).
DDG1 EXT is 50 Ohm as well, so the tested wiring needs a rising edge. "falling"
stays available for the open collector / differential outputs (not tested).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-29 11:39:00 +01:00
Mirko HollerandClaude Opus 5.5 77d08df54c fix(panda): edges during a running line are logged, not a scan error
CI for csaxs_bec / test (push) Successful in 3m27s
At 2 mm/s an extra edge at the PSO window entry arrived during the running line
(small field of view, line 4); it was ignored as designed, like on the DDG, but
wait_lines_done aborted the scan. Wrong line or pulse counts still fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-29 11:34:21 +01:00
x01dcandClaude Opus 5.5 db77f0df81 config(aerotech): aerox acceleration 1000 mm/s^2
CI for csaxs_bec / test (push) Successful in 3m24s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 11:28:15 +01:00
x01dcandClaude Opus 5.5 e4f281249b docs(aerotech): README run-up formula matches the 2x ramp margin
CI for csaxs_bec / test (push) Successful in 3m25s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 11:27:31 +01:00
x01dcandClaude Opus 5.5 5819d6b1fd fix(aerotech): limit abort explains the run-up separately from the scan range
CI for csaxs_bec / test (push) Successful in 3m31s
The message now says whether the scan range itself is outside the limits or
only the extra run-up travel for acceleration and settling, by how much, and
what to do about it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 11:24:22 +01:00
Mirko HollerandClaude Opus 5.5 37d8605aaf fix(aerotech): PSO window open beyond the line end, range switched per line
CI for csaxs_bec / test (push) Successful in 3m33s
With one closed window per scan the window exit coincided with the end of the
exposures; encoder noise at the exit edge gave extra trigger edges after the train
(2 in 11 lines on the PandA, one started an extra line). Now the window is open on the
far side of the line and only its range is switched before each line (PSOWINDOW RANGE,
no reload, so the position reference of the arm stays). Hardware test: 2 x 11 lines,
22 edges, 22 lines, 2222 gates, 0 dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-29 11:20:16 +01:00
Mirko HollerandClaude Opus 5.5 b85f8f9c38 fix(panda): wait for the late replayed PULSE train after a parameter change
The PULSE blocks replay a full train ~0.3-0.6 s after a parameter write, without a
trigger. configure_line returned after 50 ms, so the train ran into the first line and
blocked its trigger (line counter 0). Now both PULSE outputs must stay low for
PARAM_QUIET_TIME (1 s); only on a parameter change, i.e. once per scan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-29 11:20:16 +01:00
x01dcandClaude Opus 5.5 1da6330d3c feat(aerotech): scan velocity up to max_scan_velocity, run-up checked against limits
CI for csaxs_bec / test (push) Successful in 3m25s
- A3200Motor.max_scan_velocity (default: velocity) limits the scan velocity of
  aerotech_cont_grid; the move velocity is restored after the scan, also after
  an aborted scan
- run-up / run-out: 2x ramp distance + v * settle_time (was 1.2x ramp)
- the full line range including run-up / run-out and the step axis range are
  checked against the soft limits in prepare_scan
- aerox: acceleration 500 mm/s^2, max_scan_velocity 50 mm/s, moves stay 5 mm/s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 11:19:05 +01:00
x01dcandClaude Opus 5.5 2944da5609 docs(aerotech): beamline examples in the aerotech_cont_grid docstring
CI for csaxs_bec / test (push) Successful in 3m23s
Largest (3.5 x 3.0 mm) and smallest (0.8 x 1.2 mm) field of view of the last
beamtime, each as overview, quick overview and high resolution scan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 11:11:59 +01:00
x01dcandClaude Opus 5.5 d1d63fb947 fix(aerotech): move settles on the position error, not the In Position bit
CI for csaxs_bec / test (push) Successful in 3m24s
aerox settles to 10-30 nm within 0.5 s, but the controller's InPositionDistance
for X is 10 nm, so In Position took several seconds or flickered and every move
logged "not in position 2.0 s after the end of the move". The move now waits
until |PositionError| is within the axis tolerance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-29 09:38:12 +01:00
x01dcandClaude Opus 5.5 834e6ad4df fix(aerotech): quote aerocapture channel keys so the sastt config loads
CI for csaxs_bec / test (push) Successful in 3m35s
Integer YAML map keys made the DeviceConfigMessage undecodable on SciHub
(msgpack strict_map_key), so update_session_with_file hung until timeout.
A3200PositionCapture already converts the keys with int().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
2026-10-28 19:57:05 +01:00
Mirko HollerandClaude Opus 5.5 40c8d90072 refactor(aerotech): aerotech_cont_grid always runs as a snake
CI for csaxs_bec / test (push) Successful in 3m27s
Remove the snake argument and the raster path (flyback with PSO disarm/re-arm);
snake is the only mode used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-28 17:30:11 +01:00
Mirko HollerandClaude Opus 5.5 46751e4fcc feat(aerotech): aerotech_cont_grid is hardware triggered, MCS armed once
CI for csaxs_bec / test (push) Successful in 3m40s
scan_type HARDWARE_TRIGGERED: the MCS card and the detectors are armed once at stage for
all lines x frames (existing hardware_triggered mode of mcs_card_csaxs / ddg_1) instead of
per line; per line the scan only moves the axes. With trigger_source="ddg" each line is
still checked: the MCS must have reached the line's last channel, so a missing line
trigger aborts after the first line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-28 17:07:25 +01:00
Mirko HollerandClaude Opus 5.5 f137517e62 feat(aerotech): snake scan with one PSO window per scan, arm once
CI for csaxs_bec / test (push) Successful in 3m35s
aerotech_cont_grid:
- snake=True (default): alternating line direction. One PSO window per scan,
  [fast_start - v*delay, exposure_end + v*delay], armed once in pre_scan; its output rises
  on entering the window, i.e. at the low edge forward and the high edge backward.
  snake=False switches the PSO off during the flyback.
- trigger_source "ddg" (beamline), "panda" (PandA configured and armed once, every line
  checked) or None (no trigger hardware); trigger_edge for DDG1, default falling (active
  low open collector / differential PSO output).
- settle_time (default 0.15 s) for the run-up at constant speed, measured on the hardware
  2026-10-28; capture_positions defaults to False until the sampling is commissioned.
- the fast axis does not wait for In Position at the turnarounds (wait_in_position signal
  of A3200Motor, off during the scan); restore steps are all tried.
PandaLineTrigger: trigger_edge config, "falling" inverts TTLIN3.

Hardware test of the scan sequence (trigger_source=None, 1x1 mm, 11 lines, X 1 mm/s):
15.3 s instead of 23.1 s; PSO window switched on at X=0.25 forward and X=0.76 backward.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-28 16:59:29 +01:00
Mirko HollerandClaude Opus 5.5 1222198a1b fix(aerotech): move completes on the controller's In Position status
CI for csaxs_bec / test (push) Successful in 3m23s
First moves on the SAXS-TT hardware (X, Z, Y, +-0.5 mm, 2026-10-28): the move was
evaluated when the motion profile ended (MoveDone), X was still settling (1.2 um off) and
the move failed. After MoveDone, move() now waits for DriveStatus In Position
(InPositionDistance / InPositionTime, timeout in_position_timeout = 2 s) before comparing
with the target. axis_status() also reports in_position and encoder_clipping.
Tolerances per axis in the configs: X 1 um, Z/Y 5 um (InPositionDistance 5 um).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-28 16:35:21 +01:00
Mirko HollerandClaude Opus 5.5 b518e657cf feat(panda): line trigger stays armed like the DDG, every edge starts a line
CI for csaxs_bec / test (push) Successful in 3m30s
configure_line() once, arm() once, then every line trigger edge (TTLIN3 or software)
starts a line; a scan no longer re-arms per line. LUT7 accepts an edge only while armed
and while no line is running (PULSE3/PULSE4 low), so edges during a line are ignored like
on the DDG and never reach the PULSE blocks (a dropped trigger puts the FPGA 4.1 PULSE
block into the replay state). COUNTER6/7 count raw edges and accepted lines,
wait_lines_done() checks lines, gates and ignored edges. arm(one_shot=True) keeps the
single-line mode. Design SASTT_line_trigger updated on omny-panda.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-28 16:22:55 +01:00
Mirko HollerandClaude Opus 5.5 763c8e0c27 feat(panda): PandABox line trigger as DDG stand-in for the SAXS-TT Aerotech tests
CI for csaxs_bec / test (push) Successful in 3m43s
Device PandaLineTrigger (control port only): on the first line trigger edge (TTLIN3 or the
software trigger BITS.A) after arm_line(), PULSE3 -> TTLOUT2 sends a shutter pulse and
PULSE4 -> TTLOUT3 n detector pulses; COUNTER8 counts them, SRGATE1 is a one-shot arm gate.
PULSE parameters are written only when they change: on PandA FPGA 4.1 an ENABLE edge or a
parameter write often replays the previous train without a trigger.

Design SASTT_line_trigger saved on omny-panda, copy in layouts/sastt_line_trigger.ini.
Config sastt_aerotech_panda.yaml = sastt_aerotech.yaml + pandatrig.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-28 16:12:01 +01:00
Mirko HollerandClaude Opus 5.5 9c48bc7626 config(aerotech): position capture disabled for the first commissioning steps
CI for csaxs_bec / test (push) Successful in 3m26s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-28 15:19:20 +01:00
Mirko HollerandClaude Opus 5.5 3008e226d5 feat(aerotech): SAXS-TT axis and channel setup from the A3200 parameter file
CI for csaxs_bec / test (push) Successful in 3m18s
From 153722-A-1-1.prma: A3200 PC pc14643.psi.ch, axis indices X 0, Z 1, Y 2, U 3
(UU gantry slave, ZZ encoder input used by Z), limits, default speeds and ramp rates.

PSO input and DATAACQ source are now configured separately, they have different
numberings on the Npaq: motor pso_input (0-5 local counter, 6-8 MXR emulated
quadrature) + pso_counts_divider (EmulatedQuadratureDivider), capture channels are
DATAACQ sources 0-11 (6-11 = MXR channel 0-5). GlobalDoubles is 255 on SAXS-TT, so
the scratch variable moves to $global[254].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-28 15:01:19 +01:00
Mirko HollerandClaude Opus 5.5 669a7ea02b revert(aerotech): remove the RIO burst box trigger source
CI for csaxs_bec / test (push) Successful in 3m22s
This reverts commit bf77d6f6fe.

The RIO timing (1 ms steps, ~50 Hz opto outputs) has too much jitter to judge
whether the position sampling works, so the test setup will not use it. The
DMC program stays in the OMNY Galil repository (RioDDG).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-28 06:16:12 +01:00
Mirko HollerandClaude Opus 5.5 bf77d6f6fe feat(aerotech): RIO burst box as trigger source for aerotech_cont_grid
CI for csaxs_bec / test (push) Successful in 3m30s
- GalilRIOBurst (galil_rio_ddg.py): Galil RIO-47120 running
  RioDDG/rio_ddg.dmc (OMNY Galil repo) as line burst generator: burst mode
  switching, arm_burst, burst status, wait with pulse count check
- aerotech_cont_grid: trigger_source="ddg" (beamline) | "rio" (test setup
  without DDG/MCS)
- simulated RIO triggered by the PSO window of the simulated A3200
- configs: sastt_aerotech_test.yaml (A3200 + RIO), RIO in the simulated config
- tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-27 18:53:55 +01:00
Mirko HollerandClaude Opus 5.5 fe36f374fb feat(aerotech): aerotech_cont_grid scan with PSO line trigger and position capture
CI for csaxs_bec / test (push) Successful in 3m40s
- A3200Motor: arm_line_trigger/disarm_line_trigger (PSO window on the fast
  axis drives DDG1 EXT), acceleration (RAMP RATE before each move),
  encoder_channel
- A3200PositionCapture: Npaq DATAACQ latches the encoder counters on each
  detector trigger (UINT1), read back per line via ARRAY READ and published
  as async data; offset calibrated with a software PSO fire
- aerotech_cont_grid: cont_grid geometry, line start triggered by position
  instead of a software sleep
- simulator support for RAMP, $global, UNITSTOCOUNTS, PSO, DATAACQ, ARRAY READ
- configs, tests, README with wiring and commissioning checklist

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-27 18:28:29 +01:00
Mirko HollerandClaude Opus 5.5 9fac07662f feat(aerotech): A3200 controller and motor for the SAXS-TT Aerotech stages
CI for csaxs_bec / test (push) Successful in 3m29s
Npaq/A3200 via the ASCII command interface on the A3200 Windows PC:
enable, home (HOMEASYNC), MOVEABS, abort, fault ack, ~STATUS readback.
Simulated controller (sim_a3200), device configs for hardware and
simulation, tests. Commissioning checklist in devices/aerotech/README.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDyJxbBLmjZCEPUo5FM
2026-10-27 18:12:41 +01:00