From 05c09530e4bf7de45cdd507b5a913e33717d171b Mon Sep 17 00:00:00 2001 From: Sanniti Date: Tue, 2 May 2023 15:45:29 -0400 Subject: [PATCH 1/9] added gripper axes to MotorAxis and hardware Axis, updated mappers --- api/src/opentrons/hardware_control/types.py | 18 ++++++++++++------ .../protocol_engine/execution/gantry_mover.py | 2 ++ api/src/opentrons/protocol_engine/types.py | 2 ++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/api/src/opentrons/hardware_control/types.py b/api/src/opentrons/hardware_control/types.py index e61d5742b08..8967456face 100644 --- a/api/src/opentrons/hardware_control/types.py +++ b/api/src/opentrons/hardware_control/types.py @@ -30,12 +30,14 @@ class MotionChecks(enum.Enum): class Axis(enum.Enum): - X = 0 - Y = 1 - Z = 2 - A = 3 - B = 4 - C = 5 + X = 0 # Gantry X + Y = 1 # Gantry Y + Z = 2 # left pipette mount Z + A = 3 # right pipette mount Z + B = 4 # left pipette plunger + C = 5 # right pipette plunger + Z_G = 6 # Gripper Z + G = 7 # Gripper Jaws @classmethod def by_mount(cls, mount: top_types.Mount) -> "Axis": @@ -156,6 +158,8 @@ def from_axis(cls, axis: Union[Axis, "OT3Axis"]) -> "OT3Axis": Axis.A: cls.Z_R, Axis.B: cls.P_L, Axis.C: cls.P_R, + Axis.Z_G: cls.Z_G, + Axis.G: cls.G, } try: return am[axis] # type: ignore @@ -170,6 +174,8 @@ def to_axis(self) -> Axis: OT3Axis.Z_R: Axis.A, OT3Axis.P_L: Axis.B, OT3Axis.P_R: Axis.C, + OT3Axis.Z_G: Axis.Z_G, + OT3Axis.G: Axis.G, } return am[self] diff --git a/api/src/opentrons/protocol_engine/execution/gantry_mover.py b/api/src/opentrons/protocol_engine/execution/gantry_mover.py index f03035d8b73..75877a4deb3 100644 --- a/api/src/opentrons/protocol_engine/execution/gantry_mover.py +++ b/api/src/opentrons/protocol_engine/execution/gantry_mover.py @@ -22,6 +22,8 @@ MotorAxis.RIGHT_Z: HardwareAxis.A, MotorAxis.LEFT_PLUNGER: HardwareAxis.B, MotorAxis.RIGHT_PLUNGER: HardwareAxis.C, + MotorAxis.EXTENSION_Z: HardwareAxis.Z_G, + MotorAxis.EXTENSION_JAW: HardwareAxis.G, } # The height of the bottom of the pipette nozzle at home position without any tips. diff --git a/api/src/opentrons/protocol_engine/types.py b/api/src/opentrons/protocol_engine/types.py index 49e83c75667..d130ba71254 100644 --- a/api/src/opentrons/protocol_engine/types.py +++ b/api/src/opentrons/protocol_engine/types.py @@ -219,6 +219,8 @@ class MotorAxis(str, Enum): RIGHT_Z = "rightZ" LEFT_PLUNGER = "leftPlunger" RIGHT_PLUNGER = "rightPlunger" + EXTENSION_Z = "extensionZ" + EXTENSION_JAW = "extensionJaw" # TODO(mc, 2022-01-18): use opentrons_shared_data.module.dev_types.ModuleModel From a41bd3cfa50ad35d95e3f640dfee0056a7618660 Mon Sep 17 00:00:00 2001 From: Sanniti Date: Thu, 4 May 2023 17:51:39 -0400 Subject: [PATCH 2/9] use only ot2 axes and mounts for ot2's hardware controller --- api/src/opentrons/hardware_control/api.py | 3 +- .../hardware_control/backends/controller.py | 2 +- .../hardware_control/backends/simulator.py | 2 +- .../instruments/ot2/pipette_handler.py | 3 + api/src/opentrons/hardware_control/types.py | 8 + api/src/opentrons/types.py | 19 +- shared-data/command/schemas/7.json | 732 ++++++++++++++---- 7 files changed, 601 insertions(+), 168 deletions(-) diff --git a/api/src/opentrons/hardware_control/api.py b/api/src/opentrons/hardware_control/api.py index 4b07005021d..167c43894cc 100644 --- a/api/src/opentrons/hardware_control/api.py +++ b/api/src/opentrons/hardware_control/api.py @@ -571,9 +571,10 @@ async def home_plunger(self, mount: top_types.Mount) -> None: @ExecutionManagerProvider.wait_for_running async def home(self, axes: Optional[List[Axis]] = None) -> None: """Home the entire robot and initialize current position.""" + self._reset_last_mount() # Initialize/update current_position - checked_axes = axes or [ax for ax in Axis] + checked_axes = axes or [ax for ax in Axis.ot2_axes()] gantry = [ax for ax in checked_axes if ax in Axis.gantry_axes()] smoothie_gantry = [ax.name.upper() for ax in gantry] smoothie_pos = {} diff --git a/api/src/opentrons/hardware_control/backends/controller.py b/api/src/opentrons/hardware_control/backends/controller.py index f64b04a01d1..8fd9aa69415 100644 --- a/api/src/opentrons/hardware_control/backends/controller.py +++ b/api/src/opentrons/hardware_control/backends/controller.py @@ -221,7 +221,7 @@ async def get_attached_instruments( """ return { mount: await self._query_mount(mount, expected.get(mount)) - for mount in Mount + for mount in Mount.ot2_mounts() } def set_active_current(self, axis_currents: Dict[Axis, float]) -> None: diff --git a/api/src/opentrons/hardware_control/backends/simulator.py b/api/src/opentrons/hardware_control/backends/simulator.py index bc238783a08..a1126023c01 100644 --- a/api/src/opentrons/hardware_control/backends/simulator.py +++ b/api/src/opentrons/hardware_control/backends/simulator.py @@ -284,7 +284,7 @@ async def get_attached_instruments( """ return { mount: self._attached_to_mount(mount, expected.get(mount)) - for mount in types.Mount + for mount in types.Mount.ot2_mounts() } def set_active_current(self, axis_currents: Dict[Axis, float]) -> None: diff --git a/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py b/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py index 0c3a43090b9..fd2dfcd30ef 100644 --- a/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py +++ b/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py @@ -116,6 +116,9 @@ def reset_instrument(self, mount: Optional[MountType] = None) -> None: """ def _reset(m: MountType) -> None: + if isinstance(m, top_types.Mount) and m not in top_types.Mount.ot2_mounts(): + self._ihp_log.info("Received a non OT2 mount for resetting. Skipping") + return self._ihp_log.info(f"Resetting configuration for {m}") p = self._attached_instruments[m] if not p: diff --git a/api/src/opentrons/hardware_control/types.py b/api/src/opentrons/hardware_control/types.py index 8967456face..9869bb96fae 100644 --- a/api/src/opentrons/hardware_control/types.py +++ b/api/src/opentrons/hardware_control/types.py @@ -44,6 +44,7 @@ def by_mount(cls, mount: top_types.Mount) -> "Axis": bm = {top_types.Mount.LEFT: cls.Z, top_types.Mount.RIGHT: cls.A} return bm[mount] + # TODO (spp, 2023-5-4): deprecate this method & create a replacement called 'pipette_mount_axes' @classmethod def mount_axes(cls) -> Tuple["Axis", "Axis"]: """The axes which are used for moving pipettes up and down.""" @@ -68,12 +69,19 @@ def to_mount(cls, inst: "Axis") -> top_types.Mount: cls.A: top_types.Mount.RIGHT, cls.B: top_types.Mount.LEFT, cls.C: top_types.Mount.RIGHT, + cls.Z_G: top_types.Mount.EXTENSION, + cls.G: top_types.Mount.EXTENSION, }[inst] @classmethod def pipette_axes(cls) -> Tuple["Axis", "Axis"]: return cls.B, cls.C + @classmethod + def ot2_axes(cls) -> List["Axis"]: + """Returns only OT2 axes.""" + return [axis for axis in Axis if axis not in [Axis.Z_G, Axis.G]] + def __str__(self) -> str: return self.name diff --git a/api/src/opentrons/types.py b/api/src/opentrons/types.py index b3d7bb2447c..32b87820ac5 100644 --- a/api/src/opentrons/types.py +++ b/api/src/opentrons/types.py @@ -1,7 +1,7 @@ from __future__ import annotations import enum from math import sqrt, isclose -from typing import TYPE_CHECKING, Any, NamedTuple, Iterable, Union +from typing import TYPE_CHECKING, Any, NamedTuple, Iterable, Union, List from .protocols.api_support.labware_like import LabwareLike @@ -154,27 +154,40 @@ def __repr__(self) -> str: class Mount(enum.Enum): LEFT = enum.auto() RIGHT = enum.auto() + EXTENSION = enum.auto() def __str__(self) -> str: return self.name + @classmethod + def ot2_mounts(cls) -> List["Mount"]: + return [Mount.LEFT, Mount.RIGHT] + @classmethod def string_to_mount(cls, mount: str) -> "Mount": if mount == "right": return cls.RIGHT - else: + elif mount == "left": return cls.LEFT + else: + return cls.EXTENSION class MountType(str, enum.Enum): LEFT = "left" RIGHT = "right" + EXTENSION = "extension" + # TODO (spp, 2023-05-04): we should deprecate this and instead create an 'other_pipette_mount' method def other_mount(self) -> MountType: return MountType.LEFT if self is MountType.RIGHT else MountType.RIGHT def to_hw_mount(self) -> Mount: - return Mount.LEFT if self is MountType.LEFT else Mount.RIGHT + return { + MountType.LEFT: Mount.LEFT, + MountType.RIGHT: Mount.RIGHT, + MountType.EXTENSION: Mount.EXTENSION, + }[self] class OT3MountType(str, enum.Enum): diff --git a/shared-data/command/schemas/7.json b/shared-data/command/schemas/7.json index 1f9b9c6f12e..e47578d46ff 100644 --- a/shared-data/command/schemas/7.json +++ b/shared-data/command/schemas/7.json @@ -154,7 +154,11 @@ "WellOrigin": { "title": "WellOrigin", "description": "Origin of WellLocation offset.\n\nProps:\n TOP: the top-center of the well\n BOTTOM: the bottom-center of the well\n CENTER: the middle-center of the well", - "enum": ["top", "bottom", "center"], + "enum": [ + "top", + "bottom", + "center" + ], "type": "string" }, "WellOffset": { @@ -239,12 +243,21 @@ "type": "string" } }, - "required": ["labwareId", "wellName", "flowRate", "volume", "pipetteId"] + "required": [ + "labwareId", + "wellName", + "flowRate", + "volume", + "pipetteId" + ] }, "CommandIntent": { "title": "CommandIntent", "description": "Run intent for a given command.\n\nProps:\n PROTOCOL: the command is part of the protocol run itself.\n SETUP: the command is part of the setup phase of a run.", - "enum": ["protocol", "setup"], + "enum": [ + "protocol", + "setup" + ], "type": "string" }, "AspirateCreate": { @@ -255,7 +268,9 @@ "commandType": { "title": "Commandtype", "default": "aspirate", - "enum": ["aspirate"], + "enum": [ + "aspirate" + ], "type": "string" }, "params": { @@ -275,7 +290,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "AspirateInPlaceParams": { "title": "AspirateInPlaceParams", @@ -300,7 +317,11 @@ "type": "string" } }, - "required": ["flowRate", "volume", "pipetteId"] + "required": [ + "flowRate", + "volume", + "pipetteId" + ] }, "AspirateInPlaceCreate": { "title": "AspirateInPlaceCreate", @@ -310,7 +331,9 @@ "commandType": { "title": "Commandtype", "default": "aspirateInPlace", - "enum": ["aspirateInPlace"], + "enum": [ + "aspirateInPlace" + ], "type": "string" }, "params": { @@ -330,7 +353,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "CommentParams": { "title": "CommentParams", @@ -343,7 +368,9 @@ "type": "string" } }, - "required": ["message"] + "required": [ + "message" + ] }, "CommentCreate": { "title": "CommentCreate", @@ -353,7 +380,9 @@ "commandType": { "title": "Commandtype", "default": "comment", - "enum": ["comment"], + "enum": [ + "comment" + ], "type": "string" }, "params": { @@ -373,7 +402,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "CustomParams": { "title": "CustomParams", @@ -389,7 +420,9 @@ "commandType": { "title": "Commandtype", "default": "custom", - "enum": ["custom"], + "enum": [ + "custom" + ], "type": "string" }, "params": { @@ -409,7 +442,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "DispenseParams": { "title": "DispenseParams", @@ -453,7 +488,13 @@ "type": "string" } }, - "required": ["labwareId", "wellName", "flowRate", "volume", "pipetteId"] + "required": [ + "labwareId", + "wellName", + "flowRate", + "volume", + "pipetteId" + ] }, "DispenseCreate": { "title": "DispenseCreate", @@ -463,7 +504,9 @@ "commandType": { "title": "Commandtype", "default": "dispense", - "enum": ["dispense"], + "enum": [ + "dispense" + ], "type": "string" }, "params": { @@ -483,7 +526,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "DispenseInPlaceParams": { "title": "DispenseInPlaceParams", @@ -508,7 +553,11 @@ "type": "string" } }, - "required": ["flowRate", "volume", "pipetteId"] + "required": [ + "flowRate", + "volume", + "pipetteId" + ] }, "DispenseInPlaceCreate": { "title": "DispenseInPlaceCreate", @@ -518,7 +567,9 @@ "commandType": { "title": "Commandtype", "default": "dispenseInPlace", - "enum": ["dispenseInPlace"], + "enum": [ + "dispenseInPlace" + ], "type": "string" }, "params": { @@ -538,7 +589,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "BlowOutParams": { "title": "BlowOutParams", @@ -576,7 +629,12 @@ "type": "string" } }, - "required": ["labwareId", "wellName", "flowRate", "pipetteId"] + "required": [ + "labwareId", + "wellName", + "flowRate", + "pipetteId" + ] }, "BlowOutCreate": { "title": "BlowOutCreate", @@ -586,7 +644,9 @@ "commandType": { "title": "Commandtype", "default": "blowout", - "enum": ["blowout"], + "enum": [ + "blowout" + ], "type": "string" }, "params": { @@ -606,7 +666,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "BlowOutInPlaceParams": { "title": "BlowOutInPlaceParams", @@ -625,7 +687,10 @@ "type": "string" } }, - "required": ["flowRate", "pipetteId"] + "required": [ + "flowRate", + "pipetteId" + ] }, "BlowOutInPlaceCreate": { "title": "BlowOutInPlaceCreate", @@ -635,7 +700,9 @@ "commandType": { "title": "Commandtype", "default": "blowOutInPlace", - "enum": ["blowOutInPlace"], + "enum": [ + "blowOutInPlace" + ], "type": "string" }, "params": { @@ -655,12 +722,19 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "DropTipWellOrigin": { "title": "DropTipWellOrigin", "description": "The origin of a DropTipWellLocation offset.\n\nProps:\n TOP: the top-center of the well\n BOTTOM: the bottom-center of the well\n CENTER: the middle-center of the well\n DEFAULT: the default drop-tip location of the well,\n based on pipette configuration and length of the tip.", - "enum": ["top", "bottom", "center", "default"], + "enum": [ + "top", + "bottom", + "center", + "default" + ], "type": "string" }, "DropTipWellLocation": { @@ -716,7 +790,11 @@ "type": "boolean" } }, - "required": ["pipetteId", "labwareId", "wellName"] + "required": [ + "pipetteId", + "labwareId", + "wellName" + ] }, "DropTipCreate": { "title": "DropTipCreate", @@ -726,7 +804,9 @@ "commandType": { "title": "Commandtype", "default": "dropTip", - "enum": ["dropTip"], + "enum": [ + "dropTip" + ], "type": "string" }, "params": { @@ -746,12 +826,23 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "MotorAxis": { "title": "MotorAxis", "description": "Motor axis on which to issue a home command.", - "enum": ["x", "y", "leftZ", "rightZ", "leftPlunger", "rightPlunger"], + "enum": [ + "x", + "y", + "leftZ", + "rightZ", + "leftPlunger", + "rightPlunger", + "extensionZ", + "extensionJaw" + ], "type": "string" }, "HomeParams": { @@ -776,7 +867,9 @@ "commandType": { "title": "Commandtype", "default": "home", - "enum": ["home"], + "enum": [ + "home" + ], "type": "string" }, "params": { @@ -796,12 +889,27 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "DeckSlotName": { "title": "DeckSlotName", "description": "Deck slot identifiers.", - "enum": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"] + "enum": [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12" + ] }, "DeckSlotLocation": { "title": "DeckSlotLocation", @@ -812,7 +920,9 @@ "$ref": "#/definitions/DeckSlotName" } }, - "required": ["slotName"] + "required": [ + "slotName" + ] }, "ModuleLocation": { "title": "ModuleLocation", @@ -825,7 +935,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "LoadLabwareParams": { "title": "LoadLabwareParams", @@ -843,7 +955,9 @@ "$ref": "#/definitions/ModuleLocation" }, { - "enum": ["offDeck"], + "enum": [ + "offDeck" + ], "type": "string" } ] @@ -874,7 +988,12 @@ "type": "string" } }, - "required": ["location", "loadName", "namespace", "version"] + "required": [ + "location", + "loadName", + "namespace", + "version" + ] }, "LoadLabwareCreate": { "title": "LoadLabwareCreate", @@ -884,7 +1003,9 @@ "commandType": { "title": "Commandtype", "default": "loadLabware", - "enum": ["loadLabware"], + "enum": [ + "loadLabware" + ], "type": "string" }, "params": { @@ -904,7 +1025,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "LoadLiquidParams": { "title": "LoadLiquidParams", @@ -930,7 +1053,11 @@ } } }, - "required": ["liquidId", "labwareId", "volumeByWell"] + "required": [ + "liquidId", + "labwareId", + "volumeByWell" + ] }, "LoadLiquidCreate": { "title": "LoadLiquidCreate", @@ -940,7 +1067,9 @@ "commandType": { "title": "Commandtype", "default": "loadLiquid", - "enum": ["loadLiquid"], + "enum": [ + "loadLiquid" + ], "type": "string" }, "params": { @@ -960,7 +1089,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "ModuleModel": { "title": "ModuleModel", @@ -1004,7 +1135,10 @@ "type": "string" } }, - "required": ["model", "location"] + "required": [ + "model", + "location" + ] }, "LoadModuleCreate": { "title": "LoadModuleCreate", @@ -1014,7 +1148,9 @@ "commandType": { "title": "Commandtype", "default": "loadModule", - "enum": ["loadModule"], + "enum": [ + "loadModule" + ], "type": "string" }, "params": { @@ -1034,7 +1170,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "PipetteNameType": { "title": "PipetteNameType", @@ -1062,7 +1200,11 @@ "MountType": { "title": "MountType", "description": "An enumeration.", - "enum": ["left", "right"], + "enum": [ + "left", + "right", + "extension" + ], "type": "string" }, "LoadPipetteParams": { @@ -1078,7 +1220,9 @@ "$ref": "#/definitions/PipetteNameType" }, { - "enum": ["p1000_96"], + "enum": [ + "p1000_96" + ], "type": "string" } ] @@ -1097,7 +1241,10 @@ "type": "string" } }, - "required": ["pipetteName", "mount"] + "required": [ + "pipetteName", + "mount" + ] }, "LoadPipetteCreate": { "title": "LoadPipetteCreate", @@ -1107,7 +1254,9 @@ "commandType": { "title": "Commandtype", "default": "loadPipette", - "enum": ["loadPipette"], + "enum": [ + "loadPipette" + ], "type": "string" }, "params": { @@ -1127,12 +1276,18 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "LabwareMovementStrategy": { "title": "LabwareMovementStrategy", "description": "Strategy to use for labware movement.", - "enum": ["usingGripper", "manualMoveWithPause", "manualMoveWithoutPause"], + "enum": [ + "usingGripper", + "manualMoveWithPause", + "manualMoveWithoutPause" + ], "type": "string" }, "LabwareOffsetVector": { @@ -1153,7 +1308,11 @@ "type": "number" } }, - "required": ["x", "y", "z"] + "required": [ + "x", + "y", + "z" + ] }, "MoveLabwareParams": { "title": "MoveLabwareParams", @@ -1176,7 +1335,9 @@ "$ref": "#/definitions/ModuleLocation" }, { - "enum": ["offDeck"], + "enum": [ + "offDeck" + ], "type": "string" } ] @@ -1220,7 +1381,11 @@ ] } }, - "required": ["labwareId", "newLocation", "strategy"] + "required": [ + "labwareId", + "newLocation", + "strategy" + ] }, "MoveLabwareCreate": { "title": "MoveLabwareCreate", @@ -1230,7 +1395,9 @@ "commandType": { "title": "Commandtype", "default": "moveLabware", - "enum": ["moveLabware"], + "enum": [ + "moveLabware" + ], "type": "string" }, "params": { @@ -1250,12 +1417,18 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "MovementAxis": { "title": "MovementAxis", "description": "Axis on which to issue a relative movement.", - "enum": ["x", "y", "z"], + "enum": [ + "x", + "y", + "z" + ], "type": "string" }, "MoveRelativeParams": { @@ -1282,7 +1455,11 @@ "type": "number" } }, - "required": ["pipetteId", "axis", "distance"] + "required": [ + "pipetteId", + "axis", + "distance" + ] }, "MoveRelativeCreate": { "title": "MoveRelativeCreate", @@ -1292,7 +1469,9 @@ "commandType": { "title": "Commandtype", "default": "moveRelative", - "enum": ["moveRelative"], + "enum": [ + "moveRelative" + ], "type": "string" }, "params": { @@ -1312,7 +1491,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "DeckPoint": { "title": "DeckPoint", @@ -1332,7 +1513,11 @@ "type": "number" } }, - "required": ["x", "y", "z"] + "required": [ + "x", + "y", + "z" + ] }, "MoveToCoordinatesParams": { "title": "MoveToCoordinatesParams", @@ -1370,7 +1555,10 @@ ] } }, - "required": ["pipetteId", "coordinates"] + "required": [ + "pipetteId", + "coordinates" + ] }, "MoveToCoordinatesCreate": { "title": "MoveToCoordinatesCreate", @@ -1380,7 +1568,9 @@ "commandType": { "title": "Commandtype", "default": "moveToCoordinates", - "enum": ["moveToCoordinates"], + "enum": [ + "moveToCoordinates" + ], "type": "string" }, "params": { @@ -1400,7 +1590,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "MoveToWellParams": { "title": "MoveToWellParams", @@ -1448,7 +1640,11 @@ "type": "string" } }, - "required": ["labwareId", "wellName", "pipetteId"] + "required": [ + "labwareId", + "wellName", + "pipetteId" + ] }, "MoveToWellCreate": { "title": "MoveToWellCreate", @@ -1458,7 +1654,9 @@ "commandType": { "title": "Commandtype", "default": "moveToWell", - "enum": ["moveToWell"], + "enum": [ + "moveToWell" + ], "type": "string" }, "params": { @@ -1478,7 +1676,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "WaitForResumeParams": { "title": "WaitForResumeParams", @@ -1500,7 +1700,10 @@ "commandType": { "title": "Commandtype", "default": "waitForResume", - "enum": ["waitForResume", "pause"], + "enum": [ + "waitForResume", + "pause" + ], "type": "string" }, "params": { @@ -1520,7 +1723,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "WaitForDurationParams": { "title": "WaitForDurationParams", @@ -1538,7 +1743,9 @@ "type": "string" } }, - "required": ["seconds"] + "required": [ + "seconds" + ] }, "WaitForDurationCreate": { "title": "WaitForDurationCreate", @@ -1548,7 +1755,9 @@ "commandType": { "title": "Commandtype", "default": "waitForDuration", - "enum": ["waitForDuration"], + "enum": [ + "waitForDuration" + ], "type": "string" }, "params": { @@ -1568,7 +1777,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "PickUpTipParams": { "title": "PickUpTipParams", @@ -1600,7 +1811,11 @@ "type": "string" } }, - "required": ["labwareId", "wellName", "pipetteId"] + "required": [ + "labwareId", + "wellName", + "pipetteId" + ] }, "PickUpTipCreate": { "title": "PickUpTipCreate", @@ -1610,7 +1825,9 @@ "commandType": { "title": "Commandtype", "default": "pickUpTip", - "enum": ["pickUpTip"], + "enum": [ + "pickUpTip" + ], "type": "string" }, "params": { @@ -1630,7 +1847,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "SavePositionParams": { "title": "SavePositionParams", @@ -1648,7 +1867,9 @@ "type": "string" } }, - "required": ["pipetteId"] + "required": [ + "pipetteId" + ] }, "SavePositionCreate": { "title": "SavePositionCreate", @@ -1658,7 +1879,9 @@ "commandType": { "title": "Commandtype", "default": "savePosition", - "enum": ["savePosition"], + "enum": [ + "savePosition" + ], "type": "string" }, "params": { @@ -1678,7 +1901,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "SetRailLightsParams": { "title": "SetRailLightsParams", @@ -1691,7 +1916,9 @@ "type": "boolean" } }, - "required": ["on"] + "required": [ + "on" + ] }, "SetRailLightsCreate": { "title": "SetRailLightsCreate", @@ -1701,7 +1928,9 @@ "commandType": { "title": "Commandtype", "default": "setRailLights", - "enum": ["setRailLights"], + "enum": [ + "setRailLights" + ], "type": "string" }, "params": { @@ -1721,7 +1950,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "TouchTipParams": { "title": "TouchTipParams", @@ -1764,7 +1995,11 @@ "type": "number" } }, - "required": ["labwareId", "wellName", "pipetteId"] + "required": [ + "labwareId", + "wellName", + "pipetteId" + ] }, "TouchTipCreate": { "title": "TouchTipCreate", @@ -1774,7 +2009,9 @@ "commandType": { "title": "Commandtype", "default": "touchTip", - "enum": ["touchTip"], + "enum": [ + "touchTip" + ], "type": "string" }, "params": { @@ -1794,7 +2031,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureParams": { "title": "WaitForTemperatureParams", @@ -1812,7 +2051,9 @@ "type": "number" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureCreate": { "title": "WaitForTemperatureCreate", @@ -1822,7 +2063,9 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/waitForTemperature", - "enum": ["heaterShaker/waitForTemperature"], + "enum": [ + "heaterShaker/waitForTemperature" + ], "type": "string" }, "params": { @@ -1842,7 +2085,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureParams": { "title": "SetTargetTemperatureParams", @@ -1860,7 +2105,10 @@ "type": "number" } }, - "required": ["moduleId", "celsius"] + "required": [ + "moduleId", + "celsius" + ] }, "opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureCreate": { "title": "SetTargetTemperatureCreate", @@ -1870,7 +2118,9 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/setTargetTemperature", - "enum": ["heaterShaker/setTargetTemperature"], + "enum": [ + "heaterShaker/setTargetTemperature" + ], "type": "string" }, "params": { @@ -1890,7 +2140,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "DeactivateHeaterParams": { "title": "DeactivateHeaterParams", @@ -1903,7 +2155,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "DeactivateHeaterCreate": { "title": "DeactivateHeaterCreate", @@ -1913,7 +2167,9 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/deactivateHeater", - "enum": ["heaterShaker/deactivateHeater"], + "enum": [ + "heaterShaker/deactivateHeater" + ], "type": "string" }, "params": { @@ -1933,7 +2189,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "SetAndWaitForShakeSpeedParams": { "title": "SetAndWaitForShakeSpeedParams", @@ -1951,7 +2209,10 @@ "type": "number" } }, - "required": ["moduleId", "rpm"] + "required": [ + "moduleId", + "rpm" + ] }, "SetAndWaitForShakeSpeedCreate": { "title": "SetAndWaitForShakeSpeedCreate", @@ -1961,7 +2222,9 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/setAndWaitForShakeSpeed", - "enum": ["heaterShaker/setAndWaitForShakeSpeed"], + "enum": [ + "heaterShaker/setAndWaitForShakeSpeed" + ], "type": "string" }, "params": { @@ -1981,7 +2244,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "DeactivateShakerParams": { "title": "DeactivateShakerParams", @@ -1994,7 +2259,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "DeactivateShakerCreate": { "title": "DeactivateShakerCreate", @@ -2004,7 +2271,9 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/deactivateShaker", - "enum": ["heaterShaker/deactivateShaker"], + "enum": [ + "heaterShaker/deactivateShaker" + ], "type": "string" }, "params": { @@ -2024,7 +2293,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "OpenLabwareLatchParams": { "title": "OpenLabwareLatchParams", @@ -2037,7 +2308,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "OpenLabwareLatchCreate": { "title": "OpenLabwareLatchCreate", @@ -2047,7 +2320,9 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/openLabwareLatch", - "enum": ["heaterShaker/openLabwareLatch"], + "enum": [ + "heaterShaker/openLabwareLatch" + ], "type": "string" }, "params": { @@ -2067,7 +2342,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "CloseLabwareLatchParams": { "title": "CloseLabwareLatchParams", @@ -2080,7 +2357,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "CloseLabwareLatchCreate": { "title": "CloseLabwareLatchCreate", @@ -2090,7 +2369,9 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/closeLabwareLatch", - "enum": ["heaterShaker/closeLabwareLatch"], + "enum": [ + "heaterShaker/closeLabwareLatch" + ], "type": "string" }, "params": { @@ -2110,7 +2391,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "DisengageParams": { "title": "DisengageParams", @@ -2123,7 +2406,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "DisengageCreate": { "title": "DisengageCreate", @@ -2133,7 +2418,9 @@ "commandType": { "title": "Commandtype", "default": "magneticModule/disengage", - "enum": ["magneticModule/disengage"], + "enum": [ + "magneticModule/disengage" + ], "type": "string" }, "params": { @@ -2153,7 +2440,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "EngageParams": { "title": "EngageParams", @@ -2171,7 +2460,10 @@ "type": "number" } }, - "required": ["moduleId", "height"] + "required": [ + "moduleId", + "height" + ] }, "EngageCreate": { "title": "EngageCreate", @@ -2181,7 +2473,9 @@ "commandType": { "title": "Commandtype", "default": "magneticModule/engage", - "enum": ["magneticModule/engage"], + "enum": [ + "magneticModule/engage" + ], "type": "string" }, "params": { @@ -2201,7 +2495,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureParams": { "title": "SetTargetTemperatureParams", @@ -2219,7 +2515,10 @@ "type": "number" } }, - "required": ["moduleId", "celsius"] + "required": [ + "moduleId", + "celsius" + ] }, "opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureCreate": { "title": "SetTargetTemperatureCreate", @@ -2229,7 +2528,9 @@ "commandType": { "title": "Commandtype", "default": "temperatureModule/setTargetTemperature", - "enum": ["temperatureModule/setTargetTemperature"], + "enum": [ + "temperatureModule/setTargetTemperature" + ], "type": "string" }, "params": { @@ -2249,7 +2550,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureParams": { "title": "WaitForTemperatureParams", @@ -2267,7 +2570,9 @@ "type": "number" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureCreate": { "title": "WaitForTemperatureCreate", @@ -2277,7 +2582,9 @@ "commandType": { "title": "Commandtype", "default": "temperatureModule/waitForTemperature", - "enum": ["temperatureModule/waitForTemperature"], + "enum": [ + "temperatureModule/waitForTemperature" + ], "type": "string" }, "params": { @@ -2297,7 +2604,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "DeactivateTemperatureParams": { "title": "DeactivateTemperatureParams", @@ -2310,7 +2619,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "DeactivateTemperatureCreate": { "title": "DeactivateTemperatureCreate", @@ -2320,7 +2631,9 @@ "commandType": { "title": "Commandtype", "default": "temperatureModule/deactivate", - "enum": ["temperatureModule/deactivate"], + "enum": [ + "temperatureModule/deactivate" + ], "type": "string" }, "params": { @@ -2340,7 +2653,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "SetTargetBlockTemperatureParams": { "title": "SetTargetBlockTemperatureParams", @@ -2363,7 +2678,10 @@ "type": "number" } }, - "required": ["moduleId", "celsius"] + "required": [ + "moduleId", + "celsius" + ] }, "SetTargetBlockTemperatureCreate": { "title": "SetTargetBlockTemperatureCreate", @@ -2373,7 +2691,9 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/setTargetBlockTemperature", - "enum": ["thermocycler/setTargetBlockTemperature"], + "enum": [ + "thermocycler/setTargetBlockTemperature" + ], "type": "string" }, "params": { @@ -2393,7 +2713,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "WaitForBlockTemperatureParams": { "title": "WaitForBlockTemperatureParams", @@ -2406,7 +2728,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "WaitForBlockTemperatureCreate": { "title": "WaitForBlockTemperatureCreate", @@ -2416,7 +2740,9 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/waitForBlockTemperature", - "enum": ["thermocycler/waitForBlockTemperature"], + "enum": [ + "thermocycler/waitForBlockTemperature" + ], "type": "string" }, "params": { @@ -2436,7 +2762,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "SetTargetLidTemperatureParams": { "title": "SetTargetLidTemperatureParams", @@ -2454,7 +2782,10 @@ "type": "number" } }, - "required": ["moduleId", "celsius"] + "required": [ + "moduleId", + "celsius" + ] }, "SetTargetLidTemperatureCreate": { "title": "SetTargetLidTemperatureCreate", @@ -2464,7 +2795,9 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/setTargetLidTemperature", - "enum": ["thermocycler/setTargetLidTemperature"], + "enum": [ + "thermocycler/setTargetLidTemperature" + ], "type": "string" }, "params": { @@ -2484,7 +2817,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "WaitForLidTemperatureParams": { "title": "WaitForLidTemperatureParams", @@ -2497,7 +2832,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "WaitForLidTemperatureCreate": { "title": "WaitForLidTemperatureCreate", @@ -2507,7 +2844,9 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/waitForLidTemperature", - "enum": ["thermocycler/waitForLidTemperature"], + "enum": [ + "thermocycler/waitForLidTemperature" + ], "type": "string" }, "params": { @@ -2527,7 +2866,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "DeactivateBlockParams": { "title": "DeactivateBlockParams", @@ -2540,7 +2881,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "DeactivateBlockCreate": { "title": "DeactivateBlockCreate", @@ -2550,7 +2893,9 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/deactivateBlock", - "enum": ["thermocycler/deactivateBlock"], + "enum": [ + "thermocycler/deactivateBlock" + ], "type": "string" }, "params": { @@ -2570,7 +2915,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "DeactivateLidParams": { "title": "DeactivateLidParams", @@ -2583,7 +2930,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "DeactivateLidCreate": { "title": "DeactivateLidCreate", @@ -2593,7 +2942,9 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/deactivateLid", - "enum": ["thermocycler/deactivateLid"], + "enum": [ + "thermocycler/deactivateLid" + ], "type": "string" }, "params": { @@ -2613,7 +2964,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "OpenLidParams": { "title": "OpenLidParams", @@ -2626,7 +2979,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "OpenLidCreate": { "title": "OpenLidCreate", @@ -2636,7 +2991,9 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/openLid", - "enum": ["thermocycler/openLid"], + "enum": [ + "thermocycler/openLid" + ], "type": "string" }, "params": { @@ -2656,7 +3013,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "CloseLidParams": { "title": "CloseLidParams", @@ -2669,7 +3028,9 @@ "type": "string" } }, - "required": ["moduleId"] + "required": [ + "moduleId" + ] }, "CloseLidCreate": { "title": "CloseLidCreate", @@ -2679,7 +3040,9 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/closeLid", - "enum": ["thermocycler/closeLid"], + "enum": [ + "thermocycler/closeLid" + ], "type": "string" }, "params": { @@ -2699,7 +3062,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "RunProfileStepParams": { "title": "RunProfileStepParams", @@ -2717,7 +3082,10 @@ "type": "number" } }, - "required": ["celsius", "holdSeconds"] + "required": [ + "celsius", + "holdSeconds" + ] }, "RunProfileParams": { "title": "RunProfileParams", @@ -2743,7 +3111,10 @@ "type": "number" } }, - "required": ["moduleId", "profile"] + "required": [ + "moduleId", + "profile" + ] }, "RunProfileCreate": { "title": "RunProfileCreate", @@ -2753,7 +3124,9 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/runProfile", - "enum": ["thermocycler/runProfile"], + "enum": [ + "thermocycler/runProfile" + ], "type": "string" }, "params": { @@ -2773,12 +3146,17 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "CalibrateGripperParamsJaw": { "title": "CalibrateGripperParamsJaw", "description": "An enumeration.", - "enum": ["front", "rear"] + "enum": [ + "front", + "rear" + ] }, "Vec3f": { "title": "Vec3f", @@ -2798,7 +3176,11 @@ "type": "number" } }, - "required": ["x", "y", "z"] + "required": [ + "x", + "y", + "z" + ] }, "CalibrateGripperParams": { "title": "CalibrateGripperParams", @@ -2823,7 +3205,9 @@ ] } }, - "required": ["jaw"] + "required": [ + "jaw" + ] }, "CalibrateGripperCreate": { "title": "CalibrateGripperCreate", @@ -2833,7 +3217,9 @@ "commandType": { "title": "Commandtype", "default": "calibration/calibrateGripper", - "enum": ["calibration/calibrateGripper"], + "enum": [ + "calibration/calibrateGripper" + ], "type": "string" }, "params": { @@ -2853,7 +3239,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "CalibratePipetteParams": { "title": "CalibratePipetteParams", @@ -2869,7 +3257,9 @@ ] } }, - "required": ["mount"] + "required": [ + "mount" + ] }, "CalibratePipetteCreate": { "title": "CalibratePipetteCreate", @@ -2879,7 +3269,9 @@ "commandType": { "title": "Commandtype", "default": "calibration/calibratePipette", - "enum": ["calibration/calibratePipette"], + "enum": [ + "calibration/calibratePipette" + ], "type": "string" }, "params": { @@ -2899,7 +3291,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "CalibrateModuleParams": { "title": "CalibrateModuleParams", @@ -2925,7 +3319,11 @@ ] } }, - "required": ["moduleId", "labwareId", "mount"] + "required": [ + "moduleId", + "labwareId", + "mount" + ] }, "CalibrateModuleCreate": { "title": "CalibrateModuleCreate", @@ -2935,7 +3333,9 @@ "commandType": { "title": "Commandtype", "default": "calibration/calibrateModule", - "enum": ["calibration/calibrateModule"], + "enum": [ + "calibration/calibrateModule" + ], "type": "string" }, "params": { @@ -2955,7 +3355,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] }, "MoveToMaintenancePositionParams": { "title": "MoveToMaintenancePositionParams", @@ -2971,7 +3373,9 @@ ] } }, - "required": ["mount"] + "required": [ + "mount" + ] }, "MoveToMaintenancePositionCreate": { "title": "MoveToMaintenancePositionCreate", @@ -2981,7 +3385,9 @@ "commandType": { "title": "Commandtype", "default": "calibration/moveToMaintenancePosition", - "enum": ["calibration/moveToMaintenancePosition"], + "enum": [ + "calibration/moveToMaintenancePosition" + ], "type": "string" }, "params": { @@ -3001,7 +3407,9 @@ "type": "string" } }, - "required": ["params"] + "required": [ + "params" + ] } }, "$id": "opentronsCommandSchemaV7", From 0b71669a23f8d4429a11785a1ee062a0cda392c9 Mon Sep 17 00:00:00 2001 From: Sanniti Date: Mon, 8 May 2023 15:50:48 -0400 Subject: [PATCH 3/9] updated hw control, papi, engine & robot-server to use new axis & mount --- api/src/opentrons/hardware_control/api.py | 9 ++++++++- .../opentrons/hardware_control/backends/simulator.py | 2 +- .../instruments/ot2/pipette_handler.py | 4 +++- api/src/opentrons/protocol_api/core/engine/protocol.py | 4 ++++ .../protocol_api/core/legacy/legacy_protocol_core.py | 2 +- api/src/opentrons/protocol_api/protocol_context.py | 7 +++++++ .../commands/heater_shaker/open_labware_latch.py | 1 + .../heater_shaker/set_and_wait_for_shake_speed.py | 1 + .../protocol_engine/commands/thermocycler/close_lid.py | 1 + .../protocol_engine/execution/gantry_mover.py | 1 + .../commands/heater_shaker/test_open_labware_latch.py | 2 +- .../heater_shaker/test_set_and_wait_for_shake_speed.py | 2 +- .../commands/thermocycler/test_close_lid.py | 2 +- .../robot_server/service/legacy/routers/motors.py | 10 +++++++++- 14 files changed, 40 insertions(+), 8 deletions(-) diff --git a/api/src/opentrons/hardware_control/api.py b/api/src/opentrons/hardware_control/api.py index 167c43894cc..1d4299bc3bd 100644 --- a/api/src/opentrons/hardware_control/api.py +++ b/api/src/opentrons/hardware_control/api.py @@ -571,7 +571,14 @@ async def home_plunger(self, mount: top_types.Mount) -> None: @ExecutionManagerProvider.wait_for_running async def home(self, axes: Optional[List[Axis]] = None) -> None: """Home the entire robot and initialize current position.""" - + # Should we assert/ raise an error or just remove non-ot2 axes and log warning? + # No internal code passes OT3 axes as arguments on an OT2. But a user/ client + # can still explicitly specify an OT3 axis even when working on an OT2. + # Adding this check in order to prevent misuse of axes types. + if axes: + assert all( + axis in Axis.ot2_axes() for axis in axes + ), "Received a non-OT2 axis for homing." self._reset_last_mount() # Initialize/update current_position checked_axes = axes or [ax for ax in Axis.ot2_axes()] diff --git a/api/src/opentrons/hardware_control/backends/simulator.py b/api/src/opentrons/hardware_control/backends/simulator.py index a1126023c01..a74a72a47ba 100644 --- a/api/src/opentrons/hardware_control/backends/simulator.py +++ b/api/src/opentrons/hardware_control/backends/simulator.py @@ -138,7 +138,7 @@ def _sanitize_attached_instrument( self._attached_instruments = { m: _sanitize_attached_instrument(attached_instruments.get(m)) - for m in types.Mount + for m in types.Mount # Check if addition of extension Mount creates issues for this } self._stubbed_attached_modules = attached_modules self._position = copy.copy(self._smoothie_driver.homed_position) diff --git a/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py b/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py index fd2dfcd30ef..e131187a3eb 100644 --- a/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py +++ b/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py @@ -117,7 +117,9 @@ def reset_instrument(self, mount: Optional[MountType] = None) -> None: def _reset(m: MountType) -> None: if isinstance(m, top_types.Mount) and m not in top_types.Mount.ot2_mounts(): - self._ihp_log.info("Received a non OT2 mount for resetting. Skipping") + self._ihp_log.warning( + "Received a non OT2 mount for resetting. Skipping" + ) return self._ihp_log.info(f"Resetting configuration for {m}") p = self._attached_instruments[m] diff --git a/api/src/opentrons/protocol_api/core/engine/protocol.py b/api/src/opentrons/protocol_api/core/engine/protocol.py index f1a3c753796..ae0ca283734 100644 --- a/api/src/opentrons/protocol_api/core/engine/protocol.py +++ b/api/src/opentrons/protocol_api/core/engine/protocol.py @@ -218,6 +218,10 @@ def move_labware( pick_up_offset=_pick_up_offset, drop_offset=_drop_offset, ) + if strategy == LabwareMovementStrategy.USING_GRIPPER: + # Clear out last location since it is not relevant to pipetting + # and we only use last location for in-place pipetting commands + self.set_last_location(location=None, mount=Mount.EXTENSION) def _resolve_module_hardware( self, serial_number: str, model: ModuleModel diff --git a/api/src/opentrons/protocol_api/core/legacy/legacy_protocol_core.py b/api/src/opentrons/protocol_api/core/legacy/legacy_protocol_core.py index 13df5d6edc6..54cbd1bce11 100644 --- a/api/src/opentrons/protocol_api/core/legacy/legacy_protocol_core.py +++ b/api/src/opentrons/protocol_api/core/legacy/legacy_protocol_core.py @@ -74,7 +74,7 @@ def __init__( self._deck_layout = Deck() if deck_layout is None else deck_layout self._instruments: Dict[Mount, Optional[LegacyInstrumentCore]] = { - mount: None for mount in Mount + mount: None for mount in Mount.ot2_mounts() # Legacy core works only on OT2 } self._bundled_labware = bundled_labware self._extra_labware = extra_labware or {} diff --git a/api/src/opentrons/protocol_api/protocol_context.py b/api/src/opentrons/protocol_api/protocol_context.py index 87e3051a44b..b8ecfbfef0b 100644 --- a/api/src/opentrons/protocol_api/protocol_context.py +++ b/api/src/opentrons/protocol_api/protocol_context.py @@ -118,6 +118,11 @@ def __init__( self._core = core self._core_map = core_map or LoadedCoreMap() self._deck = deck or Deck(protocol_core=core, core_map=self._core_map) + + # With the introduction of Extension mount type, this dict initializes to include + # the extension mount, for both ot2 & 3. While it doesn't seem like it would + # create an issue in the current PAPI context, it would be much safer to + # only use mounts available on the robot. self._instruments: Dict[Mount, Optional[InstrumentContext]] = { mount: None for mount in Mount } @@ -592,6 +597,8 @@ def load_instrument( `mount` (if such an instrument exists) should be replaced by `instrument_name`. """ + # TODO (spp): ensure that the specified mount is valid for the robot type specified. + # So 'extension' mount should error out on ot2. instrument_name = validation.ensure_lowercase_name(instrument_name) is_96_channel = instrument_name == "p1000_96" if is_96_channel and isinstance(self._core, ProtocolEngineCore): diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py index 7e54fb858af..440d81246a3 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py @@ -71,6 +71,7 @@ async def execute(self, params: OpenLabwareLatchParams) -> OpenLabwareLatchResul [ MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, + MotorAxis.EXTENSION_Z, ] ) diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py index ef068f7c380..9fe71733251 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py @@ -78,6 +78,7 @@ async def execute( [ MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, + MotorAxis.EXTENSION_Z, ] ) diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py b/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py index 90e05f50b6a..d351f29afde 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py @@ -57,6 +57,7 @@ async def execute(self, params: CloseLidParams) -> CloseLidResult: MotorAxis.Y, MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, + MotorAxis.EXTENSION_Z, ] ) diff --git a/api/src/opentrons/protocol_engine/execution/gantry_mover.py b/api/src/opentrons/protocol_engine/execution/gantry_mover.py index 75877a4deb3..01f1875edfd 100644 --- a/api/src/opentrons/protocol_engine/execution/gantry_mover.py +++ b/api/src/opentrons/protocol_engine/execution/gantry_mover.py @@ -187,6 +187,7 @@ async def home(self, axes: Optional[List[MotorAxis]]) -> None: await self._hardware_api.home_plunger(Mount.RIGHT) else: hardware_axes = [_MOTOR_AXIS_TO_HARDWARE_AXIS[a] for a in axes] + # Hardware API will raise error if invalid axes are passed for the type of robot await self._hardware_api.home(axes=hardware_axes) diff --git a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py index 5e44cfe626d..801349d972e 100644 --- a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py +++ b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py @@ -55,7 +55,7 @@ async def test_open_labware_latch( result = await subject.execute(data) decoy.verify( hs_module_substate.raise_if_shaking(), - await movement.home([MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z]), + await movement.home([MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, MotorAxis.EXTENSION_Z]), await hs_hardware.open_labware_latch(), ) assert result == heater_shaker.OpenLabwareLatchResult(pipetteRetracted=True) diff --git a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py index 4c186e6682c..e67e316699f 100644 --- a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py +++ b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py @@ -61,7 +61,7 @@ async def test_set_and_wait_for_shake_speed( result = await subject.execute(data) decoy.verify( hs_module_substate.raise_if_labware_latch_not_closed(), - await movement.home([MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z]), + await movement.home([MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, MotorAxis.EXTENSION_Z]), await hs_hardware.set_speed(rpm=1234), ) assert result == heater_shaker.SetAndWaitForShakeSpeedResult(pipetteRetracted=True) diff --git a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py index ebbaf5a0e3f..97ba5e40968 100644 --- a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py +++ b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py @@ -49,7 +49,7 @@ async def test_close_lid( decoy.verify( await movement.home( - [MotorAxis.X, MotorAxis.Y, MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z] + [MotorAxis.X, MotorAxis.Y, MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, MotorAxis.EXTENSION_Z] ), await tc_hardware.close(), times=1, diff --git a/robot-server/robot_server/service/legacy/routers/motors.py b/robot-server/robot_server/service/legacy/routers/motors.py index 5daac6d833e..7ba6f160358 100644 --- a/robot-server/robot_server/service/legacy/routers/motors.py +++ b/robot-server/robot_server/service/legacy/routers/motors.py @@ -4,6 +4,8 @@ from opentrons.hardware_control.types import Axis from opentrons.hardware_control import HardwareControlAPI +from opentrons.protocol_engine.errors import HardwareNotSupportedError +from opentrons.protocol_engine.resources.ot3_validation import ensure_ot3_hardware from robot_server.errors import LegacyErrorResponse from robot_server.hardware import get_hardware @@ -45,7 +47,13 @@ async def get_engaged_motors( async def post_disengage_motors( axes: model.Axes, hardware: HardwareControlAPI = Depends(get_hardware) ) -> V1BasicResponse: - input_axes = [Axis[ax.upper()] for ax in axes.axes] + # Do we want this endpoint to run on OT3? + try: + hardware = ensure_ot3_hardware(hardware) + except HardwareNotSupportedError: + # Filter out non-ot2 axes when running on OT2 + input_axes = [axis for axis in input_axes if axis in Axis.ot2_axes()] + await hardware.disengage_axes(input_axes) return V1BasicResponse(message="Disengaged axes: {}".format(", ".join(axes.axes))) From 5701ab3d01778c73193c3a5958502d0b9a860810 Mon Sep 17 00:00:00 2001 From: Sanniti Date: Wed, 10 May 2023 08:58:38 -0400 Subject: [PATCH 4/9] raise errors when using extension mount and axes incorrectly --- api/src/opentrons/hardware_control/types.py | 4 +- .../protocol_api/protocol_context.py | 2 - api/src/opentrons/protocol_api/validation.py | 29 ++++++-- .../move_to_maintenance_position.py | 1 + .../protocol_engine/errors/__init__.py | 3 +- .../protocol_engine/errors/exceptions.py | 4 ++ .../protocol_engine/execution/gantry_mover.py | 8 ++- .../hardware_control/test_ot3_api.py | 12 +++- .../opentrons/protocol_api/test_validation.py | 14 +++- .../heater_shaker/test_open_labware_latch.py | 4 +- .../test_set_and_wait_for_shake_speed.py | 4 +- .../commands/thermocycler/test_close_lid.py | 8 ++- .../execution/test_gantry_mover.py | 68 ++++++++++++++++++- 13 files changed, 144 insertions(+), 17 deletions(-) diff --git a/api/src/opentrons/hardware_control/types.py b/api/src/opentrons/hardware_control/types.py index 9869bb96fae..0f6943acf67 100644 --- a/api/src/opentrons/hardware_control/types.py +++ b/api/src/opentrons/hardware_control/types.py @@ -98,11 +98,13 @@ def from_mount( top_types.Mount, top_types.MountType, top_types.OT3MountType, "OT3Mount" ], ) -> "OT3Mount": + if mount == top_types.Mount.EXTENSION or mount == top_types.MountType.EXTENSION: + return OT3Mount.GRIPPER return cls[mount.name] def to_mount(self) -> top_types.Mount: if self.value == self.GRIPPER.value: - raise KeyError("Gripper mount is not representable") + return top_types.Mount.EXTENSION return top_types.Mount[self.name] diff --git a/api/src/opentrons/protocol_api/protocol_context.py b/api/src/opentrons/protocol_api/protocol_context.py index b8ecfbfef0b..99e5f5ecf1a 100644 --- a/api/src/opentrons/protocol_api/protocol_context.py +++ b/api/src/opentrons/protocol_api/protocol_context.py @@ -597,8 +597,6 @@ def load_instrument( `mount` (if such an instrument exists) should be replaced by `instrument_name`. """ - # TODO (spp): ensure that the specified mount is valid for the robot type specified. - # So 'extension' mount should error out on ot2. instrument_name = validation.ensure_lowercase_name(instrument_name) is_96_channel = instrument_name == "p1000_96" if is_96_channel and isinstance(self._core, ProtocolEngineCore): diff --git a/api/src/opentrons/protocol_api/validation.py b/api/src/opentrons/protocol_api/validation.py index aa1225df60d..2e832ef5616 100644 --- a/api/src/opentrons/protocol_api/validation.py +++ b/api/src/opentrons/protocol_api/validation.py @@ -30,8 +30,31 @@ from .labware import Well +class InvalidPipetteMountError(ValueError): + """An error raised when attempting to load pipettes on an invalid mount.""" + + +class PipetteMountTypeError(TypeError): + """An error raised when an invalid mount type is used for loading pipettes.""" + + def ensure_mount(mount: Union[str, Mount]) -> Mount: """Ensure that an input value represents a valid Mount.""" + if mount in [Mount.EXTENSION, "extension"]: + # This would cause existing protocols that might be iterating over mount types + # for loading pipettes to raise an error because Mount now includes Extension mount. + # For example, this would raise error- + # ``` + # for i, mount in enumerate(Mount): + # pipette[i] = ctx.load_instrument("p300_single", mount) + # ``` + # But this is a very rare use case and none of the protocols in protocol library + # or protocols seen/ built by support/ science/ apps engg do this so it might be + # safe to raise this error now? + raise InvalidPipetteMountError( + f"Loading pipettes on {mount} is not allowed." + f"Use the left or right mounts instead." + ) if isinstance(mount, Mount): return mount @@ -39,14 +62,12 @@ def ensure_mount(mount: Union[str, Mount]) -> Mount: try: return Mount[mount.upper()] except KeyError as e: - # TODO(mc, 2022-08-25): create specific exception type - raise ValueError( + raise InvalidPipetteMountError( "If mount is specified as a string, it must be 'left' or 'right';" f" instead, {mount} was given." ) from e - # TODO(mc, 2022-08-25): create specific exception type - raise TypeError( + raise PipetteMountTypeError( "Instrument mount should be 'left', 'right', or an opentrons.types.Mount;" f" instead, {mount} was given." ) diff --git a/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py b/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py index de4de5e9b73..34cbd354ca3 100644 --- a/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +++ b/api/src/opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py @@ -18,6 +18,7 @@ from ...state import StateView +# Question (spp): Does this offset work for gripper mount too? # These offsets are based on testing attach flows with 8/1 channel pipettes _INSTRUMENT_ATTACH_OFFSET = Point(y=10, z=400) diff --git a/api/src/opentrons/protocol_engine/errors/__init__.py b/api/src/opentrons/protocol_engine/errors/__init__.py index f177ee35d36..8f1ad25da6c 100644 --- a/api/src/opentrons/protocol_engine/errors/__init__.py +++ b/api/src/opentrons/protocol_engine/errors/__init__.py @@ -45,6 +45,7 @@ HardwareNotSupportedError, LabwareMovementNotAllowedError, LocationIsOccupiedError, + InvalidAxisForRobotType, ) from .error_occurrence import ErrorOccurrence @@ -95,7 +96,7 @@ "HardwareNotSupportedError", "LabwareMovementNotAllowedError", "LocationIsOccupiedError", - "FirmwareUpdateRequired", + "InvalidAxisForRobotType", # error occurrence models "ErrorOccurrence", ] diff --git a/api/src/opentrons/protocol_engine/errors/exceptions.py b/api/src/opentrons/protocol_engine/errors/exceptions.py index dec84f79c04..86fbfd702f3 100644 --- a/api/src/opentrons/protocol_engine/errors/exceptions.py +++ b/api/src/opentrons/protocol_engine/errors/exceptions.py @@ -214,3 +214,7 @@ class PipetteNotReadyToAspirateError(ProtocolEngineError): class InvalidPipettingVolumeError(ProtocolEngineError): """Raised when pipetting a volume larger than the pipette volume.""" + + +class InvalidAxisForRobotType(ProtocolEngineError): + """Raised when attempting to use an axis that is not present on the given type of robot.""" diff --git a/api/src/opentrons/protocol_engine/execution/gantry_mover.py b/api/src/opentrons/protocol_engine/execution/gantry_mover.py index 01f1875edfd..c59797d3b45 100644 --- a/api/src/opentrons/protocol_engine/execution/gantry_mover.py +++ b/api/src/opentrons/protocol_engine/execution/gantry_mover.py @@ -12,7 +12,7 @@ from ..state import StateView from ..types import MotorAxis, CurrentWell -from ..errors import MustHomeError +from ..errors import MustHomeError, InvalidAxisForRobotType _MOTOR_AXIS_TO_HARDWARE_AXIS: Dict[MotorAxis, HardwareAxis] = { @@ -187,6 +187,12 @@ async def home(self, axes: Optional[List[MotorAxis]]) -> None: await self._hardware_api.home_plunger(Mount.RIGHT) else: hardware_axes = [_MOTOR_AXIS_TO_HARDWARE_AXIS[a] for a in axes] + if self._state_view.config.robot_type == "OT-2 Standard" and any( + axis not in HardwareAxis.ot2_axes() for axis in hardware_axes + ): + raise InvalidAxisForRobotType( + f"{axes} includes axes that are not valid for OT-2 Standard robot type" + ) # Hardware API will raise error if invalid axes are passed for the type of robot await self._hardware_api.home(axes=hardware_axes) diff --git a/api/tests/opentrons/hardware_control/test_ot3_api.py b/api/tests/opentrons/hardware_control/test_ot3_api.py index a1ba48bae3e..25066d197f5 100644 --- a/api/tests/opentrons/hardware_control/test_ot3_api.py +++ b/api/tests/opentrons/hardware_control/test_ot3_api.py @@ -53,7 +53,7 @@ axis_to_node, ) from opentrons_hardware.firmware_bindings.constants import NodeId -from opentrons.types import Point, Mount +from opentrons.types import Point, Mount, MountType from opentrons_hardware.hardware_control.motion import MoveStopCondition @@ -390,12 +390,14 @@ async def _update_position( (OT3Mount.RIGHT, [OT3Axis.X, OT3Axis.Y, OT3Axis.Z_R]), (OT3Mount.LEFT, [OT3Axis.X, OT3Axis.Y, OT3Axis.Z_L]), (OT3Mount.GRIPPER, [OT3Axis.X, OT3Axis.Y, OT3Axis.Z_G]), + (Mount.EXTENSION, [OT3Axis.X, OT3Axis.Y, OT3Axis.Z_G]), + (MountType.EXTENSION, [OT3Axis.X, OT3Axis.Y, OT3Axis.Z_G]), ], ) async def test_move_to_without_homing_first( ot3_hardware: ThreadManager[OT3API], mock_home: AsyncMock, - mount: OT3Mount, + mount: Union[Mount, MountType, OT3Mount], homed_axis: List[OT3Axis], ) -> None: """Before a mount can be moved, XY and the corresponding Z must be homed first""" @@ -894,6 +896,12 @@ async def test_gripper_move_to( ] +async def test_move_gripper_mount_without_gripper_attached( + ot3_hardware: ThreadManager[OT3API], mock_backend_move: AsyncMock +) -> None: + """It should move the empty gripper mount to specified position.""" + + @pytest.mark.parametrize("enable_stalls", [True, False]) async def test_move_stall_flag( ot3_hardware: ThreadManager[OT3API], diff --git a/api/tests/opentrons/protocol_api/test_validation.py b/api/tests/opentrons/protocol_api/test_validation.py index b54dbebaae7..255cefb3a48 100644 --- a/api/tests/opentrons/protocol_api/test_validation.py +++ b/api/tests/opentrons/protocol_api/test_validation.py @@ -35,12 +35,22 @@ def test_ensure_mount(input_value: Union[str, Mount], expected: Mount) -> None: def test_ensure_mount_input_invalid() -> None: """It should raise if given invalid mount input.""" - with pytest.raises(ValueError, match="must be 'left' or 'right'"): + with pytest.raises( + subject.InvalidPipetteMountError, match="must be 'left' or 'right'" + ): subject.ensure_mount("oh no") - with pytest.raises(TypeError, match="'left', 'right', or an opentrons.types.Mount"): + with pytest.raises( + subject.PipetteMountTypeError, + match="'left', 'right', or an opentrons.types.Mount", + ): subject.ensure_mount(42) # type: ignore[arg-type] + with pytest.raises( + subject.InvalidPipetteMountError, match="Use the left or right mounts instead" + ): + subject.ensure_mount(Mount.EXTENSION) + @pytest.mark.parametrize( ["input_value", "expected"], diff --git a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py index 801349d972e..a7b6e5a3205 100644 --- a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py +++ b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py @@ -55,7 +55,9 @@ async def test_open_labware_latch( result = await subject.execute(data) decoy.verify( hs_module_substate.raise_if_shaking(), - await movement.home([MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, MotorAxis.EXTENSION_Z]), + await movement.home( + [MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, MotorAxis.EXTENSION_Z] + ), await hs_hardware.open_labware_latch(), ) assert result == heater_shaker.OpenLabwareLatchResult(pipetteRetracted=True) diff --git a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py index e67e316699f..4765e5bc872 100644 --- a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py +++ b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py @@ -61,7 +61,9 @@ async def test_set_and_wait_for_shake_speed( result = await subject.execute(data) decoy.verify( hs_module_substate.raise_if_labware_latch_not_closed(), - await movement.home([MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, MotorAxis.EXTENSION_Z]), + await movement.home( + [MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, MotorAxis.EXTENSION_Z] + ), await hs_hardware.set_speed(rpm=1234), ) assert result == heater_shaker.SetAndWaitForShakeSpeedResult(pipetteRetracted=True) diff --git a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py index 97ba5e40968..c9a5d5652b6 100644 --- a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py +++ b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py @@ -49,7 +49,13 @@ async def test_close_lid( decoy.verify( await movement.home( - [MotorAxis.X, MotorAxis.Y, MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, MotorAxis.EXTENSION_Z] + [ + MotorAxis.X, + MotorAxis.Y, + MotorAxis.RIGHT_Z, + MotorAxis.LEFT_Z, + MotorAxis.EXTENSION_Z, + ] ), await tc_hardware.close(), times=1, diff --git a/api/tests/opentrons/protocol_engine/execution/test_gantry_mover.py b/api/tests/opentrons/protocol_engine/execution/test_gantry_mover.py index 3d3e470d9d1..ac621cfee65 100644 --- a/api/tests/opentrons/protocol_engine/execution/test_gantry_mover.py +++ b/api/tests/opentrons/protocol_engine/execution/test_gantry_mover.py @@ -1,6 +1,9 @@ """Test gantry movement handler with hardware API.""" +from __future__ import annotations + import pytest from decoy import Decoy +from typing import TYPE_CHECKING from opentrons.types import Mount, MountType, Point from opentrons.hardware_control import API as HardwareAPI @@ -14,7 +17,7 @@ from opentrons.protocol_engine.state import StateView, PipetteLocationData from opentrons.protocol_engine.types import MotorAxis, DeckPoint, CurrentWell -from opentrons.protocol_engine.errors import MustHomeError +from opentrons.protocol_engine.errors import MustHomeError, InvalidAxisForRobotType from opentrons.protocol_engine.execution.gantry_mover import ( HardwareGantryMover, @@ -23,6 +26,9 @@ VIRTUAL_MAX_OT3_HEIGHT, ) +if TYPE_CHECKING: + from opentrons.hardware_control.ot3api import OT3API + @pytest.fixture def mock_hardware_api(decoy: Decoy) -> HardwareAPI: @@ -274,8 +280,10 @@ async def test_home( decoy: Decoy, mock_hardware_api: HardwareAPI, hardware_subject: HardwareGantryMover, + mock_state_view: StateView, ) -> None: """It should home a set of axes.""" + decoy.when(mock_state_view.config.robot_type).then_return("OT-2 Standard") await hardware_subject.home( axes=[ MotorAxis.X, @@ -309,6 +317,64 @@ async def test_home( decoy.verify(await mock_hardware_api.home(axes=[]), times=1) +async def test_ot2_home_fails_with_ot3_axes( + decoy: Decoy, + mock_hardware_api: HardwareAPI, + hardware_subject: HardwareGantryMover, + mock_state_view: StateView, +) -> None: + """It should raise an error when homing axes that don't exist on OT2.""" + decoy.when(mock_state_view.config.robot_type).then_return("OT-2 Standard") + with pytest.raises(InvalidAxisForRobotType): + await hardware_subject.home( + axes=[ + MotorAxis.LEFT_PLUNGER, + MotorAxis.RIGHT_PLUNGER, + MotorAxis.EXTENSION_Z, + MotorAxis.EXTENSION_JAW, + ] + ) + + +@pytest.mark.ot3_only +async def test_home_on_ot3( + decoy: Decoy, + ot3_hardware_api: OT3API, + mock_state_view: StateView, +) -> None: + """Test homing all OT3 axes.""" + subject = HardwareGantryMover( + state_view=mock_state_view, hardware_api=ot3_hardware_api + ) + decoy.when(mock_state_view.config.robot_type).then_return("OT-3 Standard") + await subject.home( + axes=[ + MotorAxis.X, + MotorAxis.Y, + MotorAxis.LEFT_Z, + MotorAxis.RIGHT_Z, + MotorAxis.LEFT_PLUNGER, + MotorAxis.RIGHT_PLUNGER, + MotorAxis.EXTENSION_JAW, + MotorAxis.EXTENSION_Z, + ] + ) + decoy.verify( + await ot3_hardware_api.home( + axes=[ + HardwareAxis.X, + HardwareAxis.Y, + HardwareAxis.Z, + HardwareAxis.A, + HardwareAxis.B, + HardwareAxis.C, + HardwareAxis.G, + HardwareAxis.Z_G, + ] + ), + ) + + # TODO(mc, 2022-12-01): this is overly complicated # https://opentrons.atlassian.net/browse/RET-1287 async def test_home_z( From a441c88876ecd14bc435403f455891267c602643 Mon Sep 17 00:00:00 2001 From: Sanniti Date: Wed, 10 May 2023 08:59:34 -0400 Subject: [PATCH 5/9] use opentrons.types.MountType in instruments router --- api/src/opentrons/types.py | 20 +++++++++++++++++++ .../instruments/instrument_models.py | 17 ---------------- .../robot_server/instruments/router.py | 3 +-- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/api/src/opentrons/types.py b/api/src/opentrons/types.py index 32b87820ac5..3e78d8ab0bf 100644 --- a/api/src/opentrons/types.py +++ b/api/src/opentrons/types.py @@ -189,7 +189,27 @@ def to_hw_mount(self) -> Mount: MountType.EXTENSION: Mount.EXTENSION, }[self] + @staticmethod + def from_hw_mount(mount: Mount) -> MountType: + """Convert from Mount to MountType.""" + mount_map = {Mount.LEFT: MountType.LEFT, Mount.RIGHT: MountType.RIGHT} + return mount_map[mount] +class PipetteMountType(enum.Enum): + LEFT = "left" + RIGHT = "right" + COMBINED = "combined" # added for 96-channel. Remove if not required + + def to_mount_type(self) -> MountType: + return { + PipetteMountType.LEFT: MountType.LEFT, + PipetteMountType.RIGHT: MountType.RIGHT, + }[self] + + +# What is this used for? Can we consolidate this into MountType? +# If not, can we change the 'GRIPPER' mount name to 'EXTENSION' so that it's +# consistent with all user-facing mount names? class OT3MountType(str, enum.Enum): LEFT = "left" RIGHT = "right" diff --git a/robot-server/robot_server/instruments/instrument_models.py b/robot-server/robot_server/instruments/instrument_models.py index 75c869f1cd0..ea9bcf53f6e 100644 --- a/robot-server/robot_server/instruments/instrument_models.py +++ b/robot-server/robot_server/instruments/instrument_models.py @@ -1,7 +1,6 @@ """Request and response models for /instruments endpoints.""" from __future__ import annotations -import enum from typing_extensions import Literal from typing import Optional, TypeVar, Union, Generic from datetime import datetime @@ -9,7 +8,6 @@ from pydantic.generics import GenericModel -from opentrons.types import Mount from opentrons.calibration_storage.types import SourceType from opentrons.protocol_engine.types import Vec3f from opentrons_shared_data.pipette.dev_types import ( @@ -28,21 +26,6 @@ InstrumentType = Literal["pipette", "gripper"] -# TODO (spp, 2023-01-03): use MountType from opentrons.types once it has extension type -class MountType(enum.Enum): - """Available mount types.""" - - LEFT = "left" - RIGHT = "right" - EXTENSION = "extension" - - @staticmethod - def from_hw_mount(mount: Mount) -> MountType: - """Convert from Mount to MountType.""" - mount_map = {Mount.LEFT: MountType.LEFT, Mount.RIGHT: MountType.RIGHT} - return mount_map[mount] - - class _GenericInstrument(GenericModel, Generic[InstrumentModelT, InstrumentDataT]): """Base instrument response.""" diff --git a/robot-server/robot_server/instruments/router.py b/robot-server/robot_server/instruments/router.py index bdcca27ebb5..0b1cfa5018e 100644 --- a/robot-server/robot_server/instruments/router.py +++ b/robot-server/robot_server/instruments/router.py @@ -16,7 +16,7 @@ MultiBodyMeta, ) -from opentrons.types import Mount +from opentrons.types import Mount, MountType from opentrons.protocol_engine.types import Vec3f from opentrons.protocol_engine.resources.ot3_validation import ensure_ot3_hardware from opentrons.hardware_control import HardwareControlAPI @@ -24,7 +24,6 @@ from opentrons_shared_data.gripper.gripper_definition import GripperModelStr from .instrument_models import ( - MountType, PipetteData, Pipette, InstrumentCalibrationData, From e6d134885f8302f160f74f4bd06483bdfbd8e36c Mon Sep 17 00:00:00 2001 From: Sanniti Date: Wed, 10 May 2023 09:12:08 -0400 Subject: [PATCH 6/9] update test --- api/src/opentrons/hardware_control/types.py | 1 + api/src/opentrons/types.py | 1 + api/tests/opentrons/hardware_control/test_ot3_api.py | 7 +++---- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/api/src/opentrons/hardware_control/types.py b/api/src/opentrons/hardware_control/types.py index 0f6943acf67..3b319559cb7 100644 --- a/api/src/opentrons/hardware_control/types.py +++ b/api/src/opentrons/hardware_control/types.py @@ -153,6 +153,7 @@ def by_mount(cls, mount: Union[top_types.Mount, OT3Mount]) -> "OT3Axis": bm = { top_types.Mount.LEFT: cls.Z_L, top_types.Mount.RIGHT: cls.Z_R, + top_types.Mount.EXTENSION: cls.Z_G, OT3Mount.LEFT: cls.Z_L, OT3Mount.RIGHT: cls.Z_R, OT3Mount.GRIPPER: cls.Z_G, diff --git a/api/src/opentrons/types.py b/api/src/opentrons/types.py index 3e78d8ab0bf..da705dbf37f 100644 --- a/api/src/opentrons/types.py +++ b/api/src/opentrons/types.py @@ -195,6 +195,7 @@ def from_hw_mount(mount: Mount) -> MountType: mount_map = {Mount.LEFT: MountType.LEFT, Mount.RIGHT: MountType.RIGHT} return mount_map[mount] + class PipetteMountType(enum.Enum): LEFT = "left" RIGHT = "right" diff --git a/api/tests/opentrons/hardware_control/test_ot3_api.py b/api/tests/opentrons/hardware_control/test_ot3_api.py index 25066d197f5..8d3c90c1126 100644 --- a/api/tests/opentrons/hardware_control/test_ot3_api.py +++ b/api/tests/opentrons/hardware_control/test_ot3_api.py @@ -53,7 +53,7 @@ axis_to_node, ) from opentrons_hardware.firmware_bindings.constants import NodeId -from opentrons.types import Point, Mount, MountType +from opentrons.types import Point, Mount from opentrons_hardware.hardware_control.motion import MoveStopCondition @@ -391,17 +391,16 @@ async def _update_position( (OT3Mount.LEFT, [OT3Axis.X, OT3Axis.Y, OT3Axis.Z_L]), (OT3Mount.GRIPPER, [OT3Axis.X, OT3Axis.Y, OT3Axis.Z_G]), (Mount.EXTENSION, [OT3Axis.X, OT3Axis.Y, OT3Axis.Z_G]), - (MountType.EXTENSION, [OT3Axis.X, OT3Axis.Y, OT3Axis.Z_G]), ], ) async def test_move_to_without_homing_first( ot3_hardware: ThreadManager[OT3API], mock_home: AsyncMock, - mount: Union[Mount, MountType, OT3Mount], + mount: Union[Mount, OT3Mount], homed_axis: List[OT3Axis], ) -> None: """Before a mount can be moved, XY and the corresponding Z must be homed first""" - if mount == OT3Mount.GRIPPER: + if mount in (OT3Mount.GRIPPER, Mount.EXTENSION): # attach a gripper if we're testing the gripper mount gripper_config = gc.load(GripperModel.v1) instr_data = AttachedGripper(config=gripper_config, id="test") From 622e0415808064dff8f8482da6a751119d5e663b Mon Sep 17 00:00:00 2001 From: Sanniti Date: Wed, 10 May 2023 12:24:21 -0400 Subject: [PATCH 7/9] added todo --- api/src/opentrons/protocol_engine/execution/equipment.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/src/opentrons/protocol_engine/execution/equipment.py b/api/src/opentrons/protocol_engine/execution/equipment.py index 5817e3e1224..6e244f52678 100644 --- a/api/src/opentrons/protocol_engine/execution/equipment.py +++ b/api/src/opentrons/protocol_engine/execution/equipment.py @@ -169,6 +169,9 @@ async def load_pipette( Returns: A LoadedPipetteData object. """ + # TODO (spp, 2023-05-10): either raise error if using MountType.EXTENSION in + # load pipettes command, or change the mount type used to be a restricted + # PipetteMountType which has only pipette mounts and not the extension mount. use_virtual_pipettes = self._state_store.config.use_virtual_pipettes pipette_name_value = ( From 8e9e77ee1bd5e401bce10d53efcc4e16e8b6b1a1 Mon Sep 17 00:00:00 2001 From: Sanniti Date: Thu, 11 May 2023 17:44:34 -0400 Subject: [PATCH 8/9] addressed review comments --- api/src/opentrons/hardware_control/api.py | 9 +- .../hardware_control/backends/simulator.py | 2 +- api/src/opentrons/hardware_control/errors.py | 4 + api/src/opentrons/hardware_control/types.py | 2 + shared-data/command/schemas/7.json | 721 ++++-------------- 5 files changed, 173 insertions(+), 565 deletions(-) diff --git a/api/src/opentrons/hardware_control/api.py b/api/src/opentrons/hardware_control/api.py index aa2175041e6..3040effdda3 100644 --- a/api/src/opentrons/hardware_control/api.py +++ b/api/src/opentrons/hardware_control/api.py @@ -48,6 +48,7 @@ ) from .errors import ( MustHomeError, + NotSupportedByHardware, ) from . import modules from .robot_calibration import ( @@ -575,10 +576,10 @@ async def home(self, axes: Optional[List[Axis]] = None) -> None: # No internal code passes OT3 axes as arguments on an OT2. But a user/ client # can still explicitly specify an OT3 axis even when working on an OT2. # Adding this check in order to prevent misuse of axes types. - if axes: - assert all( - axis in Axis.ot2_axes() for axis in axes - ), "Received a non-OT2 axis for homing." + if axes and any(axis not in Axis.ot2_axes() for axis in axes): + raise NotSupportedByHardware( + f"At least one axis in {axes} is not supported on the OT2." + ) self._reset_last_mount() # Initialize/update current_position checked_axes = axes or [ax for ax in Axis.ot2_axes()] diff --git a/api/src/opentrons/hardware_control/backends/simulator.py b/api/src/opentrons/hardware_control/backends/simulator.py index a74a72a47ba..242def4e4a2 100644 --- a/api/src/opentrons/hardware_control/backends/simulator.py +++ b/api/src/opentrons/hardware_control/backends/simulator.py @@ -138,7 +138,7 @@ def _sanitize_attached_instrument( self._attached_instruments = { m: _sanitize_attached_instrument(attached_instruments.get(m)) - for m in types.Mount # Check if addition of extension Mount creates issues for this + for m in types.Mount.ot2_mounts() } self._stubbed_attached_modules = attached_modules self._position = copy.copy(self._smoothie_driver.homed_position) diff --git a/api/src/opentrons/hardware_control/errors.py b/api/src/opentrons/hardware_control/errors.py index 3661c5ef2d9..5fd5cf05cdc 100644 --- a/api/src/opentrons/hardware_control/errors.py +++ b/api/src/opentrons/hardware_control/errors.py @@ -33,6 +33,10 @@ class InvalidMoveError(ValueError): pass +class NotSupportedByHardware(ValueError): + """Error raised when attempting to use arguments and values not supported by the specific hardware.""" + + class GripperNotAttachedError(Exception): """An error raised if a gripper is accessed that is not attached.""" diff --git a/api/src/opentrons/hardware_control/types.py b/api/src/opentrons/hardware_control/types.py index 3b319559cb7..f3e7392e743 100644 --- a/api/src/opentrons/hardware_control/types.py +++ b/api/src/opentrons/hardware_control/types.py @@ -29,6 +29,8 @@ class MotionChecks(enum.Enum): BOTH = 3 +# TODO (spp, 2023-05-11): merge OT3Axis into this and make Axis the only type. +# Use Z_L, Z_R, etc as the axes with aliases for Z, A, B, C class Axis(enum.Enum): X = 0 # Gantry X Y = 1 # Gantry Y diff --git a/shared-data/command/schemas/7.json b/shared-data/command/schemas/7.json index a97770a5417..9dee24372db 100644 --- a/shared-data/command/schemas/7.json +++ b/shared-data/command/schemas/7.json @@ -157,11 +157,7 @@ "WellOrigin": { "title": "WellOrigin", "description": "Origin of WellLocation offset.\n\nProps:\n TOP: the top-center of the well\n BOTTOM: the bottom-center of the well\n CENTER: the middle-center of the well", - "enum": [ - "top", - "bottom", - "center" - ], + "enum": ["top", "bottom", "center"], "type": "string" }, "WellOffset": { @@ -246,21 +242,12 @@ "type": "string" } }, - "required": [ - "labwareId", - "wellName", - "flowRate", - "volume", - "pipetteId" - ] + "required": ["labwareId", "wellName", "flowRate", "volume", "pipetteId"] }, "CommandIntent": { "title": "CommandIntent", "description": "Run intent for a given command.\n\nProps:\n PROTOCOL: the command is part of the protocol run itself.\n SETUP: the command is part of the setup phase of a run.", - "enum": [ - "protocol", - "setup" - ], + "enum": ["protocol", "setup"], "type": "string" }, "AspirateCreate": { @@ -271,9 +258,7 @@ "commandType": { "title": "Commandtype", "default": "aspirate", - "enum": [ - "aspirate" - ], + "enum": ["aspirate"], "type": "string" }, "params": { @@ -293,9 +278,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "AspirateInPlaceParams": { "title": "AspirateInPlaceParams", @@ -320,11 +303,7 @@ "type": "string" } }, - "required": [ - "flowRate", - "volume", - "pipetteId" - ] + "required": ["flowRate", "volume", "pipetteId"] }, "AspirateInPlaceCreate": { "title": "AspirateInPlaceCreate", @@ -334,9 +313,7 @@ "commandType": { "title": "Commandtype", "default": "aspirateInPlace", - "enum": [ - "aspirateInPlace" - ], + "enum": ["aspirateInPlace"], "type": "string" }, "params": { @@ -356,9 +333,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "CommentParams": { "title": "CommentParams", @@ -371,9 +346,7 @@ "type": "string" } }, - "required": [ - "message" - ] + "required": ["message"] }, "CommentCreate": { "title": "CommentCreate", @@ -383,9 +356,7 @@ "commandType": { "title": "Commandtype", "default": "comment", - "enum": [ - "comment" - ], + "enum": ["comment"], "type": "string" }, "params": { @@ -405,9 +376,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "CustomParams": { "title": "CustomParams", @@ -423,9 +392,7 @@ "commandType": { "title": "Commandtype", "default": "custom", - "enum": [ - "custom" - ], + "enum": ["custom"], "type": "string" }, "params": { @@ -445,9 +412,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DispenseParams": { "title": "DispenseParams", @@ -491,13 +456,7 @@ "type": "string" } }, - "required": [ - "labwareId", - "wellName", - "flowRate", - "volume", - "pipetteId" - ] + "required": ["labwareId", "wellName", "flowRate", "volume", "pipetteId"] }, "DispenseCreate": { "title": "DispenseCreate", @@ -507,9 +466,7 @@ "commandType": { "title": "Commandtype", "default": "dispense", - "enum": [ - "dispense" - ], + "enum": ["dispense"], "type": "string" }, "params": { @@ -529,9 +486,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DispenseInPlaceParams": { "title": "DispenseInPlaceParams", @@ -556,11 +511,7 @@ "type": "string" } }, - "required": [ - "flowRate", - "volume", - "pipetteId" - ] + "required": ["flowRate", "volume", "pipetteId"] }, "DispenseInPlaceCreate": { "title": "DispenseInPlaceCreate", @@ -570,9 +521,7 @@ "commandType": { "title": "Commandtype", "default": "dispenseInPlace", - "enum": [ - "dispenseInPlace" - ], + "enum": ["dispenseInPlace"], "type": "string" }, "params": { @@ -592,9 +541,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "BlowOutParams": { "title": "BlowOutParams", @@ -632,12 +579,7 @@ "type": "string" } }, - "required": [ - "labwareId", - "wellName", - "flowRate", - "pipetteId" - ] + "required": ["labwareId", "wellName", "flowRate", "pipetteId"] }, "BlowOutCreate": { "title": "BlowOutCreate", @@ -647,9 +589,7 @@ "commandType": { "title": "Commandtype", "default": "blowout", - "enum": [ - "blowout" - ], + "enum": ["blowout"], "type": "string" }, "params": { @@ -669,9 +609,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "BlowOutInPlaceParams": { "title": "BlowOutInPlaceParams", @@ -690,10 +628,7 @@ "type": "string" } }, - "required": [ - "flowRate", - "pipetteId" - ] + "required": ["flowRate", "pipetteId"] }, "BlowOutInPlaceCreate": { "title": "BlowOutInPlaceCreate", @@ -703,9 +638,7 @@ "commandType": { "title": "Commandtype", "default": "blowOutInPlace", - "enum": [ - "blowOutInPlace" - ], + "enum": ["blowOutInPlace"], "type": "string" }, "params": { @@ -725,19 +658,12 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DropTipWellOrigin": { "title": "DropTipWellOrigin", "description": "The origin of a DropTipWellLocation offset.\n\nProps:\n TOP: the top-center of the well\n BOTTOM: the bottom-center of the well\n CENTER: the middle-center of the well\n DEFAULT: the default drop-tip location of the well,\n based on pipette configuration and length of the tip.", - "enum": [ - "top", - "bottom", - "center", - "default" - ], + "enum": ["top", "bottom", "center", "default"], "type": "string" }, "DropTipWellLocation": { @@ -793,11 +719,7 @@ "type": "boolean" } }, - "required": [ - "pipetteId", - "labwareId", - "wellName" - ] + "required": ["pipetteId", "labwareId", "wellName"] }, "DropTipCreate": { "title": "DropTipCreate", @@ -807,9 +729,7 @@ "commandType": { "title": "Commandtype", "default": "dropTip", - "enum": [ - "dropTip" - ], + "enum": ["dropTip"], "type": "string" }, "params": { @@ -829,9 +749,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DropTipInPlaceParams": { "title": "DropTipInPlaceParams", @@ -918,9 +836,7 @@ "commandType": { "title": "Commandtype", "default": "home", - "enum": [ - "home" - ], + "enum": ["home"], "type": "string" }, "params": { @@ -940,27 +856,12 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DeckSlotName": { "title": "DeckSlotName", "description": "Deck slot identifiers.", - "enum": [ - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12" - ] + "enum": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"] }, "DeckSlotLocation": { "title": "DeckSlotLocation", @@ -971,9 +872,7 @@ "$ref": "#/definitions/DeckSlotName" } }, - "required": [ - "slotName" - ] + "required": ["slotName"] }, "ModuleLocation": { "title": "ModuleLocation", @@ -986,9 +885,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "LoadLabwareParams": { "title": "LoadLabwareParams", @@ -1006,9 +903,7 @@ "$ref": "#/definitions/ModuleLocation" }, { - "enum": [ - "offDeck" - ], + "enum": ["offDeck"], "type": "string" } ] @@ -1039,12 +934,7 @@ "type": "string" } }, - "required": [ - "location", - "loadName", - "namespace", - "version" - ] + "required": ["location", "loadName", "namespace", "version"] }, "LoadLabwareCreate": { "title": "LoadLabwareCreate", @@ -1054,9 +944,7 @@ "commandType": { "title": "Commandtype", "default": "loadLabware", - "enum": [ - "loadLabware" - ], + "enum": ["loadLabware"], "type": "string" }, "params": { @@ -1076,9 +964,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "LoadLiquidParams": { "title": "LoadLiquidParams", @@ -1104,11 +990,7 @@ } } }, - "required": [ - "liquidId", - "labwareId", - "volumeByWell" - ] + "required": ["liquidId", "labwareId", "volumeByWell"] }, "LoadLiquidCreate": { "title": "LoadLiquidCreate", @@ -1118,9 +1000,7 @@ "commandType": { "title": "Commandtype", "default": "loadLiquid", - "enum": [ - "loadLiquid" - ], + "enum": ["loadLiquid"], "type": "string" }, "params": { @@ -1140,9 +1020,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "ModuleModel": { "title": "ModuleModel", @@ -1187,10 +1065,7 @@ "type": "string" } }, - "required": [ - "model", - "location" - ] + "required": ["model", "location"] }, "LoadModuleCreate": { "title": "LoadModuleCreate", @@ -1200,9 +1075,7 @@ "commandType": { "title": "Commandtype", "default": "loadModule", - "enum": [ - "loadModule" - ], + "enum": ["loadModule"], "type": "string" }, "params": { @@ -1222,9 +1095,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "PipetteNameType": { "title": "PipetteNameType", @@ -1253,11 +1124,7 @@ "MountType": { "title": "MountType", "description": "An enumeration.", - "enum": [ - "left", - "right", - "extension" - ], + "enum": ["left", "right", "extension"], "type": "string" }, "LoadPipetteParams": { @@ -1273,9 +1140,7 @@ "$ref": "#/definitions/PipetteNameType" }, { - "enum": [ - "p1000_96" - ], + "enum": ["p1000_96"], "type": "string" } ] @@ -1294,10 +1159,7 @@ "type": "string" } }, - "required": [ - "pipetteName", - "mount" - ] + "required": ["pipetteName", "mount"] }, "LoadPipetteCreate": { "title": "LoadPipetteCreate", @@ -1307,9 +1169,7 @@ "commandType": { "title": "Commandtype", "default": "loadPipette", - "enum": [ - "loadPipette" - ], + "enum": ["loadPipette"], "type": "string" }, "params": { @@ -1329,18 +1189,12 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "LabwareMovementStrategy": { "title": "LabwareMovementStrategy", "description": "Strategy to use for labware movement.", - "enum": [ - "usingGripper", - "manualMoveWithPause", - "manualMoveWithoutPause" - ], + "enum": ["usingGripper", "manualMoveWithPause", "manualMoveWithoutPause"], "type": "string" }, "LabwareOffsetVector": { @@ -1361,11 +1215,7 @@ "type": "number" } }, - "required": [ - "x", - "y", - "z" - ] + "required": ["x", "y", "z"] }, "MoveLabwareParams": { "title": "MoveLabwareParams", @@ -1388,9 +1238,7 @@ "$ref": "#/definitions/ModuleLocation" }, { - "enum": [ - "offDeck" - ], + "enum": ["offDeck"], "type": "string" } ] @@ -1434,11 +1282,7 @@ ] } }, - "required": [ - "labwareId", - "newLocation", - "strategy" - ] + "required": ["labwareId", "newLocation", "strategy"] }, "MoveLabwareCreate": { "title": "MoveLabwareCreate", @@ -1448,9 +1292,7 @@ "commandType": { "title": "Commandtype", "default": "moveLabware", - "enum": [ - "moveLabware" - ], + "enum": ["moveLabware"], "type": "string" }, "params": { @@ -1470,18 +1312,12 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "MovementAxis": { "title": "MovementAxis", "description": "Axis on which to issue a relative movement.", - "enum": [ - "x", - "y", - "z" - ], + "enum": ["x", "y", "z"], "type": "string" }, "MoveRelativeParams": { @@ -1508,11 +1344,7 @@ "type": "number" } }, - "required": [ - "pipetteId", - "axis", - "distance" - ] + "required": ["pipetteId", "axis", "distance"] }, "MoveRelativeCreate": { "title": "MoveRelativeCreate", @@ -1522,9 +1354,7 @@ "commandType": { "title": "Commandtype", "default": "moveRelative", - "enum": [ - "moveRelative" - ], + "enum": ["moveRelative"], "type": "string" }, "params": { @@ -1544,9 +1374,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DeckPoint": { "title": "DeckPoint", @@ -1566,11 +1394,7 @@ "type": "number" } }, - "required": [ - "x", - "y", - "z" - ] + "required": ["x", "y", "z"] }, "MoveToCoordinatesParams": { "title": "MoveToCoordinatesParams", @@ -1608,10 +1432,7 @@ ] } }, - "required": [ - "pipetteId", - "coordinates" - ] + "required": ["pipetteId", "coordinates"] }, "MoveToCoordinatesCreate": { "title": "MoveToCoordinatesCreate", @@ -1621,9 +1442,7 @@ "commandType": { "title": "Commandtype", "default": "moveToCoordinates", - "enum": [ - "moveToCoordinates" - ], + "enum": ["moveToCoordinates"], "type": "string" }, "params": { @@ -1643,9 +1462,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "MoveToWellParams": { "title": "MoveToWellParams", @@ -1693,11 +1510,7 @@ "type": "string" } }, - "required": [ - "labwareId", - "wellName", - "pipetteId" - ] + "required": ["labwareId", "wellName", "pipetteId"] }, "MoveToWellCreate": { "title": "MoveToWellCreate", @@ -1707,9 +1520,7 @@ "commandType": { "title": "Commandtype", "default": "moveToWell", - "enum": [ - "moveToWell" - ], + "enum": ["moveToWell"], "type": "string" }, "params": { @@ -1729,9 +1540,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "WaitForResumeParams": { "title": "WaitForResumeParams", @@ -1753,10 +1562,7 @@ "commandType": { "title": "Commandtype", "default": "waitForResume", - "enum": [ - "waitForResume", - "pause" - ], + "enum": ["waitForResume", "pause"], "type": "string" }, "params": { @@ -1776,9 +1582,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "WaitForDurationParams": { "title": "WaitForDurationParams", @@ -1796,9 +1600,7 @@ "type": "string" } }, - "required": [ - "seconds" - ] + "required": ["seconds"] }, "WaitForDurationCreate": { "title": "WaitForDurationCreate", @@ -1808,9 +1610,7 @@ "commandType": { "title": "Commandtype", "default": "waitForDuration", - "enum": [ - "waitForDuration" - ], + "enum": ["waitForDuration"], "type": "string" }, "params": { @@ -1830,9 +1630,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "PickUpTipParams": { "title": "PickUpTipParams", @@ -1864,11 +1662,7 @@ "type": "string" } }, - "required": [ - "labwareId", - "wellName", - "pipetteId" - ] + "required": ["labwareId", "wellName", "pipetteId"] }, "PickUpTipCreate": { "title": "PickUpTipCreate", @@ -1878,9 +1672,7 @@ "commandType": { "title": "Commandtype", "default": "pickUpTip", - "enum": [ - "pickUpTip" - ], + "enum": ["pickUpTip"], "type": "string" }, "params": { @@ -1900,9 +1692,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "SavePositionParams": { "title": "SavePositionParams", @@ -1920,9 +1710,7 @@ "type": "string" } }, - "required": [ - "pipetteId" - ] + "required": ["pipetteId"] }, "SavePositionCreate": { "title": "SavePositionCreate", @@ -1932,9 +1720,7 @@ "commandType": { "title": "Commandtype", "default": "savePosition", - "enum": [ - "savePosition" - ], + "enum": ["savePosition"], "type": "string" }, "params": { @@ -1954,9 +1740,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "SetRailLightsParams": { "title": "SetRailLightsParams", @@ -1969,9 +1753,7 @@ "type": "boolean" } }, - "required": [ - "on" - ] + "required": ["on"] }, "SetRailLightsCreate": { "title": "SetRailLightsCreate", @@ -1981,9 +1763,7 @@ "commandType": { "title": "Commandtype", "default": "setRailLights", - "enum": [ - "setRailLights" - ], + "enum": ["setRailLights"], "type": "string" }, "params": { @@ -2003,9 +1783,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "TouchTipParams": { "title": "TouchTipParams", @@ -2048,11 +1826,7 @@ "type": "number" } }, - "required": [ - "labwareId", - "wellName", - "pipetteId" - ] + "required": ["labwareId", "wellName", "pipetteId"] }, "TouchTipCreate": { "title": "TouchTipCreate", @@ -2062,9 +1836,7 @@ "commandType": { "title": "Commandtype", "default": "touchTip", - "enum": [ - "touchTip" - ], + "enum": ["touchTip"], "type": "string" }, "params": { @@ -2084,9 +1856,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureParams": { "title": "WaitForTemperatureParams", @@ -2104,9 +1874,7 @@ "type": "number" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "opentrons__protocol_engine__commands__heater_shaker__wait_for_temperature__WaitForTemperatureCreate": { "title": "WaitForTemperatureCreate", @@ -2116,9 +1884,7 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/waitForTemperature", - "enum": [ - "heaterShaker/waitForTemperature" - ], + "enum": ["heaterShaker/waitForTemperature"], "type": "string" }, "params": { @@ -2138,9 +1904,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureParams": { "title": "SetTargetTemperatureParams", @@ -2158,10 +1922,7 @@ "type": "number" } }, - "required": [ - "moduleId", - "celsius" - ] + "required": ["moduleId", "celsius"] }, "opentrons__protocol_engine__commands__heater_shaker__set_target_temperature__SetTargetTemperatureCreate": { "title": "SetTargetTemperatureCreate", @@ -2171,9 +1932,7 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/setTargetTemperature", - "enum": [ - "heaterShaker/setTargetTemperature" - ], + "enum": ["heaterShaker/setTargetTemperature"], "type": "string" }, "params": { @@ -2193,9 +1952,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DeactivateHeaterParams": { "title": "DeactivateHeaterParams", @@ -2208,9 +1965,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "DeactivateHeaterCreate": { "title": "DeactivateHeaterCreate", @@ -2220,9 +1975,7 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/deactivateHeater", - "enum": [ - "heaterShaker/deactivateHeater" - ], + "enum": ["heaterShaker/deactivateHeater"], "type": "string" }, "params": { @@ -2242,9 +1995,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "SetAndWaitForShakeSpeedParams": { "title": "SetAndWaitForShakeSpeedParams", @@ -2262,10 +2013,7 @@ "type": "number" } }, - "required": [ - "moduleId", - "rpm" - ] + "required": ["moduleId", "rpm"] }, "SetAndWaitForShakeSpeedCreate": { "title": "SetAndWaitForShakeSpeedCreate", @@ -2275,9 +2023,7 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/setAndWaitForShakeSpeed", - "enum": [ - "heaterShaker/setAndWaitForShakeSpeed" - ], + "enum": ["heaterShaker/setAndWaitForShakeSpeed"], "type": "string" }, "params": { @@ -2297,9 +2043,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DeactivateShakerParams": { "title": "DeactivateShakerParams", @@ -2312,9 +2056,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "DeactivateShakerCreate": { "title": "DeactivateShakerCreate", @@ -2324,9 +2066,7 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/deactivateShaker", - "enum": [ - "heaterShaker/deactivateShaker" - ], + "enum": ["heaterShaker/deactivateShaker"], "type": "string" }, "params": { @@ -2346,9 +2086,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "OpenLabwareLatchParams": { "title": "OpenLabwareLatchParams", @@ -2361,9 +2099,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "OpenLabwareLatchCreate": { "title": "OpenLabwareLatchCreate", @@ -2373,9 +2109,7 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/openLabwareLatch", - "enum": [ - "heaterShaker/openLabwareLatch" - ], + "enum": ["heaterShaker/openLabwareLatch"], "type": "string" }, "params": { @@ -2395,9 +2129,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "CloseLabwareLatchParams": { "title": "CloseLabwareLatchParams", @@ -2410,9 +2142,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "CloseLabwareLatchCreate": { "title": "CloseLabwareLatchCreate", @@ -2422,9 +2152,7 @@ "commandType": { "title": "Commandtype", "default": "heaterShaker/closeLabwareLatch", - "enum": [ - "heaterShaker/closeLabwareLatch" - ], + "enum": ["heaterShaker/closeLabwareLatch"], "type": "string" }, "params": { @@ -2444,9 +2172,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DisengageParams": { "title": "DisengageParams", @@ -2459,9 +2185,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "DisengageCreate": { "title": "DisengageCreate", @@ -2471,9 +2195,7 @@ "commandType": { "title": "Commandtype", "default": "magneticModule/disengage", - "enum": [ - "magneticModule/disengage" - ], + "enum": ["magneticModule/disengage"], "type": "string" }, "params": { @@ -2493,9 +2215,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "EngageParams": { "title": "EngageParams", @@ -2513,10 +2233,7 @@ "type": "number" } }, - "required": [ - "moduleId", - "height" - ] + "required": ["moduleId", "height"] }, "EngageCreate": { "title": "EngageCreate", @@ -2526,9 +2243,7 @@ "commandType": { "title": "Commandtype", "default": "magneticModule/engage", - "enum": [ - "magneticModule/engage" - ], + "enum": ["magneticModule/engage"], "type": "string" }, "params": { @@ -2548,9 +2263,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureParams": { "title": "SetTargetTemperatureParams", @@ -2568,10 +2281,7 @@ "type": "number" } }, - "required": [ - "moduleId", - "celsius" - ] + "required": ["moduleId", "celsius"] }, "opentrons__protocol_engine__commands__temperature_module__set_target_temperature__SetTargetTemperatureCreate": { "title": "SetTargetTemperatureCreate", @@ -2581,9 +2291,7 @@ "commandType": { "title": "Commandtype", "default": "temperatureModule/setTargetTemperature", - "enum": [ - "temperatureModule/setTargetTemperature" - ], + "enum": ["temperatureModule/setTargetTemperature"], "type": "string" }, "params": { @@ -2603,9 +2311,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureParams": { "title": "WaitForTemperatureParams", @@ -2623,9 +2329,7 @@ "type": "number" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "opentrons__protocol_engine__commands__temperature_module__wait_for_temperature__WaitForTemperatureCreate": { "title": "WaitForTemperatureCreate", @@ -2635,9 +2339,7 @@ "commandType": { "title": "Commandtype", "default": "temperatureModule/waitForTemperature", - "enum": [ - "temperatureModule/waitForTemperature" - ], + "enum": ["temperatureModule/waitForTemperature"], "type": "string" }, "params": { @@ -2657,9 +2359,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DeactivateTemperatureParams": { "title": "DeactivateTemperatureParams", @@ -2672,9 +2372,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "DeactivateTemperatureCreate": { "title": "DeactivateTemperatureCreate", @@ -2684,9 +2382,7 @@ "commandType": { "title": "Commandtype", "default": "temperatureModule/deactivate", - "enum": [ - "temperatureModule/deactivate" - ], + "enum": ["temperatureModule/deactivate"], "type": "string" }, "params": { @@ -2706,9 +2402,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "SetTargetBlockTemperatureParams": { "title": "SetTargetBlockTemperatureParams", @@ -2731,10 +2425,7 @@ "type": "number" } }, - "required": [ - "moduleId", - "celsius" - ] + "required": ["moduleId", "celsius"] }, "SetTargetBlockTemperatureCreate": { "title": "SetTargetBlockTemperatureCreate", @@ -2744,9 +2435,7 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/setTargetBlockTemperature", - "enum": [ - "thermocycler/setTargetBlockTemperature" - ], + "enum": ["thermocycler/setTargetBlockTemperature"], "type": "string" }, "params": { @@ -2766,9 +2455,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "WaitForBlockTemperatureParams": { "title": "WaitForBlockTemperatureParams", @@ -2781,9 +2468,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "WaitForBlockTemperatureCreate": { "title": "WaitForBlockTemperatureCreate", @@ -2793,9 +2478,7 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/waitForBlockTemperature", - "enum": [ - "thermocycler/waitForBlockTemperature" - ], + "enum": ["thermocycler/waitForBlockTemperature"], "type": "string" }, "params": { @@ -2815,9 +2498,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "SetTargetLidTemperatureParams": { "title": "SetTargetLidTemperatureParams", @@ -2835,10 +2516,7 @@ "type": "number" } }, - "required": [ - "moduleId", - "celsius" - ] + "required": ["moduleId", "celsius"] }, "SetTargetLidTemperatureCreate": { "title": "SetTargetLidTemperatureCreate", @@ -2848,9 +2526,7 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/setTargetLidTemperature", - "enum": [ - "thermocycler/setTargetLidTemperature" - ], + "enum": ["thermocycler/setTargetLidTemperature"], "type": "string" }, "params": { @@ -2870,9 +2546,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "WaitForLidTemperatureParams": { "title": "WaitForLidTemperatureParams", @@ -2885,9 +2559,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "WaitForLidTemperatureCreate": { "title": "WaitForLidTemperatureCreate", @@ -2897,9 +2569,7 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/waitForLidTemperature", - "enum": [ - "thermocycler/waitForLidTemperature" - ], + "enum": ["thermocycler/waitForLidTemperature"], "type": "string" }, "params": { @@ -2919,9 +2589,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DeactivateBlockParams": { "title": "DeactivateBlockParams", @@ -2934,9 +2602,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "DeactivateBlockCreate": { "title": "DeactivateBlockCreate", @@ -2946,9 +2612,7 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/deactivateBlock", - "enum": [ - "thermocycler/deactivateBlock" - ], + "enum": ["thermocycler/deactivateBlock"], "type": "string" }, "params": { @@ -2968,9 +2632,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "DeactivateLidParams": { "title": "DeactivateLidParams", @@ -2983,9 +2645,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "DeactivateLidCreate": { "title": "DeactivateLidCreate", @@ -2995,9 +2655,7 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/deactivateLid", - "enum": [ - "thermocycler/deactivateLid" - ], + "enum": ["thermocycler/deactivateLid"], "type": "string" }, "params": { @@ -3017,9 +2675,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "OpenLidParams": { "title": "OpenLidParams", @@ -3032,9 +2688,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "OpenLidCreate": { "title": "OpenLidCreate", @@ -3044,9 +2698,7 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/openLid", - "enum": [ - "thermocycler/openLid" - ], + "enum": ["thermocycler/openLid"], "type": "string" }, "params": { @@ -3066,9 +2718,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "CloseLidParams": { "title": "CloseLidParams", @@ -3081,9 +2731,7 @@ "type": "string" } }, - "required": [ - "moduleId" - ] + "required": ["moduleId"] }, "CloseLidCreate": { "title": "CloseLidCreate", @@ -3093,9 +2741,7 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/closeLid", - "enum": [ - "thermocycler/closeLid" - ], + "enum": ["thermocycler/closeLid"], "type": "string" }, "params": { @@ -3115,9 +2761,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "RunProfileStepParams": { "title": "RunProfileStepParams", @@ -3135,10 +2779,7 @@ "type": "number" } }, - "required": [ - "celsius", - "holdSeconds" - ] + "required": ["celsius", "holdSeconds"] }, "RunProfileParams": { "title": "RunProfileParams", @@ -3164,10 +2805,7 @@ "type": "number" } }, - "required": [ - "moduleId", - "profile" - ] + "required": ["moduleId", "profile"] }, "RunProfileCreate": { "title": "RunProfileCreate", @@ -3177,9 +2815,7 @@ "commandType": { "title": "Commandtype", "default": "thermocycler/runProfile", - "enum": [ - "thermocycler/runProfile" - ], + "enum": ["thermocycler/runProfile"], "type": "string" }, "params": { @@ -3199,17 +2835,12 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "CalibrateGripperParamsJaw": { "title": "CalibrateGripperParamsJaw", "description": "An enumeration.", - "enum": [ - "front", - "rear" - ] + "enum": ["front", "rear"] }, "Vec3f": { "title": "Vec3f", @@ -3229,11 +2860,7 @@ "type": "number" } }, - "required": [ - "x", - "y", - "z" - ] + "required": ["x", "y", "z"] }, "CalibrateGripperParams": { "title": "CalibrateGripperParams", @@ -3258,9 +2885,7 @@ ] } }, - "required": [ - "jaw" - ] + "required": ["jaw"] }, "CalibrateGripperCreate": { "title": "CalibrateGripperCreate", @@ -3270,9 +2895,7 @@ "commandType": { "title": "Commandtype", "default": "calibration/calibrateGripper", - "enum": [ - "calibration/calibrateGripper" - ], + "enum": ["calibration/calibrateGripper"], "type": "string" }, "params": { @@ -3292,9 +2915,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "CalibratePipetteParams": { "title": "CalibratePipetteParams", @@ -3310,9 +2931,7 @@ ] } }, - "required": [ - "mount" - ] + "required": ["mount"] }, "CalibratePipetteCreate": { "title": "CalibratePipetteCreate", @@ -3322,9 +2941,7 @@ "commandType": { "title": "Commandtype", "default": "calibration/calibratePipette", - "enum": [ - "calibration/calibratePipette" - ], + "enum": ["calibration/calibratePipette"], "type": "string" }, "params": { @@ -3344,9 +2961,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "CalibrateModuleParams": { "title": "CalibrateModuleParams", @@ -3372,11 +2987,7 @@ ] } }, - "required": [ - "moduleId", - "labwareId", - "mount" - ] + "required": ["moduleId", "labwareId", "mount"] }, "CalibrateModuleCreate": { "title": "CalibrateModuleCreate", @@ -3386,9 +2997,7 @@ "commandType": { "title": "Commandtype", "default": "calibration/calibrateModule", - "enum": [ - "calibration/calibrateModule" - ], + "enum": ["calibration/calibrateModule"], "type": "string" }, "params": { @@ -3408,9 +3017,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] }, "MoveToMaintenancePositionParams": { "title": "MoveToMaintenancePositionParams", @@ -3426,9 +3033,7 @@ ] } }, - "required": [ - "mount" - ] + "required": ["mount"] }, "MoveToMaintenancePositionCreate": { "title": "MoveToMaintenancePositionCreate", @@ -3438,9 +3043,7 @@ "commandType": { "title": "Commandtype", "default": "calibration/moveToMaintenancePosition", - "enum": [ - "calibration/moveToMaintenancePosition" - ], + "enum": ["calibration/moveToMaintenancePosition"], "type": "string" }, "params": { @@ -3460,9 +3063,7 @@ "type": "string" } }, - "required": [ - "params" - ] + "required": ["params"] } }, "$id": "opentronsCommandSchemaV7", From 050cc2a7bb0f215bd97fc6d53aaf78d8827655a8 Mon Sep 17 00:00:00 2001 From: Sanniti Date: Mon, 15 May 2023 20:17:37 -0400 Subject: [PATCH 9/9] added mount axes selector, fixed axes homing in tc & H/S commands --- .../heater_shaker/open_labware_latch.py | 9 +----- .../set_and_wait_for_shake_speed.py | 9 +----- .../commands/thermocycler/close_lid.py | 14 +++------ .../commands/thermocycler/open_lid.py | 13 +++----- .../opentrons/protocol_engine/state/motion.py | 12 ++++++- .../opentrons/protocol_engine/state/state.py | 1 + .../heater_shaker/test_open_labware_latch.py | 6 ++-- .../test_set_and_wait_for_shake_speed.py | 6 ++-- .../commands/thermocycler/test_close_lid.py | 14 +++------ .../commands/thermocycler/test_open_lid.py | 8 ++--- .../protocol_engine/state/test_motion_view.py | 31 +++++++++++++++++++ 11 files changed, 71 insertions(+), 52 deletions(-) diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py index 440d81246a3..76a3ee9a09d 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py @@ -2,11 +2,8 @@ from __future__ import annotations from typing import Optional, TYPE_CHECKING from typing_extensions import Literal, Type - from pydantic import BaseModel, Field -from opentrons.protocol_engine.types import MotorAxis - from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate if TYPE_CHECKING: @@ -68,11 +65,7 @@ async def execute(self, params: OpenLabwareLatchParams) -> OpenLabwareLatchResul # Move pipette away if it is close to the heater-shaker # TODO(jbl 2022-07-28) replace home movement with a retract movement await self._movement.home( - [ - MotorAxis.RIGHT_Z, - MotorAxis.LEFT_Z, - MotorAxis.EXTENSION_Z, - ] + axes=self._state_view.motion.get_robot_mount_axes() ) # Allow propagation of ModuleNotAttachedError. diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py index 9fe71733251..52041519231 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py @@ -2,11 +2,8 @@ from __future__ import annotations from typing import Optional, TYPE_CHECKING from typing_extensions import Literal, Type - from pydantic import BaseModel, Field -from opentrons.protocol_engine.types import MotorAxis - from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate if TYPE_CHECKING: @@ -75,11 +72,7 @@ async def execute( # Move pipette away if it is close to the heater-shaker # TODO(jbl 2022-07-28) replace home movement with a retract movement await self._movement.home( - [ - MotorAxis.RIGHT_Z, - MotorAxis.LEFT_Z, - MotorAxis.EXTENSION_Z, - ] + axes=self._state_view.motion.get_robot_mount_axes() ) # Allow propagation of ModuleNotAttachedError. diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py b/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py index d351f29afde..b67f1cb4aea 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py @@ -51,15 +51,11 @@ async def execute(self, params: CloseLidParams) -> CloseLidResult: # move the pipettes and gantry over the trash # do not home plunger axes because pipettes may be holding liquid - await self._movement.home( - [ - MotorAxis.X, - MotorAxis.Y, - MotorAxis.RIGHT_Z, - MotorAxis.LEFT_Z, - MotorAxis.EXTENSION_Z, - ] - ) + axes_to_home = [ + MotorAxis.X, + MotorAxis.Y, + ] + self._state_view.motion.get_robot_mount_axes() + await self._movement.home(axes=axes_to_home) if thermocycler_hardware is not None: await thermocycler_hardware.close() diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py b/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py index 6a0e7a4577a..b556a17cb13 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py @@ -51,14 +51,11 @@ async def execute(self, params: OpenLidParams) -> OpenLidResult: # move the pipettes and gantry over the trash # do not home plunger axes because pipettes may be holding liquid - await self._movement.home( - [ - MotorAxis.X, - MotorAxis.Y, - MotorAxis.RIGHT_Z, - MotorAxis.LEFT_Z, - ] - ) + axes_to_home = [ + MotorAxis.X, + MotorAxis.Y, + ] + self._state_view.motion.get_robot_mount_axes() + await self._movement.home(axes=axes_to_home) if thermocycler_hardware is not None: await thermocycler_hardware.open() diff --git a/api/src/opentrons/protocol_engine/state/motion.py b/api/src/opentrons/protocol_engine/state/motion.py index 7c98c42125f..08195901af6 100644 --- a/api/src/opentrons/protocol_engine/state/motion.py +++ b/api/src/opentrons/protocol_engine/state/motion.py @@ -12,7 +12,8 @@ from . import move_types from .. import errors -from ..types import WellLocation, CurrentWell +from ..types import WellLocation, CurrentWell, MotorAxis +from .config import Config from .labware import LabwareView from .pipettes import PipetteView from .geometry import GeometryView @@ -33,12 +34,14 @@ class MotionView: def __init__( self, + config: Config, labware_view: LabwareView, pipette_view: PipetteView, geometry_view: GeometryView, module_view: ModuleView, ) -> None: """Initialize a MotionState instance.""" + self._config = config self._labware = labware_view self._pipettes = pipette_view self._geometry = geometry_view @@ -229,3 +232,10 @@ def get_touch_tip_waypoints( motion_planning.Waypoint(position=p, critical_point=critical_point) for p in positions ] + + def get_robot_mount_axes(self) -> List[MotorAxis]: + """Get a list of axes belonging to all mounts on the robot.""" + mount_axes = [MotorAxis.LEFT_Z, MotorAxis.RIGHT_Z] + if self._config.robot_type == "OT-3 Standard": + mount_axes.append(MotorAxis.EXTENSION_Z) + return mount_axes diff --git a/api/src/opentrons/protocol_engine/state/state.py b/api/src/opentrons/protocol_engine/state/state.py index 4bb28a982bf..72dd40426ff 100644 --- a/api/src/opentrons/protocol_engine/state/state.py +++ b/api/src/opentrons/protocol_engine/state/state.py @@ -268,6 +268,7 @@ def _initialize_state(self) -> None: pipette_view=self._pipettes, ) self._motion = MotionView( + config=self._config, labware_view=self._labware, pipette_view=self._pipettes, geometry_view=self._geometry, diff --git a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py index a7b6e5a3205..6232fe27981 100644 --- a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py +++ b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py @@ -51,12 +51,14 @@ async def test_open_labware_latch( decoy.when( equipment.get_module_hardware_api(HeaterShakerModuleId("heater-shaker-id")) ).then_return(hs_hardware) - + decoy.when(state_view.motion.get_robot_mount_axes()).then_return( + [MotorAxis.EXTENSION_Z] + ) result = await subject.execute(data) decoy.verify( hs_module_substate.raise_if_shaking(), await movement.home( - [MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, MotorAxis.EXTENSION_Z] + [MotorAxis.EXTENSION_Z], ), await hs_hardware.open_labware_latch(), ) diff --git a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py index 4765e5bc872..389fd3ff53f 100644 --- a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py +++ b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py @@ -57,12 +57,14 @@ async def test_set_and_wait_for_shake_speed( decoy.when( equipment.get_module_hardware_api(HeaterShakerModuleId("heater-shaker-id")) ).then_return(hs_hardware) - + decoy.when(state_view.motion.get_robot_mount_axes()).then_return( + [MotorAxis.EXTENSION_Z] + ) result = await subject.execute(data) decoy.verify( hs_module_substate.raise_if_labware_latch_not_closed(), await movement.home( - [MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z, MotorAxis.EXTENSION_Z] + [MotorAxis.EXTENSION_Z], ), await hs_hardware.set_speed(rpm=1234), ) diff --git a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py index c9a5d5652b6..4f6ca6f0ba1 100644 --- a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py +++ b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py @@ -44,19 +44,13 @@ async def test_close_lid( decoy.when(equipment.get_module_hardware_api(expected_module_id)).then_return( tc_hardware ) - + decoy.when(state_view.motion.get_robot_mount_axes()).then_return( + [MotorAxis.EXTENSION_Z] + ) result = await subject.execute(data) decoy.verify( - await movement.home( - [ - MotorAxis.X, - MotorAxis.Y, - MotorAxis.RIGHT_Z, - MotorAxis.LEFT_Z, - MotorAxis.EXTENSION_Z, - ] - ), + await movement.home([MotorAxis.X, MotorAxis.Y, MotorAxis.EXTENSION_Z]), await tc_hardware.close(), times=1, ) diff --git a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_open_lid.py b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_open_lid.py index 5ffdfc5f71d..c6b0e980d9e 100644 --- a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_open_lid.py +++ b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_open_lid.py @@ -42,13 +42,13 @@ async def test_open_lid( decoy.when(equipment.get_module_hardware_api(expected_module_id)).then_return( tc_hardware ) - + decoy.when(state_view.motion.get_robot_mount_axes()).then_return( + [MotorAxis.EXTENSION_Z] + ) result = await subject.execute(data) decoy.verify( - await movement.home( - [MotorAxis.X, MotorAxis.Y, MotorAxis.RIGHT_Z, MotorAxis.LEFT_Z] - ), + await movement.home([MotorAxis.X, MotorAxis.Y, MotorAxis.EXTENSION_Z]), await tc_hardware.open(), times=1, ) diff --git a/api/tests/opentrons/protocol_engine/state/test_motion_view.py b/api/tests/opentrons/protocol_engine/state/test_motion_view.py index 3bbb6d4ea43..19680688644 100644 --- a/api/tests/opentrons/protocol_engine/state/test_motion_view.py +++ b/api/tests/opentrons/protocol_engine/state/test_motion_view.py @@ -1,5 +1,6 @@ """Test state getters for retrieving motion planning views of state.""" import inspect +from typing import List import pytest from decoy import Decoy @@ -15,14 +16,17 @@ LoadedPipette, DeckSlotLocation, CurrentWell, + MotorAxis, ) from opentrons.protocol_engine.state import PipetteLocationData, move_types +from opentrons.protocol_engine.state.config import Config from opentrons.protocol_engine.state.labware import LabwareView from opentrons.protocol_engine.state.pipettes import PipetteView from opentrons.protocol_engine.state.geometry import GeometryView from opentrons.protocol_engine.state.motion import MotionView from opentrons.protocol_engine.state.modules import ModuleView from opentrons.protocol_engine.state.module_substates import HeaterShakerModuleId +from opentrons_shared_data.robot.dev_types import RobotType @pytest.fixture @@ -45,8 +49,15 @@ def patch_mock_move_types(decoy: Decoy, monkeypatch: pytest.MonkeyPatch) -> None monkeypatch.setattr(move_types, name, decoy.mock(func=func)) +@pytest.fixture +def mock_engine_config(decoy: Decoy) -> Config: + """Get a ProtocolEngine config value object.""" + return decoy.mock(cls=Config) + + @pytest.fixture def subject( + mock_engine_config: Config, labware_view: LabwareView, pipette_view: PipetteView, geometry_view: GeometryView, @@ -54,6 +65,7 @@ def subject( ) -> MotionView: """Get a MotionView with its dependencies mocked out.""" return MotionView( + config=mock_engine_config, labware_view=labware_view, pipette_view=pipette_view, geometry_view=geometry_view, @@ -562,3 +574,22 @@ def test_get_touch_tip_waypoints( position=Point(x=44, y=55, z=66), critical_point=CriticalPoint.XY_CENTER ), ] + + +@pytest.mark.parametrize( + argnames=["robot_type", "expected_axes"], + argvalues=[ + ["OT-2 Standard", [MotorAxis.LEFT_Z, MotorAxis.RIGHT_Z]], + ["OT-3 Standard", [MotorAxis.LEFT_Z, MotorAxis.RIGHT_Z, MotorAxis.EXTENSION_Z]], + ], +) +def test_get_mount_axes( + decoy: Decoy, + mock_engine_config: Config, + subject: MotionView, + robot_type: RobotType, + expected_axes: List[MotorAxis], +) -> None: + """It should return the correct mount axes for the robot type.""" + decoy.when(mock_engine_config.robot_type).then_return(robot_type) + assert subject.get_robot_mount_axes() == expected_axes