From 63db1f66ddab08693f154a957dcdf0750ed205f7 Mon Sep 17 00:00:00 2001 From: Sector 25 ID-C User Date: Thu, 29 Feb 2024 14:42:32 -0600 Subject: [PATCH 01/21] Added output_enable signal to the capillary heater. --- src/haven/instrument/heater.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/haven/instrument/heater.py b/src/haven/instrument/heater.py index 0e94a4ea..e6bb47a6 100644 --- a/src/haven/instrument/heater.py +++ b/src/haven/instrument/heater.py @@ -4,7 +4,7 @@ from apstools.devices import PTC10AioChannel as PTC10AioChannelBase from apstools.devices import PTC10PositionerMixin, PTC10TcChannel from ophyd import Component as Cpt -from ophyd import EpicsSignalRO, EpicsSignalWithRBV, PVPositioner +from ophyd import EpicsSignalRO, EpicsSignalWithRBV, PVPositioner, EpicsSignal from .._iconfig import load_config from .device import aload_devices, make_device @@ -18,7 +18,7 @@ class PTC10AioChannel(PTC10AioChannelBase): SRS PTC10 AIO module """ - voltage = Cpt(EpicsSignalRO, "output_RBV", kind="config") + voltage = Cpt(EpicsSignalRO, "output_RBV", kind="normal") class CapillaryHeater(PTC10PositionerMixin, PVPositioner): @@ -28,6 +28,7 @@ class CapillaryHeater(PTC10PositionerMixin, PVPositioner): # Additional modules installed on the PTC10 pid = Cpt(PTC10AioChannel, "5A:") tc = Cpt(PTC10TcChannel, "2A:") + output_enable = Cpt(EpicsSignal, "outputEnable", kind="omitted") def load_heater_coros(config=None): From fa0ebd5dffea0f8caae2a06cb5dc2621ce9cd7b5 Mon Sep 17 00:00:00 2001 From: Sector 25 ID-C User Date: Thu, 29 Feb 2024 18:21:25 -0600 Subject: [PATCH 02/21] When preparing the aerotech PSO, first turn off both axes instead of just the current one. --- src/haven/instrument/aerotech.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/haven/instrument/aerotech.py b/src/haven/instrument/aerotech.py index 65a46a99..89971f42 100644 --- a/src/haven/instrument/aerotech.py +++ b/src/haven/instrument/aerotech.py @@ -483,7 +483,8 @@ def send_command(self, cmd: str): return status def disable_pso(self): - self.send_command(f"PSOCONTROL {self.axis} OFF") + for axis in range(2): + self.send_command(f"PSOCONTROL @{axis} OFF") def check_flyscan_bounds(self): """Check that the fly-scan params are sane at the scan start and end. From 4de87133d749123d72a570c11e13cacd7719c3f6 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Fri, 8 Mar 2024 08:58:19 -0600 Subject: [PATCH 03/21] Add the plan robot_sample --- src/conftest.py | 8 +++ src/haven/plans/robot_sample.py | 96 ++++++++++++++++++++++++++++ src/haven/tests/test_robot_sample.py | 42 ++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 src/haven/plans/robot_sample.py create mode 100644 src/haven/tests/test_robot_sample.py diff --git a/src/conftest.py b/src/conftest.py index cd81bd82..6029586f 100644 --- a/src/conftest.py +++ b/src/conftest.py @@ -34,6 +34,7 @@ from haven.instrument.slits import ApertureSlits, BladeSlits from haven.instrument.xspress import Xspress3Detector from haven.instrument.xspress import add_mcas as add_xspress_mcas +from haven.instrument.robot import Robot top_dir = Path(__file__).parent.resolve() haven_dir = top_dir / "haven" @@ -264,6 +265,13 @@ def aerotech(): return stage +@pytest.fixture() +def robot(): + RobotClass = make_fake_device(Robot) + robot = RobotClass(name="robotA", prefix="255idA:") + return robot + + @pytest.fixture() def aerotech_flyer(aerotech): flyer = aerotech.horiz diff --git a/src/haven/plans/robot_sample.py b/src/haven/plans/robot_sample.py new file mode 100644 index 00000000..b2535fc9 --- /dev/null +++ b/src/haven/plans/robot_sample.py @@ -0,0 +1,96 @@ +import logging +import warnings + +from bluesky import plan_stubs as bps +from ophyd import DeviceStatus + +from ..instrument.robot import Robot, load_robot +from ..instrument.instrument_registry import registry +from ..motor_position import rbv + + +log = logging.getLogger(__name__) + + +__all__ = ["robot_sample"] + + +def robot_sample(robot, sampleN, *args): + """ + Use robot to load sampleN at a fixed Aerotech stage position or any + motors. + + e.g. + robot_sample(robot, 9, motor1, 100, motor2, 200, motor3, 50) + + Parameters: + - robot: robot device + - sampleN: Sample number + - *args: multiple pairs of motor and pos + """ + + robot = registry.find(robot) + + # Check if power is on + # if robot.power_rbv.get() == Off: + # raise ValueError("Robot is NOT powered. Please turn on the power.") + + # Check if remote control is on + # if not robot.remote_control.get() == Off: + # raise ValueError( + # "Robot is NOT in reomete control mode. Please click on Pad for remote control." + # ) + + # Check if gripper is on + # if robot.gripper_activated.get() == Off: + # raise ValueError("Gripper is not activated. Please activate the gripper.") + + # Check if robot is running + # if robot.grogram_running.get() == On: + # raise ValueError("Robot is running now.") + + # Find motors + motor_list = [registry.find(motor) for motor in args[::2]] + + # Record the motor positions before load sampls + initial_positions = [rbv(motor) for motor in motor_list] + + # Move the aerotech to the loading position + for motor, pos in zip(args[::2], args[1::2]): + yield from bps.mv(motor, pos) + + # Load sampleN after all the other motor arrive at (pos1, pos2, pos3...) + sample = getattr( + robot.samples, f"sample{sampleN}" + ) # Access the Sample device corresponding to sampleN + yield from bps.mv(sample.load, 1) # Assuming '1' initiates the loading action + + # Return to the initial position + for motor, pos in zip(motor_list[-1::-1], initial_positions[-1::-1]): + yield from bps.mv(motor, pos) + + +# ----------------------------------------------------------------------------- +# :author: Yanna Chen +# :email: yannachen@anl.gov +# :copyright: Copyright © 2024, UChicago Argonne, LLC +# +# Distributed under the terms of the 3-Clause BSD License +# +# The full license is in the file LICENSE, distributed with this software. +# +# DISCLAIMER +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ----------------------------------------------------------------------------- diff --git a/src/haven/tests/test_robot_sample.py b/src/haven/tests/test_robot_sample.py new file mode 100644 index 00000000..2a4a6a53 --- /dev/null +++ b/src/haven/tests/test_robot_sample.py @@ -0,0 +1,42 @@ +import pytest +from ophyd.sim import motor1, motor2, motor3 +from pprint import pprint + +from haven import robot_sample + + +def test_robot_sample(robot): + + plan = robot_sample(robot, 9, motor1, 100, motor2, 200, motor3, 50) + + msgs = list(plan) + pprint(msgs) + + assert robot.name == "robotA" + assert len(msgs) == 14 + + +# ----------------------------------------------------------------------------- +# :author: Yanna Chen +# :email: yannachen@anl.gov +# :copyright: Copyright © 2024, UChicago Argonne, LLC +# +# Distributed under the terms of the 3-Clause BSD License +# +# The full license is in the file LICENSE, distributed with this software. +# +# DISCLAIMER +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ----------------------------------------------------------------------------- From 390687202692454cad1d9d2c334fcec09c5d1db8 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Fri, 8 Mar 2024 09:16:19 -0600 Subject: [PATCH 04/21] Delete unused imports --- src/haven/plans/robot_sample.py | 3 --- src/haven/tests/test_robot_sample.py | 1 - 2 files changed, 4 deletions(-) diff --git a/src/haven/plans/robot_sample.py b/src/haven/plans/robot_sample.py index b2535fc9..fa7df161 100644 --- a/src/haven/plans/robot_sample.py +++ b/src/haven/plans/robot_sample.py @@ -1,10 +1,7 @@ import logging -import warnings from bluesky import plan_stubs as bps -from ophyd import DeviceStatus -from ..instrument.robot import Robot, load_robot from ..instrument.instrument_registry import registry from ..motor_position import rbv diff --git a/src/haven/tests/test_robot_sample.py b/src/haven/tests/test_robot_sample.py index 2a4a6a53..04e19db2 100644 --- a/src/haven/tests/test_robot_sample.py +++ b/src/haven/tests/test_robot_sample.py @@ -1,4 +1,3 @@ -import pytest from ophyd.sim import motor1, motor2, motor3 from pprint import pprint From 0367c7681e3c8c1c03a022b15b4d53b698ae6b28 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Fri, 8 Mar 2024 11:32:02 -0600 Subject: [PATCH 05/21] isort the new files --- src/haven/plans/robot_sample.py | 1 - src/haven/tests/test_robot_sample.py | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/haven/plans/robot_sample.py b/src/haven/plans/robot_sample.py index fa7df161..c5c85125 100644 --- a/src/haven/plans/robot_sample.py +++ b/src/haven/plans/robot_sample.py @@ -5,7 +5,6 @@ from ..instrument.instrument_registry import registry from ..motor_position import rbv - log = logging.getLogger(__name__) diff --git a/src/haven/tests/test_robot_sample.py b/src/haven/tests/test_robot_sample.py index 04e19db2..7fc0f6d1 100644 --- a/src/haven/tests/test_robot_sample.py +++ b/src/haven/tests/test_robot_sample.py @@ -1,6 +1,7 @@ -from ophyd.sim import motor1, motor2, motor3 from pprint import pprint +from ophyd.sim import motor1, motor2, motor3 + from haven import robot_sample From e2c970f3428e977d8556aa1d9a942e23de1e5d54 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Fri, 8 Mar 2024 11:35:45 -0600 Subject: [PATCH 06/21] isort conftest --- src/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conftest.py b/src/conftest.py index 6029586f..48a0811d 100644 --- a/src/conftest.py +++ b/src/conftest.py @@ -30,11 +30,11 @@ from haven.instrument.dxp import DxpDetector from haven.instrument.dxp import add_mcas as add_dxp_mcas from haven.instrument.ion_chamber import IonChamber +from haven.instrument.robot import Robot from haven.instrument.shutter import Shutter from haven.instrument.slits import ApertureSlits, BladeSlits from haven.instrument.xspress import Xspress3Detector from haven.instrument.xspress import add_mcas as add_xspress_mcas -from haven.instrument.robot import Robot top_dir = Path(__file__).parent.resolve() haven_dir = top_dir / "haven" From afd066a871efc0e54e3ab87cdeb9c8996c24958d Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Fri, 8 Mar 2024 11:46:06 -0600 Subject: [PATCH 07/21] Update int --- src/haven/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/haven/__init__.py b/src/haven/__init__.py index 105f65c5..9043e08b 100644 --- a/src/haven/__init__.py +++ b/src/haven/__init__.py @@ -39,6 +39,7 @@ from .plans.mono_gap_calibration import calibrate_mono_gap # noqa: F401 from .plans.mono_ID_calibration import mono_ID_calibration # noqa: F401 from .plans.record_dark_current import record_dark_current # noqa: F401 +from .plans.robot_sample import robot_sample from .plans.set_energy import set_energy # noqa: F401 from .plans.shutters import close_shutters, open_shutters # noqa: F401 from .plans.xafs_scan import xafs_scan # noqa: F401 From 0ce009a5027523b6d51d5a3f2981366374a880f9 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Fri, 8 Mar 2024 13:28:12 -0600 Subject: [PATCH 08/21] update init file --- src/haven/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/haven/__init__.py b/src/haven/__init__.py index 9043e08b..5cd4a433 100644 --- a/src/haven/__init__.py +++ b/src/haven/__init__.py @@ -39,7 +39,7 @@ from .plans.mono_gap_calibration import calibrate_mono_gap # noqa: F401 from .plans.mono_ID_calibration import mono_ID_calibration # noqa: F401 from .plans.record_dark_current import record_dark_current # noqa: F401 -from .plans.robot_sample import robot_sample +from .plans.robot_sample import robot_sample #noqa:F401 from .plans.set_energy import set_energy # noqa: F401 from .plans.shutters import close_shutters, open_shutters # noqa: F401 from .plans.xafs_scan import xafs_scan # noqa: F401 From ba8df982c6f1e5324e63187bd1f2985526743469 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Fri, 8 Mar 2024 13:45:37 -0600 Subject: [PATCH 09/21] Ignore the import using # noqa: F401 --- src/haven/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/haven/__init__.py b/src/haven/__init__.py index 5cd4a433..c7a3da4e 100644 --- a/src/haven/__init__.py +++ b/src/haven/__init__.py @@ -39,7 +39,7 @@ from .plans.mono_gap_calibration import calibrate_mono_gap # noqa: F401 from .plans.mono_ID_calibration import mono_ID_calibration # noqa: F401 from .plans.record_dark_current import record_dark_current # noqa: F401 -from .plans.robot_sample import robot_sample #noqa:F401 +from .plans.robot_samp import robot_sample # noqa: F401 from .plans.set_energy import set_energy # noqa: F401 from .plans.shutters import close_shutters, open_shutters # noqa: F401 from .plans.xafs_scan import xafs_scan # noqa: F401 From 1635270480075f0591a3bea08ecf62f627dfcf41 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Fri, 8 Mar 2024 14:10:20 -0600 Subject: [PATCH 10/21] black and isort again --- src/haven/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/haven/__init__.py b/src/haven/__init__.py index c7a3da4e..392ffbc9 100644 --- a/src/haven/__init__.py +++ b/src/haven/__init__.py @@ -39,7 +39,7 @@ from .plans.mono_gap_calibration import calibrate_mono_gap # noqa: F401 from .plans.mono_ID_calibration import mono_ID_calibration # noqa: F401 from .plans.record_dark_current import record_dark_current # noqa: F401 -from .plans.robot_samp import robot_sample # noqa: F401 +from .plans.robot_samp import robot_sample # noqa: F401 from .plans.set_energy import set_energy # noqa: F401 from .plans.shutters import close_shutters, open_shutters # noqa: F401 from .plans.xafs_scan import xafs_scan # noqa: F401 From 44826ee6c43efb6e767335038431ec775cd8e5c4 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Fri, 8 Mar 2024 14:33:03 -0600 Subject: [PATCH 11/21] Update init file --- src/haven/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/haven/__init__.py b/src/haven/__init__.py index 392ffbc9..71a84219 100644 --- a/src/haven/__init__.py +++ b/src/haven/__init__.py @@ -39,7 +39,7 @@ from .plans.mono_gap_calibration import calibrate_mono_gap # noqa: F401 from .plans.mono_ID_calibration import mono_ID_calibration # noqa: F401 from .plans.record_dark_current import record_dark_current # noqa: F401 -from .plans.robot_samp import robot_sample # noqa: F401 +from .plans.robot_sample import robot_sample # noqa: F401 from .plans.set_energy import set_energy # noqa: F401 from .plans.shutters import close_shutters, open_shutters # noqa: F401 from .plans.xafs_scan import xafs_scan # noqa: F401 From 7e4f6b3d890f65fc9d243e31220d2f50a8b2515b Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Thu, 14 Mar 2024 09:25:11 -0500 Subject: [PATCH 12/21] Add unload_current_sample in the the plan robot_transfer_sample --- src/haven/plans/robot_transfer_sample.py | 97 +++++++++++++++++++ src/haven/tests/test_robot_transfer_sample.py | 47 +++++++++ 2 files changed, 144 insertions(+) create mode 100644 src/haven/plans/robot_transfer_sample.py create mode 100644 src/haven/tests/test_robot_transfer_sample.py diff --git a/src/haven/plans/robot_transfer_sample.py b/src/haven/plans/robot_transfer_sample.py new file mode 100644 index 00000000..08c34c41 --- /dev/null +++ b/src/haven/plans/robot_transfer_sample.py @@ -0,0 +1,97 @@ +import logging + +from bluesky import plan_stubs as bps + +from ..instrument.instrument_registry import registry +from ..motor_position import rbv + +log = logging.getLogger(__name__) + + +__all__ = ["robot_sample"] + + +def robot_transfer_sample(robot, sampleN, *args): + """ + Use robot to load sampleN at a fixed Aerotech stage position or any + motors. + + e.g. + robot_sample(robot, 9, motor1, 100, motor2, 200, motor3, 50) + + Parameters: + - robot: robot device + - sampleN: Sample number + - *args: multiple pairs of motor and pos + """ + + robot = registry.find(robot) + + # Check if power is on + # if robot.power_rbv.get() == Off: + # raise ValueError("Robot is NOT powered. Please turn on the power.") + + # Check if remote control is on + # if not robot.remote_control.get() == Off: + # raise ValueError( + # "Robot is NOT in reomete control mode. Please click on Pad for remote control." + # ) + + # Check if gripper is on + # if robot.gripper_activated.get() == Off: + # raise ValueError("Gripper is not activated. Please activate the gripper.") + + # Check if robot is running + # if robot.grogram_running.get() == On: + # raise ValueError("Robot is running now.") + + # Find motors + motor_list = [registry.find(motor) for motor in args[::2]] + new_positions = [pos for pos in args[1::2]] + # Record the motor positions before load sampls + initial_positions = [rbv(motor) for motor in motor_list] + + # Move the aerotech to the loading position + for motor, pos in zip(motor_list, new_positions): + yield from bps.mv(motor, pos) + + if sampleN == None: + # Unload sample + yield from bps.mv(robot.unload_current_sample, 1) + + else: + # Load sampleN after all the other motor arrive at (pos1, pos2, pos3...) + sample = getattr( + robot.samples, f"sample{sampleN}" + ) # Access the Sample device corresponding to sampleN + yield from bps.mv(sample.load, 1) # Assuming '1' initiates the loading action + + # Return to the initial position + for motor, pos in zip(motor_list[-1::-1], initial_positions[-1::-1]): + yield from bps.mv(motor, pos) + + +# ----------------------------------------------------------------------------- +# :author: Yanna Chen +# :email: yannachen@anl.gov +# :copyright: Copyright © 2024, UChicago Argonne, LLC +# +# Distributed under the terms of the 3-Clause BSD License +# +# The full license is in the file LICENSE, distributed with this software. +# +# DISCLAIMER +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ----------------------------------------------------------------------------- diff --git a/src/haven/tests/test_robot_transfer_sample.py b/src/haven/tests/test_robot_transfer_sample.py new file mode 100644 index 00000000..5f6bed36 --- /dev/null +++ b/src/haven/tests/test_robot_transfer_sample.py @@ -0,0 +1,47 @@ +from pprint import pprint + +from ophyd.sim import motor1, motor2, motor3 + +from haven import robot_transfer_sample + + +def test_robot_sample(robot): + + plan = robot_transfer_sample(robot, 9, motor1, 100, motor2, 200, motor3, 50) + + msgs = list(plan) + pprint(msgs) + + assert robot.name == "robotA" + assert len(msgs) == 14 + + unload = robot_transfer_sample(robot, None, motor1, 100) + msgs = list(unload) + pprint(msgs) + assert len(msgs) == 6 + + +# ----------------------------------------------------------------------------- +# :author: Yanna Chen +# :email: yannachen@anl.gov +# :copyright: Copyright © 2024, UChicago Argonne, LLC +# +# Distributed under the terms of the 3-Clause BSD License +# +# The full license is in the file LICENSE, distributed with this software. +# +# DISCLAIMER +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ----------------------------------------------------------------------------- From da9052e73139b0f6748031fddad579193d040649 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Thu, 14 Mar 2024 09:29:02 -0500 Subject: [PATCH 13/21] Add robot_transfer_sample into init --- src/haven/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/haven/__init__.py b/src/haven/__init__.py index 71a84219..6f3954f6 100644 --- a/src/haven/__init__.py +++ b/src/haven/__init__.py @@ -39,7 +39,7 @@ from .plans.mono_gap_calibration import calibrate_mono_gap # noqa: F401 from .plans.mono_ID_calibration import mono_ID_calibration # noqa: F401 from .plans.record_dark_current import record_dark_current # noqa: F401 -from .plans.robot_sample import robot_sample # noqa: F401 +from .plans.robot_transfer_sample import robot_transfer_sample # noqa: F401 from .plans.set_energy import set_energy # noqa: F401 from .plans.shutters import close_shutters, open_shutters # noqa: F401 from .plans.xafs_scan import xafs_scan # noqa: F401 From a5de820c4ad3efb1b6b77e83b5e4f126349dc087 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Thu, 14 Mar 2024 09:35:10 -0500 Subject: [PATCH 14/21] Get rid of debugging print statement --- src/haven/tests/test_robot_transfer_sample.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/haven/tests/test_robot_transfer_sample.py b/src/haven/tests/test_robot_transfer_sample.py index 5f6bed36..12c55fdf 100644 --- a/src/haven/tests/test_robot_transfer_sample.py +++ b/src/haven/tests/test_robot_transfer_sample.py @@ -10,14 +10,14 @@ def test_robot_sample(robot): plan = robot_transfer_sample(robot, 9, motor1, 100, motor2, 200, motor3, 50) msgs = list(plan) - pprint(msgs) + #pprint(msgs) assert robot.name == "robotA" assert len(msgs) == 14 unload = robot_transfer_sample(robot, None, motor1, 100) msgs = list(unload) - pprint(msgs) + #pprint(msgs) assert len(msgs) == 6 From 5b2f3f7e9d22bfa5b0983a91a61ab28e5a80cc4f Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Thu, 14 Mar 2024 09:38:31 -0500 Subject: [PATCH 15/21] Update __all__ --- src/haven/plans/robot_transfer_sample.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/haven/plans/robot_transfer_sample.py b/src/haven/plans/robot_transfer_sample.py index 08c34c41..4a833ccf 100644 --- a/src/haven/plans/robot_transfer_sample.py +++ b/src/haven/plans/robot_transfer_sample.py @@ -8,7 +8,7 @@ log = logging.getLogger(__name__) -__all__ = ["robot_sample"] +__all__ = ["robot_transfer_sample"] def robot_transfer_sample(robot, sampleN, *args): From 22c173f125588571dc9539833ab2136b55b9ccf2 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Thu, 14 Mar 2024 09:55:58 -0500 Subject: [PATCH 16/21] delete unused import --- src/haven/tests/test_robot_transfer_sample.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/haven/tests/test_robot_transfer_sample.py b/src/haven/tests/test_robot_transfer_sample.py index 12c55fdf..6bf88d3c 100644 --- a/src/haven/tests/test_robot_transfer_sample.py +++ b/src/haven/tests/test_robot_transfer_sample.py @@ -1,5 +1,3 @@ -from pprint import pprint - from ophyd.sim import motor1, motor2, motor3 from haven import robot_transfer_sample @@ -10,14 +8,12 @@ def test_robot_sample(robot): plan = robot_transfer_sample(robot, 9, motor1, 100, motor2, 200, motor3, 50) msgs = list(plan) - #pprint(msgs) assert robot.name == "robotA" assert len(msgs) == 14 unload = robot_transfer_sample(robot, None, motor1, 100) msgs = list(unload) - #pprint(msgs) assert len(msgs) == 6 From ee090f617d9f6af786bfea3098606a18a6aa5162 Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Thu, 14 Mar 2024 10:00:30 -0500 Subject: [PATCH 17/21] Format heater.py --- src/haven/instrument/heater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/haven/instrument/heater.py b/src/haven/instrument/heater.py index e6bb47a6..8197f813 100644 --- a/src/haven/instrument/heater.py +++ b/src/haven/instrument/heater.py @@ -4,7 +4,7 @@ from apstools.devices import PTC10AioChannel as PTC10AioChannelBase from apstools.devices import PTC10PositionerMixin, PTC10TcChannel from ophyd import Component as Cpt -from ophyd import EpicsSignalRO, EpicsSignalWithRBV, PVPositioner, EpicsSignal +from ophyd import EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV, PVPositioner from .._iconfig import load_config from .device import aload_devices, make_device From ffc1270fcb5f99615857f8d4aa547deb3dcf18ef Mon Sep 17 00:00:00 2001 From: Yanna Chen Date: Thu, 14 Mar 2024 10:09:38 -0500 Subject: [PATCH 18/21] remove old files --- src/haven/plans/robot_sample.py | 92 ---------------------------- src/haven/tests/test_robot_sample.py | 42 ------------- 2 files changed, 134 deletions(-) delete mode 100644 src/haven/plans/robot_sample.py delete mode 100644 src/haven/tests/test_robot_sample.py diff --git a/src/haven/plans/robot_sample.py b/src/haven/plans/robot_sample.py deleted file mode 100644 index c5c85125..00000000 --- a/src/haven/plans/robot_sample.py +++ /dev/null @@ -1,92 +0,0 @@ -import logging - -from bluesky import plan_stubs as bps - -from ..instrument.instrument_registry import registry -from ..motor_position import rbv - -log = logging.getLogger(__name__) - - -__all__ = ["robot_sample"] - - -def robot_sample(robot, sampleN, *args): - """ - Use robot to load sampleN at a fixed Aerotech stage position or any - motors. - - e.g. - robot_sample(robot, 9, motor1, 100, motor2, 200, motor3, 50) - - Parameters: - - robot: robot device - - sampleN: Sample number - - *args: multiple pairs of motor and pos - """ - - robot = registry.find(robot) - - # Check if power is on - # if robot.power_rbv.get() == Off: - # raise ValueError("Robot is NOT powered. Please turn on the power.") - - # Check if remote control is on - # if not robot.remote_control.get() == Off: - # raise ValueError( - # "Robot is NOT in reomete control mode. Please click on Pad for remote control." - # ) - - # Check if gripper is on - # if robot.gripper_activated.get() == Off: - # raise ValueError("Gripper is not activated. Please activate the gripper.") - - # Check if robot is running - # if robot.grogram_running.get() == On: - # raise ValueError("Robot is running now.") - - # Find motors - motor_list = [registry.find(motor) for motor in args[::2]] - - # Record the motor positions before load sampls - initial_positions = [rbv(motor) for motor in motor_list] - - # Move the aerotech to the loading position - for motor, pos in zip(args[::2], args[1::2]): - yield from bps.mv(motor, pos) - - # Load sampleN after all the other motor arrive at (pos1, pos2, pos3...) - sample = getattr( - robot.samples, f"sample{sampleN}" - ) # Access the Sample device corresponding to sampleN - yield from bps.mv(sample.load, 1) # Assuming '1' initiates the loading action - - # Return to the initial position - for motor, pos in zip(motor_list[-1::-1], initial_positions[-1::-1]): - yield from bps.mv(motor, pos) - - -# ----------------------------------------------------------------------------- -# :author: Yanna Chen -# :email: yannachen@anl.gov -# :copyright: Copyright © 2024, UChicago Argonne, LLC -# -# Distributed under the terms of the 3-Clause BSD License -# -# The full license is in the file LICENSE, distributed with this software. -# -# DISCLAIMER -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# ----------------------------------------------------------------------------- diff --git a/src/haven/tests/test_robot_sample.py b/src/haven/tests/test_robot_sample.py deleted file mode 100644 index 7fc0f6d1..00000000 --- a/src/haven/tests/test_robot_sample.py +++ /dev/null @@ -1,42 +0,0 @@ -from pprint import pprint - -from ophyd.sim import motor1, motor2, motor3 - -from haven import robot_sample - - -def test_robot_sample(robot): - - plan = robot_sample(robot, 9, motor1, 100, motor2, 200, motor3, 50) - - msgs = list(plan) - pprint(msgs) - - assert robot.name == "robotA" - assert len(msgs) == 14 - - -# ----------------------------------------------------------------------------- -# :author: Yanna Chen -# :email: yannachen@anl.gov -# :copyright: Copyright © 2024, UChicago Argonne, LLC -# -# Distributed under the terms of the 3-Clause BSD License -# -# The full license is in the file LICENSE, distributed with this software. -# -# DISCLAIMER -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# ----------------------------------------------------------------------------- From 4022cb9c2e1108c5691d3a19aa607dece3fc9c37 Mon Sep 17 00:00:00 2001 From: Sector 25 ID-C User Date: Thu, 21 Mar 2024 12:32:56 -0500 Subject: [PATCH 19/21] Add write_timeout --- src/haven/instrument/robot.py | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/haven/instrument/robot.py b/src/haven/instrument/robot.py index 13aac589..dfd2af92 100644 --- a/src/haven/instrument/robot.py +++ b/src/haven/instrument/robot.py @@ -12,11 +12,37 @@ log = logging.getLogger(__name__) +LOAD_TIMEOUT = 40 + + class Sample(Device): + """An individual robot sample that can be loaded. + + Signals + ======= + present + Whether or not a sample is physically present on the stage. + empty + Whether or not no sample is physically present on the stage. + load + Direct the robot to physically move this sample to the loading + position. Can be slow (~25-30 seconds). + unload + Direct the robot to physically remove this sample to the loading + position. Can be slow (~25-30 seconds). + x + The x position of the robot in Cartesian coordinates. + y + z + rx + ry + rz + + """ present = Cpt(EpicsSignalRO, ":present") empty = Cpt(EpicsSignalRO, ":empty") - load = Cpt(EpicsSignal, ":load", kind="omitted") - unload = Cpt(EpicsSignal, ":unload", kind="omitted") + load = Cpt(EpicsSignal, ":load", kind="omitted", write_timeout=LOAD_TIMEOUT, put_complete=True) + unload = Cpt(EpicsSignal, ":unload", kind="omitted", write_timeout=LOAD_TIMEOUT, put_complete=True) x = Cpt(EpicsSignalRO, ":x") y = Cpt(EpicsSignalRO, ":y") z = Cpt(EpicsSignalRO, ":z") @@ -94,7 +120,7 @@ class Robot(Device): # sample transfer current_sample = Cpt(EpicsSignalRO, ":current_sample", kind="config") - unload_current_sample = Cpt(EpicsSignal, ":unload_current_sample", kind="omitted") + unload_current_sample = Cpt(EpicsSignal, ":unload_current_sample", kind="omitted", write_timeout=LOAD_TIMEOUT, put_complete=True) current_sample_reset = Cpt(EpicsSignal, ":current_sample_reset", kind="omitted") home = Cpt(EpicsSignal, ":home", kind="config") cal_stage = Cpt(EpicsSignal, ":cal_stage", kind="config") From aa04419ccd587c8c9b3febfbe3aabde5b1164e34 Mon Sep 17 00:00:00 2001 From: yannachen Date: Thu, 21 Mar 2024 13:54:25 -0500 Subject: [PATCH 20/21] Update the docstring --- src/haven/instrument/robot.py | 5 +++++ src/haven/plans/robot_transfer_sample.py | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/haven/instrument/robot.py b/src/haven/instrument/robot.py index dfd2af92..acc01604 100644 --- a/src/haven/instrument/robot.py +++ b/src/haven/instrument/robot.py @@ -33,10 +33,15 @@ class Sample(Device): x The x position of the robot in Cartesian coordinates. y + The y position of the robot in Cartesian coordinates. z + The z position of the robot in Cartesian coordinates. rx + The rx position of the robot in Cartesian coordinates. ry + The ry position of the robot in Cartesian coordinates. rz + The position of the robot in Cartesian coordinates. """ present = Cpt(EpicsSignalRO, ":present") diff --git a/src/haven/plans/robot_transfer_sample.py b/src/haven/plans/robot_transfer_sample.py index 4a833ccf..bf3c8398 100644 --- a/src/haven/plans/robot_transfer_sample.py +++ b/src/haven/plans/robot_transfer_sample.py @@ -11,13 +11,20 @@ __all__ = ["robot_transfer_sample"] +ON = 1 + + def robot_transfer_sample(robot, sampleN, *args): """ Use robot to load sampleN at a fixed Aerotech stage position or any motors. e.g. + Load sample: robot_sample(robot, 9, motor1, 100, motor2, 200, motor3, 50) + + Unload sample: + robot_sample(robot, None, motor1, 100, motor2, 200, motor3, 50) Parameters: - robot: robot device @@ -57,14 +64,15 @@ def robot_transfer_sample(robot, sampleN, *args): if sampleN == None: # Unload sample - yield from bps.mv(robot.unload_current_sample, 1) + yield from bps.mv(robot.unload_current_sample, ON) else: # Load sampleN after all the other motor arrive at (pos1, pos2, pos3...) sample = getattr( robot.samples, f"sample{sampleN}" ) # Access the Sample device corresponding to sampleN - yield from bps.mv(sample.load, 1) # Assuming '1' initiates the loading action + print(sample.load) + yield from bps.mv(sample.load, ON) # Assuming '1' initiates the loading action # Return to the initial position for motor, pos in zip(motor_list[-1::-1], initial_positions[-1::-1]): From 4f9a7a53ed91c3809b35ba912edfaf27e779d757 Mon Sep 17 00:00:00 2001 From: yannachen Date: Thu, 21 Mar 2024 14:01:56 -0500 Subject: [PATCH 21/21] Formitting --- src/haven/instrument/robot.py | 25 +++++++++++++++++++++--- src/haven/plans/robot_transfer_sample.py | 2 +- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/haven/instrument/robot.py b/src/haven/instrument/robot.py index acc01604..87c3658b 100644 --- a/src/haven/instrument/robot.py +++ b/src/haven/instrument/robot.py @@ -44,10 +44,23 @@ class Sample(Device): The position of the robot in Cartesian coordinates. """ + present = Cpt(EpicsSignalRO, ":present") empty = Cpt(EpicsSignalRO, ":empty") - load = Cpt(EpicsSignal, ":load", kind="omitted", write_timeout=LOAD_TIMEOUT, put_complete=True) - unload = Cpt(EpicsSignal, ":unload", kind="omitted", write_timeout=LOAD_TIMEOUT, put_complete=True) + load = Cpt( + EpicsSignal, + ":load", + kind="omitted", + write_timeout=LOAD_TIMEOUT, + put_complete=True, + ) + unload = Cpt( + EpicsSignal, + ":unload", + kind="omitted", + write_timeout=LOAD_TIMEOUT, + put_complete=True, + ) x = Cpt(EpicsSignalRO, ":x") y = Cpt(EpicsSignalRO, ":y") z = Cpt(EpicsSignalRO, ":z") @@ -125,7 +138,13 @@ class Robot(Device): # sample transfer current_sample = Cpt(EpicsSignalRO, ":current_sample", kind="config") - unload_current_sample = Cpt(EpicsSignal, ":unload_current_sample", kind="omitted", write_timeout=LOAD_TIMEOUT, put_complete=True) + unload_current_sample = Cpt( + EpicsSignal, + ":unload_current_sample", + kind="omitted", + write_timeout=LOAD_TIMEOUT, + put_complete=True, + ) current_sample_reset = Cpt(EpicsSignal, ":current_sample_reset", kind="omitted") home = Cpt(EpicsSignal, ":home", kind="config") cal_stage = Cpt(EpicsSignal, ":cal_stage", kind="config") diff --git a/src/haven/plans/robot_transfer_sample.py b/src/haven/plans/robot_transfer_sample.py index bf3c8398..bfbaebe8 100644 --- a/src/haven/plans/robot_transfer_sample.py +++ b/src/haven/plans/robot_transfer_sample.py @@ -22,7 +22,7 @@ def robot_transfer_sample(robot, sampleN, *args): e.g. Load sample: robot_sample(robot, 9, motor1, 100, motor2, 200, motor3, 50) - + Unload sample: robot_sample(robot, None, motor1, 100, motor2, 200, motor3, 50)