fix(aerotech): position capture latches the gate start (DATAACQ trigger 3)
CI for csaxs_bec / test (push) Successful in 3m31s
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
This commit is contained in:
1 parent
28ba071d68
commit
3aca5030a2
3 files changed
+18
-9
No files matched your search
@@ -94,7 +94,9 @@ scans.aerotech_cont_grid(dev.aerox, 0, 1, 0.01, dev.aeroy, 0, 1, 0.1, exp_time=0
|
||||
the scan); X reaches 1 um within ~60 ms but 10 nm only after 0.5-2 s
|
||||
- `capture_positions=True` (default False until commissioned): device `aerocapture` latches
|
||||
the encoder counters on each detector trigger (DATAACQ on UINT1, up to 16 kHz, 4 kHz with
|
||||
MXR sources); after each line they are read back (~2600 values/s over the ASCII interface)
|
||||
MXR sources). The Npaq input is inverted compared with the A3200 help (measured
|
||||
2026-10-29): DATAACQ trigger 3 latches at the rising TTL edge at J12 (gate start, the
|
||||
default), trigger 0 at the falling one (gate end); after each line they are read back (~2600 values/s over the ASCII interface)
|
||||
and published as async data `aerocapture_positions_enc<channel>`. The counter offset is
|
||||
calibrated in pre_scan with one software PSO fire, before any trigger receiver is armed.
|
||||
|
||||
@@ -150,7 +152,7 @@ lines run back to back without re-arming.
|
||||
|-------|-----|--------|
|
||||
| TTLIN3 (50 Ω) | line trigger | Npaq J7 opto output: J7-25 (+5 V) -> J7-6, J7-7 -> TTLIN3, J7-24 -> TTLIN3 ground |
|
||||
| TTLOUT2 | "shutter": trigger edge to end of the last gate | scope |
|
||||
| TTLOUT3 | "detector" gates (high during exposure): n pulses, width exp_time - readout_time, period exp_time, first one shutter_delay after the edge | scope, later Npaq J12 pin 1 (+) / pin 2 (-) for position sampling (rising edge = exposure start) |
|
||||
| TTLOUT3 | "detector" gates (high during exposure): n pulses, width exp_time - readout_time, period exp_time, first one shutter_delay after the edge | scope and Npaq J12 pin 1 (+) / pin 2 (-) for position sampling (rising edge = exposure start, DATAACQ trigger 3) |
|
||||
|
||||
Blocks: LUT8 = TTLIN3 | BITS.A (software trigger); SRGATE1 arm gate; LUT7 = rising edge of
|
||||
LUT8 & SRGATE1 & no line running (PULSE3/PULSE4 low) -> PULSE3 (shutter), PULSE4 (gates).
|
||||
|
||||
@@ -394,7 +394,8 @@ class A3200Controller(Controller):
|
||||
def dataacq_arm(self, axis: str, trigger: int, channels: list[int], n_triggers: int) -> None:
|
||||
"""
|
||||
Capture the source signals `channels` on each trigger into the drive array,
|
||||
starting at index 0. Npaq trigger 0 = Input 12 (UINT1) rising edge, 6 = PSO firing.
|
||||
starting at index 0. Npaq trigger 0 / 3 = Input 12 (UINT1) "rising" / "falling" edge
|
||||
(measured: 3 latches when the TTL level at J12 rises), 6 = PSO firing.
|
||||
Npaq sources: 0-5 local encoder counter, 6-11 encoder multiplier (MXR) channel 0-5.
|
||||
"""
|
||||
self.command(f"DATAACQ {axis} 1 OFF")
|
||||
@@ -774,7 +775,12 @@ class A3200Motor(Device, PositionerBase):
|
||||
# Npaq DATAACQ position sources: 0-5 local encoder counter, 6-11 encoder multiplier (MXR)
|
||||
# channel 0-5 (max. 4 kHz trigger rate); 12-15 are analog inputs, not used here.
|
||||
DATAACQ_POSITION_SOURCES = 12
|
||||
DATAACQ_TRIGGER_UINT1_RISING = 0
|
||||
# Npaq DATAACQ triggers on UINT1 (J12 pin 1+/2-). Measured 2026-10-29 with a TTL gate on
|
||||
# J12 (PandA TTLOUT3, X at 2 mm/s): trigger 3 ("falling edge" in the A3200 help) latches at
|
||||
# the rising TTL edge (start of the exposure gate), trigger 0 ("rising edge") at the falling
|
||||
# TTL edge (end of the gate). The opto input is inverted compared with the help.
|
||||
DATAACQ_TRIGGER_UINT1_TTL_RISING = 3
|
||||
DATAACQ_TRIGGER_UINT1_TTL_FALLING = 0
|
||||
DATAACQ_TRIGGER_PSO_FIRING_EVENT = 6
|
||||
|
||||
|
||||
@@ -782,8 +788,8 @@ class A3200PositionCapture(PSIDeviceBase):
|
||||
"""
|
||||
Latch axis positions on an external trigger (Npaq DATAACQ, drive array).
|
||||
|
||||
Each rising edge on the trigger input (default: Input 12 / UINT1, the detector
|
||||
exposure trigger) stores the encoder counters of the configured channels in the
|
||||
Each trigger edge (default: rising TTL edge on Input 12 / UINT1, i.e. the start of the
|
||||
detector exposure gate) stores the encoder counters of the configured channels in the
|
||||
drive array. After a scan line, read_line() reads them back, converts them to user
|
||||
units (CountsPerUnit of the axis) and publishes them as async data (signals enc<source>).
|
||||
|
||||
@@ -794,7 +800,8 @@ class A3200PositionCapture(PSIDeviceBase):
|
||||
its PositionFeedbackChannel, by default its axis index in the Npaq. Values are
|
||||
in controller coordinates (the BEC motor sign is not applied).
|
||||
drive_axis: any axis of the Npaq, used to address the drive (shared array).
|
||||
trigger_input: DATAACQ trigger, 0 = Input 12 (UINT1) rising edge.
|
||||
trigger_input: DATAACQ trigger, 3 = rising TTL edge at UINT1 (gate start, default),
|
||||
0 = falling TTL edge (gate end); see DATAACQ_TRIGGER_UINT1_TTL_RISING.
|
||||
"""
|
||||
|
||||
USER_ACCESS = ["controller", "arm", "read_line", "calibrate", "disarm"]
|
||||
@@ -819,7 +826,7 @@ class A3200PositionCapture(PSIDeviceBase):
|
||||
port=8000,
|
||||
channels=None,
|
||||
drive_axis="X",
|
||||
trigger_input=DATAACQ_TRIGGER_UINT1_RISING,
|
||||
trigger_input=DATAACQ_TRIGGER_UINT1_TTL_RISING,
|
||||
socket_cls=SocketIO,
|
||||
device_manager=None,
|
||||
scan_info=None,
|
||||
|
||||
@@ -166,7 +166,7 @@ class SimA3200State:
|
||||
if not (min(start, target) <= low and high <= max(start, target)):
|
||||
return
|
||||
self.pso_window_entries += 1
|
||||
if acq["armed"] and acq["trigger"] == 0 and acq["inputs"]:
|
||||
if acq["armed"] and acq["trigger"] in (0, 3) and acq["inputs"]:
|
||||
n_triggers = acq["n_elements"] // len(acq["inputs"])
|
||||
step = (high - low) / max(n_triggers, 1)
|
||||
for k in range(n_triggers):
|
||||
|
||||
Reference in new issue
Block a user