dls-dodal 1.26.0__py3-none-any.whl → 1.27.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dls_dodal-1.26.0.dist-info → dls_dodal-1.27.0.dist-info}/METADATA +1 -1
- {dls_dodal-1.26.0.dist-info → dls_dodal-1.27.0.dist-info}/RECORD +18 -17
- dodal/_version.py +2 -2
- dodal/beamlines/i03.py +24 -9
- dodal/beamlines/i04.py +38 -6
- dodal/beamlines/i24.py +3 -1
- dodal/common/coordination.py +11 -9
- dodal/common/visit.py +1 -43
- dodal/devices/aperturescatterguard.py +41 -6
- dodal/devices/backlight.py +30 -14
- dodal/devices/fast_grid_scan.py +185 -192
- dodal/devices/robot.py +2 -0
- dodal/devices/thawer.py +15 -0
- dodal/plans/data_session_metadata.py +46 -0
- dodal/devices/panda_fast_grid_scan.py +0 -162
- {dls_dodal-1.26.0.dist-info → dls_dodal-1.27.0.dist-info}/LICENSE +0 -0
- {dls_dodal-1.26.0.dist-info → dls_dodal-1.27.0.dist-info}/WHEEL +0 -0
- {dls_dodal-1.26.0.dist-info → dls_dodal-1.27.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.26.0.dist-info → dls_dodal-1.27.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
dodal/__init__.py,sha256=y-VRpfiX-Lm5nchB9N0VfMy_6dwFqVxpSn5SiAQql9I,114
|
|
2
2
|
dodal/__main__.py,sha256=kP2S2RPitnOWpNGokjZ1Yq-1umOtp5sNOZk2B3tBPLM,111
|
|
3
|
-
dodal/_version.py,sha256=
|
|
3
|
+
dodal/_version.py,sha256=XlqTK6aXcDzaFgsrMUHCuU_TY8zt9cjwfCWklVgy2Hg,413
|
|
4
4
|
dodal/adsim.py,sha256=OW2dcS7ciD4Yq9WFw4PN_c5Bwccrmu7R-zr-u6ZCbQM,497
|
|
5
5
|
dodal/cli.py,sha256=z0UBESrNrq6Kq4rttp4uHcwS1fnOnRkKBRDHSriPpGY,2058
|
|
6
6
|
dodal/log.py,sha256=grK5-c-V6UjMERwDqYPdKbc_BpycrNb8hP0uteLOVCY,8296
|
|
@@ -9,21 +9,21 @@ dodal/beamline_specific_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
|
|
|
9
9
|
dodal/beamline_specific_utils/i03.py,sha256=Ixe1anFQl-kwRJubmQx28TIW4Zw8qDxpElNNNapWQHI,396
|
|
10
10
|
dodal/beamlines/README.md,sha256=K9MkL_GomxlsoTB7Mz-_dJA5NNSbmCfMiutchGg3C8o,404
|
|
11
11
|
dodal/beamlines/__init__.py,sha256=U0dQYFEUloCdQOs24zyfpPTncJXOO4cDcfHSevVOAw4,2890
|
|
12
|
-
dodal/beamlines/i03.py,sha256=
|
|
13
|
-
dodal/beamlines/i04.py,sha256=
|
|
12
|
+
dodal/beamlines/i03.py,sha256=nOWm9iUYOwqUDAkBXC4UkYmN2GGD1MbTgyCCMO_YXBw,16394
|
|
13
|
+
dodal/beamlines/i04.py,sha256=JOyNcUnC3wva4no2MHKp6b8gOKAcQXL_c4cBo7oneVs,13034
|
|
14
14
|
dodal/beamlines/i04_1.py,sha256=KDxSUQNhIs_NFiRaLY-Jiory0DeN7Y0ErvGuoTrwCDU,4731
|
|
15
15
|
dodal/beamlines/i20_1.py,sha256=XJpey1-XZnCVpjK6-tODRYeBofqV44BL8lK5OSdQgiI,746
|
|
16
16
|
dodal/beamlines/i22.py,sha256=TlXgAuRYM4JS733tyZyLMYDyC7ajwg85_XzYI5qh46U,7574
|
|
17
17
|
dodal/beamlines/i23.py,sha256=iEFkrA4sPQsRLGAmeD263jPMX4u2SF1NK4_KYqnVwow,1402
|
|
18
|
-
dodal/beamlines/i24.py,sha256=
|
|
18
|
+
dodal/beamlines/i24.py,sha256=LIe8tu_ZJsoeQH7tYRZHSvqQ9C9zBGOXO6rb1DPCYjQ,4595
|
|
19
19
|
dodal/beamlines/p38.py,sha256=0uRL4GVs1sGobr0BZpDDbtStNJcipT6o4FvoA_OWLaE,7120
|
|
20
20
|
dodal/beamlines/p45.py,sha256=TNIkC-SBfj0ayZtlLLXW9xCSi5CzJkO8XpAMIo8fjao,2957
|
|
21
21
|
dodal/common/__init__.py,sha256=ZC4ICKUDB0BDxRaVy8nmqclVmDBne-dPtk6UJsoFq6I,258
|
|
22
|
-
dodal/common/coordination.py,sha256=
|
|
22
|
+
dodal/common/coordination.py,sha256=OxIjDiO1-9A9KESRPFtzwkvvQlavbgA5RHemlbubBPg,1168
|
|
23
23
|
dodal/common/maths.py,sha256=JRSBhbMzwlicKp1_Bsfu9gA79JJA_Dgq9EpbExFH65M,1829
|
|
24
24
|
dodal/common/types.py,sha256=M0gZs9F7--gREF8VYJn-Y1Mt9mIEgp1aLY3oUpUkSno,546
|
|
25
25
|
dodal/common/udc_directory_provider.py,sha256=zNlt_VgdAlyBtVN7neTHk_0tWBbI4pPUL7q9WQOzXvo,1260
|
|
26
|
-
dodal/common/visit.py,sha256=
|
|
26
|
+
dodal/common/visit.py,sha256=MhrFbLptMG0Wvd2nHubBwQ44qAzoP4Bf4_z_-wO8rh0,6063
|
|
27
27
|
dodal/common/beamlines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
28
|
dodal/common/beamlines/beamline_parameters.py,sha256=N22dtDLw3Hlo7EUmGxe4qFGcu7OnldwCz_mU7yK2rd0,3577
|
|
29
29
|
dodal/common/beamlines/beamline_utils.py,sha256=AgmH9wpnFQ4DHAA7_Yo0COa2piX2ksFxukFt2_600kA,4488
|
|
@@ -32,15 +32,15 @@ dodal/devices/CTAB.py,sha256=_MfL_KH4uDPxq_RuHFEZ9HVXOpUnQb5be3csoz9DdAs,1630
|
|
|
32
32
|
dodal/devices/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
dodal/devices/adsim.py,sha256=dMU0TKIuiODHYFHQOH4_5UvB8iJtaJEtjqaEDGjcU-w,311
|
|
34
34
|
dodal/devices/aperture.py,sha256=0MtTzKMDZ5DVAz0DE0kXI0M76VCp0y9vFsrMggEMpxk,586
|
|
35
|
-
dodal/devices/aperturescatterguard.py,sha256=
|
|
35
|
+
dodal/devices/aperturescatterguard.py,sha256=2JJsEPJGJHrI0ztv1cSaP7H5T6qdzDfUcN-VEQ39B8o,11012
|
|
36
36
|
dodal/devices/attenuator.py,sha256=OD7fElTIMHWk7ZopPqEu29lionm7WwgC0-Kvl8vBIb0,2599
|
|
37
|
-
dodal/devices/backlight.py,sha256=
|
|
37
|
+
dodal/devices/backlight.py,sha256=vsNGZB4C_mVMafllvJlOTghsfv6UqALMKUMLXu3WZ5k,1115
|
|
38
38
|
dodal/devices/beamstop.py,sha256=8L3qhlk-3ZBOp10xK1i8qZqYTGOXX1mVF1MgXoN0dfg,215
|
|
39
39
|
dodal/devices/cryostream.py,sha256=6MU4rXIOL33C-8F3DVfAtv0ZnwiysTtawjkeePd5IrQ,332
|
|
40
40
|
dodal/devices/dcm.py,sha256=vfyGYDzfSwTiNqlzkfNjkrL-Q1hNVSgJddvJ5Un_lvg,1610
|
|
41
41
|
dodal/devices/eiger.py,sha256=NE4tHdqgUZpUxJLQbd5lLUIHZcpeotppexJGlDNByzM,13868
|
|
42
42
|
dodal/devices/eiger_odin.py,sha256=U5Byb7uNwDdNscBRp7yBYQrsjKrKXl2l5WdSpL09lAw,6980
|
|
43
|
-
dodal/devices/fast_grid_scan.py,sha256=
|
|
43
|
+
dodal/devices/fast_grid_scan.py,sha256=_jsiUxpMO2rAGDhTFPN8J35e6E0oreLpKYi6W8wQGzs,12798
|
|
44
44
|
dodal/devices/fluorescence_detector_motion.py,sha256=RrXfPmJzWnAjcjp9u0AnJEfjvWPMKburVTySB2hxYbw,181
|
|
45
45
|
dodal/devices/flux.py,sha256=RtPStHw7Mad0igVKntKWVZfuZn2clokVJqH14HLix6M,198
|
|
46
46
|
dodal/devices/focusing_mirror.py,sha256=aRqBkE3OgaXpH6lP3v1VbSYgHsMMbSsPPXzeyAGf_Pg,6435
|
|
@@ -50,9 +50,8 @@ dodal/devices/logging_ophyd_device.py,sha256=xw4lbyqq5_ehESGterVEfubJsBiJTWvBp5b
|
|
|
50
50
|
dodal/devices/lower_gonio_stages.py,sha256=oJ_Xeuqs5E8AWAoZX52jD1qV6pCSjCOjdwnXFKz_xjw,229
|
|
51
51
|
dodal/devices/motors.py,sha256=aKtMv5q_4b1eFhzyuk2-D6zDsY_6cqAmG59y5LWUz1s,1328
|
|
52
52
|
dodal/devices/p45.py,sha256=jzBW2fGRhIbGzSRs5Fgupxro6aqE611n1RTcrTTG-yY,1047
|
|
53
|
-
dodal/devices/panda_fast_grid_scan.py,sha256=cQmrs3pQ3P_J1e5C1IOdjDZibRthIHjqY98eaH5kLCE,5424
|
|
54
53
|
dodal/devices/qbpm1.py,sha256=OY7-WbdxMiLGUK8Z57ezwqSXbHxoPP-y3GvBgj9kgMA,220
|
|
55
|
-
dodal/devices/robot.py,sha256=
|
|
54
|
+
dodal/devices/robot.py,sha256=V5Gk-e1ZczU7y8SqU4_1YXYQJ6knoVFtXLZmIDY9MI4,2530
|
|
56
55
|
dodal/devices/s4_slit_gaps.py,sha256=j3kgF9WfGFaU9xdUuiAh-QqI5u_vhiAftaDVINt91SM,243
|
|
57
56
|
dodal/devices/scatterguard.py,sha256=0qnvhoo3RjLsrxVgIoDJpryqunlgMVgaTsoyKRC2g4Y,331
|
|
58
57
|
dodal/devices/scintillator.py,sha256=4Dej1a6HRom9GRwTDsaTKGfvloP20POUqIeHqsI8-R8,184
|
|
@@ -61,6 +60,7 @@ dodal/devices/smargon.py,sha256=ml96h7E1C31qPo8jocAepSouIVXgpIR0vuMF99nZjqM,2964
|
|
|
61
60
|
dodal/devices/status.py,sha256=TuUGidZ4Ar-WCRc_sX0wn58DmL6brj1pMr8rNF5Z6VU,1198
|
|
62
61
|
dodal/devices/synchrotron.py,sha256=E5vcSum-zoD5vIZxa2Xcl0gAkeRqY6a-AfZQICCwLHg,1947
|
|
63
62
|
dodal/devices/tetramm.py,sha256=dHA15KkJhBHwtmbivDua_aVqFbvK47TVQG7KXmn8jQ8,8041
|
|
63
|
+
dodal/devices/thawer.py,sha256=L5OYSdzGvx6dIkGgcTbITAbFAm0OKEVVqYBb4MPstOg,382
|
|
64
64
|
dodal/devices/turbo_slit.py,sha256=W3ZRIqDhq4iMhr5GcIiWvl2U1GaPtGanqkL7upQOZTY,1132
|
|
65
65
|
dodal/devices/undulator.py,sha256=kn84MQpuBHtQj7H7HeBoAYKXu5buGKvTgs3tf2gdEdw,2074
|
|
66
66
|
dodal/devices/undulator_dcm.py,sha256=TC9fO55r1YIG_88PPbGGtzfjcRJcaoC2ny51JiDOEX4,5199
|
|
@@ -113,9 +113,10 @@ dodal/devices/zocalo/zocalo_interaction.py,sha256=B6TBTDwUlluksLTwC4TiEEgfFzWLOm
|
|
|
113
113
|
dodal/devices/zocalo/zocalo_results.py,sha256=U4Vk4OF-eL8w0BR-fbw3k4jyRo6G3Ywaf8NMAkjr4Hs,9658
|
|
114
114
|
dodal/parameters/experiment_parameter_base.py,sha256=O7JamfuJ5cYHkPf9tsHJPqn-OMHTAGouigvM1cDFehE,313
|
|
115
115
|
dodal/plans/check_topup.py,sha256=VOkHak88_r-pdTsSnwAJnbvlK2_UhKnO5I36pJmWKvQ,2985
|
|
116
|
-
|
|
117
|
-
dls_dodal-1.
|
|
118
|
-
dls_dodal-1.
|
|
119
|
-
dls_dodal-1.
|
|
120
|
-
dls_dodal-1.
|
|
121
|
-
dls_dodal-1.
|
|
116
|
+
dodal/plans/data_session_metadata.py,sha256=QNx9rb1EfGBHb21eFekIi7KjNhC0PL-SVKBCggDuNeg,1650
|
|
117
|
+
dls_dodal-1.27.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
118
|
+
dls_dodal-1.27.0.dist-info/METADATA,sha256=mkrOjI4F9mwAZOTOLTSPRfNZu5W1wqlqDo3FOOWn6qs,16837
|
|
119
|
+
dls_dodal-1.27.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
120
|
+
dls_dodal-1.27.0.dist-info/entry_points.txt,sha256=wpzz9FsTiYxI8OBwLKX9V9ResLwThBSmtRMcPwII0FA,46
|
|
121
|
+
dls_dodal-1.27.0.dist-info/top_level.txt,sha256=xIozdmZk_wmMV4wugpq9-6eZs0vgADNUKz3j2UAwlhc,6
|
|
122
|
+
dls_dodal-1.27.0.dist-info/RECORD,,
|
dodal/_version.py
CHANGED
dodal/beamlines/i03.py
CHANGED
|
@@ -14,17 +14,17 @@ from dodal.devices.dcm import DCM
|
|
|
14
14
|
from dodal.devices.detector import DetectorParams
|
|
15
15
|
from dodal.devices.detector.detector_motion import DetectorMotion
|
|
16
16
|
from dodal.devices.eiger import EigerDetector
|
|
17
|
-
from dodal.devices.fast_grid_scan import
|
|
17
|
+
from dodal.devices.fast_grid_scan import PandAFastGridScan, ZebraFastGridScan
|
|
18
18
|
from dodal.devices.flux import Flux
|
|
19
19
|
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, VFMMirrorVoltages
|
|
20
20
|
from dodal.devices.oav.oav_detector import OAV, OAVConfigParams
|
|
21
21
|
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
22
|
-
from dodal.devices.panda_fast_grid_scan import PandAFastGridScan
|
|
23
22
|
from dodal.devices.qbpm1 import QBPM1
|
|
24
23
|
from dodal.devices.robot import BartRobot
|
|
25
24
|
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
26
25
|
from dodal.devices.smargon import Smargon
|
|
27
26
|
from dodal.devices.synchrotron import Synchrotron
|
|
27
|
+
from dodal.devices.thawer import Thawer
|
|
28
28
|
from dodal.devices.undulator import Undulator
|
|
29
29
|
from dodal.devices.undulator_dcm import UndulatorDCM
|
|
30
30
|
from dodal.devices.webcam import Webcam
|
|
@@ -199,16 +199,16 @@ def eiger(
|
|
|
199
199
|
)
|
|
200
200
|
|
|
201
201
|
|
|
202
|
-
def
|
|
202
|
+
def zebra_fast_grid_scan(
|
|
203
203
|
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
204
|
-
) ->
|
|
205
|
-
"""Get the i03
|
|
204
|
+
) -> ZebraFastGridScan:
|
|
205
|
+
"""Get the i03 zebra_fast_grid_scan device, instantiate it if it hasn't already been.
|
|
206
206
|
If this is called when already instantiated in i03, it will return the existing object.
|
|
207
207
|
"""
|
|
208
208
|
return device_instantiation(
|
|
209
|
-
device_factory=
|
|
210
|
-
name="
|
|
211
|
-
prefix="-MO-SGON-01:",
|
|
209
|
+
device_factory=ZebraFastGridScan,
|
|
210
|
+
name="zebra_fast_grid_scan",
|
|
211
|
+
prefix="-MO-SGON-01:FGS:",
|
|
212
212
|
wait=wait_for_connection,
|
|
213
213
|
fake=fake_with_ophyd_sim,
|
|
214
214
|
)
|
|
@@ -219,7 +219,7 @@ def panda_fast_grid_scan(
|
|
|
219
219
|
) -> PandAFastGridScan:
|
|
220
220
|
"""Get the i03 panda_fast_grid_scan device, instantiate it if it hasn't already been.
|
|
221
221
|
If this is called when already instantiated in i03, it will return the existing object.
|
|
222
|
-
This is used instead of the
|
|
222
|
+
This is used instead of the zebra_fast_grid_scan device when using the PandA.
|
|
223
223
|
"""
|
|
224
224
|
return device_instantiation(
|
|
225
225
|
device_factory=PandAFastGridScan,
|
|
@@ -480,3 +480,18 @@ def webcam(
|
|
|
480
480
|
fake_with_ophyd_sim,
|
|
481
481
|
url="http://i03-webcam1/axis-cgi/jpg/image.cgi",
|
|
482
482
|
)
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def thawer(
|
|
486
|
+
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
487
|
+
) -> Thawer:
|
|
488
|
+
"""Get the i03 thawer, instantiate it if it hasn't already been.
|
|
489
|
+
If this is called when already instantiated in i03, it will return the existing object.
|
|
490
|
+
"""
|
|
491
|
+
return device_instantiation(
|
|
492
|
+
Thawer,
|
|
493
|
+
"thawer",
|
|
494
|
+
"-EA-THAW-01",
|
|
495
|
+
wait_for_connection,
|
|
496
|
+
fake_with_ophyd_sim,
|
|
497
|
+
)
|
dodal/beamlines/i04.py
CHANGED
|
@@ -8,15 +8,17 @@ from dodal.devices.dcm import DCM
|
|
|
8
8
|
from dodal.devices.detector import DetectorParams
|
|
9
9
|
from dodal.devices.detector.detector_motion import DetectorMotion
|
|
10
10
|
from dodal.devices.eiger import EigerDetector
|
|
11
|
-
from dodal.devices.fast_grid_scan import
|
|
11
|
+
from dodal.devices.fast_grid_scan import ZebraFastGridScan
|
|
12
12
|
from dodal.devices.flux import Flux
|
|
13
13
|
from dodal.devices.i04.transfocator import Transfocator
|
|
14
14
|
from dodal.devices.ipin import IPin
|
|
15
15
|
from dodal.devices.motors import XYZPositioner
|
|
16
16
|
from dodal.devices.oav.oav_detector import OAV, OAVConfigParams
|
|
17
|
+
from dodal.devices.robot import BartRobot
|
|
17
18
|
from dodal.devices.s4_slit_gaps import S4SlitGaps
|
|
18
19
|
from dodal.devices.smargon import Smargon
|
|
19
20
|
from dodal.devices.synchrotron import Synchrotron
|
|
21
|
+
from dodal.devices.thawer import Thawer
|
|
20
22
|
from dodal.devices.undulator import Undulator
|
|
21
23
|
from dodal.devices.xbpm_feedback import XBPMFeedbackI04
|
|
22
24
|
from dodal.devices.zebra import Zebra
|
|
@@ -258,15 +260,15 @@ def eiger(
|
|
|
258
260
|
)
|
|
259
261
|
|
|
260
262
|
|
|
261
|
-
def
|
|
263
|
+
def zebra_fast_grid_scan(
|
|
262
264
|
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
263
|
-
) ->
|
|
264
|
-
"""Get the i04
|
|
265
|
+
) -> ZebraFastGridScan:
|
|
266
|
+
"""Get the i04 zebra_fast_grid_scan device, instantiate it if it hasn't already been.
|
|
265
267
|
If this is called when already instantiated in i04, it will return the existing object.
|
|
266
268
|
"""
|
|
267
269
|
return device_instantiation(
|
|
268
|
-
device_factory=
|
|
269
|
-
name="
|
|
270
|
+
device_factory=ZebraFastGridScan,
|
|
271
|
+
name="zebra_fast_grid_scan",
|
|
270
272
|
prefix="-MO-SGON-01:",
|
|
271
273
|
wait=wait_for_connection,
|
|
272
274
|
fake=fake_with_ophyd_sim,
|
|
@@ -363,3 +365,33 @@ def detector_motion(
|
|
|
363
365
|
wait=wait_for_connection,
|
|
364
366
|
fake=fake_with_ophyd_sim,
|
|
365
367
|
)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def thawer(
|
|
371
|
+
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
372
|
+
) -> Thawer:
|
|
373
|
+
"""Get the i04 thawer, instantiate it if it hasn't already been.
|
|
374
|
+
If this is called when already instantiated in i04, it will return the existing object.
|
|
375
|
+
"""
|
|
376
|
+
return device_instantiation(
|
|
377
|
+
Thawer,
|
|
378
|
+
"thawer",
|
|
379
|
+
"-EA-THAW-01",
|
|
380
|
+
wait_for_connection,
|
|
381
|
+
fake_with_ophyd_sim,
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def robot(
|
|
386
|
+
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
387
|
+
) -> BartRobot:
|
|
388
|
+
"""Get the i04 robot device, instantiate it if it hasn't already been.
|
|
389
|
+
If this is called when already instantiated in i04, it will return the existing object.
|
|
390
|
+
"""
|
|
391
|
+
return device_instantiation(
|
|
392
|
+
BartRobot,
|
|
393
|
+
"robot",
|
|
394
|
+
"-MO-ROBOT-01:",
|
|
395
|
+
wait_for_connection,
|
|
396
|
+
fake_with_ophyd_sim,
|
|
397
|
+
)
|
dodal/beamlines/i24.py
CHANGED
|
@@ -11,7 +11,9 @@ from dodal.devices.zebra import Zebra
|
|
|
11
11
|
from dodal.log import set_beamline as set_log_beamline
|
|
12
12
|
from dodal.utils import get_beamline_name, skip_device
|
|
13
13
|
|
|
14
|
-
ZOOM_PARAMS_FILE =
|
|
14
|
+
ZOOM_PARAMS_FILE = (
|
|
15
|
+
"/dls_sw/i24/software/gda_versions/gda_9_34/config/xml/jCameraManZoomLevels.xml"
|
|
16
|
+
)
|
|
15
17
|
DISPLAY_CONFIG = "/dls_sw/i24/software/gda_versions/var/display.configuration"
|
|
16
18
|
|
|
17
19
|
BL = get_beamline_name("s24")
|
dodal/common/coordination.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import uuid
|
|
2
|
+
from typing import Any
|
|
2
3
|
|
|
3
4
|
from dodal.common.types import Group
|
|
4
5
|
|
|
@@ -16,19 +17,20 @@ def group_uuid(name: str) -> Group:
|
|
|
16
17
|
return f"{name}-{str(uuid.uuid4())[:6]}"
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
def inject(name: str): # type: ignore
|
|
20
|
+
def inject(name: str) -> Any: # type: ignore
|
|
20
21
|
"""
|
|
21
|
-
Function to mark a
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
e.g. For a 1-dimensional scan, that is usually performed on a
|
|
27
|
-
|
|
22
|
+
Function to mark a defaulted argument of a plan as a reference to a device stored
|
|
23
|
+
in another context and not available to be referenced directly.
|
|
24
|
+
Bypasses type checking, returning x as Any and therefore valid as a default
|
|
25
|
+
argument, leaving handling to the context from which the plan is called.
|
|
26
|
+
Assumes that device.name is unique.
|
|
27
|
+
e.g. For a 1-dimensional scan, that is usually performed on a Movable with
|
|
28
|
+
name "stage_x"
|
|
29
|
+
|
|
28
30
|
def scan(x: Movable = inject("stage_x"), start: float = 0.0 ...)
|
|
29
31
|
|
|
30
32
|
Args:
|
|
31
|
-
name (str): Name of a
|
|
33
|
+
name (str): Name of a Device to be fetched from an external context
|
|
32
34
|
|
|
33
35
|
Returns:
|
|
34
36
|
Any: name but without typing checking, valid as any default type
|
dodal/common/visit.py
CHANGED
|
@@ -3,14 +3,10 @@ from pathlib import Path
|
|
|
3
3
|
from typing import Optional
|
|
4
4
|
|
|
5
5
|
from aiohttp import ClientSession
|
|
6
|
-
from bluesky import plan_stubs as bps
|
|
7
|
-
from bluesky import preprocessors as bpp
|
|
8
|
-
from bluesky.utils import make_decorator
|
|
9
6
|
from ophyd_async.core import DirectoryInfo
|
|
10
7
|
from pydantic import BaseModel
|
|
11
8
|
|
|
12
|
-
from dodal.common.
|
|
13
|
-
from dodal.common.types import MsgGenerator, UpdatingDirectoryProvider
|
|
9
|
+
from dodal.common.types import UpdatingDirectoryProvider
|
|
14
10
|
from dodal.log import LOGGER
|
|
15
11
|
|
|
16
12
|
"""
|
|
@@ -156,41 +152,3 @@ class StaticVisitDirectoryProvider(UpdatingDirectoryProvider):
|
|
|
156
152
|
raise ValueError(
|
|
157
153
|
"No current collection, update() needs to be called at least once"
|
|
158
154
|
)
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
DATA_SESSION = "data_session"
|
|
162
|
-
DATA_GROUPS = "data_groups"
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
def attach_metadata(
|
|
166
|
-
plan: MsgGenerator, provider: UpdatingDirectoryProvider | None
|
|
167
|
-
) -> MsgGenerator:
|
|
168
|
-
"""
|
|
169
|
-
Attach data session metadata to the runs within a plan and make it correlate
|
|
170
|
-
with an ophyd-async DirectoryProvider.
|
|
171
|
-
|
|
172
|
-
This updates the directory provider (which in turn makes a call to to a service
|
|
173
|
-
to figure out which scan number we are using for such a scan), and ensures the
|
|
174
|
-
start document contains the correct data session.
|
|
175
|
-
|
|
176
|
-
Args:
|
|
177
|
-
plan: The plan to preprocess
|
|
178
|
-
provider: The directory provider that participating detectors are aware of.
|
|
179
|
-
|
|
180
|
-
Returns:
|
|
181
|
-
MsgGenerator: A plan
|
|
182
|
-
|
|
183
|
-
Yields:
|
|
184
|
-
Iterator[Msg]: Plan messages
|
|
185
|
-
"""
|
|
186
|
-
if provider is None:
|
|
187
|
-
provider = beamline_utils.get_directory_provider()
|
|
188
|
-
yield from bps.wait_for([provider.update])
|
|
189
|
-
directory_info: DirectoryInfo = provider()
|
|
190
|
-
# https://github.com/DiamondLightSource/dodal/issues/452
|
|
191
|
-
# As part of 452, write each dataCollection into their own folder, then can use resource_dir directly
|
|
192
|
-
data_session = directory_info.prefix.removesuffix("-")
|
|
193
|
-
yield from bpp.inject_md_wrapper(plan, md={DATA_SESSION: data_session})
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
attach_metadata_decorator = make_decorator(attach_metadata)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from collections import OrderedDict, namedtuple
|
|
3
3
|
from dataclasses import asdict, dataclass
|
|
4
|
+
from enum import Enum
|
|
4
5
|
|
|
5
6
|
from bluesky.protocols import Movable, Reading
|
|
6
7
|
from ophyd_async.core import AsyncStatus, SignalR, StandardReadable
|
|
@@ -48,8 +49,22 @@ class SingleAperturePosition:
|
|
|
48
49
|
)
|
|
49
50
|
|
|
50
51
|
|
|
52
|
+
# Use StrEnum once we stop python 3.10 support
|
|
53
|
+
class AperturePositionGDANames(str, Enum):
|
|
54
|
+
LARGE_APERTURE = "LARGE_APERTURE"
|
|
55
|
+
MEDIUM_APERTURE = "MEDIUM_APERTURE"
|
|
56
|
+
SMALL_APERTURE = "SMALL_APERTURE"
|
|
57
|
+
ROBOT_LOAD = "ROBOT_LOAD"
|
|
58
|
+
|
|
59
|
+
def __str__(self):
|
|
60
|
+
return str(self.value)
|
|
61
|
+
|
|
62
|
+
|
|
51
63
|
def position_from_params(
|
|
52
|
-
name: str,
|
|
64
|
+
name: str,
|
|
65
|
+
GDA_name: AperturePositionGDANames,
|
|
66
|
+
radius_microns: float | None,
|
|
67
|
+
params: dict,
|
|
53
68
|
) -> SingleAperturePosition:
|
|
54
69
|
return SingleAperturePosition(
|
|
55
70
|
name,
|
|
@@ -77,7 +92,8 @@ def tolerances_from_params(params: dict) -> ApertureScatterguardTolerances:
|
|
|
77
92
|
|
|
78
93
|
@dataclass
|
|
79
94
|
class AperturePositions:
|
|
80
|
-
"""Holds the motor positions needed to select a particular aperture size.
|
|
95
|
+
"""Holds the motor positions needed to select a particular aperture size. This class should be instantiated with definitions for its sizes
|
|
96
|
+
using from_gda_beamline_params"""
|
|
81
97
|
|
|
82
98
|
LARGE: SingleAperturePosition
|
|
83
99
|
MEDIUM: SingleAperturePosition
|
|
@@ -93,13 +109,32 @@ class AperturePositions:
|
|
|
93
109
|
@classmethod
|
|
94
110
|
def from_gda_beamline_params(cls, params):
|
|
95
111
|
return cls(
|
|
96
|
-
LARGE=position_from_params(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
112
|
+
LARGE=position_from_params(
|
|
113
|
+
"Large", AperturePositionGDANames.LARGE_APERTURE, 100, params
|
|
114
|
+
),
|
|
115
|
+
MEDIUM=position_from_params(
|
|
116
|
+
"Medium", AperturePositionGDANames.MEDIUM_APERTURE, 50, params
|
|
117
|
+
),
|
|
118
|
+
SMALL=position_from_params(
|
|
119
|
+
"Small", AperturePositionGDANames.SMALL_APERTURE, 20, params
|
|
120
|
+
),
|
|
121
|
+
ROBOT_LOAD=position_from_params(
|
|
122
|
+
"Robot load", AperturePositionGDANames.ROBOT_LOAD, None, params
|
|
123
|
+
),
|
|
100
124
|
tolerances=tolerances_from_params(params),
|
|
101
125
|
)
|
|
102
126
|
|
|
127
|
+
def get_position_from_gda_aperture_name(
|
|
128
|
+
self, gda_aperture_name: AperturePositionGDANames
|
|
129
|
+
) -> SingleAperturePosition:
|
|
130
|
+
apertures = [ap for ap in self.as_list() if ap.GDA_name == gda_aperture_name]
|
|
131
|
+
if not apertures:
|
|
132
|
+
raise ValueError(
|
|
133
|
+
f"Tried to convert unknown aperture name {gda_aperture_name} to a SingleAperturePosition"
|
|
134
|
+
)
|
|
135
|
+
else:
|
|
136
|
+
return apertures[0]
|
|
137
|
+
|
|
103
138
|
def as_list(self) -> list[SingleAperturePosition]:
|
|
104
139
|
return [
|
|
105
140
|
self.LARGE,
|
dodal/devices/backlight.py
CHANGED
|
@@ -1,20 +1,36 @@
|
|
|
1
|
-
from
|
|
1
|
+
from enum import Enum
|
|
2
2
|
|
|
3
|
+
from ophyd_async.core import AsyncStatus, StandardReadable
|
|
4
|
+
from ophyd_async.epics.signal import epics_signal_rw
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BacklightPower(str, Enum):
|
|
8
|
+
ON = "On"
|
|
9
|
+
OFF = "Off"
|
|
3
10
|
|
|
4
|
-
class Backlight(Device):
|
|
5
|
-
"""Simple device to trigger the pneumatic in/out."""
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
IN =
|
|
12
|
+
class BacklightPosition(str, Enum):
|
|
13
|
+
IN = "In"
|
|
14
|
+
OUT = "Out"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Backlight(StandardReadable):
|
|
18
|
+
"""Simple device to trigger the pneumatic in/out."""
|
|
9
19
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
20
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
21
|
+
with self.add_children_as_readables():
|
|
22
|
+
self.power = epics_signal_rw(BacklightPower, prefix + "-EA-BLIT-01:TOGGLE")
|
|
23
|
+
self.position = epics_signal_rw(
|
|
24
|
+
BacklightPosition, prefix + "-EA-BL-01:CTRL"
|
|
25
|
+
)
|
|
26
|
+
super().__init__(name)
|
|
13
27
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
28
|
+
@AsyncStatus.wrap
|
|
29
|
+
async def set(self, position: BacklightPosition):
|
|
30
|
+
"""This setter will turn the backlight on when we move it in to the beam and off
|
|
31
|
+
when we move it out."""
|
|
32
|
+
await self.position.set(position)
|
|
33
|
+
if position == BacklightPosition.OUT:
|
|
34
|
+
await self.power.set(BacklightPower.OFF)
|
|
18
35
|
else:
|
|
19
|
-
|
|
20
|
-
return status
|
|
36
|
+
await self.power.set(BacklightPower.ON)
|
dodal/devices/fast_grid_scan.py
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
from typing import Any
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from typing import Any, Generic, TypeVar
|
|
4
3
|
|
|
5
4
|
import numpy as np
|
|
6
5
|
from bluesky.plan_stubs import mv
|
|
7
6
|
from numpy import ndarray
|
|
8
|
-
from
|
|
9
|
-
|
|
7
|
+
from ophyd_async.core import (
|
|
8
|
+
AsyncStatus,
|
|
10
9
|
Device,
|
|
11
|
-
EpicsSignal,
|
|
12
|
-
EpicsSignalRO,
|
|
13
|
-
EpicsSignalWithRBV,
|
|
14
10
|
Signal,
|
|
11
|
+
SignalR,
|
|
12
|
+
SoftSignalBackend,
|
|
13
|
+
StandardReadable,
|
|
14
|
+
wait_for_value,
|
|
15
15
|
)
|
|
16
|
-
from
|
|
16
|
+
from ophyd_async.epics.signal import (
|
|
17
|
+
epics_signal_r,
|
|
18
|
+
epics_signal_rw,
|
|
19
|
+
)
|
|
20
|
+
from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
|
|
17
21
|
from pydantic import validator
|
|
18
22
|
from pydantic.dataclasses import dataclass
|
|
19
23
|
|
|
20
24
|
from dodal.devices.motors import XYZLimitBundle
|
|
21
|
-
from dodal.devices.status import await_value
|
|
22
25
|
from dodal.log import LOGGER
|
|
23
26
|
from dodal.parameters.experiment_parameter_base import AbstractExperimentWithBeamParams
|
|
24
27
|
|
|
@@ -50,9 +53,6 @@ class GridScanParamsCommon(AbstractExperimentWithBeamParams):
|
|
|
50
53
|
layout to EPICS. The parameters and functions of this class are common
|
|
51
54
|
to both the zebra and panda triggered fast grid scans.
|
|
52
55
|
|
|
53
|
-
Motion program will do a grid in x-y then rotate omega +90 and perform
|
|
54
|
-
a grid in x-z.
|
|
55
|
-
|
|
56
56
|
The grid specified is where data is taken e.g. it can be assumed the first frame is
|
|
57
57
|
at x_start, y1_start, z1_start and subsequent frames are N*step_size away.
|
|
58
58
|
"""
|
|
@@ -75,6 +75,21 @@ class GridScanParamsCommon(AbstractExperimentWithBeamParams):
|
|
|
75
75
|
# Whether to set the stub offsets after centering
|
|
76
76
|
set_stub_offsets: bool = False
|
|
77
77
|
|
|
78
|
+
def get_param_positions(self) -> dict:
|
|
79
|
+
return {
|
|
80
|
+
"x_steps": self.x_steps,
|
|
81
|
+
"y_steps": self.y_steps,
|
|
82
|
+
"z_steps": self.z_steps,
|
|
83
|
+
"x_step_size": self.x_step_size,
|
|
84
|
+
"y_step_size": self.y_step_size,
|
|
85
|
+
"z_step_size": self.z_step_size,
|
|
86
|
+
"x_start": self.x_start,
|
|
87
|
+
"y1_start": self.y1_start,
|
|
88
|
+
"y2_start": self.y2_start,
|
|
89
|
+
"z1_start": self.z1_start,
|
|
90
|
+
"z2_start": self.z2_start,
|
|
91
|
+
}
|
|
92
|
+
|
|
78
93
|
class Config:
|
|
79
94
|
arbitrary_types_allowed = True
|
|
80
95
|
fields = {
|
|
@@ -153,21 +168,21 @@ class GridScanParamsCommon(AbstractExperimentWithBeamParams):
|
|
|
153
168
|
)
|
|
154
169
|
|
|
155
170
|
|
|
156
|
-
|
|
157
|
-
"""
|
|
158
|
-
Holder class for the parameters of a grid scan in a similar
|
|
159
|
-
layout to EPICS. These params are used for the zebra-triggered
|
|
160
|
-
fast grid scan
|
|
171
|
+
ParamType = TypeVar("ParamType", bound=GridScanParamsCommon)
|
|
161
172
|
|
|
162
|
-
Motion program will do a grid in x-y then rotate omega +90 and perform
|
|
163
|
-
a grid in x-z.
|
|
164
173
|
|
|
165
|
-
|
|
166
|
-
|
|
174
|
+
class ZebraGridScanParams(GridScanParamsCommon):
|
|
175
|
+
"""
|
|
176
|
+
Params for standard Zebra FGS. Adds on the dwell time
|
|
167
177
|
"""
|
|
168
178
|
|
|
169
179
|
dwell_time_ms: float = 10
|
|
170
180
|
|
|
181
|
+
def get_param_positions(self):
|
|
182
|
+
param_positions = super().get_param_positions()
|
|
183
|
+
param_positions["dwell_time_ms"] = self.dwell_time_ms
|
|
184
|
+
return param_positions
|
|
185
|
+
|
|
171
186
|
@validator("dwell_time_ms", always=True, check_fields=True)
|
|
172
187
|
def non_integer_dwell_time(cls, dwell_time_ms: float) -> float:
|
|
173
188
|
dwell_time_floor_rounded = np.floor(dwell_time_ms)
|
|
@@ -181,181 +196,159 @@ class GridScanParams(GridScanParamsCommon):
|
|
|
181
196
|
return dwell_time_ms
|
|
182
197
|
|
|
183
198
|
|
|
184
|
-
class
|
|
199
|
+
class PandAGridScanParams(GridScanParamsCommon):
|
|
200
|
+
"""
|
|
201
|
+
Params for panda constant-motion scan. Adds on the goniometer run-up distance
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
run_up_distance_mm: float = 0.17
|
|
205
|
+
|
|
206
|
+
def get_param_positions(self):
|
|
207
|
+
param_positions = super().get_param_positions()
|
|
208
|
+
param_positions["run_up_distance_mm"] = self.run_up_distance_mm
|
|
209
|
+
return param_positions
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class MotionProgram(Device):
|
|
213
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
214
|
+
super().__init__(name)
|
|
215
|
+
self.running = epics_signal_r(float, prefix + "PROGBITS")
|
|
216
|
+
self.program_number = epics_signal_r(float, prefix + "CS1:PROG_NUM")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class ExpectedImages(SignalR[int]):
|
|
220
|
+
def __init__(self, parent: "FastGridScanCommon") -> None:
|
|
221
|
+
super().__init__(SoftSignalBackend(int))
|
|
222
|
+
self.parent: "FastGridScanCommon" = parent
|
|
223
|
+
|
|
224
|
+
async def get_value(self):
|
|
225
|
+
x = await self.parent.x_steps.get_value()
|
|
226
|
+
y = await self.parent.y_steps.get_value()
|
|
227
|
+
z = await self.parent.z_steps.get_value()
|
|
228
|
+
first_grid = x * y
|
|
229
|
+
second_grid = x * z
|
|
230
|
+
return first_grid + second_grid
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class FastGridScanCommon(StandardReadable, ABC, Generic[ParamType]):
|
|
234
|
+
"""Device for a general fast grid scan
|
|
235
|
+
|
|
236
|
+
When the motion program is started, the goniometer will move in a snake-like grid trajectory,
|
|
237
|
+
with X as the fast axis and Y as the slow axis. If Z steps isn't 0, the goniometer will
|
|
238
|
+
then rotate in the omega direction such that it moves from the X-Y, to the X-Z plane then
|
|
239
|
+
do a second grid scan. The detector is triggered after every x step.
|
|
240
|
+
See https://github.com/DiamondLightSource/hyperion/wiki/Coordinate-Systems for more
|
|
185
241
|
"""
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
242
|
+
|
|
243
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
244
|
+
super().__init__(name)
|
|
245
|
+
self.x_steps = epics_signal_rw_rbv(int, "X_NUM_STEPS")
|
|
246
|
+
self.y_steps = epics_signal_rw_rbv(
|
|
247
|
+
int, "X_NUM_STEPS"
|
|
248
|
+
) # Number of vertical steps during the first grid scan
|
|
249
|
+
self.z_steps = epics_signal_rw_rbv(
|
|
250
|
+
int, "X_NUM_STEPS"
|
|
251
|
+
) # Number of vertical steps during the second grid scan, after the rotation in omega
|
|
252
|
+
self.x_step_size = epics_signal_rw_rbv(float, "X_STEP_SIZE")
|
|
253
|
+
self.y_step_size = epics_signal_rw_rbv(float, "Y_STEP_SIZE")
|
|
254
|
+
self.z_step_size = epics_signal_rw_rbv(float, "Z_STEP_SIZE")
|
|
255
|
+
self.x_start = epics_signal_rw_rbv(float, "X_START")
|
|
256
|
+
self.y1_start = epics_signal_rw_rbv(float, "Y_START")
|
|
257
|
+
self.y2_start = epics_signal_rw_rbv(float, "Y2_START")
|
|
258
|
+
self.z1_start = epics_signal_rw_rbv(float, "Z_START")
|
|
259
|
+
self.z2_start = epics_signal_rw_rbv(float, "Z2_START")
|
|
260
|
+
|
|
261
|
+
self.position_counter = epics_signal_rw(
|
|
262
|
+
int, "POS_COUNTER", write_pv="POS_COUNTER_WRITE"
|
|
263
|
+
)
|
|
264
|
+
self.x_counter = epics_signal_r(int, "X_COUNTER")
|
|
265
|
+
self.y_counter = epics_signal_r(int, "Y_COUNTER")
|
|
266
|
+
self.scan_invalid = epics_signal_r(float, "SCAN_INVALID")
|
|
267
|
+
|
|
268
|
+
self.run_cmd = epics_signal_rw(int, "RUN.PROC")
|
|
269
|
+
self.stop_cmd = epics_signal_rw(int, "STOP.PROC")
|
|
270
|
+
self.status = epics_signal_r(float, "SCAN_STATUS")
|
|
271
|
+
|
|
272
|
+
self.expected_images = ExpectedImages(parent=self)
|
|
273
|
+
|
|
274
|
+
self.motion_program = MotionProgram(prefix)
|
|
275
|
+
|
|
276
|
+
# Kickoff timeout in seconds
|
|
277
|
+
self.KICKOFF_TIMEOUT: float = 5.0
|
|
278
|
+
|
|
279
|
+
self.COMPLETE_STATUS: float = 60.0
|
|
280
|
+
|
|
281
|
+
self.movable_params: dict[str, Signal] = {
|
|
282
|
+
"x_steps": self.x_steps,
|
|
283
|
+
"y_steps": self.y_steps,
|
|
284
|
+
"z_steps": self.z_steps,
|
|
285
|
+
"x_step_size": self.x_step_size,
|
|
286
|
+
"y_step_size": self.y_step_size,
|
|
287
|
+
"z_step_size": self.z_step_size,
|
|
288
|
+
"x_start": self.x_start,
|
|
289
|
+
"y1_start": self.y1_start,
|
|
290
|
+
"y2_start": self.y2_start,
|
|
291
|
+
"z1_start": self.z1_start,
|
|
292
|
+
"z2_start": self.z2_start,
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
@AsyncStatus.wrap
|
|
296
|
+
async def kickoff(self):
|
|
297
|
+
curr_prog = await self.motion_program.program_number.get_value()
|
|
298
|
+
running = await self.motion_program.running.get_value()
|
|
299
|
+
if running:
|
|
300
|
+
LOGGER.info(f"Motion program {curr_prog} still running, waiting...")
|
|
301
|
+
await wait_for_value(self.motion_program.running, 0, self.KICKOFF_TIMEOUT)
|
|
302
|
+
|
|
303
|
+
LOGGER.debug("Running scan")
|
|
304
|
+
await self.run_cmd.set(1)
|
|
305
|
+
LOGGER.info("Waiting for FGS to start")
|
|
306
|
+
await wait_for_value(self.status, 1, self.KICKOFF_TIMEOUT)
|
|
307
|
+
LOGGER.debug("FGS kicked off")
|
|
308
|
+
|
|
309
|
+
@AsyncStatus.wrap
|
|
310
|
+
async def complete(self):
|
|
311
|
+
await wait_for_value(self.status, 0, self.COMPLETE_STATUS)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
class ZebraFastGridScan(FastGridScanCommon[ZebraGridScanParams]):
|
|
315
|
+
"""Device for standard Zebra FGS. In this scan, the goniometer's velocity profile follows a parabolic shape between X steps,
|
|
316
|
+
with the slowest points occuring at each X step.
|
|
189
317
|
"""
|
|
190
318
|
|
|
191
|
-
def __init__(self,
|
|
192
|
-
super().__init__(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
self.
|
|
196
|
-
self.
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
except ZeroDivisionError:
|
|
208
|
-
fraction = 0
|
|
209
|
-
time_remaining = 0
|
|
210
|
-
except Exception as e:
|
|
211
|
-
fraction = None
|
|
212
|
-
time_remaining = None
|
|
213
|
-
self.set_exception(e)
|
|
214
|
-
self.clean_up()
|
|
215
|
-
else:
|
|
216
|
-
time_remaining = time_elapsed / fraction
|
|
217
|
-
for watcher in self._watchers:
|
|
218
|
-
watcher(
|
|
219
|
-
name=self._name,
|
|
220
|
-
current=value,
|
|
221
|
-
initial=0,
|
|
222
|
-
target=self._target_count,
|
|
223
|
-
unit="images",
|
|
224
|
-
precision=0,
|
|
225
|
-
fraction=fraction,
|
|
226
|
-
time_elapsed=time_elapsed,
|
|
227
|
-
time_remaining=time_remaining,
|
|
319
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
320
|
+
super().__init__(prefix, name)
|
|
321
|
+
|
|
322
|
+
# Time taken to travel between X steps
|
|
323
|
+
self.dwell_time_ms = epics_signal_rw_rbv(float, "DWELL_TIME")
|
|
324
|
+
self.movable_params["dwell_time_ms"] = self.dwell_time_ms
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class PandAFastGridScan(FastGridScanCommon[PandAGridScanParams]):
|
|
328
|
+
"""Device for panda constant-motion scan"""
|
|
329
|
+
|
|
330
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
331
|
+
super().__init__(prefix, name)
|
|
332
|
+
self.time_between_x_steps_ms = (
|
|
333
|
+
epics_signal_rw_rbv( # Used by motion controller to set goniometer velocity
|
|
334
|
+
float, "TIME_BETWEEN_X_STEPS"
|
|
228
335
|
)
|
|
336
|
+
)
|
|
229
337
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
338
|
+
# Distance before and after the grid given to allow goniometer to reach desired speed while it is within the
|
|
339
|
+
# grid
|
|
340
|
+
self.run_up_distance_mm = epics_signal_rw_rbv(float, "RUNUP_DISTANCE")
|
|
341
|
+
self.movable_params["run_up_distance_mm"] = self.run_up_distance_mm
|
|
234
342
|
|
|
235
|
-
def clean_up(self):
|
|
236
|
-
self.device.position_counter.clear_sub(self._notify_watchers)
|
|
237
|
-
self.device.status.clear_sub(self._running_changed)
|
|
238
343
|
|
|
344
|
+
def set_fast_grid_scan_params(scan: FastGridScanCommon[ParamType], params: ParamType):
|
|
345
|
+
to_move = []
|
|
239
346
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
z_steps = Component(EpicsSignalWithRBV, "FGS:Z_NUM_STEPS")
|
|
249
|
-
|
|
250
|
-
x_step_size = Component(EpicsSignalWithRBV, "FGS:X_STEP_SIZE")
|
|
251
|
-
y_step_size = Component(EpicsSignalWithRBV, "FGS:Y_STEP_SIZE")
|
|
252
|
-
z_step_size = Component(EpicsSignalWithRBV, "FGS:Z_STEP_SIZE")
|
|
253
|
-
|
|
254
|
-
dwell_time_ms = Component(EpicsSignalWithRBV, "FGS:DWELL_TIME")
|
|
255
|
-
|
|
256
|
-
x_start = Component(EpicsSignalWithRBV, "FGS:X_START")
|
|
257
|
-
y1_start = Component(EpicsSignalWithRBV, "FGS:Y_START")
|
|
258
|
-
y2_start = Component(EpicsSignalWithRBV, "FGS:Y2_START")
|
|
259
|
-
z1_start = Component(EpicsSignalWithRBV, "FGS:Z_START")
|
|
260
|
-
z2_start = Component(EpicsSignalWithRBV, "FGS:Z2_START")
|
|
261
|
-
|
|
262
|
-
position_counter = Component(
|
|
263
|
-
EpicsSignal, "FGS:POS_COUNTER", write_pv="FGS:POS_COUNTER_WRITE"
|
|
264
|
-
)
|
|
265
|
-
x_counter = Component(EpicsSignalRO, "FGS:X_COUNTER")
|
|
266
|
-
y_counter = Component(EpicsSignalRO, "FGS:Y_COUNTER")
|
|
267
|
-
scan_invalid = Component(EpicsSignalRO, "FGS:SCAN_INVALID")
|
|
268
|
-
|
|
269
|
-
run_cmd = Component(EpicsSignal, "FGS:RUN.PROC")
|
|
270
|
-
stop_cmd = Component(EpicsSignal, "FGS:STOP.PROC")
|
|
271
|
-
status = Component(EpicsSignalRO, "FGS:SCAN_STATUS")
|
|
272
|
-
|
|
273
|
-
expected_images = Component(Signal)
|
|
274
|
-
|
|
275
|
-
motion_program = Component(MotionProgram, "")
|
|
276
|
-
|
|
277
|
-
# Kickoff timeout in seconds
|
|
278
|
-
KICKOFF_TIMEOUT: float = 5.0
|
|
279
|
-
|
|
280
|
-
def __init__(self, *args, **kwargs):
|
|
281
|
-
super().__init__(*args, **kwargs)
|
|
282
|
-
|
|
283
|
-
def set_expected_images(*_, **__):
|
|
284
|
-
x = int(self.x_steps.get())
|
|
285
|
-
y = int(self.y_steps.get())
|
|
286
|
-
z = int(self.z_steps.get())
|
|
287
|
-
first_grid = x * y
|
|
288
|
-
second_grid = x * z
|
|
289
|
-
self.expected_images.put(first_grid + second_grid)
|
|
290
|
-
|
|
291
|
-
self.x_steps.subscribe(set_expected_images)
|
|
292
|
-
self.y_steps.subscribe(set_expected_images)
|
|
293
|
-
self.z_steps.subscribe(set_expected_images)
|
|
294
|
-
|
|
295
|
-
def is_invalid(self) -> bool:
|
|
296
|
-
if "GONP" in self.scan_invalid.pvname:
|
|
297
|
-
return False
|
|
298
|
-
return bool(self.scan_invalid.get())
|
|
299
|
-
|
|
300
|
-
def kickoff(self) -> StatusBase:
|
|
301
|
-
st = DeviceStatus(device=self, timeout=self.KICKOFF_TIMEOUT)
|
|
302
|
-
|
|
303
|
-
def scan():
|
|
304
|
-
try:
|
|
305
|
-
curr_prog = self.motion_program.program_number.get()
|
|
306
|
-
running = self.motion_program.running.get()
|
|
307
|
-
if running:
|
|
308
|
-
LOGGER.info(f"Motion program {curr_prog} still running, waiting...")
|
|
309
|
-
await_value(self.motion_program.running, 0).wait()
|
|
310
|
-
LOGGER.debug("Running scan")
|
|
311
|
-
self.run_cmd.put(1)
|
|
312
|
-
LOGGER.info("Waiting for FGS to start")
|
|
313
|
-
await_value(self.status, 1).wait()
|
|
314
|
-
st.set_finished()
|
|
315
|
-
LOGGER.debug(f"{st} finished, exiting FGS kickoff thread")
|
|
316
|
-
except Exception as e:
|
|
317
|
-
st.set_exception(e)
|
|
318
|
-
|
|
319
|
-
threading.Thread(target=scan, daemon=True).start()
|
|
320
|
-
LOGGER.info("Returning FGS kickoff status")
|
|
321
|
-
return st
|
|
322
|
-
|
|
323
|
-
def complete(self) -> DeviceStatus:
|
|
324
|
-
return GridScanCompleteStatus(self)
|
|
325
|
-
|
|
326
|
-
def collect(self):
|
|
327
|
-
return {}
|
|
328
|
-
|
|
329
|
-
def describe_collect(self):
|
|
330
|
-
return {}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
def set_fast_grid_scan_params(scan: FastGridScan, params: GridScanParams):
|
|
334
|
-
yield from mv(
|
|
335
|
-
scan.x_steps,
|
|
336
|
-
params.x_steps,
|
|
337
|
-
scan.y_steps,
|
|
338
|
-
params.y_steps,
|
|
339
|
-
scan.z_steps,
|
|
340
|
-
params.z_steps,
|
|
341
|
-
scan.x_step_size,
|
|
342
|
-
params.x_step_size,
|
|
343
|
-
scan.y_step_size,
|
|
344
|
-
params.y_step_size,
|
|
345
|
-
scan.z_step_size,
|
|
346
|
-
params.z_step_size,
|
|
347
|
-
scan.dwell_time_ms,
|
|
348
|
-
params.dwell_time_ms,
|
|
349
|
-
scan.x_start,
|
|
350
|
-
params.x_start,
|
|
351
|
-
scan.y1_start,
|
|
352
|
-
params.y1_start,
|
|
353
|
-
scan.y2_start,
|
|
354
|
-
params.y2_start,
|
|
355
|
-
scan.z1_start,
|
|
356
|
-
params.z1_start,
|
|
357
|
-
scan.z2_start,
|
|
358
|
-
params.z2_start,
|
|
359
|
-
scan.position_counter,
|
|
360
|
-
0,
|
|
361
|
-
)
|
|
347
|
+
# Create arguments for bps.mv
|
|
348
|
+
for key in scan.movable_params.keys():
|
|
349
|
+
to_move.extend([scan.movable_params[key], params.__dict__[key]])
|
|
350
|
+
|
|
351
|
+
# Counter should always start at 0
|
|
352
|
+
to_move.extend([scan.position_counter, 0])
|
|
353
|
+
|
|
354
|
+
yield from mv(*to_move)
|
dodal/devices/robot.py
CHANGED
|
@@ -35,6 +35,8 @@ class BartRobot(StandardReadable, Movable):
|
|
|
35
35
|
self.gonio_pin_sensor = epics_signal_r(PinMounted, prefix + "PIN_MOUNTED")
|
|
36
36
|
self.next_pin = epics_signal_rw_rbv(float, prefix + "NEXT_PIN")
|
|
37
37
|
self.next_puck = epics_signal_rw_rbv(float, prefix + "NEXT_PUCK")
|
|
38
|
+
self.next_sample_id = epics_signal_rw_rbv(float, prefix + "NEXT_ID")
|
|
39
|
+
self.sample_id = epics_signal_r(float, prefix + "CURRENT_ID_RBV")
|
|
38
40
|
self.load = epics_signal_x(prefix + "LOAD.PROC")
|
|
39
41
|
self.program_running = epics_signal_r(bool, prefix + "PROGRAM_RUNNING")
|
|
40
42
|
self.program_name = epics_signal_r(str, prefix + "PROGRAM_NAME")
|
dodal/devices/thawer.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
from ophyd_async.core import StandardReadable
|
|
4
|
+
from ophyd_async.epics.signal import epics_signal_rw
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ThawerStates(str, Enum):
|
|
8
|
+
OFF = "Off"
|
|
9
|
+
ON = "On"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Thawer(StandardReadable):
|
|
13
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
14
|
+
self.control = epics_signal_rw(ThawerStates, prefix + ":CTRL")
|
|
15
|
+
super().__init__(name)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from bluesky import plan_stubs as bps
|
|
2
|
+
from bluesky import preprocessors as bpp
|
|
3
|
+
from bluesky.utils import make_decorator
|
|
4
|
+
from ophyd_async.core import DirectoryInfo
|
|
5
|
+
|
|
6
|
+
from dodal.common.beamlines import beamline_utils
|
|
7
|
+
from dodal.common.types import MsgGenerator, UpdatingDirectoryProvider
|
|
8
|
+
|
|
9
|
+
DATA_SESSION = "data_session"
|
|
10
|
+
DATA_GROUPS = "data_groups"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def attach_data_session_metadata_wrapper(
|
|
14
|
+
plan: MsgGenerator, provider: UpdatingDirectoryProvider | None = None
|
|
15
|
+
) -> MsgGenerator:
|
|
16
|
+
"""
|
|
17
|
+
Attach data session metadata to the runs within a plan and make it correlate
|
|
18
|
+
with an ophyd-async DirectoryProvider.
|
|
19
|
+
|
|
20
|
+
This updates the directory provider (which in turn makes a call to to a service
|
|
21
|
+
to figure out which scan number we are using for such a scan), and ensures the
|
|
22
|
+
start document contains the correct data session.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
plan: The plan to preprocess
|
|
26
|
+
provider: The directory provider that participating detectors are aware of.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
MsgGenerator: A plan
|
|
30
|
+
|
|
31
|
+
Yields:
|
|
32
|
+
Iterator[Msg]: Plan messages
|
|
33
|
+
"""
|
|
34
|
+
if provider is None:
|
|
35
|
+
provider = beamline_utils.get_directory_provider()
|
|
36
|
+
yield from bps.wait_for([provider.update])
|
|
37
|
+
directory_info: DirectoryInfo = provider()
|
|
38
|
+
# https://github.com/DiamondLightSource/dodal/issues/452
|
|
39
|
+
# As part of 452, write each dataCollection into their own folder, then can use resource_dir directly
|
|
40
|
+
data_session = directory_info.prefix.removesuffix("-")
|
|
41
|
+
yield from bpp.inject_md_wrapper(plan, md={DATA_SESSION: data_session})
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
attach_data_session_metadata_decorator = make_decorator(
|
|
45
|
+
attach_data_session_metadata_wrapper
|
|
46
|
+
)
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import threading
|
|
2
|
-
|
|
3
|
-
from bluesky.plan_stubs import mv
|
|
4
|
-
from ophyd import (
|
|
5
|
-
Component,
|
|
6
|
-
Device,
|
|
7
|
-
EpicsSignal,
|
|
8
|
-
EpicsSignalRO,
|
|
9
|
-
EpicsSignalWithRBV,
|
|
10
|
-
Signal,
|
|
11
|
-
)
|
|
12
|
-
from ophyd.status import DeviceStatus, StatusBase
|
|
13
|
-
|
|
14
|
-
from dodal.devices.fast_grid_scan import GridScanParamsCommon
|
|
15
|
-
from dodal.devices.status import await_value
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class GridScanCompleteStatus(DeviceStatus):
|
|
19
|
-
"""
|
|
20
|
-
A Status for the grid scan completion
|
|
21
|
-
Progress bar functionality has been removed for now in the panda fast grid scan
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
def __init__(self, *args, **kwargs):
|
|
25
|
-
super().__init__(*args, **kwargs)
|
|
26
|
-
|
|
27
|
-
self.device.status.subscribe(self._running_changed)
|
|
28
|
-
|
|
29
|
-
def _running_changed(self, value=None, old_value=None, **kwargs):
|
|
30
|
-
if (old_value == 1) and (value == 0):
|
|
31
|
-
self.set_finished()
|
|
32
|
-
self.clean_up()
|
|
33
|
-
|
|
34
|
-
def clean_up(self):
|
|
35
|
-
self.device.status.clear_sub(self._running_changed)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class PandAGridScanParams(GridScanParamsCommon):
|
|
39
|
-
"""
|
|
40
|
-
Holder class for the parameters of a grid scan in a similar
|
|
41
|
-
layout to EPICS. These params are used for the panda-triggered
|
|
42
|
-
constant motion grid scan
|
|
43
|
-
|
|
44
|
-
Motion program will do a grid in x-y then rotate omega +90 and perform
|
|
45
|
-
a grid in x-z.
|
|
46
|
-
|
|
47
|
-
The grid specified is where data is taken e.g. it can be assumed the first frame is
|
|
48
|
-
at x_start, y1_start, z1_start and subsequent frames are N*step_size away.
|
|
49
|
-
"""
|
|
50
|
-
|
|
51
|
-
run_up_distance_mm: float = 0.17
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class PandAFastGridScan(Device):
|
|
55
|
-
"""This is similar to the regular FastGridScan device. It has two extra PVs: runup distance and time between x steps.
|
|
56
|
-
Dwell time is not moved in this scan.
|
|
57
|
-
"""
|
|
58
|
-
|
|
59
|
-
x_steps: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "X_NUM_STEPS")
|
|
60
|
-
y_steps: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "Y_NUM_STEPS")
|
|
61
|
-
z_steps: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "Z_NUM_STEPS")
|
|
62
|
-
|
|
63
|
-
x_step_size: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "X_STEP_SIZE")
|
|
64
|
-
y_step_size: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "Y_STEP_SIZE")
|
|
65
|
-
z_step_size: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "Z_STEP_SIZE")
|
|
66
|
-
|
|
67
|
-
# This value is fixed by the time between X steps detector deadtime. The only reason it is a PV
|
|
68
|
-
# Is so the value can be read by the motion program in the PPMAC
|
|
69
|
-
time_between_x_steps_ms = Component(EpicsSignalWithRBV, "TIME_BETWEEN_X_STEPS")
|
|
70
|
-
|
|
71
|
-
run_up_distance: EpicsSignalWithRBV = Component(EpicsSignal, "RUNUP_DISTANCE")
|
|
72
|
-
|
|
73
|
-
x_start: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "X_START")
|
|
74
|
-
y1_start: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "Y_START")
|
|
75
|
-
y2_start: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "Y2_START")
|
|
76
|
-
z1_start: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "Z_START")
|
|
77
|
-
z2_start: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "Z2_START")
|
|
78
|
-
|
|
79
|
-
position_counter: EpicsSignalRO = Component(EpicsSignalRO, "Y_COUNTER")
|
|
80
|
-
scan_invalid: EpicsSignalRO = Component(EpicsSignalRO, "SCAN_INVALID")
|
|
81
|
-
|
|
82
|
-
run_cmd: EpicsSignal = Component(EpicsSignal, "RUN.PROC")
|
|
83
|
-
stop_cmd: EpicsSignal = Component(EpicsSignal, "STOP.PROC")
|
|
84
|
-
status: EpicsSignalRO = Component(EpicsSignalRO, "SCAN_STATUS")
|
|
85
|
-
|
|
86
|
-
expected_images: Signal = Component(Signal)
|
|
87
|
-
|
|
88
|
-
# Kickoff timeout in seconds
|
|
89
|
-
KICKOFF_TIMEOUT: float = 5.0
|
|
90
|
-
|
|
91
|
-
def __init__(self, *args, **kwargs):
|
|
92
|
-
super().__init__(*args, **kwargs)
|
|
93
|
-
|
|
94
|
-
def set_expected_images(*_, **__):
|
|
95
|
-
x, y, z = self.x_steps.get(), self.y_steps.get(), self.z_steps.get()
|
|
96
|
-
first_grid = x * y
|
|
97
|
-
second_grid = x * z
|
|
98
|
-
self.expected_images.put(first_grid + second_grid)
|
|
99
|
-
|
|
100
|
-
self.x_steps.subscribe(set_expected_images)
|
|
101
|
-
self.y_steps.subscribe(set_expected_images)
|
|
102
|
-
self.z_steps.subscribe(set_expected_images)
|
|
103
|
-
|
|
104
|
-
def is_invalid(self) -> bool:
|
|
105
|
-
if "GONP" in self.scan_invalid.pvname:
|
|
106
|
-
return False
|
|
107
|
-
return self.scan_invalid.get()
|
|
108
|
-
|
|
109
|
-
def kickoff(self) -> StatusBase:
|
|
110
|
-
# Check running already here?
|
|
111
|
-
st = DeviceStatus(device=self, timeout=self.KICKOFF_TIMEOUT)
|
|
112
|
-
|
|
113
|
-
def scan():
|
|
114
|
-
try:
|
|
115
|
-
self.log.debug("Running scan")
|
|
116
|
-
self.run_cmd.put(1)
|
|
117
|
-
self.log.debug("Waiting for scan to start")
|
|
118
|
-
await_value(self.status, 1).wait()
|
|
119
|
-
st.set_finished()
|
|
120
|
-
except Exception as e:
|
|
121
|
-
st.set_exception(e)
|
|
122
|
-
|
|
123
|
-
threading.Thread(target=scan, daemon=True).start()
|
|
124
|
-
return st
|
|
125
|
-
|
|
126
|
-
def complete(self) -> DeviceStatus:
|
|
127
|
-
return GridScanCompleteStatus(self)
|
|
128
|
-
|
|
129
|
-
def collect(self):
|
|
130
|
-
return {}
|
|
131
|
-
|
|
132
|
-
def describe_collect(self):
|
|
133
|
-
return {}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
def set_fast_grid_scan_params(scan: PandAFastGridScan, params: PandAGridScanParams):
|
|
137
|
-
yield from mv(
|
|
138
|
-
scan.x_steps,
|
|
139
|
-
params.x_steps,
|
|
140
|
-
scan.y_steps,
|
|
141
|
-
params.y_steps,
|
|
142
|
-
scan.z_steps,
|
|
143
|
-
params.z_steps,
|
|
144
|
-
scan.x_step_size,
|
|
145
|
-
params.x_step_size,
|
|
146
|
-
scan.y_step_size,
|
|
147
|
-
params.y_step_size,
|
|
148
|
-
scan.z_step_size,
|
|
149
|
-
params.z_step_size,
|
|
150
|
-
scan.x_start,
|
|
151
|
-
params.x_start,
|
|
152
|
-
scan.y1_start,
|
|
153
|
-
params.y1_start,
|
|
154
|
-
scan.y2_start,
|
|
155
|
-
params.y2_start,
|
|
156
|
-
scan.z1_start,
|
|
157
|
-
params.z1_start,
|
|
158
|
-
scan.z2_start,
|
|
159
|
-
params.z2_start,
|
|
160
|
-
scan.run_up_distance,
|
|
161
|
-
params.run_up_distance_mm,
|
|
162
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|