diff --git a/tomcat_bec/Readme.md b/tomcat_bec/Readme.md index 68d0d35..811a711 100644 --- a/tomcat_bec/Readme.md +++ b/tomcat_bec/Readme.md @@ -67,11 +67,9 @@ in Visual Studio Code, a really handy IDE if you have a fast connection: code & ``` - - ### The Tomcat BEC repository -The Tomcat BEC repository is a collection of Tomcat specific ophyd devices, scans, and +The Tomcat BEC repository is a collection of Tomcat specific ophyd devices, scans, scripts and device configurations. It tries to enforce a standard structure across beamlines and it's **maintenance is the responsibility of the beamline.** I.e. it should be handed over from controls while still keeping the basic structure: @@ -95,6 +93,7 @@ From the list of folders the most important ones are: - device_configs : Ophyd device datbase as YAML file - devices : Ophyd device repository (i.e. Aerotech, Gigafrost) - scans : Tomcat specific base scans in the low-level API + - scripts : Scripts and scans using the high level API The official location of the beamline repository is: ``` @@ -124,8 +123,8 @@ Tomcat beamlines and ensure their collaboration. Namely the rotation stage with controller, the GigaFrost camera and the Standard-DAQ recording system. The individual repositories have more documentation on the components, but as a short summary, the Aerotech Automation1 IOC is a recently developed EPICS driver, the GigaFrost IOC is an ancient offshoot of Helge's camera driver -and the std-DAQ communicated via hybrid websocket and REST-API and also provides throttled preview -streams. +and the std-DAQ is a non-EPICS device that is controlled via a hybrid websocket and REST interface. +The DAQ also provides preview streams with hardcoded throttling. Note that the standard bluesky event model applies, i.e. configure sets up the device, stage and trigger for stepping interface and kickoff and collect for flyers. This will be updated with the @@ -133,7 +132,7 @@ recently updated event model. Redundant staging raises an exception. ### Seeing is believing (GUI) -Since seeing is believing, it's often a good idea to bring up the panels and get some visual +Since seeing is believing, it's often a good idea to bring up some panels and get visual feedback. You can start the standard CaQtDM panels for the Aerotech and GigaFrost from any beamline console running the contros stack by: ``` @@ -168,6 +167,7 @@ def.gfclient.unstage() dev.daq_stream0.unstage() ``` + ## Reseting the Automation1 iSMC There's some electrical disturbance at SLS that can bring the system to a problematic state. A workaround is to remotely reset the iSMC: @@ -179,17 +179,78 @@ FIXME: There is a known desync in PSO inputs upon iSMC restart that requires res -### Simple scans -As I was unsure about the various triggering modes of the Gigafrost, I only prepared a simple -step scanning implementation that is compatible with the standard bluesky step scanning interface -using soft-triggers +## Scans at the testbench + +The current repository has several implemented scans, often offering different solutions to the +same problem using different APIs while providing similar functionality. The BEC itself has two +scan APIs for low- and highlevel scans, and the fastest scans can be directly implemented on the +Automation1 iSMC. The implemented BEC scans combine motor motion, PSO triggering, Gigafrost and +stdDAQ control and position capture in internal or external triggering mode. They were +intentionally designed to provide the same interface, althogh not every combination was tested. + +As I was unsure about the various triggering modes of the Gigafrost, so currently it's implemented +with only sofware trigger that is compatible with the standard bluesky step scanning interface. + + +### demostepscan + +Simple step scan in the scripting API that performs the device configuration and hands over to +a standard BEC scan routine. Note that there's absolutely no readback from the GigaFrost so we +don't know when it finished acquiring. ``` -scans.simplestep(range=(-20, 160), steps=18, exp_time=2, exp_burst=220) +def demostepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_point=1, settling_time=0, sync='event') ``` -### Templated script scans +### gigastep -A template has been prepared, but we should wait until I can test final cabling. +Simple step scan in the low level API that performs the device configuration loops over each +position in BEC and reads back the position data. Note that there's absolutely no readback from the GigaFrost so we +don't know when it finished acquiring. +``` +scans.gigastep(scan_start, scan_end, steps, exp_time=0.005, settling_time=0.2, burst_at_each_point = 1, sync='event') +``` + +### snapnstep + +Scripted step scan that sets up all components, creates an AeroScript file from template and +executes it on the Automation1 iSMC controller. Upon succesfull completion it reads back the +positions from the data capture. + +NOTE: This scan just launches the GigaFrost, but hardware triggering is currently not implemented. +``` +scans.snapnstep(scan_start, scan_end, steps, exp_time=0.005, settling_time=0.2, burst_at_each_point = 1, sync='event') +``` + + +### sequencescan + +Scripted scan that sets up all components, creates an AeroScript file from template and executes it +on the Automation1 iSMC controller. Upon succesfull completion it reads back the positions from the +data capture. Position readback works wth both internal and external triggers. + +NOTE: This scan just launches the GigaFrost, but hardware triggering is currently not implemented. + +``` +scans.sequencescan(scan_start, gate_high, gate_low, repeats=1, repmode="PosNeg", exp_time=0.005, exp_frames=180, roix=2016, roiy=2016, sync="pso") +``` + + +### demosequencescan + +Basic sequence scan in the high level API that calls the corresponding low-level scan with some +extra checks. +``` +demosequencescan(scan_start, gate_high, gate_low, repeats=1, repmode="PosNeg", exp_time=0.005, exp_frames=180, roix=2016, roiy=2016, sync="pso") +``` + + +### becsequencescan + +Basic sequence scan script in BEC's high level interface. It a performs all trigger configurations +movements and readback from BEC. +``` +becsequencescan(scan_start, gate_high, gate_low, repeats=1, repmode="PosNeg", exp_time=0.005, exp_frames=180, roix=2016, roiy=2016, sync="pso") +``` diff --git a/tomcat_bec/devices/aerotech/AerotechSnapAndStepTemplate.ascript b/tomcat_bec/devices/aerotech/AerotechSnapAndStepTemplate.ascript index fa212d2..320975f 100644 --- a/tomcat_bec/devices/aerotech/AerotechSnapAndStepTemplate.ascript +++ b/tomcat_bec/devices/aerotech/AerotechSnapAndStepTemplate.ascript @@ -10,6 +10,7 @@ program var $iNumSteps as integer = {{ scan.numsteps }} var $fStepSize as real = {{ scan.stepsize }} var $fExposureTimeSec as real = {{ scan.exptime }} + var $fSettlingTimeSec as real = {{ scan.settle }} var $fVelJog as real = {{ scan.travel or 200 }} var $fVelScan as real = {{ scan.velocity or 50 }} var $fAcceleration = {{ scan.acceleration or 500 }} @@ -78,6 +79,7 @@ program TaskSetError(TaskGetIndex(), "AxisFault on axis ROTY") end + Dwell($fSettlingTimeSec) PsoEventGenerateSingle($axis) Dwell($fExposureTimeSec) $fPosNext = $fPosNext + $fStepSize diff --git a/tomcat_bec/scans/tomcat_scanbase.py b/tomcat_bec/scans/tomcat_scanbase.py index 61b261a..5920766 100644 --- a/tomcat_bec/scans/tomcat_scanbase.py +++ b/tomcat_bec/scans/tomcat_scanbase.py @@ -247,6 +247,7 @@ class GigaStepScanBase(ScanBase): exp_time = 0.005, settling_time = 0.2, burst_at_each_point = 1, + sync='event', **kwargs): super().__init__( exp_time=exp_time, @@ -270,8 +271,12 @@ class GigaStepScanBase(ScanBase): self.exp_time = settling_time + exp_time * 2 * burst_at_each_point # Prepare configuration dicts + # Aerotech DDC settings: Internal event trigger: PsoEvent = 1 + t_modes = {'pso': 0, 'event': 1, 'inp0': 2, 'inp1': 4} + daq_trigger = t_modes[sync] + self.psocfg = {} - self.daqcfg = {'ntotal': self.scan_ntotal, 'trigger': 1} + self.daqcfg = {'ntotal': self.scan_ntotal, 'trigger': daq_trigger} self.camcfg = { "ntotal": self.scan_ntotal, "nimages": burst_at_each_point, @@ -342,7 +347,7 @@ class SnapAndStepScanBase(TemplatedScanBase): } def __init__(self, scan_start, scan_end, steps, - exp_time=0.005, burst_at_each_point=1, + exp_time=0.005, settling_time=0, burst_at_each_point=1, roix=2016, roiy=2016, sync="event", **kwargs): # Auto-setup configuration parameters from input self.scan_start = scan_start @@ -350,6 +355,7 @@ class SnapAndStepScanBase(TemplatedScanBase): self.scan_steps = steps self.exp_time = exp_time self.exp_burst = burst_at_each_point + self.settling_time = settling_time # Synthetic values self.scan_stepsize = (scan_end-scan_start)/steps @@ -361,6 +367,7 @@ class SnapAndStepScanBase(TemplatedScanBase): 'stepsize': self.scan_stepsize, 'numsteps': self.scan_steps, 'exptime': self.exp_time*self.exp_burst + 'settling': self.settling_time } # Aerotech DDC settings: Internal event trigger: PsoEvent = 1