opentrons 8.2.0a3__py2.py3-none-any.whl → 8.3.0__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/config/defaults_ot3.py +1 -0
- 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 +33 -21
- opentrons/hardware_control/backends/flex_protocol.py +17 -7
- opentrons/hardware_control/backends/ot3controller.py +213 -63
- opentrons/hardware_control/backends/ot3simulator.py +18 -9
- opentrons/hardware_control/backends/ot3utils.py +43 -15
- opentrons/hardware_control/dev_types.py +4 -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 +15 -22
- 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 +23 -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 +78 -31
- 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 +22 -1
- opentrons/hardware_control/protocols/motion_controller.py +7 -0
- opentrons/hardware_control/robot_calibration.py +1 -1
- opentrons/hardware_control/types.py +61 -0
- opentrons/legacy_commands/commands.py +37 -0
- opentrons/legacy_commands/types.py +39 -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 +191 -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 +73 -4
- opentrons/protocol_api/core/labware.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +87 -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 +61 -3
- opentrons/protocol_api/core/protocol.py +34 -1
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/instrument_context.py +299 -44
- opentrons/protocol_api/labware.py +248 -9
- 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 +262 -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 +121 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +1 -3
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +20 -6
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +1 -2
- opentrons/protocol_engine/commands/absorbance_reader/read.py +40 -10
- 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 +140 -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 +79 -8
- opentrons/protocol_engine/commands/evotip_dispense.py +156 -0
- opentrons/protocol_engine/commands/evotip_seal_pipette.py +331 -0
- opentrons/protocol_engine/commands/evotip_unseal_pipette.py +160 -0
- 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 +125 -31
- opentrons/protocol_engine/commands/load_labware.py +33 -6
- 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 +28 -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 +9 -3
- 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 +5 -2
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +13 -4
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +2 -5
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +1 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +4 -2
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +2 -5
- 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 +12 -0
- opentrons/protocol_engine/errors/error_occurrence.py +19 -20
- opentrons/protocol_engine/errors/exceptions.py +76 -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 +369 -8
- opentrons/protocol_engine/execution/hardware_stopper.py +7 -7
- opentrons/protocol_engine/execution/movement.py +27 -0
- opentrons/protocol_engine/execution/pipetting.py +5 -1
- opentrons/protocol_engine/execution/tip_handler.py +34 -15
- 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 +18 -0
- opentrons/protocol_engine/resources/module_data_provider.py +1 -1
- opentrons/protocol_engine/resources/pipette_data_provider.py +26 -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 +22 -14
- opentrons/protocol_engine/state/files.py +10 -12
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/frustum_helpers.py +63 -69
- opentrons/protocol_engine/state/geometry.py +47 -1
- opentrons/protocol_engine/state/labware.py +92 -26
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +16 -4
- opentrons/protocol_engine/state/modules.py +56 -71
- opentrons/protocol_engine/state/motion.py +6 -1
- opentrons/protocol_engine/state/pipettes.py +149 -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.2.0a3.dist-info → opentrons-8.3.0.dist-info}/METADATA +16 -15
- {opentrons-8.2.0a3.dist-info → opentrons-8.3.0.dist-info}/RECORD +238 -208
- {opentrons-8.2.0a3.dist-info → opentrons-8.3.0.dist-info}/WHEEL +1 -1
- {opentrons-8.2.0a3.dist-info → opentrons-8.3.0.dist-info}/LICENSE +0 -0
- {opentrons-8.2.0a3.dist-info → opentrons-8.3.0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.2.0a3.dist-info → opentrons-8.3.0.dist-info}/top_level.txt +0 -0
|
@@ -10,7 +10,13 @@ from opentrons_shared_data.pipette.types import PipetteNameType
|
|
|
10
10
|
from opentrons_shared_data.labware.types import LabwareDefinition
|
|
11
11
|
from opentrons_shared_data.robot.types import RobotType
|
|
12
12
|
|
|
13
|
-
from opentrons.types import
|
|
13
|
+
from opentrons.types import (
|
|
14
|
+
DeckSlotName,
|
|
15
|
+
StagingSlotName,
|
|
16
|
+
Location,
|
|
17
|
+
Mount,
|
|
18
|
+
Point,
|
|
19
|
+
)
|
|
14
20
|
from opentrons.hardware_control import SyncHardwareAPI
|
|
15
21
|
from opentrons.hardware_control.modules.types import ModuleModel
|
|
16
22
|
from opentrons.protocols.api_support.util import AxisMaxSpeeds
|
|
@@ -19,6 +25,7 @@ from .instrument import InstrumentCoreType
|
|
|
19
25
|
from .labware import LabwareCoreType, LabwareLoadParams
|
|
20
26
|
from .module import ModuleCoreType
|
|
21
27
|
from .._liquid import Liquid, LiquidClass
|
|
28
|
+
from .robot import AbstractRobot
|
|
22
29
|
from .._types import OffDeckType
|
|
23
30
|
from ..disposal_locations import TrashBin, WasteChute
|
|
24
31
|
|
|
@@ -93,6 +100,17 @@ class AbstractProtocol(
|
|
|
93
100
|
"""Load an adapter using its identifying parameters"""
|
|
94
101
|
...
|
|
95
102
|
|
|
103
|
+
@abstractmethod
|
|
104
|
+
def load_lid(
|
|
105
|
+
self,
|
|
106
|
+
load_name: str,
|
|
107
|
+
location: LabwareCoreType,
|
|
108
|
+
namespace: Optional[str],
|
|
109
|
+
version: Optional[int],
|
|
110
|
+
) -> LabwareCoreType:
|
|
111
|
+
"""Load an individual lid labware using its identifying parameters. Must be loaded on a labware."""
|
|
112
|
+
...
|
|
113
|
+
|
|
96
114
|
@abstractmethod
|
|
97
115
|
def move_labware(
|
|
98
116
|
self,
|
|
@@ -190,6 +208,17 @@ class AbstractProtocol(
|
|
|
190
208
|
) -> None:
|
|
191
209
|
...
|
|
192
210
|
|
|
211
|
+
@abstractmethod
|
|
212
|
+
def load_lid_stack(
|
|
213
|
+
self,
|
|
214
|
+
load_name: str,
|
|
215
|
+
location: Union[DeckSlotName, StagingSlotName, LabwareCoreType],
|
|
216
|
+
quantity: int,
|
|
217
|
+
namespace: Optional[str],
|
|
218
|
+
version: Optional[int],
|
|
219
|
+
) -> LabwareCoreType:
|
|
220
|
+
...
|
|
221
|
+
|
|
193
222
|
@abstractmethod
|
|
194
223
|
def get_deck_definition(self) -> DeckDefinitionV5:
|
|
195
224
|
"""Get the geometry definition of the robot's deck."""
|
|
@@ -257,3 +286,7 @@ class AbstractProtocol(
|
|
|
257
286
|
self, labware_core: LabwareCoreType
|
|
258
287
|
) -> Union[str, LabwareCoreType, ModuleCoreType, OffDeckType]:
|
|
259
288
|
"""Get labware parent location."""
|
|
289
|
+
|
|
290
|
+
@abstractmethod
|
|
291
|
+
def load_robot(self) -> AbstractRobot:
|
|
292
|
+
"""Load a Robot Core context into a protocol"""
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from abc import abstractmethod, ABC
|
|
2
|
+
from typing import Optional, Union
|
|
3
|
+
|
|
4
|
+
from opentrons.types import AxisMapType, Mount, Point
|
|
5
|
+
from opentrons_shared_data.pipette.types import PipetteNameType
|
|
6
|
+
from opentrons.protocol_api._types import PlungerPositionTypes, PipetteActionTypes
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AbstractRobot(ABC):
|
|
10
|
+
@abstractmethod
|
|
11
|
+
def get_pipette_type_from_engine(
|
|
12
|
+
self, mount: Union[Mount, str]
|
|
13
|
+
) -> Optional[PipetteNameType]:
|
|
14
|
+
...
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def get_plunger_position_from_volume(
|
|
18
|
+
self, mount: Mount, volume: float, action: PipetteActionTypes, robot_type: str
|
|
19
|
+
) -> float:
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def get_plunger_position_from_name(
|
|
24
|
+
self, mount: Mount, position_name: PlungerPositionTypes
|
|
25
|
+
) -> float:
|
|
26
|
+
...
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def move_to(self, mount: Mount, destination: Point, speed: Optional[float]) -> None:
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
@abstractmethod
|
|
33
|
+
def move_axes_to(
|
|
34
|
+
self,
|
|
35
|
+
axis_map: AxisMapType,
|
|
36
|
+
critical_point: Optional[AxisMapType],
|
|
37
|
+
speed: Optional[float],
|
|
38
|
+
) -> None:
|
|
39
|
+
...
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def move_axes_relative(self, axis_map: AxisMapType, speed: Optional[float]) -> None:
|
|
43
|
+
...
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def release_grip(self) -> None:
|
|
47
|
+
...
|
|
48
|
+
|
|
49
|
+
@abstractmethod
|
|
50
|
+
def close_gripper(self, force: Optional[float] = None) -> None:
|
|
51
|
+
...
|
|
@@ -2,12 +2,14 @@ from __future__ import annotations
|
|
|
2
2
|
import logging
|
|
3
3
|
from contextlib import ExitStack
|
|
4
4
|
from typing import Any, List, Optional, Sequence, Union, cast, Dict
|
|
5
|
-
from opentrons.protocol_engine.errors.exceptions import TipNotAttachedError
|
|
6
5
|
from opentrons_shared_data.errors.exceptions import (
|
|
7
6
|
CommandPreconditionViolated,
|
|
8
7
|
CommandParameterLimitViolated,
|
|
9
8
|
UnexpectedTipRemovalError,
|
|
9
|
+
UnsupportedHardwareCommand,
|
|
10
10
|
)
|
|
11
|
+
from opentrons_shared_data.robot.types import RobotTypeEnum
|
|
12
|
+
|
|
11
13
|
from opentrons.legacy_broker import LegacyBroker
|
|
12
14
|
from opentrons.hardware_control.dev_types import PipetteDict
|
|
13
15
|
from opentrons import types
|
|
@@ -15,8 +17,7 @@ from opentrons.legacy_commands import commands as cmds
|
|
|
15
17
|
|
|
16
18
|
from opentrons.legacy_commands import publisher
|
|
17
19
|
from opentrons.protocols.advanced_control.mix import mix_from_kwargs
|
|
18
|
-
from opentrons.protocols.advanced_control import
|
|
19
|
-
|
|
20
|
+
from opentrons.protocols.advanced_control.transfers import transfer as v1_transfer
|
|
20
21
|
from opentrons.protocols.api_support.deck_type import NoTrashDefinedError
|
|
21
22
|
from opentrons.protocols.api_support.types import APIVersion
|
|
22
23
|
from opentrons.protocols.api_support import instrument
|
|
@@ -28,7 +29,6 @@ from opentrons.protocols.api_support.util import (
|
|
|
28
29
|
APIVersionError,
|
|
29
30
|
UnsupportedAPIError,
|
|
30
31
|
)
|
|
31
|
-
from opentrons.hardware_control.nozzle_manager import NozzleConfigurationType
|
|
32
32
|
|
|
33
33
|
from .core.common import InstrumentCore, ProtocolCore
|
|
34
34
|
from .core.engine import ENGINE_CORE_API_VERSION
|
|
@@ -36,10 +36,13 @@ from .core.legacy.legacy_instrument_core import LegacyInstrumentCore
|
|
|
36
36
|
from .config import Clearances
|
|
37
37
|
from .disposal_locations import TrashBin, WasteChute
|
|
38
38
|
from ._nozzle_layout import NozzleLayout
|
|
39
|
+
from ._liquid import LiquidClass
|
|
39
40
|
from . import labware, validation
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
from ..config import feature_flags
|
|
42
|
+
from ..protocols.advanced_control.transfers.common import (
|
|
43
|
+
TransferTipPolicyV2,
|
|
44
|
+
TransferTipPolicyV2Type,
|
|
45
|
+
)
|
|
43
46
|
|
|
44
47
|
_DEFAULT_ASPIRATE_CLEARANCE = 1.0
|
|
45
48
|
_DEFAULT_DISPENSE_CLEARANCE = 1.0
|
|
@@ -60,6 +63,10 @@ _DISPOSAL_LOCATION_OFFSET_ADDED_IN = APIVersion(2, 18)
|
|
|
60
63
|
"""The version after which offsets for deck configured trash containers and changes to alternating tip drop behavior were introduced."""
|
|
61
64
|
_PARTIAL_NOZZLE_CONFIGURATION_SINGLE_ROW_PARTIAL_COLUMN_ADDED_IN = APIVersion(2, 20)
|
|
62
65
|
"""The version after which partial nozzle configurations of single, row, and partial column layouts became available."""
|
|
66
|
+
_AIR_GAP_TRACKING_ADDED_IN = APIVersion(2, 22)
|
|
67
|
+
"""The version after which air gaps should be implemented with a separate call instead of an aspirate for better liquid volume tracking."""
|
|
68
|
+
|
|
69
|
+
AdvancedLiquidHandling = v1_transfer.AdvancedLiquidHandling
|
|
63
70
|
|
|
64
71
|
|
|
65
72
|
class InstrumentContext(publisher.CommandPublisher):
|
|
@@ -257,9 +264,10 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
257
264
|
self.api_version >= APIVersion(2, 20)
|
|
258
265
|
and well is not None
|
|
259
266
|
and self.liquid_presence_detection
|
|
260
|
-
and self.
|
|
267
|
+
and self._core.nozzle_configuration_valid_for_lld()
|
|
261
268
|
and self._core.get_current_volume() == 0
|
|
262
269
|
):
|
|
270
|
+
self._raise_if_pressure_not_supported_by_pipette()
|
|
263
271
|
self.require_liquid_presence(well=well)
|
|
264
272
|
|
|
265
273
|
with publisher.publish_context(
|
|
@@ -513,6 +521,8 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
513
521
|
``pipette.mix(1, location=wellplate['A1'])`` is a valid call, but
|
|
514
522
|
``pipette.mix(1, wellplate['A1'])`` is not.
|
|
515
523
|
|
|
524
|
+
.. versionchanged:: 2.21
|
|
525
|
+
Does not repeatedly check for liquid presence.
|
|
516
526
|
"""
|
|
517
527
|
_log.debug(
|
|
518
528
|
"mixing {}uL with {} repetitions in {} at rate={}".format(
|
|
@@ -753,7 +763,11 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
753
763
|
``pipette.air_gap(height=2)``. If you call ``air_gap`` with a single,
|
|
754
764
|
unnamed argument, it will always be interpreted as a volume.
|
|
755
765
|
|
|
756
|
-
|
|
766
|
+
.. TODO: restore this as a note block for 2.22 docs
|
|
767
|
+
Before API version 2.22, this function was implemented as an aspirate, and
|
|
768
|
+
dispensing into a well would add the air gap volume to the liquid tracked in
|
|
769
|
+
the well. At or above API version 2.22, air gap volume is not counted as liquid
|
|
770
|
+
when dispensing into a well.
|
|
757
771
|
"""
|
|
758
772
|
if not self._core.has_tip():
|
|
759
773
|
raise UnexpectedTipRemovalError("air_gap", self.name, self.mount)
|
|
@@ -765,7 +779,12 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
765
779
|
raise RuntimeError("No previous Well cached to perform air gap")
|
|
766
780
|
target = loc.labware.as_well().top(height)
|
|
767
781
|
self.move_to(target, publish=False)
|
|
768
|
-
self.
|
|
782
|
+
if self.api_version >= _AIR_GAP_TRACKING_ADDED_IN:
|
|
783
|
+
c_vol = self._core.get_available_volume() if volume is None else volume
|
|
784
|
+
flow_rate = self._core.get_aspirate_flow_rate()
|
|
785
|
+
self._core.air_gap_in_place(c_vol, flow_rate)
|
|
786
|
+
else:
|
|
787
|
+
self.aspirate(volume)
|
|
769
788
|
return self
|
|
770
789
|
|
|
771
790
|
@publisher.publish(command=cmds.return_tip)
|
|
@@ -934,7 +953,7 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
934
953
|
if location is None:
|
|
935
954
|
if (
|
|
936
955
|
nozzle_map is not None
|
|
937
|
-
and nozzle_map.configuration != NozzleConfigurationType.FULL
|
|
956
|
+
and nozzle_map.configuration != types.NozzleConfigurationType.FULL
|
|
938
957
|
and self.starting_tip is not None
|
|
939
958
|
):
|
|
940
959
|
# Disallowing this avoids concerning the system with the direction
|
|
@@ -1206,7 +1225,6 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
1206
1225
|
self._core.home_plunger()
|
|
1207
1226
|
return self
|
|
1208
1227
|
|
|
1209
|
-
# TODO (spp, 2024-03-08): verify if ok to & change source & dest types to AdvancedLiquidHandling
|
|
1210
1228
|
@publisher.publish(command=cmds.distribute)
|
|
1211
1229
|
@requires_version(2, 0)
|
|
1212
1230
|
def distribute(
|
|
@@ -1246,7 +1264,6 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
1246
1264
|
|
|
1247
1265
|
return self.transfer(volume, source, dest, **kwargs)
|
|
1248
1266
|
|
|
1249
|
-
# TODO (spp, 2024-03-08): verify if ok to & change source & dest types to AdvancedLiquidHandling
|
|
1250
1267
|
@publisher.publish(command=cmds.consolidate)
|
|
1251
1268
|
@requires_version(2, 0)
|
|
1252
1269
|
def consolidate(
|
|
@@ -1396,9 +1413,9 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
1396
1413
|
mix_strategy, mix_opts = mix_from_kwargs(kwargs)
|
|
1397
1414
|
|
|
1398
1415
|
if trash:
|
|
1399
|
-
drop_tip =
|
|
1416
|
+
drop_tip = v1_transfer.DropTipStrategy.TRASH
|
|
1400
1417
|
else:
|
|
1401
|
-
drop_tip =
|
|
1418
|
+
drop_tip = v1_transfer.DropTipStrategy.RETURN
|
|
1402
1419
|
|
|
1403
1420
|
new_tip = kwargs.get("new_tip")
|
|
1404
1421
|
if isinstance(new_tip, str):
|
|
@@ -1420,19 +1437,19 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
1420
1437
|
|
|
1421
1438
|
if blow_out and not blowout_location:
|
|
1422
1439
|
if self.current_volume:
|
|
1423
|
-
blow_out_strategy =
|
|
1440
|
+
blow_out_strategy = v1_transfer.BlowOutStrategy.SOURCE
|
|
1424
1441
|
else:
|
|
1425
|
-
blow_out_strategy =
|
|
1442
|
+
blow_out_strategy = v1_transfer.BlowOutStrategy.TRASH
|
|
1426
1443
|
elif blow_out and blowout_location:
|
|
1427
1444
|
if blowout_location == "source well":
|
|
1428
|
-
blow_out_strategy =
|
|
1445
|
+
blow_out_strategy = v1_transfer.BlowOutStrategy.SOURCE
|
|
1429
1446
|
elif blowout_location == "destination well":
|
|
1430
|
-
blow_out_strategy =
|
|
1447
|
+
blow_out_strategy = v1_transfer.BlowOutStrategy.DEST
|
|
1431
1448
|
elif blowout_location == "trash":
|
|
1432
|
-
blow_out_strategy =
|
|
1449
|
+
blow_out_strategy = v1_transfer.BlowOutStrategy.TRASH
|
|
1433
1450
|
|
|
1434
1451
|
if new_tip != types.TransferTipPolicy.NEVER:
|
|
1435
|
-
|
|
1452
|
+
_, next_tip = labware.next_available_tip(
|
|
1436
1453
|
self.starting_tip,
|
|
1437
1454
|
self.tip_racks,
|
|
1438
1455
|
active_channels,
|
|
@@ -1444,9 +1461,9 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
1444
1461
|
|
|
1445
1462
|
touch_tip = None
|
|
1446
1463
|
if kwargs.get("touch_tip"):
|
|
1447
|
-
touch_tip =
|
|
1464
|
+
touch_tip = v1_transfer.TouchTipStrategy.ALWAYS
|
|
1448
1465
|
|
|
1449
|
-
default_args =
|
|
1466
|
+
default_args = v1_transfer.Transfer()
|
|
1450
1467
|
|
|
1451
1468
|
disposal = kwargs.get("disposal_volume")
|
|
1452
1469
|
if disposal is None:
|
|
@@ -1459,7 +1476,7 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
1459
1476
|
f"working volume, {max_volume}uL"
|
|
1460
1477
|
)
|
|
1461
1478
|
|
|
1462
|
-
transfer_args =
|
|
1479
|
+
transfer_args = v1_transfer.Transfer(
|
|
1463
1480
|
new_tip=new_tip or default_args.new_tip,
|
|
1464
1481
|
air_gap=air_gap,
|
|
1465
1482
|
carryover=kwargs.get("carryover") or default_args.carryover,
|
|
@@ -1472,10 +1489,10 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
1472
1489
|
blow_out_strategy=blow_out_strategy or default_args.blow_out_strategy,
|
|
1473
1490
|
touch_tip_strategy=(touch_tip or default_args.touch_tip_strategy),
|
|
1474
1491
|
)
|
|
1475
|
-
transfer_options =
|
|
1492
|
+
transfer_options = v1_transfer.TransferOptions(
|
|
1476
1493
|
transfer=transfer_args, mix=mix_opts
|
|
1477
1494
|
)
|
|
1478
|
-
plan =
|
|
1495
|
+
plan = v1_transfer.TransferPlan(
|
|
1479
1496
|
volume,
|
|
1480
1497
|
source,
|
|
1481
1498
|
dest,
|
|
@@ -1488,10 +1505,113 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
1488
1505
|
self._execute_transfer(plan)
|
|
1489
1506
|
return self
|
|
1490
1507
|
|
|
1491
|
-
def _execute_transfer(self, plan:
|
|
1508
|
+
def _execute_transfer(self, plan: v1_transfer.TransferPlan) -> None:
|
|
1492
1509
|
for cmd in plan:
|
|
1493
1510
|
getattr(self, cmd["method"])(*cmd["args"], **cmd["kwargs"])
|
|
1494
1511
|
|
|
1512
|
+
def transfer_liquid(
|
|
1513
|
+
self,
|
|
1514
|
+
liquid_class: LiquidClass,
|
|
1515
|
+
volume: float,
|
|
1516
|
+
source: Union[
|
|
1517
|
+
labware.Well, Sequence[labware.Well], Sequence[Sequence[labware.Well]]
|
|
1518
|
+
],
|
|
1519
|
+
dest: Union[
|
|
1520
|
+
labware.Well, Sequence[labware.Well], Sequence[Sequence[labware.Well]]
|
|
1521
|
+
],
|
|
1522
|
+
new_tip: TransferTipPolicyV2Type = "once",
|
|
1523
|
+
tip_drop_location: Optional[
|
|
1524
|
+
Union[types.Location, labware.Well, TrashBin, WasteChute]
|
|
1525
|
+
] = None, # Maybe call this 'tip_drop_location' which is similar to PD
|
|
1526
|
+
) -> InstrumentContext:
|
|
1527
|
+
"""Transfer liquid from source to dest using the specified liquid class properties.
|
|
1528
|
+
|
|
1529
|
+
TODO: Add args description.
|
|
1530
|
+
"""
|
|
1531
|
+
if not feature_flags.allow_liquid_classes(
|
|
1532
|
+
robot_type=RobotTypeEnum.robot_literal_to_enum(
|
|
1533
|
+
self._protocol_core.robot_type
|
|
1534
|
+
)
|
|
1535
|
+
):
|
|
1536
|
+
raise NotImplementedError("This method is not implemented.")
|
|
1537
|
+
|
|
1538
|
+
flat_sources_list = validation.ensure_valid_flat_wells_list_for_transfer_v2(
|
|
1539
|
+
source
|
|
1540
|
+
)
|
|
1541
|
+
flat_dests_list = validation.ensure_valid_flat_wells_list_for_transfer_v2(dest)
|
|
1542
|
+
for well in flat_sources_list + flat_dests_list:
|
|
1543
|
+
instrument.validate_takes_liquid(
|
|
1544
|
+
location=well.top(),
|
|
1545
|
+
reject_module=True,
|
|
1546
|
+
reject_adapter=True,
|
|
1547
|
+
)
|
|
1548
|
+
if len(flat_sources_list) != len(flat_dests_list):
|
|
1549
|
+
raise ValueError(
|
|
1550
|
+
"Sources and destinations should be of the same length in order to perform a transfer."
|
|
1551
|
+
" To transfer liquid from one source to many destinations, use 'distribute_liquid',"
|
|
1552
|
+
" to transfer liquid onto one destinations from many sources, use 'consolidate_liquid'."
|
|
1553
|
+
)
|
|
1554
|
+
|
|
1555
|
+
valid_new_tip = validation.ensure_new_tip_policy(new_tip)
|
|
1556
|
+
if valid_new_tip == TransferTipPolicyV2.NEVER:
|
|
1557
|
+
if self._last_tip_picked_up_from is None:
|
|
1558
|
+
raise RuntimeError(
|
|
1559
|
+
"Pipette has no tip attached to perform transfer."
|
|
1560
|
+
" Either do a pick_up_tip beforehand or specify a new_tip parameter"
|
|
1561
|
+
" of 'once' or 'always'."
|
|
1562
|
+
)
|
|
1563
|
+
else:
|
|
1564
|
+
tiprack = self._last_tip_picked_up_from.parent
|
|
1565
|
+
else:
|
|
1566
|
+
tiprack, well = labware.next_available_tip(
|
|
1567
|
+
starting_tip=self.starting_tip,
|
|
1568
|
+
tip_racks=self.tip_racks,
|
|
1569
|
+
channels=self.active_channels,
|
|
1570
|
+
nozzle_map=self._core.get_nozzle_map(),
|
|
1571
|
+
)
|
|
1572
|
+
if self.current_volume != 0:
|
|
1573
|
+
raise RuntimeError(
|
|
1574
|
+
"A transfer on a liquid class cannot start with liquid already in the tip."
|
|
1575
|
+
" Ensure that all previously aspirated liquid is dispensed before starting"
|
|
1576
|
+
" a new transfer."
|
|
1577
|
+
)
|
|
1578
|
+
|
|
1579
|
+
_trash_location: Union[types.Location, labware.Well, TrashBin, WasteChute]
|
|
1580
|
+
if tip_drop_location is None:
|
|
1581
|
+
saved_trash = self.trash_container
|
|
1582
|
+
if isinstance(saved_trash, labware.Labware):
|
|
1583
|
+
_trash_location = saved_trash.wells()[0]
|
|
1584
|
+
else:
|
|
1585
|
+
_trash_location = saved_trash
|
|
1586
|
+
else:
|
|
1587
|
+
_trash_location = tip_drop_location
|
|
1588
|
+
|
|
1589
|
+
checked_trash_location = (
|
|
1590
|
+
validation.ensure_valid_tip_drop_location_for_transfer_v2(
|
|
1591
|
+
tip_drop_location=_trash_location
|
|
1592
|
+
)
|
|
1593
|
+
)
|
|
1594
|
+
liquid_class_id = self._core.load_liquid_class(
|
|
1595
|
+
liquid_class=liquid_class,
|
|
1596
|
+
pipette_load_name=self.name,
|
|
1597
|
+
tiprack_uri=tiprack.uri,
|
|
1598
|
+
)
|
|
1599
|
+
|
|
1600
|
+
self._core.transfer_liquid(
|
|
1601
|
+
liquid_class_id=liquid_class_id,
|
|
1602
|
+
volume=volume,
|
|
1603
|
+
source=[well._core for well in flat_sources_list],
|
|
1604
|
+
dest=[well._core for well in flat_dests_list],
|
|
1605
|
+
new_tip=valid_new_tip,
|
|
1606
|
+
trash_location=(
|
|
1607
|
+
checked_trash_location._core
|
|
1608
|
+
if isinstance(checked_trash_location, labware.Well)
|
|
1609
|
+
else checked_trash_location
|
|
1610
|
+
),
|
|
1611
|
+
)
|
|
1612
|
+
|
|
1613
|
+
return self
|
|
1614
|
+
|
|
1495
1615
|
@requires_version(2, 0)
|
|
1496
1616
|
def delay(self, *args: Any, **kwargs: Any) -> None:
|
|
1497
1617
|
"""
|
|
@@ -1592,6 +1712,147 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
1592
1712
|
|
|
1593
1713
|
return self
|
|
1594
1714
|
|
|
1715
|
+
@requires_version(2, 22)
|
|
1716
|
+
def resin_tip_seal(
|
|
1717
|
+
self,
|
|
1718
|
+
location: Union[labware.Well, labware.Labware],
|
|
1719
|
+
) -> InstrumentContext:
|
|
1720
|
+
"""Seal resin tips onto the pipette.
|
|
1721
|
+
|
|
1722
|
+
The location provided should contain resin tips. Sealing the
|
|
1723
|
+
tip will perform a `pick up` action but there will be no tip tracking
|
|
1724
|
+
associated with the pipette.
|
|
1725
|
+
|
|
1726
|
+
:param location: A location containing resin tips, must be a Labware or a Well.
|
|
1727
|
+
|
|
1728
|
+
:type location: :py:class:`~.types.Location`
|
|
1729
|
+
"""
|
|
1730
|
+
if isinstance(location, labware.Labware):
|
|
1731
|
+
well = location.wells()[0]
|
|
1732
|
+
else:
|
|
1733
|
+
well = location
|
|
1734
|
+
|
|
1735
|
+
with publisher.publish_context(
|
|
1736
|
+
broker=self.broker,
|
|
1737
|
+
command=cmds.seal(
|
|
1738
|
+
instrument=self,
|
|
1739
|
+
location=well,
|
|
1740
|
+
),
|
|
1741
|
+
):
|
|
1742
|
+
self._core.resin_tip_seal(
|
|
1743
|
+
location=well.top(), well_core=well._core, in_place=False
|
|
1744
|
+
)
|
|
1745
|
+
return self
|
|
1746
|
+
|
|
1747
|
+
@requires_version(2, 22)
|
|
1748
|
+
def resin_tip_unseal(
|
|
1749
|
+
self,
|
|
1750
|
+
location: Union[labware.Well, labware.Labware],
|
|
1751
|
+
) -> InstrumentContext:
|
|
1752
|
+
"""Release resin tips from the pipette.
|
|
1753
|
+
|
|
1754
|
+
The location provided should be a valid location to drop resin tips.
|
|
1755
|
+
|
|
1756
|
+
:param location: A location containing that can accept tips.
|
|
1757
|
+
|
|
1758
|
+
:type location: :py:class:`~.types.Location`
|
|
1759
|
+
|
|
1760
|
+
:param home_after:
|
|
1761
|
+
Whether to home the pipette after dropping the tip. If not specified
|
|
1762
|
+
defaults to ``True`` on a Flex. The plunger will not home on an unseal.
|
|
1763
|
+
|
|
1764
|
+
When ``False``, the pipette does not home its plunger. This can save a few
|
|
1765
|
+
seconds, but is not recommended. Homing helps the robot track the pipette's
|
|
1766
|
+
position.
|
|
1767
|
+
|
|
1768
|
+
"""
|
|
1769
|
+
if isinstance(location, labware.Labware):
|
|
1770
|
+
well = location.wells()[0]
|
|
1771
|
+
else:
|
|
1772
|
+
well = location
|
|
1773
|
+
|
|
1774
|
+
with publisher.publish_context(
|
|
1775
|
+
broker=self.broker,
|
|
1776
|
+
command=cmds.unseal(
|
|
1777
|
+
instrument=self,
|
|
1778
|
+
location=well,
|
|
1779
|
+
),
|
|
1780
|
+
):
|
|
1781
|
+
self._core.resin_tip_unseal(location=well.top(), well_core=well._core)
|
|
1782
|
+
|
|
1783
|
+
return self
|
|
1784
|
+
|
|
1785
|
+
@requires_version(2, 22)
|
|
1786
|
+
def resin_tip_dispense(
|
|
1787
|
+
self,
|
|
1788
|
+
location: types.Location,
|
|
1789
|
+
volume: Optional[float] = None,
|
|
1790
|
+
rate: Optional[float] = None,
|
|
1791
|
+
) -> InstrumentContext:
|
|
1792
|
+
"""Dispense a volume from resin tips into a labware.
|
|
1793
|
+
|
|
1794
|
+
The location provided should contain resin tips labware as well as a
|
|
1795
|
+
receptical for dispensed liquid. Dispensing from tip will perform a
|
|
1796
|
+
`dispense` action of the specified volume at a desired flow rate.
|
|
1797
|
+
|
|
1798
|
+
:param location: A location containing resin tips.
|
|
1799
|
+
:type location: :py:class:`~.types.Location`
|
|
1800
|
+
|
|
1801
|
+
:param volume: Will default to maximum, recommended to use the default.
|
|
1802
|
+
The volume, in µL, that the pipette will prepare to handle.
|
|
1803
|
+
:type volume: float
|
|
1804
|
+
|
|
1805
|
+
:param rate: Will default to 10.0, recommended to use the default. How quickly
|
|
1806
|
+
a pipette dispenses liquid. The speed in µL/s is calculated as
|
|
1807
|
+
``rate`` multiplied by :py:attr:`flow_rate.dispense<flow_rate>`.
|
|
1808
|
+
:type rate: float
|
|
1809
|
+
|
|
1810
|
+
"""
|
|
1811
|
+
well: Optional[labware.Well] = None
|
|
1812
|
+
last_location = self._get_last_location_by_api_version()
|
|
1813
|
+
|
|
1814
|
+
try:
|
|
1815
|
+
target = validation.validate_location(
|
|
1816
|
+
location=location, last_location=last_location
|
|
1817
|
+
)
|
|
1818
|
+
except validation.NoLocationError as e:
|
|
1819
|
+
raise RuntimeError(
|
|
1820
|
+
"If dispense is called without an explicit location, another"
|
|
1821
|
+
" method that moves to a location (such as move_to or "
|
|
1822
|
+
"aspirate) must previously have been called so the robot "
|
|
1823
|
+
"knows where it is."
|
|
1824
|
+
) from e
|
|
1825
|
+
|
|
1826
|
+
if isinstance(target, validation.WellTarget):
|
|
1827
|
+
well = target.well
|
|
1828
|
+
if target.location:
|
|
1829
|
+
move_to_location = target.location
|
|
1830
|
+
elif well.parent._core.is_fixed_trash():
|
|
1831
|
+
move_to_location = target.well.top()
|
|
1832
|
+
else:
|
|
1833
|
+
move_to_location = target.well.bottom(
|
|
1834
|
+
z=self._well_bottom_clearances.dispense
|
|
1835
|
+
)
|
|
1836
|
+
else:
|
|
1837
|
+
raise RuntimeError(
|
|
1838
|
+
"A well must be specified when using `resin_tip_dispense`."
|
|
1839
|
+
)
|
|
1840
|
+
|
|
1841
|
+
with publisher.publish_context(
|
|
1842
|
+
broker=self.broker,
|
|
1843
|
+
command=cmds.resin_tip_dispense(
|
|
1844
|
+
instrument=self,
|
|
1845
|
+
flow_rate=rate,
|
|
1846
|
+
),
|
|
1847
|
+
):
|
|
1848
|
+
self._core.resin_tip_dispense(
|
|
1849
|
+
move_to_location,
|
|
1850
|
+
well_core=well._core,
|
|
1851
|
+
volume=volume,
|
|
1852
|
+
flow_rate=rate,
|
|
1853
|
+
)
|
|
1854
|
+
return self
|
|
1855
|
+
|
|
1595
1856
|
@requires_version(2, 18)
|
|
1596
1857
|
def _retract(
|
|
1597
1858
|
self,
|
|
@@ -1694,6 +1955,8 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
1694
1955
|
@liquid_presence_detection.setter
|
|
1695
1956
|
@requires_version(2, 20)
|
|
1696
1957
|
def liquid_presence_detection(self, enable: bool) -> None:
|
|
1958
|
+
if enable:
|
|
1959
|
+
self._raise_if_pressure_not_supported_by_pipette()
|
|
1697
1960
|
self._core.set_liquid_presence_detection(enable)
|
|
1698
1961
|
|
|
1699
1962
|
@property
|
|
@@ -1870,19 +2133,6 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
1870
2133
|
else:
|
|
1871
2134
|
return self._protocol_core.get_last_location()
|
|
1872
2135
|
|
|
1873
|
-
def _96_tip_config_valid(self) -> bool:
|
|
1874
|
-
n_map = self._core.get_nozzle_map()
|
|
1875
|
-
channels = self._core.get_active_channels()
|
|
1876
|
-
if channels == 96:
|
|
1877
|
-
if (
|
|
1878
|
-
n_map.back_left != n_map.full_instrument_back_left
|
|
1879
|
-
and n_map.front_right != n_map.full_instrument_front_right
|
|
1880
|
-
):
|
|
1881
|
-
raise TipNotAttachedError(
|
|
1882
|
-
"Either the front right or the back left nozzle must have a tip attached to do LLD."
|
|
1883
|
-
)
|
|
1884
|
-
return True
|
|
1885
|
-
|
|
1886
2136
|
def __repr__(self) -> str:
|
|
1887
2137
|
return "<{}: {} in {}>".format(
|
|
1888
2138
|
self.__class__.__name__,
|
|
@@ -2143,8 +2393,8 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
2143
2393
|
.. note::
|
|
2144
2394
|
The pressure sensors for the Flex 8-channel pipette are on channels 1 and 8 (positions A1 and H1). For the Flex 96-channel pipette, the pressure sensors are on channels 1 and 96 (positions A1 and H12). Other channels on multi-channel pipettes do not have sensors and cannot detect liquid.
|
|
2145
2395
|
"""
|
|
2396
|
+
self._raise_if_pressure_not_supported_by_pipette()
|
|
2146
2397
|
loc = well.top()
|
|
2147
|
-
self._96_tip_config_valid()
|
|
2148
2398
|
return self._core.detect_liquid_presence(well._core, loc)
|
|
2149
2399
|
|
|
2150
2400
|
@requires_version(2, 20)
|
|
@@ -2156,8 +2406,8 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
2156
2406
|
.. note::
|
|
2157
2407
|
The pressure sensors for the Flex 8-channel pipette are on channels 1 and 8 (positions A1 and H1). For the Flex 96-channel pipette, the pressure sensors are on channels 1 and 96 (positions A1 and H12). Other channels on multi-channel pipettes do not have sensors and cannot detect liquid.
|
|
2158
2408
|
"""
|
|
2409
|
+
self._raise_if_pressure_not_supported_by_pipette()
|
|
2159
2410
|
loc = well.top()
|
|
2160
|
-
self._96_tip_config_valid()
|
|
2161
2411
|
self._core.liquid_probe_with_recovery(well._core, loc)
|
|
2162
2412
|
|
|
2163
2413
|
@requires_version(2, 20)
|
|
@@ -2170,9 +2420,8 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
2170
2420
|
|
|
2171
2421
|
This is intended for Opentrons internal use only and is not a guaranteed API.
|
|
2172
2422
|
"""
|
|
2173
|
-
|
|
2423
|
+
self._raise_if_pressure_not_supported_by_pipette()
|
|
2174
2424
|
loc = well.top()
|
|
2175
|
-
self._96_tip_config_valid()
|
|
2176
2425
|
height = self._core.liquid_probe_without_recovery(well._core, loc)
|
|
2177
2426
|
return height
|
|
2178
2427
|
|
|
@@ -2192,6 +2441,12 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
2192
2441
|
)
|
|
2193
2442
|
# SINGLE, QUADRANT and ALL are supported by all pipettes
|
|
2194
2443
|
|
|
2444
|
+
def _raise_if_pressure_not_supported_by_pipette(self) -> None:
|
|
2445
|
+
if not self._core._pressure_supported_by_pipette():
|
|
2446
|
+
raise UnsupportedHardwareCommand(
|
|
2447
|
+
"Pressure sensor not available for this pipette"
|
|
2448
|
+
)
|
|
2449
|
+
|
|
2195
2450
|
def _handle_aspirate_target(
|
|
2196
2451
|
self, target: validation.ValidTarget
|
|
2197
2452
|
) -> tuple[types.Location, Optional[labware.Well], Optional[bool]]:
|