External enable works, trigger input seems dead
This commit is contained in:
@@ -545,14 +545,29 @@ class GigaFrostCamera(PSIDetectorBase):
|
||||
self.cfgCntNum.set(num_images).wait()
|
||||
self.cfgCorrMode.set(correction_mode).wait()
|
||||
|
||||
# if trigger_mode is not None:
|
||||
# self.set_trigger_mode(str(trigger_mode))
|
||||
if trigger_mode is not None:
|
||||
self.set_trigger_mode(str(trigger_mode))
|
||||
|
||||
# Commit parameter
|
||||
self.cmdSetParam.set(1).wait()
|
||||
|
||||
def set_trigger_mode(self, trigger_mode):
|
||||
if trigger_mode == "soft":
|
||||
"""
|
||||
|
||||
NOTE: The trigger input appears to be dead, it completely ignores the
|
||||
supplied signal. Use external enable instead, that works!
|
||||
"""
|
||||
|
||||
if trigger_mode == "default":
|
||||
# trigger modes
|
||||
self.cfgCntStartBit.set(1).wait()
|
||||
self.cfgCntEndBit.set(0).wait()
|
||||
|
||||
# set modes
|
||||
self.enable_mode = "soft"
|
||||
self.trigger_mode = "auto"
|
||||
self.exposure_mode = "timer"
|
||||
elif trigger_mode == "soft":
|
||||
# Switch to physical enable signal
|
||||
self.cfgEnableScheme.set(0).wait()
|
||||
# Set enable signal to always
|
||||
@@ -590,6 +605,16 @@ class GigaFrostCamera(PSIDetectorBase):
|
||||
# Set trigger edge to fixed frames on posedge
|
||||
self.cfgCntStartBit.set(1).wait()
|
||||
self.cfgCntEndBit.set(0).wait()
|
||||
elif trigger_mode in ["ext_enable", "external_enable"]:
|
||||
# Switch to physical enable signal
|
||||
self.cfgEnableScheme.set(0).wait()
|
||||
# Trigger modes
|
||||
self.cfgCntStartBit.set(1).wait()
|
||||
self.cfgCntEndBit.set(0).wait()
|
||||
# Set modes
|
||||
self.enable_mode = "external"
|
||||
self.trigger_mode = "auto"
|
||||
self.exposure_mode = "timer"
|
||||
else:
|
||||
raise RuntimeError(f"Unsupported trigger mode: {trigger_mode}")
|
||||
|
||||
|
||||
+111
-105
@@ -2,7 +2,12 @@
|
||||
""" Tomcat scan base class examples
|
||||
|
||||
A collection of example scan base classes using Automation1 rotation stage,
|
||||
GigaFrost camera and the StandardDAQ pipeline.
|
||||
GigaFrost camera and the StandardDAQ pipeline.
|
||||
|
||||
NOTE: As an explicit request from Tomcat, all devices must be freely
|
||||
interchangeable, including the simultaneous use of multiple devices. Therefore
|
||||
the devices were prepared in such a way, that the scans need to address
|
||||
devices.
|
||||
|
||||
Created on Mon Sep 16 16:45:11 2024
|
||||
|
||||
@@ -18,23 +23,23 @@ from bec_server.scan_server.scans import AsyncFlyScanBase, ScanBase
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
|
||||
class TomcatStepScan(ScanBase):
|
||||
"""Simple software step scan forTomcat
|
||||
|
||||
Example class for simple BEC-based step scans using the low-level API. All it does is
|
||||
translate conventional kwargs to tomcat specific naming scheme.
|
||||
Example class for simple BEC-based step scan using the low-level API.
|
||||
All it does is translate conventional kwargs to tomcat specific device
|
||||
pareameters and launches the standard step scan.
|
||||
|
||||
Example
|
||||
-------
|
||||
>>> scans.gigastep(scan_start=-25, scan_end=155, steps=180, exp_time=0.005, exp_burst=5)
|
||||
>>> scans.tomcatstepscan(scan_start=-25, scan_end=155, steps=180, exp_time=0.005, exp_burst=5)
|
||||
"""
|
||||
|
||||
scan_name = "tomcatstepscan"
|
||||
required_kwargs = ["scan_start", "scan_end", "steps"]
|
||||
gui_config = {
|
||||
"Movement parameters": ["steps"],
|
||||
"Acquisition parameters": ["exp_time", "burst_at_each_point", "roix", "roiy"],
|
||||
"Acquisition parameters": ["exp_time", "exp_burst", "roix", "roiy"],
|
||||
}
|
||||
|
||||
def _get_scan_motors(self):
|
||||
@@ -47,7 +52,7 @@ class TomcatStepScan(ScanBase):
|
||||
steps: int,
|
||||
exp_time=0.005,
|
||||
settling_time=0.2,
|
||||
burst_at_each_point=1,
|
||||
exp_burst=1,
|
||||
roix=2016,
|
||||
roiy=2016,
|
||||
sync="event",
|
||||
@@ -55,18 +60,18 @@ class TomcatStepScan(ScanBase):
|
||||
):
|
||||
# Converting generic kwargs to tomcat device configuration parameters
|
||||
# Used by gigafrost
|
||||
kwargs['parameter']['kwargs']["exposure_time_ms"] = 1000 * exp_time
|
||||
kwargs['parameter']['kwargs']["exposure_period_ms"] = 2 * 1000 * exp_time
|
||||
kwargs['parameter']['kwargs']["exposure_num_burst"] = burst_at_each_point
|
||||
kwargs['parameter']['kwargs']["image_width"] = roix
|
||||
kwargs['parameter']['kwargs']["image_height"] = roiy
|
||||
kwargs["parameter"]["kwargs"]["exposure_time_ms"] = 1000 * exp_time
|
||||
kwargs["parameter"]["kwargs"]["exposure_period_ms"] = 2 * 1000 * exp_time
|
||||
kwargs["parameter"]["kwargs"]["exposure_num_burst"] = exp_burst
|
||||
kwargs["parameter"]["kwargs"]["image_width"] = roix
|
||||
kwargs["parameter"]["kwargs"]["image_height"] = roiy
|
||||
# Used by stdDAQ and DDC
|
||||
kwargs['parameter']['kwargs']["num_points_total"] = burst_at_each_point * (steps + 1)
|
||||
kwargs["parameter"]["kwargs"]["num_points_total"] = exp_burst * (steps + 1)
|
||||
t_modes = {"pso": 0, "event": 1, "inp0": 2, "inp1": 4}
|
||||
ddc_trigger = t_modes[sync]
|
||||
kwargs['parameter']['kwargs']["ddc_trigger"] = ddc_trigger
|
||||
kwargs["parameter"]["kwargs"]["ddc_trigger"] = ddc_trigger
|
||||
# Use PSO trigger
|
||||
kwargs['parameter']['kwargs']["pso_wavemode"] = "pulsed"
|
||||
kwargs["parameter"]["kwargs"]["pso_wavemode"] = "pulsed"
|
||||
|
||||
super().__init__(
|
||||
exp_time=exp_time,
|
||||
@@ -84,21 +89,17 @@ class TomcatStepScan(ScanBase):
|
||||
self.scan_steps = steps
|
||||
self.scan_stepsize = (scan_end - scan_start) / steps
|
||||
|
||||
|
||||
def _calculate_positions(self) -> None:
|
||||
"""Pre-calculate scan positions"""
|
||||
for ii in range(self.scan_steps + 1):
|
||||
self.positions.append(self.scan_start + ii * self.scan_stepsize)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class TomcatSnapNStep(AsyncFlyScanBase):
|
||||
"""Simple software step scan forTomcat
|
||||
|
||||
Example class for simple BEC-based step scans using the low-level API. All it does is
|
||||
translate conventional kwargs to tomcat specific naming scheme.
|
||||
Example class for simple BEC-based step scans using the low-level API. All it does is
|
||||
translate conventional kwargs to tomcat specific naming scheme.
|
||||
|
||||
Example
|
||||
-------
|
||||
@@ -109,7 +110,7 @@ class TomcatSnapNStep(AsyncFlyScanBase):
|
||||
required_kwargs = ["scan_start", "scan_end", "steps"]
|
||||
gui_config = {
|
||||
"Movement parameters": ["steps"],
|
||||
"Acquisition parameters": ["exp_time", "burst_at_each_point", "roix", "roiy"],
|
||||
"Acquisition parameters": ["exp_time", "exp_burst", "roix", "roiy"],
|
||||
}
|
||||
|
||||
def _get_scan_motors(self):
|
||||
@@ -122,7 +123,7 @@ class TomcatSnapNStep(AsyncFlyScanBase):
|
||||
steps: int,
|
||||
exp_time=0.005,
|
||||
settling_time=0.2,
|
||||
burst_at_each_point=1,
|
||||
exp_burst=1,
|
||||
roix=2016,
|
||||
roiy=2016,
|
||||
sync="event",
|
||||
@@ -130,44 +131,35 @@ class TomcatSnapNStep(AsyncFlyScanBase):
|
||||
):
|
||||
# Converting generic kwargs to tomcat device configuration parameters
|
||||
# Used by gigafrost
|
||||
kwargs['parameter']['kwargs']["exposure_time_ms"] = 1000 * exp_time
|
||||
kwargs['parameter']['kwargs']["exposure_period_ms"] = 2 * 1000 * exp_time
|
||||
kwargs['parameter']['kwargs']["exposure_num_burst"] = burst_at_each_point
|
||||
kwargs['parameter']['kwargs']["image_width"] = roix
|
||||
kwargs['parameter']['kwargs']["image_height"] = roiy
|
||||
kwargs["parameter"]["kwargs"]["exposure_time_ms"] = 1000 * exp_time
|
||||
kwargs["parameter"]["kwargs"]["exposure_period_ms"] = 2 * 1000 * exp_time
|
||||
kwargs["parameter"]["kwargs"]["exposure_num_burst"] = exp_burst
|
||||
kwargs["parameter"]["kwargs"]["image_width"] = roix
|
||||
kwargs["parameter"]["kwargs"]["image_height"] = roiy
|
||||
# Used by stdDAQ and DDC
|
||||
kwargs['parameter']['kwargs']["num_points_total"] = burst_at_each_point * (steps + 1)
|
||||
kwargs["parameter"]["kwargs"]["num_points_total"] = exp_burst * (steps + 1)
|
||||
t_modes = {"pso": 0, "event": 1, "inp0": 2, "inp1": 4}
|
||||
ddc_trigger = t_modes[sync]
|
||||
kwargs['parameter']['kwargs']["ddc_trigger"] = ddc_trigger
|
||||
kwargs["parameter"]["kwargs"]["ddc_trigger"] = ddc_trigger
|
||||
# Use PSO trigger (disable triggering)
|
||||
kwargs['parameter']['kwargs']["pso_distance"] = 0
|
||||
kwargs["parameter"]["kwargs"]["pso_distance"] = 0
|
||||
|
||||
# For position calculation
|
||||
self.scan_start = scan_start
|
||||
self.scan_end = scan_end
|
||||
self.scan_steps = steps
|
||||
self.scan_stepsize = (scan_end - scan_start) / steps
|
||||
self.scan_ntotal = burst_at_each_point * (steps + 1)
|
||||
self.scan_ntotal = exp_burst * (steps + 1)
|
||||
self.exp_burst = exp_burst
|
||||
self.settling_time = settling_time
|
||||
self.scan_sync = sync
|
||||
|
||||
# Aerotech DDC settings: Internal event trigger: PsoEvent = 1
|
||||
p_modes = {"pso": "PsoOutput", "event": "PsoEvent", "inp0": "HighSpeedInput0RisingEdge", "inp1": "HighSpeedInput1RisingEdge",}
|
||||
# Used for Aeroscript file substitutions for the task interface
|
||||
filename = "AerotechSnapAndStepTemplate.ascript"
|
||||
filesubs = {
|
||||
"startpos": self.scan_start,
|
||||
"stepsize": self.scan_stepsize,
|
||||
"numsteps": self.scan_steps,
|
||||
"exptime": 2 * exp_time * burst_at_each_point,
|
||||
"settling": settling_time,
|
||||
"psotrigger": p_modes[sync],
|
||||
"npoints": self.scan_ntotal,
|
||||
}
|
||||
filesubs = self.get_filesubs()
|
||||
filetext = self.render_file(filename, filesubs)
|
||||
|
||||
# Task inteface
|
||||
kwargs['parameter']['kwargs']["script_text"] = filetext
|
||||
kwargs['parameter']['kwargs']["script_file"] = "bec.ascript"
|
||||
|
||||
kwargs["parameter"]["kwargs"]["script_text"] = filetext
|
||||
kwargs["parameter"]["kwargs"]["script_file"] = "bec.ascript"
|
||||
|
||||
super().__init__(
|
||||
exp_time=exp_time,
|
||||
@@ -178,13 +170,30 @@ class TomcatSnapNStep(AsyncFlyScanBase):
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def get_filesubs(self) -> dict:
|
||||
"""Generate jinja template substitutions."""
|
||||
p_modes = {
|
||||
"pso": "PsoOutput",
|
||||
"event": "PsoEvent",
|
||||
"inp0": "HighSpeedInput0RisingEdge",
|
||||
"inp1": "HighSpeedInput1RisingEdge",
|
||||
}
|
||||
filesubs = {
|
||||
"startpos": self.scan_start,
|
||||
"stepsize": self.scan_stepsize,
|
||||
"numsteps": self.scan_steps,
|
||||
"exptime": 2 * self.exp_time * self.exp_burst,
|
||||
"settling": self.settling_time,
|
||||
"psotrigger": p_modes[self.scan_sync],
|
||||
"npoints": self.scan_ntotal,
|
||||
}
|
||||
return filesubs
|
||||
|
||||
def render_file(self, filename, filesubs):
|
||||
"""Prepare action: render AeroScript file"""
|
||||
# Load the test file
|
||||
if filename is not None:
|
||||
filename = os.path.join(
|
||||
os.path.dirname(__file__), "../devices/aerotech/" + filename
|
||||
)
|
||||
filename = os.path.join(os.path.dirname(__file__), "../devices/aerotech/" + filename)
|
||||
logger.info(f"Attempting to load file {filename}")
|
||||
with open(filename) as f:
|
||||
templatetext = f.read()
|
||||
@@ -219,26 +228,21 @@ class TomcatSnapNStep(AsyncFlyScanBase):
|
||||
# positions = yield from self.stubs.send_rpc_and_wait(self.daqname, "collect")
|
||||
# logger.info(f"Finished scan with collected positions: {positions}")
|
||||
|
||||
|
||||
def cleanup(self):
|
||||
"""Set scan progress to 1 to finish the scan"""
|
||||
self.num_pos = 1
|
||||
return super().cleanup()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class TomcatSimpleSequence(AsyncFlyScanBase):
|
||||
"""Simple software step scan forTomcat
|
||||
|
||||
Example class for simple BEC-based step scans using the low-level API. All it does is
|
||||
translate conventional kwargs to tomcat specific naming scheme.
|
||||
Example class for simple AeroScript-based step scan using the low-level API. All it does is
|
||||
translate meaningful kwargs to device specific naming scheme.
|
||||
|
||||
Example
|
||||
-------
|
||||
>>> scans.tomcatsimplesequencescan(33, 180, 180, exp_time=0.005, exp_frames=1800, repeats=10)
|
||||
>>> scans.tomcatsimplesequencescan(33, 180, 180, exp_time=0.005, exp_burst=1800, repeats=10)
|
||||
"""
|
||||
|
||||
scan_name = "tomcatsimplesequencescan"
|
||||
@@ -250,7 +254,7 @@ class TomcatSimpleSequence(AsyncFlyScanBase):
|
||||
"gate_high",
|
||||
"gate_low",
|
||||
"exp_time",
|
||||
"exp_frames",
|
||||
"exp_burst",
|
||||
"roix",
|
||||
"roiy",
|
||||
"sync",
|
||||
@@ -265,13 +269,13 @@ class TomcatSimpleSequence(AsyncFlyScanBase):
|
||||
scan_start: float,
|
||||
gate_high: float,
|
||||
gate_low: float,
|
||||
repeats: int=1,
|
||||
repmode: str="PosNeg",
|
||||
exp_time: float=0.005,
|
||||
exp_frames: float=180,
|
||||
roix: int=2016,
|
||||
roiy: int=2016,
|
||||
sync: str="pso",
|
||||
repeats: int = 1,
|
||||
repmode: str = "PosNeg",
|
||||
exp_time: float = 0.005,
|
||||
exp_burst: float = 180,
|
||||
roix: int = 2016,
|
||||
roiy: int = 2016,
|
||||
sync: str = "pso",
|
||||
**kwargs,
|
||||
):
|
||||
# Auto-setup configuration parameters from input
|
||||
@@ -281,63 +285,47 @@ class TomcatSimpleSequence(AsyncFlyScanBase):
|
||||
self.scan_repnum = repeats
|
||||
self.scan_repmode = repmode.upper()
|
||||
self.exp_time = exp_time
|
||||
self.exp_frames = exp_frames
|
||||
self.exp_burst = exp_burst
|
||||
self.scan_sync = sync
|
||||
|
||||
# Synthetic values
|
||||
self.scan_velocity = gate_high / (exp_time * exp_frames)
|
||||
self.scan_ntotal = exp_burst * repeats
|
||||
self.scan_velocity = gate_high / (exp_time * exp_burst)
|
||||
self.scan_acceleration = 500
|
||||
self.scan_safedistance = 10
|
||||
self.scan_accdistance = (
|
||||
self.scan_safedistance
|
||||
+ 0.5 * self.scan_velocity * self.scan_velocity / self.scan_acceleration
|
||||
)
|
||||
self.scan_ntotal = exp_frames * repeats
|
||||
|
||||
if self.scan_repmode in ("POS", "NEG"):
|
||||
self.scan_range = repeats * (gate_high + gate_low)
|
||||
elif self.scan_repmode in ("POSNEG", "NEGPOS"):
|
||||
self.scan_range = gate_high + gate_low
|
||||
else:
|
||||
raise RuntimeError(f"Unsupported repetition mode: {repmode}")
|
||||
|
||||
|
||||
raise RuntimeError(f"Unsupported repetition mode: {self.scan_repmode}")
|
||||
|
||||
# Converting generic kwargs to tomcat device configuration parameters
|
||||
# Used by gigafrost
|
||||
kwargs['parameter']['kwargs']["exposure_time_ms"] = 1000 * exp_time
|
||||
kwargs['parameter']['kwargs']["exposure_period_ms"] = 2 * 1000 * exp_time
|
||||
kwargs['parameter']['kwargs']["exposure_num_burst"] = exp_frames
|
||||
kwargs['parameter']['kwargs']["image_width"] = roix
|
||||
kwargs['parameter']['kwargs']["image_height"] = roiy
|
||||
kwargs["parameter"]["kwargs"]["exposure_time_ms"] = 1000 * exp_time
|
||||
kwargs["parameter"]["kwargs"]["exposure_period_ms"] = 2 * 1000 * exp_time
|
||||
kwargs["parameter"]["kwargs"]["exposure_num_burst"] = exp_burst
|
||||
kwargs["parameter"]["kwargs"]["image_width"] = roix
|
||||
kwargs["parameter"]["kwargs"]["image_height"] = roiy
|
||||
# Used by stdDAQ and DDC
|
||||
kwargs['parameter']['kwargs']["num_points_total"] = exp_frames * (self.scan_repnum + 1)
|
||||
kwargs["parameter"]["kwargs"]["num_points_total"] = exp_burst * (self.scan_repnum + 1)
|
||||
t_modes = {"pso": 0, "event": 1, "inp0": 2, "inp1": 4}
|
||||
ddc_trigger = t_modes[sync]
|
||||
kwargs['parameter']['kwargs']["ddc_trigger"] = ddc_trigger
|
||||
kwargs["parameter"]["kwargs"]["ddc_trigger"] = ddc_trigger
|
||||
# Use PSO trigger (disable triggering)
|
||||
kwargs['parameter']['kwargs']["pso_distance"] = 0
|
||||
kwargs["parameter"]["kwargs"]["pso_distance"] = 0
|
||||
|
||||
# Aerotech DDC settings: Internal event trigger: PsoEvent = 1
|
||||
p_modes = {"pso": "PsoOutput", "event": "PsoEvent", "inp0": "HighSpeedInput0RisingEdge", "inp1": "HighSpeedInput1RisingEdge",}
|
||||
# Used for Aeroscript file substitutions for the task interface
|
||||
filename = "AerotechSimpleSequenceTemplate.ascript"
|
||||
filesubs = {
|
||||
"startpos": self.scan_start,
|
||||
"scanrange": self.scan_range,
|
||||
"nrepeat": self.scan_repnum,
|
||||
"scanvel": self.scan_velocity,
|
||||
"scanacc": self.scan_acceleration,
|
||||
"accdist": self.scan_accdistance,
|
||||
"npoints": self.scan_ntotal,
|
||||
"scandir": self.scan_repmode.upper(),
|
||||
"psotrigger": p_modes[sync],
|
||||
}
|
||||
filesubs = self.get_positions(filesubs)
|
||||
filesubs = self.get_filesubs()
|
||||
filetext = self.render_file(filename, filesubs)
|
||||
|
||||
# Task inteface
|
||||
kwargs['parameter']['kwargs']["script_text"] = filetext
|
||||
kwargs['parameter']['kwargs']["script_file"] = "bec.ascript"
|
||||
|
||||
kwargs["parameter"]["kwargs"]["script_text"] = filetext
|
||||
kwargs["parameter"]["kwargs"]["script_file"] = "bec.ascript"
|
||||
|
||||
super().__init__(
|
||||
exp_time=exp_time,
|
||||
@@ -352,9 +340,7 @@ class TomcatSimpleSequence(AsyncFlyScanBase):
|
||||
"""Prepare action: render AeroScript file"""
|
||||
# Load the test file
|
||||
if filename is not None:
|
||||
filename = os.path.join(
|
||||
os.path.dirname(__file__), "../devices/aerotech/" + filename
|
||||
)
|
||||
filename = os.path.join(os.path.dirname(__file__), "../devices/aerotech/" + filename)
|
||||
logger.info(f"Attempting to load file {filename}")
|
||||
with open(filename) as f:
|
||||
templatetext = f.read()
|
||||
@@ -389,7 +375,27 @@ class TomcatSimpleSequence(AsyncFlyScanBase):
|
||||
# positions = yield from self.stubs.send_rpc_and_wait(self.daqname, "collect")
|
||||
# logger.info(f"Finished scan with collected positions: {positions}")
|
||||
|
||||
def get_positions(self, filesubs: dict={}):
|
||||
def get_filesubs(self):
|
||||
"""Generate jinja template substitutions."""
|
||||
# Aerotech DDC settings: Internal event trigger: PsoEvent = 1
|
||||
p_modes = {
|
||||
"pso": "PsoOutput",
|
||||
"event": "PsoEvent",
|
||||
"inp0": "HighSpeedInput0RisingEdge",
|
||||
"inp1": "HighSpeedInput1RisingEdge",
|
||||
}
|
||||
filesubs = {
|
||||
"startpos": self.scan_start,
|
||||
"scanrange": self.scan_range,
|
||||
"nrepeat": self.scan_repnum,
|
||||
"scanvel": self.scan_velocity,
|
||||
"scanacc": self.scan_acceleration,
|
||||
"accdist": self.scan_accdistance,
|
||||
"npoints": self.scan_ntotal,
|
||||
"scandir": self.scan_repmode,
|
||||
"psotrigger": p_modes[self.scan_sync],
|
||||
}
|
||||
|
||||
# Fill PSO vectors according to scan direction
|
||||
# NOTE: Distance counter is bidirectional
|
||||
pso_bounds_pos = []
|
||||
@@ -412,4 +418,4 @@ class TomcatSimpleSequence(AsyncFlyScanBase):
|
||||
def cleanup(self):
|
||||
"""Set scan progress to 1 to finish the scan"""
|
||||
self.num_pos = 1
|
||||
return super().cleanup()
|
||||
return super().cleanup()
|
||||
|
||||
Reference in New Issue
Block a user