opentrons 8.3.0a0__py2.py3-none-any.whl → 8.3.0a2__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opentrons/calibration_storage/deck_configuration.py +3 -3
- opentrons/calibration_storage/file_operators.py +3 -3
- opentrons/calibration_storage/helpers.py +3 -1
- opentrons/calibration_storage/ot2/models/v1.py +16 -29
- opentrons/calibration_storage/ot2/tip_length.py +7 -4
- opentrons/calibration_storage/ot3/models/v1.py +14 -23
- opentrons/cli/analyze.py +18 -6
- opentrons/drivers/asyncio/communication/__init__.py +2 -0
- opentrons/drivers/asyncio/communication/errors.py +16 -3
- opentrons/drivers/asyncio/communication/serial_connection.py +24 -9
- opentrons/drivers/command_builder.py +2 -2
- opentrons/drivers/flex_stacker/__init__.py +9 -0
- opentrons/drivers/flex_stacker/abstract.py +89 -0
- opentrons/drivers/flex_stacker/driver.py +260 -0
- opentrons/drivers/flex_stacker/simulator.py +109 -0
- opentrons/drivers/flex_stacker/types.py +138 -0
- opentrons/drivers/heater_shaker/driver.py +18 -3
- opentrons/drivers/temp_deck/driver.py +13 -3
- opentrons/drivers/thermocycler/driver.py +17 -3
- opentrons/execute.py +3 -1
- opentrons/hardware_control/__init__.py +1 -2
- opentrons/hardware_control/api.py +28 -20
- opentrons/hardware_control/backends/flex_protocol.py +4 -6
- opentrons/hardware_control/backends/ot3controller.py +177 -59
- opentrons/hardware_control/backends/ot3simulator.py +10 -8
- opentrons/hardware_control/backends/ot3utils.py +3 -13
- opentrons/hardware_control/dev_types.py +2 -0
- opentrons/hardware_control/emulation/heater_shaker.py +4 -0
- opentrons/hardware_control/emulation/module_server/client.py +1 -1
- opentrons/hardware_control/emulation/module_server/server.py +5 -3
- opentrons/hardware_control/emulation/settings.py +3 -4
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +2 -1
- opentrons/hardware_control/instruments/ot2/pipette.py +9 -21
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +8 -1
- opentrons/hardware_control/instruments/ot3/gripper.py +2 -2
- opentrons/hardware_control/instruments/ot3/pipette.py +13 -22
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -1
- opentrons/hardware_control/modules/mod_abc.py +2 -2
- opentrons/hardware_control/motion_utilities.py +68 -0
- opentrons/hardware_control/nozzle_manager.py +39 -41
- opentrons/hardware_control/ot3_calibration.py +1 -1
- opentrons/hardware_control/ot3api.py +34 -22
- opentrons/hardware_control/protocols/gripper_controller.py +3 -0
- opentrons/hardware_control/protocols/hardware_manager.py +5 -1
- opentrons/hardware_control/protocols/liquid_handler.py +18 -0
- opentrons/hardware_control/protocols/motion_controller.py +6 -0
- opentrons/hardware_control/robot_calibration.py +1 -1
- opentrons/hardware_control/types.py +61 -0
- opentrons/protocol_api/__init__.py +20 -1
- opentrons/protocol_api/_liquid.py +24 -49
- opentrons/protocol_api/_liquid_properties.py +754 -0
- opentrons/protocol_api/_types.py +24 -0
- opentrons/protocol_api/core/common.py +2 -0
- opentrons/protocol_api/core/engine/instrument.py +67 -10
- opentrons/protocol_api/core/engine/labware.py +29 -7
- opentrons/protocol_api/core/engine/protocol.py +130 -5
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/well.py +4 -1
- opentrons/protocol_api/core/instrument.py +42 -4
- opentrons/protocol_api/core/labware.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +34 -3
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +32 -1
- opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +34 -3
- opentrons/protocol_api/core/protocol.py +34 -1
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/instrument_context.py +145 -43
- opentrons/protocol_api/labware.py +231 -7
- opentrons/protocol_api/module_contexts.py +21 -17
- opentrons/protocol_api/protocol_context.py +125 -4
- opentrons/protocol_api/robot_context.py +204 -32
- opentrons/protocol_api/validation.py +261 -3
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/actions.py +2 -3
- opentrons/protocol_engine/clients/sync_client.py +18 -0
- opentrons/protocol_engine/commands/__init__.py +81 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +0 -2
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +19 -5
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +0 -1
- opentrons/protocol_engine/commands/absorbance_reader/read.py +32 -9
- opentrons/protocol_engine/commands/air_gap_in_place.py +160 -0
- opentrons/protocol_engine/commands/aspirate.py +103 -53
- opentrons/protocol_engine/commands/aspirate_in_place.py +55 -51
- opentrons/protocol_engine/commands/blow_out.py +44 -39
- opentrons/protocol_engine/commands/blow_out_in_place.py +21 -32
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +13 -6
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +1 -1
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +3 -3
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +1 -1
- opentrons/protocol_engine/commands/command.py +73 -66
- opentrons/protocol_engine/commands/command_unions.py +101 -1
- opentrons/protocol_engine/commands/comment.py +1 -1
- opentrons/protocol_engine/commands/configure_for_volume.py +10 -3
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +6 -4
- opentrons/protocol_engine/commands/custom.py +6 -12
- opentrons/protocol_engine/commands/dispense.py +82 -48
- opentrons/protocol_engine/commands/dispense_in_place.py +71 -51
- opentrons/protocol_engine/commands/drop_tip.py +52 -31
- opentrons/protocol_engine/commands/drop_tip_in_place.py +13 -3
- opentrons/protocol_engine/commands/generate_command_schema.py +4 -11
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/home.py +13 -4
- opentrons/protocol_engine/commands/liquid_probe.py +60 -25
- opentrons/protocol_engine/commands/load_labware.py +29 -7
- opentrons/protocol_engine/commands/load_lid.py +146 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +189 -0
- opentrons/protocol_engine/commands/load_liquid.py +12 -4
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +31 -10
- opentrons/protocol_engine/commands/load_pipette.py +19 -8
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +1 -1
- opentrons/protocol_engine/commands/magnetic_module/engage.py +1 -1
- opentrons/protocol_engine/commands/move_labware.py +19 -6
- opentrons/protocol_engine/commands/move_relative.py +35 -25
- opentrons/protocol_engine/commands/move_to_addressable_area.py +40 -27
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +53 -32
- opentrons/protocol_engine/commands/move_to_coordinates.py +36 -22
- opentrons/protocol_engine/commands/move_to_well.py +40 -24
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +49 -27
- opentrons/protocol_engine/commands/pipetting_common.py +169 -87
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +24 -33
- opentrons/protocol_engine/commands/reload_labware.py +1 -1
- opentrons/protocol_engine/commands/retract_axis.py +1 -1
- opentrons/protocol_engine/commands/robot/__init__.py +69 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +86 -0
- opentrons/protocol_engine/commands/robot/common.py +18 -0
- opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
- opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
- opentrons/protocol_engine/commands/robot/move_to.py +94 -0
- opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +77 -0
- opentrons/protocol_engine/commands/save_position.py +14 -5
- opentrons/protocol_engine/commands/set_rail_lights.py +1 -1
- opentrons/protocol_engine/commands/set_status_bar.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +8 -2
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +9 -3
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +11 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/touch_tip.py +65 -16
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +4 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +1 -4
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +1 -4
- opentrons/protocol_engine/commands/verify_tip_presence.py +11 -4
- opentrons/protocol_engine/commands/wait_for_duration.py +10 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +10 -3
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/error_occurrence.py +19 -20
- opentrons/protocol_engine/errors/exceptions.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +73 -5
- opentrons/protocol_engine/execution/gantry_mover.py +364 -8
- opentrons/protocol_engine/execution/movement.py +27 -0
- opentrons/protocol_engine/execution/pipetting.py +5 -1
- opentrons/protocol_engine/execution/tip_handler.py +4 -6
- opentrons/protocol_engine/notes/notes.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +7 -6
- opentrons/protocol_engine/resources/labware_data_provider.py +1 -1
- opentrons/protocol_engine/resources/labware_validation.py +5 -0
- opentrons/protocol_engine/resources/module_data_provider.py +1 -1
- opentrons/protocol_engine/resources/pipette_data_provider.py +12 -0
- opentrons/protocol_engine/slot_standardization.py +9 -9
- opentrons/protocol_engine/state/_move_types.py +9 -5
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +25 -61
- opentrons/protocol_engine/state/command_history.py +12 -0
- opentrons/protocol_engine/state/commands.py +17 -13
- opentrons/protocol_engine/state/files.py +10 -12
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/frustum_helpers.py +57 -32
- opentrons/protocol_engine/state/geometry.py +47 -1
- opentrons/protocol_engine/state/labware.py +79 -25
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +16 -4
- opentrons/protocol_engine/state/modules.py +52 -70
- opentrons/protocol_engine/state/motion.py +6 -1
- opentrons/protocol_engine/state/pipettes.py +135 -58
- opentrons/protocol_engine/state/state.py +21 -2
- opentrons/protocol_engine/state/state_summary.py +4 -2
- opentrons/protocol_engine/state/tips.py +11 -44
- opentrons/protocol_engine/state/update_types.py +343 -48
- opentrons/protocol_engine/state/wells.py +19 -11
- opentrons/protocol_engine/types.py +176 -28
- opentrons/protocol_reader/extract_labware_definitions.py +5 -2
- opentrons/protocol_reader/file_format_validator.py +5 -5
- opentrons/protocol_runner/json_file_reader.py +9 -3
- opentrons/protocol_runner/json_translator.py +51 -25
- opentrons/protocol_runner/legacy_command_mapper.py +66 -64
- opentrons/protocol_runner/protocol_runner.py +35 -4
- opentrons/protocol_runner/python_protocol_wrappers.py +1 -1
- opentrons/protocol_runner/run_orchestrator.py +13 -3
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +1 -1
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +56 -0
- opentrons/protocols/advanced_control/{transfers.py → transfers/transfer.py} +10 -85
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/instrument.py +1 -1
- opentrons/protocols/api_support/util.py +10 -0
- opentrons/protocols/labware.py +70 -8
- opentrons/protocols/models/json_protocol.py +5 -9
- opentrons/simulate.py +3 -1
- opentrons/types.py +162 -2
- opentrons/util/entrypoint_util.py +2 -5
- opentrons/util/logging_config.py +1 -1
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/METADATA +16 -15
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/RECORD +229 -202
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/WHEEL +1 -1
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/LICENSE +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/entry_points.txt +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/top_level.txt +0 -0
opentrons/protocol_api/_types.py
CHANGED
|
@@ -17,3 +17,27 @@ A special location value, indicating that a labware is not currently on the robo
|
|
|
17
17
|
|
|
18
18
|
See :ref:`off-deck-location` for details on using ``OFF_DECK`` with :py:obj:`ProtocolContext.move_labware()`.
|
|
19
19
|
"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class PlungerPositionTypes(enum.Enum):
|
|
23
|
+
PLUNGER_TOP = "top"
|
|
24
|
+
PLUNGER_BOTTOM = "bottom"
|
|
25
|
+
PLUNGER_BLOWOUT = "blow_out"
|
|
26
|
+
PLUNGER_DROPTIP = "drop_tip"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
PLUNGER_TOP: Final = PlungerPositionTypes.PLUNGER_TOP
|
|
30
|
+
PLUNGER_BOTTOM: Final = PlungerPositionTypes.PLUNGER_BOTTOM
|
|
31
|
+
PLUNGER_BLOWOUT: Final = PlungerPositionTypes.PLUNGER_BLOWOUT
|
|
32
|
+
PLUNGER_DROPTIP: Final = PlungerPositionTypes.PLUNGER_DROPTIP
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PipetteActionTypes(enum.Enum):
|
|
36
|
+
ASPIRATE_ACTION = "aspirate"
|
|
37
|
+
DISPENSE_ACTION = "dispense"
|
|
38
|
+
BLOWOUT_ACTION = "blowout"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
ASPIRATE_ACTION: Final = PipetteActionTypes.ASPIRATE_ACTION
|
|
42
|
+
DISPENSE_ACTION: Final = PipetteActionTypes.DISPENSE_ACTION
|
|
43
|
+
BLOWOUT_ACTION: Final = PipetteActionTypes.BLOWOUT_ACTION
|
|
@@ -14,6 +14,7 @@ from .module import (
|
|
|
14
14
|
)
|
|
15
15
|
from .protocol import AbstractProtocol
|
|
16
16
|
from .well import AbstractWellCore
|
|
17
|
+
from .robot import AbstractRobot
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
WellCore = AbstractWellCore
|
|
@@ -26,4 +27,5 @@ ThermocyclerCore = AbstractThermocyclerCore
|
|
|
26
27
|
HeaterShakerCore = AbstractHeaterShakerCore
|
|
27
28
|
MagneticBlockCore = AbstractMagneticBlockCore
|
|
28
29
|
AbsorbanceReaderCore = AbstractAbsorbanceReaderCore
|
|
30
|
+
RobotCore = AbstractRobot
|
|
29
31
|
ProtocolCore = AbstractProtocol[InstrumentCore, LabwareCore, ModuleCore]
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"""ProtocolEngine-based InstrumentContext core implementation."""
|
|
2
|
-
from __future__ import annotations
|
|
3
2
|
|
|
4
|
-
from
|
|
5
|
-
from opentrons.protocols.api_support.types import APIVersion
|
|
3
|
+
from __future__ import annotations
|
|
6
4
|
|
|
7
|
-
from
|
|
5
|
+
from typing import Optional, TYPE_CHECKING, cast, Union, List
|
|
6
|
+
from opentrons.types import Location, Mount, NozzleConfigurationType, NozzleMapInterface
|
|
8
7
|
from opentrons.hardware_control import SyncHardwareAPI
|
|
9
8
|
from opentrons.hardware_control.dev_types import PipetteDict
|
|
10
9
|
from opentrons.protocols.api_support.util import FlowRates, find_value_for_api_version
|
|
10
|
+
from opentrons.protocols.api_support.types import APIVersion
|
|
11
|
+
from opentrons.protocols.advanced_control.transfers.common import TransferTipPolicyV2
|
|
11
12
|
from opentrons.protocol_engine import commands as cmd
|
|
12
13
|
from opentrons.protocol_engine import (
|
|
13
14
|
DeckPoint,
|
|
@@ -26,6 +27,7 @@ from opentrons.protocol_engine.types import (
|
|
|
26
27
|
PRIMARY_NOZZLE_LITERAL,
|
|
27
28
|
NozzleLayoutConfigurationType,
|
|
28
29
|
AddressableOffsetVector,
|
|
30
|
+
LiquidClassRecord,
|
|
29
31
|
)
|
|
30
32
|
from opentrons.protocol_engine.errors.exceptions import TipNotAttachedError
|
|
31
33
|
from opentrons.protocol_engine.clients import SyncClient as EngineClient
|
|
@@ -35,18 +37,15 @@ from opentrons_shared_data.errors.exceptions import (
|
|
|
35
37
|
UnsupportedHardwareCommand,
|
|
36
38
|
)
|
|
37
39
|
from opentrons.protocol_api._nozzle_layout import NozzleLayout
|
|
38
|
-
from opentrons.hardware_control.nozzle_manager import NozzleConfigurationType
|
|
39
|
-
from opentrons.hardware_control.nozzle_manager import NozzleMap
|
|
40
40
|
from . import overlap_versions, pipette_movement_conflict
|
|
41
41
|
|
|
42
|
-
from ..instrument import AbstractInstrument
|
|
43
42
|
from .well import WellCore
|
|
44
|
-
|
|
43
|
+
from ..instrument import AbstractInstrument
|
|
45
44
|
from ...disposal_locations import TrashBin, WasteChute
|
|
46
45
|
|
|
47
46
|
if TYPE_CHECKING:
|
|
48
47
|
from .protocol import ProtocolCore
|
|
49
|
-
|
|
48
|
+
from opentrons.protocol_api._liquid import LiquidClass
|
|
50
49
|
|
|
51
50
|
_DISPENSE_VOLUME_VALIDATION_ADDED_IN = APIVersion(2, 17)
|
|
52
51
|
|
|
@@ -114,6 +113,19 @@ class InstrumentCore(AbstractInstrument[WellCore]):
|
|
|
114
113
|
pipette_id=self._pipette_id, speed=speed
|
|
115
114
|
)
|
|
116
115
|
|
|
116
|
+
def air_gap_in_place(self, volume: float, flow_rate: float) -> None:
|
|
117
|
+
"""Aspirate a given volume of air from the current location of the pipette.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
volume: The volume of air to aspirate, in microliters.
|
|
121
|
+
folw_rate: The flow rate of air into the pipette, in microliters/s
|
|
122
|
+
"""
|
|
123
|
+
self._engine_client.execute_command(
|
|
124
|
+
cmd.AirGapInPlaceParams(
|
|
125
|
+
pipetteId=self._pipette_id, volume=volume, flowRate=flow_rate
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
|
|
117
129
|
def aspirate(
|
|
118
130
|
self,
|
|
119
131
|
location: Location,
|
|
@@ -734,7 +746,7 @@ class InstrumentCore(AbstractInstrument[WellCore]):
|
|
|
734
746
|
self._pipette_id
|
|
735
747
|
)
|
|
736
748
|
|
|
737
|
-
def get_nozzle_map(self) ->
|
|
749
|
+
def get_nozzle_map(self) -> NozzleMapInterface:
|
|
738
750
|
return self._engine_client.state.tips.get_pipette_nozzle_map(self._pipette_id)
|
|
739
751
|
|
|
740
752
|
def has_tip(self) -> bool:
|
|
@@ -852,6 +864,45 @@ class InstrumentCore(AbstractInstrument[WellCore]):
|
|
|
852
864
|
)
|
|
853
865
|
)
|
|
854
866
|
|
|
867
|
+
def load_liquid_class(
|
|
868
|
+
self,
|
|
869
|
+
liquid_class: LiquidClass,
|
|
870
|
+
pipette_load_name: str,
|
|
871
|
+
tiprack_uri: str,
|
|
872
|
+
) -> str:
|
|
873
|
+
"""Load a liquid class into the engine and return its ID."""
|
|
874
|
+
transfer_props = liquid_class.get_for(
|
|
875
|
+
pipette=pipette_load_name, tiprack=tiprack_uri
|
|
876
|
+
)
|
|
877
|
+
|
|
878
|
+
liquid_class_record = LiquidClassRecord(
|
|
879
|
+
liquidClassName=liquid_class.name,
|
|
880
|
+
pipetteModel=self.get_model(), # TODO: verify this is the correct 'model' to use
|
|
881
|
+
tiprack=tiprack_uri,
|
|
882
|
+
aspirate=transfer_props.aspirate.as_shared_data_model(),
|
|
883
|
+
singleDispense=transfer_props.dispense.as_shared_data_model(),
|
|
884
|
+
multiDispense=transfer_props.multi_dispense.as_shared_data_model()
|
|
885
|
+
if transfer_props.multi_dispense
|
|
886
|
+
else None,
|
|
887
|
+
)
|
|
888
|
+
result = self._engine_client.execute_command_without_recovery(
|
|
889
|
+
cmd.LoadLiquidClassParams(
|
|
890
|
+
liquidClassRecord=liquid_class_record,
|
|
891
|
+
)
|
|
892
|
+
)
|
|
893
|
+
return result.liquidClassId
|
|
894
|
+
|
|
895
|
+
def transfer_liquid(
|
|
896
|
+
self,
|
|
897
|
+
liquid_class_id: str,
|
|
898
|
+
volume: float,
|
|
899
|
+
source: List[WellCore],
|
|
900
|
+
dest: List[WellCore],
|
|
901
|
+
new_tip: TransferTipPolicyV2,
|
|
902
|
+
trash_location: Union[WellCore, Location, TrashBin, WasteChute],
|
|
903
|
+
) -> None:
|
|
904
|
+
"""Execute transfer using liquid class properties."""
|
|
905
|
+
|
|
855
906
|
def retract(self) -> None:
|
|
856
907
|
"""Retract this instrument to the top of the gantry."""
|
|
857
908
|
z_axis = self._engine_client.state.pipettes.get_z_axis(self._pipette_id)
|
|
@@ -937,3 +988,9 @@ class InstrumentCore(AbstractInstrument[WellCore]):
|
|
|
937
988
|
self._protocol_core.set_last_location(location=loc, mount=self.get_mount())
|
|
938
989
|
|
|
939
990
|
return result.z_position
|
|
991
|
+
|
|
992
|
+
def nozzle_configuration_valid_for_lld(self) -> bool:
|
|
993
|
+
"""Check if the nozzle configuration currently supports LLD."""
|
|
994
|
+
return self._engine_client.state.pipettes.get_nozzle_configuration_supports_lld(
|
|
995
|
+
self.pipette_id
|
|
996
|
+
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""ProtocolEngine-based Labware core implementations."""
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional, cast, Dict
|
|
3
4
|
|
|
4
5
|
from opentrons_shared_data.labware.types import (
|
|
5
6
|
LabwareParameters as LabwareParametersDict,
|
|
@@ -19,11 +20,12 @@ from opentrons.protocol_engine.types import (
|
|
|
19
20
|
LabwareOffsetCreate,
|
|
20
21
|
LabwareOffsetVector,
|
|
21
22
|
)
|
|
22
|
-
from opentrons.types import DeckSlotName, Point, StagingSlotName
|
|
23
|
-
from opentrons.hardware_control.nozzle_manager import NozzleMap
|
|
23
|
+
from opentrons.types import DeckSlotName, NozzleMapInterface, Point, StagingSlotName
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
from ..._liquid import Liquid
|
|
26
27
|
from ..labware import AbstractLabware, LabwareLoadParams
|
|
28
|
+
|
|
27
29
|
from .well import WellCore
|
|
28
30
|
|
|
29
31
|
|
|
@@ -90,12 +92,14 @@ class LabwareCore(AbstractLabware[WellCore]):
|
|
|
90
92
|
|
|
91
93
|
def get_definition(self) -> LabwareDefinitionDict:
|
|
92
94
|
"""Get the labware's definition as a plain dictionary."""
|
|
93
|
-
return cast(
|
|
95
|
+
return cast(
|
|
96
|
+
LabwareDefinitionDict, self._definition.model_dump(exclude_none=True)
|
|
97
|
+
)
|
|
94
98
|
|
|
95
99
|
def get_parameters(self) -> LabwareParametersDict:
|
|
96
100
|
return cast(
|
|
97
101
|
LabwareParametersDict,
|
|
98
|
-
self._definition.parameters.
|
|
102
|
+
self._definition.parameters.model_dump(exclude_none=True),
|
|
99
103
|
)
|
|
100
104
|
|
|
101
105
|
def get_quirks(self) -> List[str]:
|
|
@@ -116,7 +120,7 @@ class LabwareCore(AbstractLabware[WellCore]):
|
|
|
116
120
|
details={"kind": "labware-not-in-slot"},
|
|
117
121
|
)
|
|
118
122
|
|
|
119
|
-
request = LabwareOffsetCreate.
|
|
123
|
+
request = LabwareOffsetCreate.model_construct(
|
|
120
124
|
definitionUri=self.get_uri(),
|
|
121
125
|
location=offset_location,
|
|
122
126
|
vector=LabwareOffsetVector(x=delta.x, y=delta.y, z=delta.z),
|
|
@@ -162,7 +166,7 @@ class LabwareCore(AbstractLabware[WellCore]):
|
|
|
162
166
|
self,
|
|
163
167
|
num_tips: int,
|
|
164
168
|
starting_tip: Optional[WellCore],
|
|
165
|
-
nozzle_map: Optional[
|
|
169
|
+
nozzle_map: Optional[NozzleMapInterface],
|
|
166
170
|
) -> Optional[str]:
|
|
167
171
|
return self._engine_client.state.tips.get_next_tip(
|
|
168
172
|
labware_id=self._labware_id,
|
|
@@ -203,3 +207,21 @@ class LabwareCore(AbstractLabware[WellCore]):
|
|
|
203
207
|
LocationIsStagingSlotError,
|
|
204
208
|
):
|
|
205
209
|
return None
|
|
210
|
+
|
|
211
|
+
def load_liquid(self, volumes: Dict[str, float], liquid: Liquid) -> None:
|
|
212
|
+
"""Load liquid into wells of the labware."""
|
|
213
|
+
self._engine_client.execute_command(
|
|
214
|
+
cmd.LoadLiquidParams(
|
|
215
|
+
labwareId=self._labware_id, liquidId=liquid._id, volumeByWell=volumes
|
|
216
|
+
)
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def load_empty(self, wells: List[str]) -> None:
|
|
220
|
+
"""Mark wells of the labware as empty."""
|
|
221
|
+
self._engine_client.execute_command(
|
|
222
|
+
cmd.LoadLiquidParams(
|
|
223
|
+
labwareId=self._labware_id,
|
|
224
|
+
liquidId="EMPTY",
|
|
225
|
+
volumeByWell={well: 0.0 for well in wells},
|
|
226
|
+
)
|
|
227
|
+
)
|
|
@@ -6,6 +6,7 @@ from opentrons_shared_data.liquid_classes import LiquidClassDefinitionDoesNotExi
|
|
|
6
6
|
|
|
7
7
|
from opentrons.protocol_engine import commands as cmd
|
|
8
8
|
from opentrons.protocol_engine.commands import LoadModuleResult
|
|
9
|
+
|
|
9
10
|
from opentrons_shared_data.deck.types import DeckDefinitionV5, SlotDefV3
|
|
10
11
|
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
11
12
|
from opentrons_shared_data.labware.types import LabwareDefinition as LabwareDefDict
|
|
@@ -63,6 +64,7 @@ from ..protocol import AbstractProtocol
|
|
|
63
64
|
from ..labware import LabwareLoadParams
|
|
64
65
|
from .labware import LabwareCore
|
|
65
66
|
from .instrument import InstrumentCore
|
|
67
|
+
from .robot import RobotCore
|
|
66
68
|
from .module_core import (
|
|
67
69
|
ModuleCore,
|
|
68
70
|
TemperatureModuleCore,
|
|
@@ -82,7 +84,9 @@ if TYPE_CHECKING:
|
|
|
82
84
|
|
|
83
85
|
class ProtocolCore(
|
|
84
86
|
AbstractProtocol[
|
|
85
|
-
InstrumentCore,
|
|
87
|
+
InstrumentCore,
|
|
88
|
+
LabwareCore,
|
|
89
|
+
Union[ModuleCore, NonConnectedModuleCore],
|
|
86
90
|
]
|
|
87
91
|
):
|
|
88
92
|
"""Protocol API core using a ProtocolEngine.
|
|
@@ -189,7 +193,7 @@ class ProtocolCore(
|
|
|
189
193
|
) -> LabwareLoadParams:
|
|
190
194
|
"""Add a labware definition to the set of loadable definitions."""
|
|
191
195
|
uri = self._engine_client.add_labware_definition(
|
|
192
|
-
LabwareDefinition.
|
|
196
|
+
LabwareDefinition.model_validate(definition)
|
|
193
197
|
)
|
|
194
198
|
return LabwareLoadParams.from_uri(uri)
|
|
195
199
|
|
|
@@ -229,6 +233,9 @@ class ProtocolCore(
|
|
|
229
233
|
)
|
|
230
234
|
# FIXME(jbl, 2023-08-14) validating after loading the object issue
|
|
231
235
|
validation.ensure_definition_is_labware(load_result.definition)
|
|
236
|
+
validation.ensure_definition_is_not_lid_after_api_version(
|
|
237
|
+
self.api_version, load_result.definition
|
|
238
|
+
)
|
|
232
239
|
|
|
233
240
|
# FIXME(mm, 2023-02-21):
|
|
234
241
|
#
|
|
@@ -318,6 +325,52 @@ class ProtocolCore(
|
|
|
318
325
|
|
|
319
326
|
return labware_core
|
|
320
327
|
|
|
328
|
+
def load_lid(
|
|
329
|
+
self,
|
|
330
|
+
load_name: str,
|
|
331
|
+
location: LabwareCore,
|
|
332
|
+
namespace: Optional[str],
|
|
333
|
+
version: Optional[int],
|
|
334
|
+
) -> LabwareCore:
|
|
335
|
+
"""Load an individual lid using its identifying parameters. Must be loaded on an existing Labware."""
|
|
336
|
+
load_location = self._convert_labware_location(location=location)
|
|
337
|
+
custom_labware_params = (
|
|
338
|
+
self._engine_client.state.labware.find_custom_labware_load_params()
|
|
339
|
+
)
|
|
340
|
+
namespace, version = load_labware_params.resolve(
|
|
341
|
+
load_name, namespace, version, custom_labware_params
|
|
342
|
+
)
|
|
343
|
+
load_result = self._engine_client.execute_command_without_recovery(
|
|
344
|
+
cmd.LoadLidParams(
|
|
345
|
+
loadName=load_name,
|
|
346
|
+
location=load_location,
|
|
347
|
+
namespace=namespace,
|
|
348
|
+
version=version,
|
|
349
|
+
)
|
|
350
|
+
)
|
|
351
|
+
# FIXME(chb, 2024-12-06) validating after loading the object issue
|
|
352
|
+
validation.ensure_definition_is_lid(load_result.definition)
|
|
353
|
+
|
|
354
|
+
deck_conflict.check(
|
|
355
|
+
engine_state=self._engine_client.state,
|
|
356
|
+
new_labware_id=load_result.labwareId,
|
|
357
|
+
existing_disposal_locations=self._disposal_locations,
|
|
358
|
+
# TODO: We can now fetch these IDs from engine too.
|
|
359
|
+
# See comment in self.load_labware().
|
|
360
|
+
#
|
|
361
|
+
# Wrapping .keys() in list() is just to make Decoy verification easier.
|
|
362
|
+
existing_labware_ids=list(self._labware_cores_by_id.keys()),
|
|
363
|
+
existing_module_ids=list(self._module_cores_by_id.keys()),
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
labware_core = LabwareCore(
|
|
367
|
+
labware_id=load_result.labwareId,
|
|
368
|
+
engine_client=self._engine_client,
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
self._labware_cores_by_id[labware_core.labware_id] = labware_core
|
|
372
|
+
return labware_core
|
|
373
|
+
|
|
321
374
|
def move_labware(
|
|
322
375
|
self,
|
|
323
376
|
labware_core: LabwareCore,
|
|
@@ -422,6 +475,8 @@ class ProtocolCore(
|
|
|
422
475
|
raise InvalidModuleLocationError(deck_slot, model.name)
|
|
423
476
|
|
|
424
477
|
robot_type = self._engine_client.state.config.robot_type
|
|
478
|
+
# todo(mm, 2024-12-03): This might be possible to remove:
|
|
479
|
+
# Protocol Engine will normalize the deck slot itself.
|
|
425
480
|
normalized_deck_slot = deck_slot.to_equivalent_for_robot_type(robot_type)
|
|
426
481
|
|
|
427
482
|
result = self._engine_client.execute_command_without_recovery(
|
|
@@ -502,6 +557,12 @@ class ProtocolCore(
|
|
|
502
557
|
load_module_result=load_module_result, model=model
|
|
503
558
|
)
|
|
504
559
|
|
|
560
|
+
def load_robot(self) -> RobotCore:
|
|
561
|
+
"""Load a robot core into the RobotContext."""
|
|
562
|
+
return RobotCore(
|
|
563
|
+
engine_client=self._engine_client, sync_hardware_api=self._sync_hardware
|
|
564
|
+
)
|
|
565
|
+
|
|
505
566
|
def load_instrument(
|
|
506
567
|
self,
|
|
507
568
|
instrument_name: PipetteNameType,
|
|
@@ -632,6 +693,72 @@ class ProtocolCore(
|
|
|
632
693
|
self._last_location = location
|
|
633
694
|
self._last_mount = mount
|
|
634
695
|
|
|
696
|
+
def load_lid_stack(
|
|
697
|
+
self,
|
|
698
|
+
load_name: str,
|
|
699
|
+
location: Union[DeckSlotName, StagingSlotName, LabwareCore],
|
|
700
|
+
quantity: int,
|
|
701
|
+
namespace: Optional[str],
|
|
702
|
+
version: Optional[int],
|
|
703
|
+
) -> LabwareCore:
|
|
704
|
+
"""Load a Stack of Lids to a given location, creating a Lid Stack."""
|
|
705
|
+
if quantity < 1:
|
|
706
|
+
raise ValueError(
|
|
707
|
+
"When loading a lid stack quantity cannot be less than one."
|
|
708
|
+
)
|
|
709
|
+
if isinstance(location, DeckSlotName) or isinstance(location, StagingSlotName):
|
|
710
|
+
load_location = self._convert_labware_location(location=location)
|
|
711
|
+
else:
|
|
712
|
+
if isinstance(location, LabwareCore):
|
|
713
|
+
load_location = self._convert_labware_location(location=location)
|
|
714
|
+
else:
|
|
715
|
+
raise ValueError(
|
|
716
|
+
"Expected type of Labware Location for lid stack must be Labware, not Legacy Labware or Well."
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
custom_labware_params = (
|
|
720
|
+
self._engine_client.state.labware.find_custom_labware_load_params()
|
|
721
|
+
)
|
|
722
|
+
namespace, version = load_labware_params.resolve(
|
|
723
|
+
load_name, namespace, version, custom_labware_params
|
|
724
|
+
)
|
|
725
|
+
|
|
726
|
+
load_result = self._engine_client.execute_command_without_recovery(
|
|
727
|
+
cmd.LoadLidStackParams(
|
|
728
|
+
loadName=load_name,
|
|
729
|
+
location=load_location,
|
|
730
|
+
namespace=namespace,
|
|
731
|
+
version=version,
|
|
732
|
+
quantity=quantity,
|
|
733
|
+
)
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
# FIXME(CHB, 2024-12-04) just like load labware and load adapter we have a validating after loading the object issue
|
|
737
|
+
validation.ensure_definition_is_lid(load_result.definition)
|
|
738
|
+
|
|
739
|
+
deck_conflict.check(
|
|
740
|
+
engine_state=self._engine_client.state,
|
|
741
|
+
new_labware_id=load_result.stackLabwareId,
|
|
742
|
+
existing_disposal_locations=self._disposal_locations,
|
|
743
|
+
# TODO (spp, 2023-11-27): We've been using IDs from _labware_cores_by_id
|
|
744
|
+
# and _module_cores_by_id instead of getting the lists directly from engine
|
|
745
|
+
# because of the chance of engine carrying labware IDs from LPC too.
|
|
746
|
+
# But with https://github.com/Opentrons/opentrons/pull/13943,
|
|
747
|
+
# & LPC in maintenance runs, we can now rely on engine state for these IDs too.
|
|
748
|
+
# Wrapping .keys() in list() is just to make Decoy verification easier.
|
|
749
|
+
existing_labware_ids=list(self._labware_cores_by_id.keys()),
|
|
750
|
+
existing_module_ids=list(self._module_cores_by_id.keys()),
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
labware_core = LabwareCore(
|
|
754
|
+
labware_id=load_result.stackLabwareId,
|
|
755
|
+
engine_client=self._engine_client,
|
|
756
|
+
)
|
|
757
|
+
|
|
758
|
+
self._labware_cores_by_id[labware_core.labware_id] = labware_core
|
|
759
|
+
|
|
760
|
+
return labware_core
|
|
761
|
+
|
|
635
762
|
def get_deck_definition(self) -> DeckDefinitionV5:
|
|
636
763
|
"""Get the geometry definition of the robot's deck."""
|
|
637
764
|
return self._engine_client.state.labware.get_deck_definition()
|
|
@@ -725,9 +852,7 @@ class ProtocolCore(
|
|
|
725
852
|
_id=liquid.id,
|
|
726
853
|
name=liquid.displayName,
|
|
727
854
|
description=liquid.description,
|
|
728
|
-
display_color=(
|
|
729
|
-
liquid.displayColor.__root__ if liquid.displayColor else None
|
|
730
|
-
),
|
|
855
|
+
display_color=(liquid.displayColor.root if liquid.displayColor else None),
|
|
731
856
|
)
|
|
732
857
|
|
|
733
858
|
def define_liquid_class(self, name: str) -> LiquidClass:
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from typing import Optional, Dict, Union
|
|
2
|
+
from opentrons.hardware_control import SyncHardwareAPI
|
|
3
|
+
|
|
4
|
+
from opentrons.types import Mount, MountType, Point, AxisType, AxisMapType
|
|
5
|
+
from opentrons_shared_data.pipette import types as pip_types
|
|
6
|
+
from opentrons.protocol_api._types import PipetteActionTypes, PlungerPositionTypes
|
|
7
|
+
from opentrons.protocol_engine import commands as cmd
|
|
8
|
+
from opentrons.protocol_engine.clients import SyncClient as EngineClient
|
|
9
|
+
from opentrons.protocol_engine.types import DeckPoint, MotorAxis
|
|
10
|
+
|
|
11
|
+
from opentrons.protocol_api.core.robot import AbstractRobot
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_AXIS_TYPE_TO_MOTOR_AXIS = {
|
|
15
|
+
AxisType.X: MotorAxis.X,
|
|
16
|
+
AxisType.Y: MotorAxis.Y,
|
|
17
|
+
AxisType.P_L: MotorAxis.LEFT_PLUNGER,
|
|
18
|
+
AxisType.P_R: MotorAxis.RIGHT_PLUNGER,
|
|
19
|
+
AxisType.Z_L: MotorAxis.LEFT_Z,
|
|
20
|
+
AxisType.Z_R: MotorAxis.RIGHT_Z,
|
|
21
|
+
AxisType.Z_G: MotorAxis.EXTENSION_Z,
|
|
22
|
+
AxisType.G: MotorAxis.EXTENSION_JAW,
|
|
23
|
+
AxisType.Q: MotorAxis.AXIS_96_CHANNEL_CAM,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class RobotCore(AbstractRobot):
|
|
28
|
+
"""Robot API core using a ProtocolEngine.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
engine_client: A client to the ProtocolEngine that is executing the protocol.
|
|
32
|
+
api_version: The Python Protocol API versionat which this core is operating.
|
|
33
|
+
sync_hardware: A SynchronousAdapter-wrapped Hardware Control API.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self, engine_client: EngineClient, sync_hardware_api: SyncHardwareAPI
|
|
38
|
+
) -> None:
|
|
39
|
+
self._engine_client = engine_client
|
|
40
|
+
self._sync_hardware_api = sync_hardware_api
|
|
41
|
+
|
|
42
|
+
def _convert_to_engine_mount(self, axis_map: AxisMapType) -> Dict[MotorAxis, float]:
|
|
43
|
+
return {_AXIS_TYPE_TO_MOTOR_AXIS[ax]: dist for ax, dist in axis_map.items()}
|
|
44
|
+
|
|
45
|
+
def get_pipette_type_from_engine(
|
|
46
|
+
self, mount: Union[Mount, str]
|
|
47
|
+
) -> Optional[pip_types.PipetteNameType]:
|
|
48
|
+
"""Get the pipette attached to the given mount."""
|
|
49
|
+
if isinstance(mount, Mount):
|
|
50
|
+
engine_mount = MountType[mount.name]
|
|
51
|
+
else:
|
|
52
|
+
if mount.lower() == "right":
|
|
53
|
+
engine_mount = MountType.RIGHT
|
|
54
|
+
else:
|
|
55
|
+
engine_mount = MountType.LEFT
|
|
56
|
+
maybe_pipette = self._engine_client.state.pipettes.get_by_mount(engine_mount)
|
|
57
|
+
return maybe_pipette.pipetteName if maybe_pipette else None
|
|
58
|
+
|
|
59
|
+
def get_plunger_position_from_name(
|
|
60
|
+
self, mount: Mount, position_name: PlungerPositionTypes
|
|
61
|
+
) -> float:
|
|
62
|
+
engine_mount = MountType[mount.name]
|
|
63
|
+
maybe_pipette = self._engine_client.state.pipettes.get_by_mount(engine_mount)
|
|
64
|
+
if not maybe_pipette:
|
|
65
|
+
return 0.0
|
|
66
|
+
return self._engine_client.state.pipettes.lookup_plunger_position_name(
|
|
67
|
+
maybe_pipette.id, position_name.value
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def get_plunger_position_from_volume(
|
|
71
|
+
self, mount: Mount, volume: float, action: PipetteActionTypes, robot_type: str
|
|
72
|
+
) -> float:
|
|
73
|
+
engine_mount = MountType[mount.name]
|
|
74
|
+
maybe_pipette = self._engine_client.state.pipettes.get_by_mount(engine_mount)
|
|
75
|
+
if not maybe_pipette:
|
|
76
|
+
raise RuntimeError(
|
|
77
|
+
f"Cannot load plunger position as no pipette is attached to {mount}"
|
|
78
|
+
)
|
|
79
|
+
convert_volume = (
|
|
80
|
+
self._engine_client.state.pipettes.lookup_volume_to_mm_conversion(
|
|
81
|
+
maybe_pipette.id, volume, action.value
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
plunger_bottom = (
|
|
85
|
+
self._engine_client.state.pipettes.lookup_plunger_position_name(
|
|
86
|
+
maybe_pipette.id, "bottom"
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
mm = volume / convert_volume
|
|
90
|
+
if robot_type == "OT-2 Standard":
|
|
91
|
+
position = plunger_bottom + mm
|
|
92
|
+
else:
|
|
93
|
+
position = plunger_bottom - mm
|
|
94
|
+
return round(position, 6)
|
|
95
|
+
|
|
96
|
+
def move_to(self, mount: Mount, destination: Point, speed: Optional[float]) -> None:
|
|
97
|
+
engine_mount = MountType[mount.name]
|
|
98
|
+
engine_destination = DeckPoint(
|
|
99
|
+
x=destination.x, y=destination.y, z=destination.z
|
|
100
|
+
)
|
|
101
|
+
self._engine_client.execute_command(
|
|
102
|
+
cmd.robot.MoveToParams(
|
|
103
|
+
mount=engine_mount, destination=engine_destination, speed=speed
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def move_axes_to(
|
|
108
|
+
self,
|
|
109
|
+
axis_map: AxisMapType,
|
|
110
|
+
critical_point: Optional[AxisMapType],
|
|
111
|
+
speed: Optional[float],
|
|
112
|
+
) -> None:
|
|
113
|
+
axis_engine_map = self._convert_to_engine_mount(axis_map)
|
|
114
|
+
if critical_point:
|
|
115
|
+
critical_point_engine = self._convert_to_engine_mount(critical_point)
|
|
116
|
+
else:
|
|
117
|
+
critical_point_engine = None
|
|
118
|
+
|
|
119
|
+
self._engine_client.execute_command(
|
|
120
|
+
cmd.robot.MoveAxesToParams(
|
|
121
|
+
axis_map=axis_engine_map,
|
|
122
|
+
critical_point=critical_point_engine,
|
|
123
|
+
speed=speed,
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def move_axes_relative(self, axis_map: AxisMapType, speed: Optional[float]) -> None:
|
|
128
|
+
axis_engine_map = self._convert_to_engine_mount(axis_map)
|
|
129
|
+
self._engine_client.execute_command(
|
|
130
|
+
cmd.robot.MoveAxesRelativeParams(axis_map=axis_engine_map, speed=speed)
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def release_grip(self) -> None:
|
|
134
|
+
self._engine_client.execute_command(cmd.robot.openGripperJawParams())
|
|
135
|
+
|
|
136
|
+
def close_gripper(self, force: Optional[float] = None) -> None:
|
|
137
|
+
self._engine_client.execute_command(
|
|
138
|
+
cmd.robot.closeGripperJawParams(force=force)
|
|
139
|
+
)
|
|
@@ -130,7 +130,10 @@ class WellCore(AbstractWellCore):
|
|
|
130
130
|
liquid: Liquid,
|
|
131
131
|
volume: float,
|
|
132
132
|
) -> None:
|
|
133
|
-
"""Load liquid into a well.
|
|
133
|
+
"""Load liquid into a well.
|
|
134
|
+
|
|
135
|
+
If the well is known to be empty, use ``load_empty()`` instead of calling this with a 0.0 volume.
|
|
136
|
+
"""
|
|
134
137
|
self._engine_client.execute_command(
|
|
135
138
|
cmd.LoadLiquidParams(
|
|
136
139
|
labwareId=self._labware_id,
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from abc import abstractmethod, ABC
|
|
6
|
-
from typing import Any, Generic, Optional, TypeVar, Union
|
|
6
|
+
from typing import Any, Generic, Optional, TypeVar, Union, List
|
|
7
7
|
|
|
8
8
|
from opentrons import types
|
|
9
9
|
from opentrons.hardware_control.dev_types import PipetteDict
|
|
10
10
|
from opentrons.protocols.api_support.util import FlowRates
|
|
11
|
+
from opentrons.protocols.advanced_control.transfers.common import TransferTipPolicyV2
|
|
11
12
|
from opentrons.protocol_api._nozzle_layout import NozzleLayout
|
|
12
|
-
from opentrons.
|
|
13
|
-
|
|
13
|
+
from opentrons.protocol_api._liquid import LiquidClass
|
|
14
14
|
from ..disposal_locations import TrashBin, WasteChute
|
|
15
15
|
from .well import WellCoreType
|
|
16
16
|
|
|
@@ -24,6 +24,14 @@ class AbstractInstrument(ABC, Generic[WellCoreType]):
|
|
|
24
24
|
def set_default_speed(self, speed: float) -> None:
|
|
25
25
|
...
|
|
26
26
|
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def air_gap_in_place(self, volume: float, flow_rate: float) -> None:
|
|
29
|
+
"""Aspirate a given volume of air from the current location of the pipette.
|
|
30
|
+
Args:
|
|
31
|
+
volume: The volume of air to aspirate, in microliters.
|
|
32
|
+
flow_rate: The flow rate of air into the pipette, in microliters.
|
|
33
|
+
"""
|
|
34
|
+
|
|
27
35
|
@abstractmethod
|
|
28
36
|
def aspirate(
|
|
29
37
|
self,
|
|
@@ -222,7 +230,7 @@ class AbstractInstrument(ABC, Generic[WellCoreType]):
|
|
|
222
230
|
...
|
|
223
231
|
|
|
224
232
|
@abstractmethod
|
|
225
|
-
def get_nozzle_map(self) ->
|
|
233
|
+
def get_nozzle_map(self) -> types.NozzleMapInterface:
|
|
226
234
|
...
|
|
227
235
|
|
|
228
236
|
@abstractmethod
|
|
@@ -302,6 +310,32 @@ class AbstractInstrument(ABC, Generic[WellCoreType]):
|
|
|
302
310
|
"""
|
|
303
311
|
...
|
|
304
312
|
|
|
313
|
+
@abstractmethod
|
|
314
|
+
def load_liquid_class(
|
|
315
|
+
self,
|
|
316
|
+
liquid_class: LiquidClass,
|
|
317
|
+
pipette_load_name: str,
|
|
318
|
+
tiprack_uri: str,
|
|
319
|
+
) -> str:
|
|
320
|
+
"""Load the liquid class properties of given pipette and tiprack into the engine.
|
|
321
|
+
|
|
322
|
+
Returns: ID of the liquid class record
|
|
323
|
+
"""
|
|
324
|
+
...
|
|
325
|
+
|
|
326
|
+
@abstractmethod
|
|
327
|
+
def transfer_liquid(
|
|
328
|
+
self,
|
|
329
|
+
liquid_class_id: str,
|
|
330
|
+
volume: float,
|
|
331
|
+
source: List[WellCoreType],
|
|
332
|
+
dest: List[WellCoreType],
|
|
333
|
+
new_tip: TransferTipPolicyV2,
|
|
334
|
+
trash_location: Union[WellCoreType, types.Location, TrashBin, WasteChute],
|
|
335
|
+
) -> None:
|
|
336
|
+
"""Transfer a liquid from source to dest according to liquid class properties."""
|
|
337
|
+
...
|
|
338
|
+
|
|
305
339
|
@abstractmethod
|
|
306
340
|
def is_tip_tracking_available(self) -> bool:
|
|
307
341
|
"""Return whether auto tip tracking is available for the pipette's current nozzle configuration."""
|
|
@@ -331,5 +365,9 @@ class AbstractInstrument(ABC, Generic[WellCoreType]):
|
|
|
331
365
|
"""Do a liquid probe to find the level of the liquid in the well."""
|
|
332
366
|
...
|
|
333
367
|
|
|
368
|
+
@abstractmethod
|
|
369
|
+
def nozzle_configuration_valid_for_lld(self) -> bool:
|
|
370
|
+
"""Check if the nozzle configuration currently supports LLD."""
|
|
371
|
+
|
|
334
372
|
|
|
335
373
|
InstrumentCoreType = TypeVar("InstrumentCoreType", bound=AbstractInstrument[Any])
|