dls-dodal 1.68.0__py3-none-any.whl → 2.0.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.68.0.dist-info → dls_dodal-2.0.0.dist-info}/METADATA +1 -31
- dls_dodal-2.0.0.dist-info/RECORD +354 -0
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/WHEEL +1 -1
- dodal/_version.py +2 -2
- dodal/beamlines/__init__.py +10 -17
- dodal/beamlines/adsim.py +40 -33
- dodal/beamlines/b01_1.py +11 -0
- dodal/beamlines/b07.py +17 -21
- dodal/beamlines/b07_1.py +20 -22
- dodal/beamlines/b07_shared.py +12 -0
- dodal/beamlines/b16.py +1 -1
- dodal/beamlines/b21.py +15 -6
- dodal/beamlines/i02_1.py +17 -45
- dodal/beamlines/i02_2.py +6 -12
- dodal/beamlines/i03.py +8 -5
- dodal/beamlines/i03_supervisor.py +19 -0
- dodal/beamlines/i04.py +87 -184
- dodal/beamlines/i05.py +9 -39
- dodal/beamlines/i05_1.py +4 -13
- dodal/beamlines/i05_shared.py +51 -0
- dodal/beamlines/i06_1.py +26 -0
- dodal/beamlines/{i06.py → i06_shared.py} +25 -14
- dodal/beamlines/i07.py +14 -16
- dodal/beamlines/i09.py +76 -29
- dodal/beamlines/i09_1.py +25 -56
- dodal/beamlines/i09_1_shared.py +61 -0
- dodal/beamlines/i09_2.py +6 -100
- dodal/beamlines/i09_2_shared.py +110 -0
- dodal/beamlines/i10.py +60 -54
- dodal/beamlines/i10_1.py +99 -10
- dodal/beamlines/{i10_optics.py → i10_shared.py} +80 -66
- dodal/beamlines/i11.py +31 -18
- dodal/beamlines/i13_1.py +1 -1
- dodal/beamlines/i15.py +6 -6
- dodal/beamlines/i15_1.py +6 -6
- dodal/beamlines/i16.py +11 -0
- dodal/beamlines/i17.py +37 -28
- dodal/beamlines/i18.py +3 -4
- dodal/beamlines/i19_1.py +95 -34
- dodal/beamlines/i19_2.py +68 -52
- dodal/beamlines/i19_optics.py +26 -13
- dodal/beamlines/i20_1.py +17 -11
- dodal/beamlines/i21.py +44 -29
- dodal/beamlines/i22.py +19 -4
- dodal/beamlines/i23.py +20 -27
- dodal/beamlines/i24.py +64 -113
- dodal/beamlines/k07.py +99 -5
- dodal/beamlines/p38.py +3 -3
- dodal/beamlines/p60.py +35 -14
- dodal/beamlines/p99.py +16 -15
- dodal/beamlines/training_rig.py +20 -12
- dodal/cli.py +36 -2
- dodal/common/__init__.py +2 -1
- dodal/common/beamlines/beamline_parameters.py +2 -1
- dodal/common/beamlines/beamline_utils.py +11 -9
- dodal/common/beamlines/commissioning_mode.py +6 -3
- dodal/common/coordination.py +12 -14
- dodal/common/crystal_metadata.py +5 -8
- dodal/common/device_utils.py +4 -3
- dodal/common/maths.py +87 -19
- dodal/common/udc_directory_provider.py +13 -8
- dodal/common/visit.py +18 -21
- dodal/common/watcher_utils.py +13 -12
- dodal/device_manager.py +94 -54
- dodal/devices/aperturescatterguard.py +26 -27
- dodal/devices/areadetector/plugins/cam.py +1 -3
- dodal/devices/areadetector/plugins/mjpg.py +6 -5
- dodal/devices/attenuator/attenuator.py +12 -11
- dodal/devices/beamlines/b07/__init__.py +3 -0
- dodal/devices/{b07_1 → beamlines/b07_1}/__init__.py +2 -2
- dodal/devices/{b07_1 → beamlines/b07_1}/ccmc.py +5 -10
- dodal/devices/{b16 → beamlines/b16}/detector.py +2 -3
- dodal/devices/{i02_1 → beamlines/i02_1}/fast_grid_scan.py +2 -3
- dodal/devices/{i02_1 → beamlines/i02_1}/sample_motors.py +1 -1
- dodal/devices/{i03 → beamlines/i03}/beamsize.py +11 -7
- dodal/devices/{i03 → beamlines/i03}/dcm.py +1 -2
- dodal/devices/{i03 → beamlines/i03}/undulator_dcm.py +4 -5
- dodal/devices/beamlines/i04/beam_centre.py +151 -0
- dodal/devices/{i04 → beamlines/i04}/beamsize.py +11 -7
- dodal/devices/beamlines/i04/max_pixel.py +25 -0
- dodal/devices/{i04 → beamlines/i04}/murko_results.py +23 -8
- dodal/devices/{i04 → beamlines/i04}/transfocator.py +10 -15
- dodal/devices/beamlines/i05/__init__.py +3 -0
- dodal/devices/beamlines/i06_shared/__init__.py +3 -0
- dodal/devices/beamlines/i06_shared/i06_enum.py +7 -0
- dodal/devices/{i07 → beamlines/i07}/dcm.py +2 -3
- dodal/devices/{i07 → beamlines/i07}/id.py +8 -9
- dodal/devices/beamlines/i09/__init__.py +3 -0
- dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/hard_energy.py +5 -6
- dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/hard_undulator_functions.py +19 -16
- dodal/devices/{i10 → beamlines/i10}/diagnostics.py +4 -3
- dodal/devices/{i10 → beamlines/i10}/i10_apple2.py +37 -51
- dodal/devices/{i10 → beamlines/i10}/rasor/rasor_current_amp.py +1 -24
- dodal/devices/{i10 → beamlines/i10}/rasor/rasor_motors.py +2 -2
- dodal/devices/{i10 → beamlines/i10}/slits.py +5 -3
- dodal/devices/beamlines/i10_1/__init__.py +9 -0
- dodal/devices/beamlines/i10_1/electromagnet/magnet.py +16 -0
- dodal/devices/beamlines/i10_1/electromagnet/stages.py +14 -0
- dodal/devices/beamlines/i10_1/scaler_cards.py +13 -0
- dodal/devices/{i11 → beamlines/i11}/cyberstar_blower.py +1 -1
- dodal/devices/{i11 → beamlines/i11}/diff_stages.py +4 -6
- dodal/devices/{i11 → beamlines/i11}/mythen.py +3 -4
- dodal/devices/{i11 → beamlines/i11}/nx100robot.py +6 -6
- dodal/devices/{i11 → beamlines/i11}/spinner.py +1 -1
- dodal/devices/{i13_1 → beamlines/i13_1}/merlin.py +1 -1
- dodal/devices/{i15 → beamlines/i15}/dcm.py +1 -2
- dodal/devices/{i15 → beamlines/i15}/focussing_mirror.py +5 -5
- dodal/devices/{i15 → beamlines/i15}/jack.py +2 -2
- dodal/devices/{i15 → beamlines/i15}/multilayer_mirror.py +1 -1
- dodal/devices/{i17 → beamlines/i17}/i17_apple2.py +16 -22
- dodal/devices/{i18 → beamlines/i18}/diode.py +1 -1
- dodal/devices/{i19 → beamlines/i19}/access_controlled/attenuator_motor_squad.py +12 -8
- dodal/devices/{i19 → beamlines/i19}/access_controlled/blueapi_device.py +16 -15
- dodal/devices/beamlines/i19/access_controlled/piezo_control.py +72 -0
- dodal/devices/{i19 → beamlines/i19}/access_controlled/shutter.py +11 -9
- dodal/devices/{i19 → beamlines/i19}/backlight.py +3 -1
- dodal/devices/{i19 → beamlines/i19}/mapt_configuration.py +2 -1
- dodal/devices/{i19 → beamlines/i19}/pin_col_stages.py +11 -8
- dodal/devices/beamlines/i19/pin_tip.py +32 -0
- dodal/devices/beamlines/i21/__init__.py +3 -0
- dodal/devices/{i22 → beamlines/i22}/dcm.py +1 -2
- dodal/devices/{i22 → beamlines/i22}/fswitch.py +1 -3
- dodal/devices/{i22 → beamlines/i22}/nxsas.py +5 -4
- dodal/devices/{i24 → beamlines/i24}/beam_center.py +1 -1
- dodal/devices/{i24 → beamlines/i24}/beamstop.py +2 -2
- dodal/devices/{i24 → beamlines/i24}/commissioning_jungfrau.py +12 -12
- dodal/devices/{i24 → beamlines/i24}/dcm.py +1 -3
- dodal/devices/{i24 → beamlines/i24}/dual_backlight.py +3 -3
- dodal/devices/{i24 → beamlines/i24}/pmac.py +9 -7
- dodal/devices/{p60 → beamlines/p60}/lab_xray_source.py +1 -1
- dodal/devices/beamlines/p99/__init__.py +0 -0
- dodal/devices/{p99 → beamlines/p99}/andor2_point.py +11 -15
- dodal/devices/bimorph_mirror.py +22 -20
- dodal/devices/collimation_table.py +3 -2
- dodal/devices/common_dcm.py +30 -20
- dodal/devices/controllers.py +2 -2
- dodal/devices/cryostream.py +8 -0
- dodal/devices/current_amplifiers/current_amplifier.py +16 -18
- dodal/devices/current_amplifiers/current_amplifier_detector.py +9 -10
- dodal/devices/current_amplifiers/femto.py +8 -9
- dodal/devices/current_amplifiers/sr570.py +16 -16
- dodal/devices/current_amplifiers/struck_scaler_counter.py +5 -5
- dodal/devices/detector/det_resolution.py +9 -8
- dodal/devices/detector/detector.py +4 -2
- dodal/devices/diamond_filter.py +3 -4
- dodal/devices/eiger.py +32 -17
- dodal/devices/eiger_odin.py +1 -1
- dodal/devices/electron_analyser/base/__init__.py +3 -3
- dodal/devices/electron_analyser/base/base_controller.py +32 -21
- dodal/devices/electron_analyser/base/base_detector.py +15 -20
- dodal/devices/electron_analyser/base/base_driver_io.py +39 -46
- dodal/devices/electron_analyser/base/base_enums.py +0 -5
- dodal/devices/electron_analyser/base/base_region.py +29 -31
- dodal/devices/electron_analyser/base/base_util.py +18 -16
- dodal/devices/electron_analyser/base/energy_sources.py +35 -40
- dodal/devices/electron_analyser/specs/specs_detector.py +7 -6
- dodal/devices/electron_analyser/vgscienta/vgscienta_detector.py +7 -6
- dodal/devices/eurotherm.py +3 -2
- dodal/devices/fast_grid_scan.py +31 -34
- dodal/devices/fast_shutter.py +125 -39
- dodal/devices/flux.py +1 -1
- dodal/devices/focusing_mirror.py +29 -11
- dodal/devices/hutch_shutter.py +6 -6
- dodal/devices/insertion_device/__init__.py +20 -8
- dodal/devices/insertion_device/apple2_controller.py +371 -0
- dodal/devices/insertion_device/apple2_undulator.py +184 -587
- dodal/devices/insertion_device/apple_knot_controller.py +222 -0
- dodal/devices/insertion_device/energy.py +161 -0
- dodal/devices/insertion_device/energy_motor_lookup.py +21 -28
- dodal/devices/insertion_device/lookup_table_models.py +47 -52
- dodal/devices/insertion_device/polarisation.py +36 -0
- dodal/devices/ipin.py +1 -1
- dodal/devices/linkam3.py +7 -5
- dodal/devices/motors.py +107 -19
- dodal/devices/mx_phase1/beamstop.py +2 -4
- dodal/devices/oav/oav_calculations.py +20 -13
- dodal/devices/oav/oav_detector.py +92 -22
- dodal/devices/oav/oav_parameters.py +4 -9
- dodal/devices/oav/oav_to_redis_forwarder.py +22 -18
- dodal/devices/oav/pin_image_recognition/__init__.py +4 -6
- dodal/devices/oav/pin_image_recognition/manual_test.py +1 -2
- dodal/devices/oav/pin_image_recognition/utils.py +30 -32
- dodal/devices/oav/snapshots/grid_overlay.py +10 -9
- dodal/devices/oav/snapshots/snapshot_image_processing.py +15 -13
- dodal/devices/oav/utils.py +20 -6
- dodal/devices/p45.py +3 -9
- dodal/devices/pgm.py +8 -14
- dodal/devices/pressure_jump_cell.py +93 -32
- dodal/devices/qbpm.py +1 -3
- dodal/devices/robot.py +45 -20
- dodal/devices/s4_slit_gaps.py +1 -1
- dodal/devices/selectable_source.py +41 -0
- dodal/devices/slits.py +2 -5
- dodal/devices/smargon.py +2 -3
- dodal/devices/temperture_controller/lakeshore/lakeshore.py +38 -64
- dodal/devices/temperture_controller/lakeshore/lakeshore_io.py +21 -35
- dodal/devices/tetramm.py +7 -7
- dodal/devices/turbo_slit.py +8 -7
- dodal/devices/undulator.py +42 -56
- dodal/devices/util/adjuster_plans.py +2 -3
- dodal/devices/util/epics_util.py +10 -10
- dodal/devices/util/lookup_tables.py +17 -18
- dodal/devices/v2f.py +2 -3
- dodal/devices/watsonmarlow323_pump.py +1 -1
- dodal/devices/xbpm_feedback.py +3 -2
- dodal/devices/xspress3/xspress3.py +8 -11
- dodal/devices/xspress3/xspress3_channel.py +3 -6
- dodal/devices/zebra/zebra.py +21 -7
- dodal/devices/zebra/zebra_constants_mapping.py +12 -7
- dodal/devices/zebra/zebra_controlled_shutter.py +2 -1
- dodal/devices/zocalo/zocalo_interaction.py +14 -14
- dodal/devices/zocalo/zocalo_results.py +33 -33
- dodal/log.py +23 -20
- dodal/plan_stubs/check_topup.py +15 -15
- dodal/plan_stubs/data_session.py +6 -6
- dodal/plan_stubs/motor_utils.py +22 -18
- dodal/plan_stubs/pressure_jump_cell.py +18 -0
- dodal/plan_stubs/wrapped.py +40 -55
- dodal/plans/bimorph.py +63 -52
- dodal/plans/configure_arm_trigger_and_disarm_detector.py +0 -1
- dodal/plans/device_setup_plans/__init__.py +5 -0
- dodal/plans/device_setup_plans/setup_pin_tip_params.py +63 -0
- dodal/plans/preprocessors/verify_undulator_gap.py +10 -8
- dodal/plans/spec_path.py +3 -5
- dodal/plans/verify_undulator_gap.py +1 -2
- dodal/plans/wrapped.py +4 -3
- dodal/testing/__init__.py +0 -0
- dodal/testing/electron_analyser/device_factory.py +5 -7
- dodal/testing/fixtures/devices/apple2.py +38 -0
- dodal/testing/fixtures/run_engine.py +3 -7
- dodal/testing/fixtures/utils.py +1 -2
- dodal/utils.py +60 -58
- dls_dodal-1.68.0.dist-info/RECORD +0 -330
- dodal/beamline_specific_utils/i05_shared.py +0 -14
- dodal/devices/b07/__init__.py +0 -3
- dodal/devices/i04/max_pixel.py +0 -38
- dodal/devices/i05/__init__.py +0 -3
- dodal/devices/i09/__init__.py +0 -3
- dodal/devices/i21/__init__.py +0 -5
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/licenses/LICENSE +0 -0
- {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/top_level.txt +0 -0
- /dodal/{beamline_specific_utils → devices/beamlines}/__init__.py +0 -0
- /dodal/devices/{b07 → beamlines/b07}/enums.py +0 -0
- /dodal/devices/{b07_1 → beamlines/b07_1}/enums.py +0 -0
- /dodal/devices/{b16 → beamlines/b16}/__init__.py +0 -0
- /dodal/devices/{i02_1 → beamlines/i02_1}/__init__.py +0 -0
- /dodal/devices/{i02_2 → beamlines/i02_2}/__init__.py +0 -0
- /dodal/devices/{i03 → beamlines/i03}/__init__.py +0 -0
- /dodal/devices/{i03 → beamlines/i03}/constants.py +0 -0
- /dodal/devices/{i04 → beamlines/i04}/__init__.py +0 -0
- /dodal/devices/{i04 → beamlines/i04}/constants.py +0 -0
- /dodal/devices/{i05 → beamlines/i05}/enums.py +0 -0
- /dodal/devices/{i07 → beamlines/i07}/__init__.py +0 -0
- /dodal/devices/{i09 → beamlines/i09}/enums.py +0 -0
- /dodal/devices/{i09_1 → beamlines/i09_1}/__init__.py +0 -0
- /dodal/devices/{i09_1 → beamlines/i09_1}/enums.py +0 -0
- /dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/__init__.py +0 -0
- /dodal/devices/{i09_2_shared → beamlines/i09_2_shared}/__init__.py +0 -0
- /dodal/devices/{i09_2_shared → beamlines/i09_2_shared}/i09_apple2.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/__init__.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/i10_setting_data.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/mirrors.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/rasor/__init__.py +0 -0
- /dodal/devices/{i10 → beamlines/i10}/rasor/rasor_scaler_cards.py +0 -0
- /dodal/devices/{i11 → beamlines/i10_1/electromagnet}/__init__.py +0 -0
- /dodal/devices/{i13_1 → beamlines/i11}/__init__.py +0 -0
- /dodal/devices/{i15 → beamlines/i13_1}/__init__.py +0 -0
- /dodal/devices/{i13_1 → beamlines/i13_1}/merlin_controller.py +0 -0
- /dodal/devices/{i17 → beamlines/i15}/__init__.py +0 -0
- /dodal/devices/{i15 → beamlines/i15}/laue.py +0 -0
- /dodal/devices/{i15 → beamlines/i15}/motors.py +0 -0
- /dodal/devices/{i15 → beamlines/i15}/rail.py +0 -0
- /dodal/devices/{i18 → beamlines/i17}/__init__.py +0 -0
- /dodal/devices/{i19 → beamlines/i18}/__init__.py +0 -0
- /dodal/devices/{i18 → beamlines/i18}/kb_mirror.py +0 -0
- /dodal/devices/{i19/access_controlled → beamlines/i19}/__init__.py +0 -0
- /dodal/devices/{i20_1 → beamlines/i19/access_controlled}/__init__.py +0 -0
- /dodal/devices/{i19 → beamlines/i19}/access_controlled/hutch_access.py +0 -0
- /dodal/devices/{i19 → beamlines/i19}/beamstop.py +0 -0
- /dodal/devices/{i19 → beamlines/i19}/diffractometer.py +0 -0
- /dodal/devices/{i22 → beamlines/i20_1}/__init__.py +0 -0
- /dodal/devices/{i21 → beamlines/i21}/enums.py +0 -0
- /dodal/devices/{i24 → beamlines/i22}/__init__.py +0 -0
- /dodal/devices/{p99 → beamlines/i24}/__init__.py +0 -0
- /dodal/devices/{i24 → beamlines/i24}/aperture.py +0 -0
- /dodal/devices/{i24 → beamlines/i24}/focus_mirrors.py +0 -0
- /dodal/devices/{i24 → beamlines/i24}/vgonio.py +0 -0
- /dodal/devices/{p60 → beamlines/p60}/__init__.py +0 -0
- /dodal/devices/{p60 → beamlines/p60}/enums.py +0 -0
- /dodal/devices/{p99 → beamlines/p99}/sample_stage.py +0 -0
- /dodal/devices/insertion_device/{id_enum.py → enum.py} +0 -0
dodal/devices/ipin.py
CHANGED
|
@@ -20,7 +20,7 @@ class IPinGain(SubsetEnum):
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class IPin(StandardReadable):
|
|
23
|
-
"""Simple device to get the ipin reading"""
|
|
23
|
+
"""Simple device to get the ipin reading."""
|
|
24
24
|
|
|
25
25
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
26
26
|
with self.add_children_as_readables(
|
dodal/devices/linkam3.py
CHANGED
|
@@ -14,15 +14,17 @@ class PumpControl(StrictEnum):
|
|
|
14
14
|
# TODO: Make use of Status PV:
|
|
15
15
|
# https://github.com/DiamondLightSource/dodal/issues/338
|
|
16
16
|
class Linkam3(StandardReadable):
|
|
17
|
-
"""Device to represent a Linkam3 temperature controller
|
|
17
|
+
"""Device to represent a Linkam3 temperature controller.
|
|
18
18
|
|
|
19
19
|
Attributes:
|
|
20
|
-
tolerance (float): Deadband around the setpoint within which the position is
|
|
21
|
-
|
|
20
|
+
tolerance (float): Deadband around the setpoint within which the position is
|
|
21
|
+
assumed to have been reached.
|
|
22
|
+
settle_time (int): The delay between reaching the setpoint and the move being
|
|
23
|
+
considered complete.
|
|
22
24
|
|
|
23
25
|
Args:
|
|
24
|
-
prefix (str): PV prefix for this device
|
|
25
|
-
name (str):
|
|
26
|
+
prefix (str): PV prefix for this device.
|
|
27
|
+
name (str): Unique name for this device.
|
|
26
28
|
"""
|
|
27
29
|
|
|
28
30
|
tolerance: float = 0.5
|
dodal/devices/motors.py
CHANGED
|
@@ -8,29 +8,31 @@ from ophyd_async.epics.motor import Motor
|
|
|
8
8
|
_X, _Y, _Z = "X", "Y", "Z"
|
|
9
9
|
|
|
10
10
|
_OMEGA = "OMEGA"
|
|
11
|
+
_POLAR = "POLAR"
|
|
12
|
+
_AZIMUTH = "AZIMUTH"
|
|
13
|
+
_TILT = "TILT"
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
class Stage(StandardReadable, ABC):
|
|
14
|
-
"""
|
|
15
|
-
For these devices, the following co-ordinates are typical but not enforced:
|
|
17
|
+
"""For these devices, the following co-ordinates are typical but not enforced:
|
|
16
18
|
- z is horizontal & parallel to the direction of beam travel
|
|
17
19
|
- y is vertical and antiparallel to the force of gravity
|
|
18
20
|
- x is the cross product of y🞬z
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Infix between the common prefix and the EPICS motor record fields for the field.
|
|
28
|
-
"""
|
|
22
|
+
Attributes:
|
|
23
|
+
prefix (str): Common part of the EPICS PV for all motors, including ":".
|
|
24
|
+
name (str, optional): Name of the stage, each child motor will be named
|
|
25
|
+
"{name}-{field_name}".
|
|
26
|
+
*_infix: Infix between the common prefix and the EPICS motor record fields for
|
|
27
|
+
the field.
|
|
28
|
+
""" # noqa D415
|
|
29
29
|
|
|
30
30
|
...
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class XThetaStage(Stage):
|
|
34
|
+
"""Two-axis stage with an x and a theta motor."""
|
|
35
|
+
|
|
34
36
|
def __init__(
|
|
35
37
|
self, prefix: str, name: str = "", x_infix: str = _X, theta_infix: str = "A"
|
|
36
38
|
):
|
|
@@ -41,6 +43,8 @@ class XThetaStage(Stage):
|
|
|
41
43
|
|
|
42
44
|
|
|
43
45
|
class XYStage(Stage):
|
|
46
|
+
"""A standard two-axis stage with an x and a y motor."""
|
|
47
|
+
|
|
44
48
|
def __init__(
|
|
45
49
|
self, prefix: str, name: str = "", x_infix: str = _X, y_infix: str = _Y
|
|
46
50
|
):
|
|
@@ -51,6 +55,8 @@ class XYStage(Stage):
|
|
|
51
55
|
|
|
52
56
|
|
|
53
57
|
class XYZStage(XYStage):
|
|
58
|
+
"""A standard three-axis stage with an x, a y, and a z motor."""
|
|
59
|
+
|
|
54
60
|
def __init__(
|
|
55
61
|
self,
|
|
56
62
|
prefix: str,
|
|
@@ -65,6 +71,8 @@ class XYZStage(XYStage):
|
|
|
65
71
|
|
|
66
72
|
|
|
67
73
|
class XYZThetaStage(XYZStage):
|
|
74
|
+
"""Four-axis stage with a standard xyz stage and one axis of rotation: theta."""
|
|
75
|
+
|
|
68
76
|
def __init__(
|
|
69
77
|
self,
|
|
70
78
|
prefix: str,
|
|
@@ -80,6 +88,8 @@ class XYZThetaStage(XYZStage):
|
|
|
80
88
|
|
|
81
89
|
|
|
82
90
|
class XYZOmegaStage(XYZStage):
|
|
91
|
+
"""Four-axis stage with a standard xyz stage and one axis of rotation: omega."""
|
|
92
|
+
|
|
83
93
|
def __init__(
|
|
84
94
|
self,
|
|
85
95
|
prefix: str,
|
|
@@ -94,7 +104,69 @@ class XYZOmegaStage(XYZStage):
|
|
|
94
104
|
super().__init__(prefix, name, x_infix, y_infix, z_infix)
|
|
95
105
|
|
|
96
106
|
|
|
107
|
+
class XYZPolarStage(XYZStage):
|
|
108
|
+
"""Four-axis stage with a standard xyz stage and one axis of rotation: polar."""
|
|
109
|
+
|
|
110
|
+
def __init__(
|
|
111
|
+
self,
|
|
112
|
+
prefix: str,
|
|
113
|
+
name: str = "",
|
|
114
|
+
x_infix: str = _X,
|
|
115
|
+
y_infix: str = _Y,
|
|
116
|
+
z_infix: str = _Z,
|
|
117
|
+
polar_infix: str = _POLAR,
|
|
118
|
+
) -> None:
|
|
119
|
+
with self.add_children_as_readables():
|
|
120
|
+
self.polar = Motor(prefix + polar_infix)
|
|
121
|
+
super().__init__(prefix, name, x_infix, y_infix, z_infix)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class XYZPolarAzimuthStage(XYZPolarStage):
|
|
125
|
+
"""Five-axis stage with a standard xyz stage and two axis of rotation: polar and
|
|
126
|
+
azimuth.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
def __init__(
|
|
130
|
+
self,
|
|
131
|
+
prefix: str,
|
|
132
|
+
name: str = "",
|
|
133
|
+
x_infix: str = _X,
|
|
134
|
+
y_infix: str = _Y,
|
|
135
|
+
z_infix: str = _Z,
|
|
136
|
+
polar_infix: str = _POLAR,
|
|
137
|
+
azimuth_infix: str = _AZIMUTH,
|
|
138
|
+
):
|
|
139
|
+
with self.add_children_as_readables():
|
|
140
|
+
self.azimuth = Motor(prefix + azimuth_infix)
|
|
141
|
+
super().__init__(prefix, name, x_infix, y_infix, z_infix, polar_infix)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class XYZPolarAzimuthTiltStage(XYZPolarAzimuthStage):
|
|
145
|
+
"""Six-axis stage with a standard xyz stage and three axis of rotation: polar,
|
|
146
|
+
azimuth and tilt.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
def __init__(
|
|
150
|
+
self,
|
|
151
|
+
prefix: str,
|
|
152
|
+
name: str = "",
|
|
153
|
+
x_infix: str = _X,
|
|
154
|
+
y_infix: str = _Y,
|
|
155
|
+
z_infix: str = _Z,
|
|
156
|
+
polar_infix: str = _POLAR,
|
|
157
|
+
azimuth_infix: str = _AZIMUTH,
|
|
158
|
+
tilt_infix: str = _TILT,
|
|
159
|
+
):
|
|
160
|
+
with self.add_children_as_readables():
|
|
161
|
+
self.tilt = Motor(prefix + tilt_infix)
|
|
162
|
+
super().__init__(
|
|
163
|
+
prefix, name, x_infix, y_infix, z_infix, polar_infix, azimuth_infix
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
97
167
|
class XYPhiStage(XYStage):
|
|
168
|
+
"""Three-axis stage with a standard xy stage and one axis of rotation: phi."""
|
|
169
|
+
|
|
98
170
|
def __init__(
|
|
99
171
|
self,
|
|
100
172
|
prefix: str,
|
|
@@ -109,6 +181,8 @@ class XYPhiStage(XYStage):
|
|
|
109
181
|
|
|
110
182
|
|
|
111
183
|
class XYPitchStage(XYStage):
|
|
184
|
+
"""Three-axis stage with a standard xy stage and one axis of rotation: pitch."""
|
|
185
|
+
|
|
112
186
|
def __init__(
|
|
113
187
|
self,
|
|
114
188
|
prefix: str,
|
|
@@ -123,6 +197,8 @@ class XYPitchStage(XYStage):
|
|
|
123
197
|
|
|
124
198
|
|
|
125
199
|
class XYRollStage(XYStage):
|
|
200
|
+
"""Three-axis stage with a standard xy stage and one axis of rotation: roll."""
|
|
201
|
+
|
|
126
202
|
def __init__(
|
|
127
203
|
self,
|
|
128
204
|
prefix: str,
|
|
@@ -137,6 +213,10 @@ class XYRollStage(XYStage):
|
|
|
137
213
|
|
|
138
214
|
|
|
139
215
|
class XYZPitchYawStage(XYZStage):
|
|
216
|
+
"""Five-axis stage with a standard xyz stage and two axes of rotation: pitch and
|
|
217
|
+
yaw.
|
|
218
|
+
"""
|
|
219
|
+
|
|
140
220
|
def __init__(
|
|
141
221
|
self,
|
|
142
222
|
prefix: str,
|
|
@@ -154,6 +234,10 @@ class XYZPitchYawStage(XYZStage):
|
|
|
154
234
|
|
|
155
235
|
|
|
156
236
|
class XYZPitchYawRollStage(XYZStage):
|
|
237
|
+
"""Five-axis stage with a standard xyz stage and three axes of rotation: pitch, yaw,
|
|
238
|
+
and roll.
|
|
239
|
+
"""
|
|
240
|
+
|
|
157
241
|
def __init__(
|
|
158
242
|
self,
|
|
159
243
|
prefix: str,
|
|
@@ -173,6 +257,10 @@ class XYZPitchYawRollStage(XYZStage):
|
|
|
173
257
|
|
|
174
258
|
|
|
175
259
|
class SixAxisGonio(XYZOmegaStage):
|
|
260
|
+
"""Six-axis goniometer with a standard xyz stage and three axes of rotation:
|
|
261
|
+
kappa, phi and omega.
|
|
262
|
+
"""
|
|
263
|
+
|
|
176
264
|
def __init__(
|
|
177
265
|
self,
|
|
178
266
|
prefix: str,
|
|
@@ -184,9 +272,6 @@ class SixAxisGonio(XYZOmegaStage):
|
|
|
184
272
|
phi_infix: str = "PHI",
|
|
185
273
|
omega_infix: str = _OMEGA,
|
|
186
274
|
):
|
|
187
|
-
"""Six-axis goniometer with a standard xyz stage and three axes of rotation:
|
|
188
|
-
kappa, phi and omega.
|
|
189
|
-
"""
|
|
190
275
|
with self.add_children_as_readables():
|
|
191
276
|
self.kappa = Motor(prefix + kappa_infix)
|
|
192
277
|
self.phi = Motor(prefix + phi_infix)
|
|
@@ -198,6 +283,10 @@ class SixAxisGonio(XYZOmegaStage):
|
|
|
198
283
|
|
|
199
284
|
|
|
200
285
|
class SixAxisGonioKappaPhi(XYZStage):
|
|
286
|
+
"""Six-axis goniometer with a standard xyz stage and two axes of rotation:
|
|
287
|
+
kappa and phi.
|
|
288
|
+
"""
|
|
289
|
+
|
|
201
290
|
def __init__(
|
|
202
291
|
self,
|
|
203
292
|
prefix: str,
|
|
@@ -208,9 +297,6 @@ class SixAxisGonioKappaPhi(XYZStage):
|
|
|
208
297
|
kappa_infix: str = "KAPPA",
|
|
209
298
|
phi_infix: str = "PHI",
|
|
210
299
|
):
|
|
211
|
-
"""Six-axis goniometer with a standard xyz stage and two axes of rotation:
|
|
212
|
-
kappa and phi.
|
|
213
|
-
"""
|
|
214
300
|
with self.add_children_as_readables():
|
|
215
301
|
self.kappa = Motor(prefix + kappa_infix)
|
|
216
302
|
self.phi = Motor(prefix + phi_infix)
|
|
@@ -218,6 +304,8 @@ class SixAxisGonioKappaPhi(XYZStage):
|
|
|
218
304
|
|
|
219
305
|
|
|
220
306
|
class YZStage(Stage):
|
|
307
|
+
"""Two-axis stage with an x and a z motor."""
|
|
308
|
+
|
|
221
309
|
def __init__(
|
|
222
310
|
self, prefix: str, name: str = "", y_infix: str = _Y, z_infix: str = _Z
|
|
223
311
|
) -> None:
|
|
@@ -244,9 +332,9 @@ def create_axis_perp_to_rotation(motor_theta: Motor, motor_i: Motor, motor_j: Mo
|
|
|
244
332
|
Args:
|
|
245
333
|
motor_theta (Motor): this is the rotation axis of the sample.
|
|
246
334
|
motor_i (Motor): this is the axis that, when the sample is at 0 deg rotation,
|
|
247
|
-
|
|
335
|
+
a move here is entirely parallel with the derived axis.
|
|
248
336
|
motor_j (Motor): this is the axis that, when the sample is at 90 deg rotation,
|
|
249
|
-
|
|
337
|
+
a move here is entirely parallel with the derived axis.
|
|
250
338
|
"""
|
|
251
339
|
|
|
252
340
|
def _get(j_val: float, i_val: float, rot_value: float) -> float:
|
|
@@ -14,8 +14,7 @@ _BEAMSTOP_OUT_DELTA_Y_MM = -2
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class BeamstopPositions(StrictEnum):
|
|
17
|
-
"""
|
|
18
|
-
Beamstop positions.
|
|
17
|
+
"""Beamstop positions.
|
|
19
18
|
GDA supports Standard/High/Low resolution positions, as well as parked and
|
|
20
19
|
robot load however all 3 resolution positions are the same. We also
|
|
21
20
|
do not use the robot load position in Hyperion.
|
|
@@ -35,8 +34,7 @@ class BeamstopPositions(StrictEnum):
|
|
|
35
34
|
|
|
36
35
|
|
|
37
36
|
class Beamstop(StandardReadable):
|
|
38
|
-
"""
|
|
39
|
-
Beamstop for I03 and I04.
|
|
37
|
+
"""Beamstop for I03 and I04.
|
|
40
38
|
|
|
41
39
|
Attributes:
|
|
42
40
|
x: beamstop x position in mm
|
|
@@ -11,19 +11,24 @@ def camera_coordinates_to_xyz_mm(
|
|
|
11
11
|
y_vertical_sign: int,
|
|
12
12
|
z_vertical_sign: int,
|
|
13
13
|
) -> np.ndarray:
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
For an overview of the coordinate system for I03 see
|
|
14
|
+
"""Converts from (horizontal,vertical) pixel measurements from the OAV camera into
|
|
15
|
+
to (x, y, z) motor coordinates in millimetres.
|
|
16
|
+
For an overview of the coordinate system for I03 see
|
|
17
|
+
https://github.com/DiamondLightSource/hyperion/wiki/Gridscan-Coordinate-System.
|
|
17
18
|
|
|
18
19
|
Args:
|
|
19
20
|
horizontal (float): A i value from the camera in pixels.
|
|
20
21
|
vertical (float): A j value from the camera in pixels.
|
|
21
|
-
omega (float): The omega angle of the smargon that the horizontal, vertical
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
omega (float): The omega angle of the smargon that the horizontal, vertical
|
|
23
|
+
measurements were obtained at.
|
|
24
|
+
microns_per_i_pixel (float): The number of microns per i pixel, adjusted for
|
|
25
|
+
the zoom level horizontal was measured at.
|
|
26
|
+
microns_per_j_pixel (float): The number of microns per j pixel, adjusted for
|
|
27
|
+
the zoom level vertical was measured at.
|
|
28
|
+
x_horizontal_sign (int): Direction mapping for x, positive means the oav and
|
|
29
|
+
motor are on same direction, default from hyperion.
|
|
30
|
+
y_vertical_sign (int): Direction mapping for y.
|
|
31
|
+
z_vertical_sign (int): Direction mapping for z.
|
|
27
32
|
"""
|
|
28
33
|
# Convert the vertical and horizontal into mm.
|
|
29
34
|
horizontal *= microns_per_i_pixel * 1e-3
|
|
@@ -49,15 +54,17 @@ def calculate_beam_distance(
|
|
|
49
54
|
horizontal_pixels: int,
|
|
50
55
|
vertical_pixels: int,
|
|
51
56
|
) -> tuple[int, int]:
|
|
52
|
-
"""
|
|
53
|
-
|
|
57
|
+
"""Calculates the distance between the beam centre and the given (horizontal,
|
|
58
|
+
vertical).
|
|
54
59
|
|
|
55
60
|
Args:
|
|
61
|
+
beam_centre (tuple[int, int]): The position of the beam in pixels.
|
|
56
62
|
horizontal_pixels (int): The x (camera coordinates) value in pixels.
|
|
57
63
|
vertical_pixels (int): The y (camera coordinates) value in pixels.
|
|
64
|
+
|
|
58
65
|
Returns:
|
|
59
|
-
The distance between the beam centre and the (horizontal, vertical) point
|
|
60
|
-
|
|
66
|
+
tuple: The distance between the beam centre and the (horizontal, vertical) point
|
|
67
|
+
in pixels as a tuple (horizontal_distance, vertical_distance).
|
|
61
68
|
"""
|
|
62
69
|
beam_x, beam_y = beam_centre
|
|
63
70
|
return (
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
from enum import IntEnum
|
|
2
3
|
|
|
3
4
|
from bluesky.protocols import Movable
|
|
4
5
|
from ophyd_async.core import (
|
|
5
6
|
DEFAULT_TIMEOUT,
|
|
6
7
|
AsyncStatus,
|
|
8
|
+
DeviceMock,
|
|
9
|
+
DeviceVector,
|
|
7
10
|
LazyMock,
|
|
8
11
|
SignalR,
|
|
9
12
|
SignalRW,
|
|
10
13
|
StandardReadable,
|
|
14
|
+
default_mock_class,
|
|
11
15
|
derived_signal_r,
|
|
12
16
|
soft_signal_rw,
|
|
13
17
|
)
|
|
@@ -22,6 +26,7 @@ from dodal.devices.oav.oav_parameters import (
|
|
|
22
26
|
)
|
|
23
27
|
from dodal.devices.oav.snapshots.snapshot import Snapshot
|
|
24
28
|
from dodal.devices.oav.snapshots.snapshot_with_grid import SnapshotWithGrid
|
|
29
|
+
from dodal.log import LOGGER
|
|
25
30
|
|
|
26
31
|
|
|
27
32
|
class Coords(IntEnum):
|
|
@@ -56,37 +61,99 @@ class NullZoomController(BaseZoomController):
|
|
|
56
61
|
await self.level.set(value, wait=True)
|
|
57
62
|
|
|
58
63
|
|
|
59
|
-
class
|
|
64
|
+
class BeamCentreForZoom(StandardReadable):
|
|
65
|
+
"""These PVs hold the beam centre on the OAV at each zoom level.
|
|
66
|
+
|
|
67
|
+
When the zoom level is changed the IOC will update the OAV overlay PVs to be at
|
|
68
|
+
these positions.
|
|
60
69
|
"""
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
|
|
71
|
+
def __init__(
|
|
72
|
+
self, prefix: str, level_name_pv_suffix: str, centre_value_pv_suffix: str
|
|
73
|
+
) -> None:
|
|
74
|
+
self.level_name = epics_signal_r(
|
|
75
|
+
str, f"{prefix}MP:SELECT.{level_name_pv_suffix}"
|
|
76
|
+
)
|
|
77
|
+
self.x_centre = epics_signal_rw(
|
|
78
|
+
float, f"{prefix}PBCX:VAL{centre_value_pv_suffix}"
|
|
79
|
+
)
|
|
80
|
+
self.y_centre = epics_signal_rw(
|
|
81
|
+
float, f"{prefix}PBCY:VAL{centre_value_pv_suffix}"
|
|
82
|
+
)
|
|
83
|
+
super().__init__()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class InstantMovingZoom(DeviceMock["ZoomController"]):
|
|
87
|
+
"""Mock behaviour that instantly moves the zoom."""
|
|
88
|
+
|
|
89
|
+
async def connect(self, device: "ZoomController") -> None:
|
|
90
|
+
"""Mock signals to do an instant move on setpoint write."""
|
|
91
|
+
device.DELAY_BETWEEN_MOTORS_AND_IMAGE_UPDATING_S = 0.001 # type:ignore
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@default_mock_class(InstantMovingZoom)
|
|
95
|
+
class ZoomController(BaseZoomController):
|
|
96
|
+
"""Device to control the zoom level. This should be set like::
|
|
97
|
+
|
|
98
|
+
oav = OAV(name="oav")
|
|
63
99
|
oav.zoom_controller.set("1.0x")
|
|
64
100
|
|
|
65
101
|
Note that changing the zoom may change the AD wiring on the associated OAV, as such
|
|
66
|
-
you should wait on any zoom
|
|
67
|
-
"""
|
|
102
|
+
you should wait on any zoom changes to finish before changing the OAV wiring.
|
|
103
|
+
""" # noqa 415
|
|
104
|
+
|
|
105
|
+
DELAY_BETWEEN_MOTORS_AND_IMAGE_UPDATING_S = 2
|
|
68
106
|
|
|
69
107
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
70
108
|
self.percentage = epics_signal_rw(float, f"{prefix}ZOOMPOSCMD")
|
|
71
109
|
|
|
72
110
|
# Level is the string description of the zoom level e.g. "1.0x" or "1.0"
|
|
73
111
|
self.level = epics_signal_rw(str, f"{prefix}MP:SELECT")
|
|
112
|
+
|
|
74
113
|
super().__init__(name=name)
|
|
75
114
|
|
|
76
115
|
@AsyncStatus.wrap
|
|
77
116
|
async def set(self, value: str):
|
|
78
117
|
await self.level.set(value, wait=True)
|
|
118
|
+
LOGGER.info(
|
|
119
|
+
f"Waiting {self.DELAY_BETWEEN_MOTORS_AND_IMAGE_UPDATING_S} seconds for zoom to be noticeable"
|
|
120
|
+
)
|
|
121
|
+
await asyncio.sleep(self.DELAY_BETWEEN_MOTORS_AND_IMAGE_UPDATING_S)
|
|
79
122
|
|
|
80
123
|
|
|
81
|
-
class
|
|
82
|
-
""
|
|
83
|
-
|
|
124
|
+
class ZoomControllerWithBeamCentres(ZoomController):
|
|
125
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
126
|
+
level_to_centre_mapping = [
|
|
127
|
+
("ZRST", "A"),
|
|
128
|
+
("ONST", "B"),
|
|
129
|
+
("TWST", "C"),
|
|
130
|
+
("THST", "D"),
|
|
131
|
+
("FRST", "E"),
|
|
132
|
+
("FVST", "F"),
|
|
133
|
+
("SXST", "G"),
|
|
134
|
+
("SVST", "H"),
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
self.beam_centres = DeviceVector(
|
|
138
|
+
{
|
|
139
|
+
i: BeamCentreForZoom(prefix, *level_to_centre_mapping[i])
|
|
140
|
+
for i in range(len(level_to_centre_mapping))
|
|
141
|
+
}
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
super().__init__(prefix, name)
|
|
145
|
+
|
|
84
146
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
147
|
+
class OAV(StandardReadable):
|
|
148
|
+
"""Class for oav device.
|
|
149
|
+
|
|
150
|
+
Attributes:
|
|
151
|
+
x_direction(int, optional): Should only be 1 or -1, with 1 indicating the oav x
|
|
152
|
+
direction is the same with motor x.
|
|
153
|
+
y_direction(int, optional): Same with x_direction but for motor y.
|
|
154
|
+
z_direction(int, optional): Same with x_direction but for motor z.
|
|
155
|
+
mjpg_x_size_pv(str, optional): PV infix for x_size in mjpg.
|
|
156
|
+
mjpg_y_size_pv(str, optional): PV infix for y_size in mjpg.
|
|
90
157
|
"""
|
|
91
158
|
|
|
92
159
|
beam_centre_i: SignalR[int]
|
|
@@ -118,6 +185,7 @@ class OAV(StandardReadable):
|
|
|
118
185
|
self.zoom_controller = zoom_controller
|
|
119
186
|
|
|
120
187
|
self.cam = Cam(f"{prefix}CAM:", name=name)
|
|
188
|
+
|
|
121
189
|
with self.add_children_as_readables():
|
|
122
190
|
self.grid_snapshot = SnapshotWithGrid(
|
|
123
191
|
f"{prefix}{mjpeg_prefix}:", name, mjpg_x_size_pv, mjpg_y_size_pv
|
|
@@ -170,16 +238,17 @@ class OAV(StandardReadable):
|
|
|
170
238
|
|
|
171
239
|
|
|
172
240
|
class OAVBeamCentreFile(OAV):
|
|
173
|
-
"""
|
|
174
|
-
OAV device that reads its beam centre values from a file. The config parameter
|
|
241
|
+
"""OAV device that reads its beam centre values from a file. The config parameter
|
|
175
242
|
must be a OAVConfigBeamCentre object, as this contains a filepath to where the beam
|
|
176
243
|
centre values are stored.
|
|
177
244
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
245
|
+
Attributes:
|
|
246
|
+
x_direction(int, optional): Should only be 1 or -1, with 1 indicating the oav x
|
|
247
|
+
direction is the same with motor x.
|
|
248
|
+
y_direction(int, optional): Same with x_direction but for motor y.
|
|
249
|
+
z_direction(int, optional): Same with x_direction but for motor z.
|
|
250
|
+
mjpg_x_size_pv(str, optional): PV infix for x_size in mjpg.
|
|
251
|
+
mjpg_y_size_pv(str, optional): PV infix for y_size in mjpg.
|
|
183
252
|
"""
|
|
184
253
|
|
|
185
254
|
def __init__(
|
|
@@ -225,8 +294,9 @@ class OAVBeamCentreFile(OAV):
|
|
|
225
294
|
self.set_name(self.name)
|
|
226
295
|
|
|
227
296
|
def _get_beam_position(self, zoom_level: str, size: int, coord: int) -> int:
|
|
228
|
-
"""Extracts the beam location in pixels `xCentre` `yCentre`, for a requested
|
|
229
|
-
zoom level.
|
|
297
|
+
"""Extracts the beam location in pixels `xCentre` `yCentre`, for a requested
|
|
298
|
+
zoom level.
|
|
299
|
+
"""
|
|
230
300
|
_zoom = self._read_current_zoom(zoom_level)
|
|
231
301
|
value = self.parameters[_zoom].crosshair[coord]
|
|
232
302
|
return int(value * size / DEFAULT_OAV_WINDOW[coord])
|
|
@@ -25,9 +25,7 @@ def _get_element_as_float(node: Element, element_name: str) -> float:
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class OAVParameters:
|
|
28
|
-
"""
|
|
29
|
-
The parameters to set up the OAV depending on the context.
|
|
30
|
-
"""
|
|
28
|
+
"""The parameters to set up the OAV depending on the context."""
|
|
31
29
|
|
|
32
30
|
def __init__(
|
|
33
31
|
self,
|
|
@@ -45,8 +43,7 @@ class OAVParameters:
|
|
|
45
43
|
|
|
46
44
|
@staticmethod
|
|
47
45
|
def load_json(filename: str) -> tuple[dict[str, Any], dict[str, dict]]:
|
|
48
|
-
"""
|
|
49
|
-
Loads the json from the specified file, and returns a dict with all the
|
|
46
|
+
"""Loads the json from the specified file, and returns a dict with all the
|
|
50
47
|
individual top-level k-v pairs, and one with all the subdicts.
|
|
51
48
|
"""
|
|
52
49
|
with open(filename) as f:
|
|
@@ -101,9 +98,7 @@ class OAVParameters:
|
|
|
101
98
|
self.max_tip_distance: float = update("max_tip_distance", float, default=300)
|
|
102
99
|
|
|
103
100
|
def get_max_tip_distance_in_pixels(self, microns_per_pixel: float) -> float:
|
|
104
|
-
"""
|
|
105
|
-
Get the maximum tip distance in pixels.
|
|
106
|
-
"""
|
|
101
|
+
"""Get the maximum tip distance in pixels."""
|
|
107
102
|
return self.max_tip_distance / microns_per_pixel
|
|
108
103
|
|
|
109
104
|
|
|
@@ -154,7 +149,7 @@ class OAVConfig(OAVConfigBase[ZoomParams]):
|
|
|
154
149
|
|
|
155
150
|
|
|
156
151
|
class OAVConfigBeamCentre(OAVConfigBase[ZoomParamsCrosshair]):
|
|
157
|
-
"""
|
|
152
|
+
"""Read the OAV config files and return a dictionary of {'zoom_level': ZoomParams}
|
|
158
153
|
with information about microns per pixels and crosshairs.
|
|
159
154
|
"""
|
|
160
155
|
|
|
@@ -45,12 +45,23 @@ class OAVSource(StandardReadable):
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
|
|
48
|
-
"""Forwards OAV image data to redis.
|
|
48
|
+
"""Forwards OAV image data to redis.
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
> bps.monitor(oav_forwarder.uuid)
|
|
52
|
-
> bps.complete(oav_forwarder)
|
|
50
|
+
To use call::
|
|
53
51
|
|
|
52
|
+
bps.kickoff(oav_forwarder)
|
|
53
|
+
bps.monitor(oav_forwarder.uuid)
|
|
54
|
+
bps.complete(oav_forwarder)
|
|
55
|
+
|
|
56
|
+
Reads image data from the MJPEG stream on an OAV and forwards it into a
|
|
57
|
+
redis database. This is currently only used for murko integration.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
prefix (str): The PV prefix of the OAV.
|
|
61
|
+
redis_host (str): The host where the redis database is running.
|
|
62
|
+
redis_password (str): The password for the redis database.
|
|
63
|
+
redis_db (int): Which redis database to connect to, defaults to 0.
|
|
64
|
+
name (str): The name of this device.
|
|
54
65
|
"""
|
|
55
66
|
|
|
56
67
|
DATA_EXPIRY_DAYS = 7
|
|
@@ -68,16 +79,6 @@ class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
|
|
|
68
79
|
redis_db: int = 0,
|
|
69
80
|
name: str = "",
|
|
70
81
|
) -> None:
|
|
71
|
-
"""Reads image data from the MJPEG stream on an OAV and forwards it into a
|
|
72
|
-
redis database. This is currently only used for murko integration.
|
|
73
|
-
|
|
74
|
-
Arguments:
|
|
75
|
-
prefix: str the PV prefix of the OAV
|
|
76
|
-
redis_host: str the host where the redis database is running
|
|
77
|
-
redis_password: str the password for the redis database
|
|
78
|
-
redis_db: int which redis database to connect to, defaults to 0
|
|
79
|
-
name: str the name of this device
|
|
80
|
-
"""
|
|
81
82
|
self.counter = epics_signal_r(int, f"{prefix}CAM:ArrayCounter_RBV")
|
|
82
83
|
self.sources = DeviceVector(
|
|
83
84
|
{
|
|
@@ -109,7 +110,9 @@ class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
|
|
|
109
110
|
):
|
|
110
111
|
"""Stores the raw bytes of the jpeg image in redis. Murko ultimately wants a
|
|
111
112
|
pickled numpy array of pixel values but raw byes are more space efficient. There
|
|
112
|
-
may be better ways of doing this, see
|
|
113
|
+
may be better ways of doing this, see
|
|
114
|
+
https://github.com/DiamondLightSource/mx-bluesky/issues/592.
|
|
115
|
+
"""
|
|
113
116
|
jpeg_bytes = await get_next_jpeg(response)
|
|
114
117
|
sample_id = await self.sample_id.get_value()
|
|
115
118
|
redis_key = f"murko:{sample_id}:raw"
|
|
@@ -131,12 +134,13 @@ class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
|
|
|
131
134
|
await function_to_do(response, source)
|
|
132
135
|
|
|
133
136
|
async def _stream_to_redis(self, response: ClientResponse, source: OAVSource):
|
|
134
|
-
"""Uses the update of the frame counter as a trigger to pull an image off the
|
|
135
|
-
and into redis.
|
|
137
|
+
"""Uses the update of the frame counter as a trigger to pull an image off the
|
|
138
|
+
OAV and into redis.
|
|
136
139
|
|
|
137
140
|
The frame counter is continually increasing on the timescales we store data and
|
|
138
141
|
so can be used as a uuid. If the OAV is updating too quickly we may drop frames
|
|
139
|
-
but in this case a best effort on getting as many frames as possible is
|
|
142
|
+
but in this case a best effort on getting as many frames as possible is
|
|
143
|
+
sufficient.
|
|
140
144
|
"""
|
|
141
145
|
done_status = AsyncStatus(
|
|
142
146
|
asyncio.wait_for(self._stop_flag.wait(), timeout=self.TIMEOUT)
|