opentrons 8.1.0a0__py2.py3-none-any.whl → 8.2.0a0__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/cli/analyze.py +71 -7
- opentrons/config/__init__.py +9 -0
- opentrons/config/advanced_settings.py +22 -0
- opentrons/config/defaults_ot3.py +14 -36
- opentrons/config/feature_flags.py +4 -0
- opentrons/config/types.py +6 -17
- opentrons/drivers/absorbance_reader/abstract.py +27 -3
- opentrons/drivers/absorbance_reader/async_byonoy.py +207 -154
- opentrons/drivers/absorbance_reader/driver.py +24 -15
- opentrons/drivers/absorbance_reader/hid_protocol.py +79 -50
- opentrons/drivers/absorbance_reader/simulator.py +32 -6
- opentrons/drivers/types.py +23 -1
- opentrons/execute.py +2 -2
- opentrons/hardware_control/api.py +18 -10
- opentrons/hardware_control/backends/controller.py +3 -2
- opentrons/hardware_control/backends/flex_protocol.py +11 -5
- opentrons/hardware_control/backends/ot3controller.py +18 -50
- opentrons/hardware_control/backends/ot3simulator.py +7 -6
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +22 -82
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -2
- opentrons/hardware_control/module_control.py +43 -2
- opentrons/hardware_control/modules/__init__.py +7 -1
- opentrons/hardware_control/modules/absorbance_reader.py +230 -83
- opentrons/hardware_control/modules/errors.py +7 -0
- opentrons/hardware_control/modules/heater_shaker.py +8 -3
- opentrons/hardware_control/modules/magdeck.py +12 -3
- opentrons/hardware_control/modules/mod_abc.py +27 -2
- opentrons/hardware_control/modules/tempdeck.py +15 -7
- opentrons/hardware_control/modules/thermocycler.py +69 -3
- opentrons/hardware_control/modules/types.py +11 -5
- opentrons/hardware_control/modules/update.py +11 -5
- opentrons/hardware_control/modules/utils.py +3 -1
- opentrons/hardware_control/ot3_calibration.py +6 -6
- opentrons/hardware_control/ot3api.py +126 -89
- opentrons/hardware_control/poller.py +15 -11
- opentrons/hardware_control/protocols/__init__.py +1 -7
- opentrons/hardware_control/protocols/instrument_configurer.py +14 -2
- opentrons/hardware_control/protocols/liquid_handler.py +5 -0
- opentrons/motion_planning/__init__.py +2 -0
- opentrons/motion_planning/waypoints.py +32 -0
- opentrons/protocol_api/__init__.py +2 -1
- opentrons/protocol_api/_liquid.py +87 -1
- opentrons/protocol_api/_parameter_context.py +10 -1
- opentrons/protocol_api/core/engine/deck_conflict.py +0 -297
- opentrons/protocol_api/core/engine/instrument.py +29 -25
- opentrons/protocol_api/core/engine/labware.py +10 -2
- opentrons/protocol_api/core/engine/module_core.py +129 -17
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +355 -0
- opentrons/protocol_api/core/engine/protocol.py +55 -2
- opentrons/protocol_api/core/instrument.py +2 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +5 -2
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/module.py +22 -4
- opentrons/protocol_api/core/protocol.py +5 -2
- opentrons/protocol_api/instrument_context.py +52 -20
- opentrons/protocol_api/labware.py +13 -1
- opentrons/protocol_api/module_contexts.py +68 -13
- opentrons/protocol_api/protocol_context.py +38 -4
- opentrons/protocol_api/validation.py +5 -3
- opentrons/protocol_engine/__init__.py +10 -9
- opentrons/protocol_engine/actions/__init__.py +5 -0
- opentrons/protocol_engine/actions/actions.py +42 -25
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/sync_client.py +7 -1
- opentrons/protocol_engine/clients/transports.py +1 -1
- opentrons/protocol_engine/commands/__init__.py +0 -4
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +41 -11
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +161 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +53 -9
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +160 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +196 -0
- opentrons/protocol_engine/commands/aspirate.py +29 -16
- opentrons/protocol_engine/commands/aspirate_in_place.py +32 -15
- opentrons/protocol_engine/commands/blow_out.py +63 -14
- opentrons/protocol_engine/commands/blow_out_in_place.py +55 -13
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +2 -5
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +3 -4
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +2 -5
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +6 -4
- opentrons/protocol_engine/commands/command.py +28 -17
- opentrons/protocol_engine/commands/command_unions.py +37 -24
- opentrons/protocol_engine/commands/comment.py +5 -3
- opentrons/protocol_engine/commands/configure_for_volume.py +11 -14
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +9 -15
- opentrons/protocol_engine/commands/custom.py +5 -3
- opentrons/protocol_engine/commands/dispense.py +42 -20
- opentrons/protocol_engine/commands/dispense_in_place.py +32 -14
- opentrons/protocol_engine/commands/drop_tip.py +68 -15
- opentrons/protocol_engine/commands/drop_tip_in_place.py +52 -11
- opentrons/protocol_engine/commands/get_tip_presence.py +5 -3
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +8 -6
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +8 -4
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +6 -4
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +6 -6
- opentrons/protocol_engine/commands/home.py +11 -5
- opentrons/protocol_engine/commands/liquid_probe.py +146 -88
- opentrons/protocol_engine/commands/load_labware.py +19 -5
- opentrons/protocol_engine/commands/load_liquid.py +18 -7
- opentrons/protocol_engine/commands/load_module.py +43 -6
- opentrons/protocol_engine/commands/load_pipette.py +18 -17
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +6 -6
- opentrons/protocol_engine/commands/magnetic_module/engage.py +6 -4
- opentrons/protocol_engine/commands/move_labware.py +106 -19
- opentrons/protocol_engine/commands/move_relative.py +15 -3
- opentrons/protocol_engine/commands/move_to_addressable_area.py +29 -4
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +13 -4
- opentrons/protocol_engine/commands/move_to_coordinates.py +11 -5
- opentrons/protocol_engine/commands/move_to_well.py +37 -10
- opentrons/protocol_engine/commands/pick_up_tip.py +50 -29
- opentrons/protocol_engine/commands/pipetting_common.py +39 -15
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +62 -15
- opentrons/protocol_engine/commands/reload_labware.py +13 -4
- opentrons/protocol_engine/commands/retract_axis.py +6 -3
- opentrons/protocol_engine/commands/save_position.py +2 -3
- opentrons/protocol_engine/commands/set_rail_lights.py +5 -3
- opentrons/protocol_engine/commands/set_status_bar.py +5 -3
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +6 -4
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +3 -4
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +6 -6
- opentrons/protocol_engine/commands/thermocycler/__init__.py +19 -0
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +8 -8
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +8 -4
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +165 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +6 -6
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +3 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +3 -4
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +6 -4
- opentrons/protocol_engine/commands/touch_tip.py +19 -7
- opentrons/protocol_engine/commands/unsafe/__init__.py +30 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +6 -4
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -4
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +5 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +194 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +75 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +5 -3
- opentrons/protocol_engine/commands/verify_tip_presence.py +5 -5
- opentrons/protocol_engine/commands/wait_for_duration.py +5 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +5 -3
- opentrons/protocol_engine/create_protocol_engine.py +41 -8
- opentrons/protocol_engine/engine_support.py +2 -1
- opentrons/protocol_engine/error_recovery_policy.py +14 -3
- opentrons/protocol_engine/errors/__init__.py +18 -0
- opentrons/protocol_engine/errors/exceptions.py +114 -2
- opentrons/protocol_engine/execution/__init__.py +2 -0
- opentrons/protocol_engine/execution/command_executor.py +22 -13
- opentrons/protocol_engine/execution/create_queue_worker.py +5 -1
- opentrons/protocol_engine/execution/door_watcher.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +2 -1
- opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
- opentrons/protocol_engine/execution/gantry_mover.py +4 -2
- opentrons/protocol_engine/execution/hardware_stopper.py +3 -3
- opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +1 -4
- opentrons/protocol_engine/execution/labware_movement.py +6 -3
- opentrons/protocol_engine/execution/movement.py +8 -3
- opentrons/protocol_engine/execution/pipetting.py +7 -4
- opentrons/protocol_engine/execution/queue_worker.py +6 -2
- opentrons/protocol_engine/execution/run_control.py +1 -1
- opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +1 -1
- opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +2 -1
- opentrons/protocol_engine/execution/tip_handler.py +77 -43
- opentrons/protocol_engine/notes/__init__.py +14 -2
- opentrons/protocol_engine/notes/notes.py +18 -1
- opentrons/protocol_engine/plugins.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +54 -31
- opentrons/protocol_engine/resources/__init__.py +2 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +58 -5
- opentrons/protocol_engine/resources/file_provider.py +157 -0
- opentrons/protocol_engine/resources/fixture_validation.py +5 -0
- opentrons/protocol_engine/resources/labware_validation.py +10 -0
- opentrons/protocol_engine/state/__init__.py +0 -70
- opentrons/protocol_engine/state/addressable_areas.py +1 -1
- opentrons/protocol_engine/state/command_history.py +21 -2
- opentrons/protocol_engine/state/commands.py +110 -31
- opentrons/protocol_engine/state/files.py +59 -0
- opentrons/protocol_engine/state/frustum_helpers.py +440 -0
- opentrons/protocol_engine/state/geometry.py +359 -15
- opentrons/protocol_engine/state/labware.py +166 -63
- opentrons/protocol_engine/state/liquids.py +1 -1
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +19 -3
- opentrons/protocol_engine/state/modules.py +167 -85
- opentrons/protocol_engine/state/motion.py +16 -9
- opentrons/protocol_engine/state/pipettes.py +157 -317
- opentrons/protocol_engine/state/state.py +30 -1
- opentrons/protocol_engine/state/state_summary.py +3 -0
- opentrons/protocol_engine/state/tips.py +69 -114
- opentrons/protocol_engine/state/update_types.py +408 -0
- opentrons/protocol_engine/state/wells.py +236 -0
- opentrons/protocol_engine/types.py +90 -0
- opentrons/protocol_reader/file_format_validator.py +83 -15
- opentrons/protocol_runner/json_translator.py +21 -5
- opentrons/protocol_runner/legacy_command_mapper.py +27 -6
- opentrons/protocol_runner/legacy_context_plugin.py +27 -71
- opentrons/protocol_runner/protocol_runner.py +6 -3
- opentrons/protocol_runner/run_orchestrator.py +26 -6
- opentrons/protocols/advanced_control/mix.py +3 -5
- opentrons/protocols/advanced_control/transfers.py +125 -56
- opentrons/protocols/api_support/constants.py +1 -1
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/labware_like.py +4 -4
- opentrons/protocols/api_support/tip_tracker.py +2 -2
- opentrons/protocols/api_support/types.py +15 -2
- opentrons/protocols/api_support/util.py +30 -42
- opentrons/protocols/duration/errors.py +1 -1
- opentrons/protocols/duration/estimator.py +50 -29
- opentrons/protocols/execution/dev_types.py +2 -2
- opentrons/protocols/execution/execute_json_v4.py +15 -10
- opentrons/protocols/execution/execute_python.py +8 -3
- opentrons/protocols/geometry/planning.py +12 -12
- opentrons/protocols/labware.py +17 -33
- opentrons/simulate.py +3 -3
- opentrons/types.py +30 -3
- opentrons/util/logging_config.py +34 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/METADATA +5 -4
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/RECORD +227 -215
- opentrons/protocol_engine/commands/absorbance_reader/measure.py +0 -94
- opentrons/protocol_engine/commands/configuring_common.py +0 -26
- opentrons/protocol_runner/thread_async_queue.py +0 -174
- /opentrons/protocol_engine/state/{abstract_store.py → _abstract_store.py} +0 -0
- /opentrons/protocol_engine/state/{move_types.py → _move_types.py} +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/LICENSE +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/WHEEL +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/top_level.txt +0 -0
|
@@ -13,7 +13,7 @@ from ..errors import (
|
|
|
13
13
|
HeaterShakerLabwareLatchStatusUnknown,
|
|
14
14
|
WrongModuleTypeError,
|
|
15
15
|
)
|
|
16
|
-
from ..state import StateStore
|
|
16
|
+
from ..state.state import StateStore
|
|
17
17
|
from ..state.module_substates import HeaterShakerModuleSubState
|
|
18
18
|
from ..types import (
|
|
19
19
|
HeaterShakerMovementRestrictors,
|
|
@@ -61,9 +61,6 @@ class HeaterShakerMovementFlagger:
|
|
|
61
61
|
return # Labware on a module, but not a Heater-Shaker.
|
|
62
62
|
|
|
63
63
|
if hs_substate.labware_latch_status == HeaterShakerLatchStatus.CLOSED:
|
|
64
|
-
# TODO (spp, 2022-10-27): This only raises if latch status is 'idle_closed'.
|
|
65
|
-
# We need to update the flagger to raise if latch status is anything other
|
|
66
|
-
# than 'idle_open'
|
|
67
64
|
raise HeaterShakerLabwareLatchNotOpenError(
|
|
68
65
|
"Heater-Shaker labware latch must be open when moving labware to/from it."
|
|
69
66
|
)
|
|
@@ -9,7 +9,7 @@ from opentrons.hardware_control import HardwareControlAPI
|
|
|
9
9
|
from opentrons.hardware_control.types import OT3Mount, Axis
|
|
10
10
|
from opentrons.motion_planning import get_gripper_labware_movement_waypoints
|
|
11
11
|
|
|
12
|
-
from opentrons.protocol_engine.state import StateStore
|
|
12
|
+
from opentrons.protocol_engine.state.state import StateStore
|
|
13
13
|
from opentrons.protocol_engine.resources.ot3_validation import ensure_ot3_hardware
|
|
14
14
|
|
|
15
15
|
from .thermocycler_movement_flagger import ThermocyclerMovementFlagger
|
|
@@ -37,8 +37,6 @@ if TYPE_CHECKING:
|
|
|
37
37
|
_GRIPPER_HOMED_POSITION_Z = 166.125 # Height of the center of the gripper critical point from the deck when homed
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
# TODO (spp, 2022-10-20): name this GripperMovementHandler if it doesn't handle
|
|
41
|
-
# any non-gripper implementations
|
|
42
40
|
class LabwareMovementHandler:
|
|
43
41
|
"""Implementation logic for labware movement."""
|
|
44
42
|
|
|
@@ -128,6 +126,7 @@ class LabwareMovementHandler:
|
|
|
128
126
|
current_location=current_location,
|
|
129
127
|
)
|
|
130
128
|
|
|
129
|
+
current_labware = self._state_store.labware.get_definition(labware_id)
|
|
131
130
|
async with self._thermocycler_plate_lifter.lift_plate_for_labware_movement(
|
|
132
131
|
labware_location=current_location
|
|
133
132
|
):
|
|
@@ -136,6 +135,7 @@ class LabwareMovementHandler:
|
|
|
136
135
|
from_location=current_location,
|
|
137
136
|
to_location=new_location,
|
|
138
137
|
additional_offset_vector=user_offset_data,
|
|
138
|
+
current_labware=current_labware,
|
|
139
139
|
)
|
|
140
140
|
)
|
|
141
141
|
from_labware_center = self._state_store.geometry.get_labware_grip_point(
|
|
@@ -177,6 +177,9 @@ class LabwareMovementHandler:
|
|
|
177
177
|
labware_id
|
|
178
178
|
)
|
|
179
179
|
well_bbox = self._state_store.labware.get_well_bbox(labware_id)
|
|
180
|
+
# todo(mm, 2024-09-26): This currently raises a lower-level 2015 FailedGripperPickupError.
|
|
181
|
+
# Convert this to a higher-level 3001 LabwareDroppedError or 3002 LabwareNotPickedUpError,
|
|
182
|
+
# depending on what waypoint we're at, to propagate a more specific error code to users.
|
|
180
183
|
ot3api.raise_error_if_gripper_pickup_failed(
|
|
181
184
|
expected_grip_width=labware_bbox.y,
|
|
182
185
|
grip_width_uncertainty_wider=abs(
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import logging
|
|
5
|
-
from typing import Optional, List
|
|
5
|
+
from typing import Optional, List, Union
|
|
6
6
|
|
|
7
7
|
from opentrons.types import Point, MountType
|
|
8
8
|
from opentrons.hardware_control import HardwareControlAPI
|
|
@@ -10,13 +10,14 @@ from opentrons_shared_data.errors.exceptions import PositionUnknownError
|
|
|
10
10
|
|
|
11
11
|
from ..types import (
|
|
12
12
|
WellLocation,
|
|
13
|
+
LiquidHandlingWellLocation,
|
|
13
14
|
DeckPoint,
|
|
14
15
|
MovementAxis,
|
|
15
16
|
MotorAxis,
|
|
16
17
|
CurrentWell,
|
|
17
18
|
AddressableOffsetVector,
|
|
18
19
|
)
|
|
19
|
-
from ..state import StateStore
|
|
20
|
+
from ..state.state import StateStore
|
|
20
21
|
from ..resources import ModelUtils
|
|
21
22
|
from .thermocycler_movement_flagger import ThermocyclerMovementFlagger
|
|
22
23
|
from .heater_shaker_movement_flagger import HeaterShakerMovementFlagger
|
|
@@ -66,11 +67,12 @@ class MovementHandler:
|
|
|
66
67
|
pipette_id: str,
|
|
67
68
|
labware_id: str,
|
|
68
69
|
well_name: str,
|
|
69
|
-
well_location: Optional[WellLocation] = None,
|
|
70
|
+
well_location: Optional[Union[WellLocation, LiquidHandlingWellLocation]] = None,
|
|
70
71
|
current_well: Optional[CurrentWell] = None,
|
|
71
72
|
force_direct: bool = False,
|
|
72
73
|
minimum_z_height: Optional[float] = None,
|
|
73
74
|
speed: Optional[float] = None,
|
|
75
|
+
operation_volume: Optional[float] = None,
|
|
74
76
|
) -> Point:
|
|
75
77
|
"""Move to a specific well."""
|
|
76
78
|
self._state_store.labware.raise_if_labware_inaccessible_by_pipette(
|
|
@@ -129,6 +131,7 @@ class MovementHandler:
|
|
|
129
131
|
current_well=current_well,
|
|
130
132
|
force_direct=force_direct,
|
|
131
133
|
minimum_z_height=minimum_z_height,
|
|
134
|
+
operation_volume=operation_volume,
|
|
132
135
|
)
|
|
133
136
|
|
|
134
137
|
speed = self._state_store.pipettes.get_movement_speed(
|
|
@@ -151,6 +154,7 @@ class MovementHandler:
|
|
|
151
154
|
speed: Optional[float] = None,
|
|
152
155
|
stay_at_highest_possible_z: bool = False,
|
|
153
156
|
ignore_tip_configuration: Optional[bool] = True,
|
|
157
|
+
highest_possible_z_extra_offset: Optional[float] = None,
|
|
154
158
|
) -> Point:
|
|
155
159
|
"""Move to a specific addressable area."""
|
|
156
160
|
# Check for presence of heater shakers on deck, and if planned
|
|
@@ -201,6 +205,7 @@ class MovementHandler:
|
|
|
201
205
|
minimum_z_height=minimum_z_height,
|
|
202
206
|
stay_at_max_travel_z=stay_at_highest_possible_z,
|
|
203
207
|
ignore_tip_configuration=ignore_tip_configuration,
|
|
208
|
+
max_travel_z_extra_margin=highest_possible_z_extra_offset,
|
|
204
209
|
)
|
|
205
210
|
|
|
206
211
|
speed = self._state_store.pipettes.get_movement_speed(
|
|
@@ -5,7 +5,8 @@ from contextlib import contextmanager
|
|
|
5
5
|
|
|
6
6
|
from opentrons.hardware_control import HardwareControlAPI
|
|
7
7
|
|
|
8
|
-
from ..state import StateView
|
|
8
|
+
from ..state.state import StateView
|
|
9
|
+
from ..state.pipettes import HardwarePipette
|
|
9
10
|
from ..notes import CommandNoteAdder, CommandNote
|
|
10
11
|
from ..errors.exceptions import (
|
|
11
12
|
TipNotAttachedError,
|
|
@@ -186,7 +187,9 @@ class HardwarePipettingHandler(PipettingHandler):
|
|
|
186
187
|
mount=hw_pipette.mount,
|
|
187
188
|
max_z_dist=well_depth - lld_min_height + well_location.offset.z,
|
|
188
189
|
)
|
|
189
|
-
|
|
190
|
+
labware_pos = self._state_view.geometry.get_labware_position(labware_id)
|
|
191
|
+
relative_height = z_pos - labware_pos.z - well_def.z
|
|
192
|
+
return float(relative_height)
|
|
190
193
|
|
|
191
194
|
@contextmanager
|
|
192
195
|
def _set_flow_rate(
|
|
@@ -285,8 +288,8 @@ class VirtualPipettingHandler(PipettingHandler):
|
|
|
285
288
|
well_location: WellLocation,
|
|
286
289
|
) -> float:
|
|
287
290
|
"""Detect liquid level."""
|
|
288
|
-
|
|
289
|
-
return
|
|
291
|
+
well_def = self._state_view.labware.get_well_definition(labware_id, well_name)
|
|
292
|
+
return well_def.depth
|
|
290
293
|
|
|
291
294
|
def _validate_tip_attached(self, pipette_id: str, command_name: str) -> None:
|
|
292
295
|
"""Validate if there is a tip attached."""
|
|
@@ -3,7 +3,7 @@ import asyncio
|
|
|
3
3
|
from logging import getLogger
|
|
4
4
|
from typing import Optional, AsyncGenerator, Callable
|
|
5
5
|
|
|
6
|
-
from ..state import StateStore
|
|
6
|
+
from ..state.state import StateStore
|
|
7
7
|
from .command_executor import CommandExecutor
|
|
8
8
|
|
|
9
9
|
log = getLogger(__name__)
|
|
@@ -69,7 +69,11 @@ class QueueWorker:
|
|
|
69
69
|
|
|
70
70
|
async def _run_commands(self) -> None:
|
|
71
71
|
async for command_id in self._command_generator():
|
|
72
|
-
|
|
72
|
+
try:
|
|
73
|
+
await self._command_executor.execute(command_id=command_id)
|
|
74
|
+
except BaseException:
|
|
75
|
+
log.exception("Unhandled failure in command executor")
|
|
76
|
+
raise
|
|
73
77
|
# Yield to the event loop in case we're executing a long sequence of commands
|
|
74
78
|
# that never yields internally. For example, a long sequence of comment commands.
|
|
75
79
|
await asyncio.sleep(0)
|
|
@@ -7,7 +7,7 @@ from opentrons.hardware_control import HardwareControlAPI
|
|
|
7
7
|
from opentrons.hardware_control.modules import Thermocycler as HardwareThermocycler
|
|
8
8
|
|
|
9
9
|
from ..types import ModuleLocation, LabwareLocation
|
|
10
|
-
from ..state import StateStore
|
|
10
|
+
from ..state.state import StateStore
|
|
11
11
|
from ..errors import ThermocyclerNotOpenError, WrongModuleTypeError
|
|
12
12
|
|
|
13
13
|
|
|
@@ -5,7 +5,8 @@ import asyncio
|
|
|
5
5
|
from typing import TYPE_CHECKING, AsyncGenerator, Optional
|
|
6
6
|
from opentrons.hardware_control.modules.thermocycler import Thermocycler
|
|
7
7
|
from opentrons.protocol_engine.types import LabwareLocation, ModuleLocation, ModuleModel
|
|
8
|
-
from opentrons.protocol_engine.state import StateStore
|
|
8
|
+
from opentrons.protocol_engine.state.state import StateStore
|
|
9
|
+
from opentrons.protocol_engine.state.module_substates import ThermocyclerModuleId
|
|
9
10
|
from contextlib import asynccontextmanager
|
|
10
11
|
|
|
11
12
|
if TYPE_CHECKING:
|
|
@@ -4,6 +4,9 @@ from typing_extensions import Protocol as TypingProtocol
|
|
|
4
4
|
|
|
5
5
|
from opentrons.hardware_control import HardwareControlAPI
|
|
6
6
|
from opentrons.hardware_control.types import FailedTipStateCheck, InstrumentProbeType
|
|
7
|
+
from opentrons.protocol_engine.errors.exceptions import PickUpTipTipNotAttachedError
|
|
8
|
+
from opentrons.types import Mount
|
|
9
|
+
|
|
7
10
|
from opentrons_shared_data.errors.exceptions import (
|
|
8
11
|
CommandPreconditionViolated,
|
|
9
12
|
CommandParameterLimitViolated,
|
|
@@ -11,7 +14,7 @@ from opentrons_shared_data.errors.exceptions import (
|
|
|
11
14
|
)
|
|
12
15
|
|
|
13
16
|
from ..resources import LabwareDataProvider, ensure_ot3_hardware
|
|
14
|
-
from ..state import StateView
|
|
17
|
+
from ..state.state import StateView
|
|
15
18
|
from ..types import TipGeometry, TipPresenceStatus
|
|
16
19
|
from ..errors import (
|
|
17
20
|
HardwareNotSupportedError,
|
|
@@ -68,18 +71,27 @@ class TipHandler(TypingProtocol):
|
|
|
68
71
|
|
|
69
72
|
Returns:
|
|
70
73
|
Tip geometry of the picked up tip.
|
|
74
|
+
|
|
75
|
+
Raises:
|
|
76
|
+
PickUpTipTipNotAttachedError
|
|
71
77
|
"""
|
|
72
78
|
...
|
|
73
79
|
|
|
74
80
|
async def drop_tip(self, pipette_id: str, home_after: Optional[bool]) -> None:
|
|
75
|
-
"""Drop the attached tip into the
|
|
81
|
+
"""Drop the attached tip into the current location.
|
|
76
82
|
|
|
77
83
|
Pipette should be in place over the destination prior to calling this method.
|
|
84
|
+
|
|
85
|
+
Raises:
|
|
86
|
+
TipAttachedError
|
|
78
87
|
"""
|
|
79
88
|
|
|
80
|
-
|
|
89
|
+
def cache_tip(self, pipette_id: str, tip: TipGeometry) -> None:
|
|
81
90
|
"""Tell the Hardware API that a tip is attached."""
|
|
82
91
|
|
|
92
|
+
def remove_tip(self, pipette_id: str) -> None:
|
|
93
|
+
"""Tell the hardware API that no tip is attached."""
|
|
94
|
+
|
|
83
95
|
async def get_tip_presence(self, pipette_id: str) -> TipPresenceStatus:
|
|
84
96
|
"""Get tip presence status on the pipette."""
|
|
85
97
|
|
|
@@ -89,7 +101,12 @@ class TipHandler(TypingProtocol):
|
|
|
89
101
|
expected: TipPresenceStatus,
|
|
90
102
|
follow_singular_sensor: Optional[InstrumentProbeType] = None,
|
|
91
103
|
) -> None:
|
|
92
|
-
"""
|
|
104
|
+
"""Use sensors to verify that a tip is or is not physically attached.
|
|
105
|
+
|
|
106
|
+
Raises:
|
|
107
|
+
TipNotAttachedError or TipAttachedError, as appropriate, if the physical
|
|
108
|
+
status doesn't match what was expected.
|
|
109
|
+
"""
|
|
93
110
|
|
|
94
111
|
|
|
95
112
|
async def _available_for_nozzle_layout( # noqa: C901
|
|
@@ -187,6 +204,11 @@ class HardwareTipHandler(TipHandler):
|
|
|
187
204
|
self._labware_data_provider = labware_data_provider or LabwareDataProvider()
|
|
188
205
|
self._state_view = state_view
|
|
189
206
|
|
|
207
|
+
# WARNING: ErrorRecoveryHardwareStateSynchronizer can currently construct several
|
|
208
|
+
# instances of this class per run, in addition to the main instance used
|
|
209
|
+
# for command execution. We're therefore depending on this class being
|
|
210
|
+
# stateless, so consider that before adding additional attributes here.
|
|
211
|
+
|
|
190
212
|
async def available_for_nozzle_layout(
|
|
191
213
|
self,
|
|
192
214
|
pipette_id: str,
|
|
@@ -195,7 +217,7 @@ class HardwareTipHandler(TipHandler):
|
|
|
195
217
|
front_right_nozzle: Optional[str] = None,
|
|
196
218
|
back_left_nozzle: Optional[str] = None,
|
|
197
219
|
) -> Dict[str, str]:
|
|
198
|
-
"""
|
|
220
|
+
"""See documentation on abstract base class."""
|
|
199
221
|
if self._state_view.pipettes.get_attached_tip(pipette_id):
|
|
200
222
|
raise CommandPreconditionViolated(
|
|
201
223
|
message=f"Cannot configure nozzle layout of {str(self)} while it has tips attached."
|
|
@@ -211,8 +233,8 @@ class HardwareTipHandler(TipHandler):
|
|
|
211
233
|
labware_id: str,
|
|
212
234
|
well_name: str,
|
|
213
235
|
) -> TipGeometry:
|
|
214
|
-
"""
|
|
215
|
-
hw_mount = self.
|
|
236
|
+
"""See documentation on abstract base class."""
|
|
237
|
+
hw_mount = self._get_hw_mount(pipette_id)
|
|
216
238
|
|
|
217
239
|
nominal_tip_geometry = self._state_view.geometry.get_nominal_tip_geometry(
|
|
218
240
|
pipette_id=pipette_id, labware_id=labware_id, well_name=well_name
|
|
@@ -224,33 +246,29 @@ class HardwareTipHandler(TipHandler):
|
|
|
224
246
|
nominal_fallback=nominal_tip_geometry.length,
|
|
225
247
|
)
|
|
226
248
|
|
|
249
|
+
tip_geometry = TipGeometry(
|
|
250
|
+
length=actual_tip_length,
|
|
251
|
+
diameter=nominal_tip_geometry.diameter,
|
|
252
|
+
volume=nominal_tip_geometry.volume,
|
|
253
|
+
)
|
|
254
|
+
|
|
227
255
|
await self._hardware_api.tip_pickup_moves(
|
|
228
256
|
mount=hw_mount, presses=None, increment=None
|
|
229
257
|
)
|
|
230
|
-
|
|
258
|
+
try:
|
|
259
|
+
await self.verify_tip_presence(pipette_id, TipPresenceStatus.PRESENT)
|
|
260
|
+
except TipNotAttachedError as e:
|
|
261
|
+
raise PickUpTipTipNotAttachedError(tip_geometry=tip_geometry) from e
|
|
231
262
|
|
|
232
|
-
self.
|
|
233
|
-
await self._hardware_api.prepare_for_aspirate(hw_mount)
|
|
263
|
+
self.cache_tip(pipette_id, tip_geometry)
|
|
234
264
|
|
|
235
|
-
self._hardware_api.
|
|
236
|
-
mount=hw_mount,
|
|
237
|
-
tiprack_diameter=nominal_tip_geometry.diameter,
|
|
238
|
-
)
|
|
239
|
-
|
|
240
|
-
self._hardware_api.set_working_volume(
|
|
241
|
-
mount=hw_mount,
|
|
242
|
-
tip_volume=nominal_tip_geometry.volume,
|
|
243
|
-
)
|
|
265
|
+
await self._hardware_api.prepare_for_aspirate(hw_mount)
|
|
244
266
|
|
|
245
|
-
return
|
|
246
|
-
length=actual_tip_length,
|
|
247
|
-
diameter=nominal_tip_geometry.diameter,
|
|
248
|
-
volume=nominal_tip_geometry.volume,
|
|
249
|
-
)
|
|
267
|
+
return tip_geometry
|
|
250
268
|
|
|
251
269
|
async def drop_tip(self, pipette_id: str, home_after: Optional[bool]) -> None:
|
|
252
|
-
"""
|
|
253
|
-
hw_mount = self.
|
|
270
|
+
"""See documentation on abstract base class."""
|
|
271
|
+
hw_mount = self._get_hw_mount(pipette_id)
|
|
254
272
|
|
|
255
273
|
# Let the hardware controller handle defaulting home_after since its behavior
|
|
256
274
|
# differs between machines
|
|
@@ -259,14 +277,18 @@ class HardwareTipHandler(TipHandler):
|
|
|
259
277
|
else:
|
|
260
278
|
kwargs = {}
|
|
261
279
|
|
|
262
|
-
await self._hardware_api.
|
|
280
|
+
await self._hardware_api.tip_drop_moves(mount=hw_mount, **kwargs)
|
|
281
|
+
|
|
282
|
+
# Allow TipNotAttachedError to propagate.
|
|
263
283
|
await self.verify_tip_presence(pipette_id, TipPresenceStatus.ABSENT)
|
|
264
284
|
|
|
265
|
-
|
|
266
|
-
"""Tell the Hardware API that a tip is attached."""
|
|
267
|
-
hw_mount = self._state_view.pipettes.get_mount(pipette_id).to_hw_mount()
|
|
285
|
+
self.remove_tip(pipette_id)
|
|
268
286
|
|
|
269
|
-
|
|
287
|
+
def cache_tip(self, pipette_id: str, tip: TipGeometry) -> None:
|
|
288
|
+
"""See documentation on abstract base class."""
|
|
289
|
+
hw_mount = self._get_hw_mount(pipette_id)
|
|
290
|
+
|
|
291
|
+
self._hardware_api.cache_tip(mount=hw_mount, tip_length=tip.length)
|
|
270
292
|
|
|
271
293
|
self._hardware_api.set_current_tiprack_diameter(
|
|
272
294
|
mount=hw_mount,
|
|
@@ -278,12 +300,18 @@ class HardwareTipHandler(TipHandler):
|
|
|
278
300
|
tip_volume=tip.volume,
|
|
279
301
|
)
|
|
280
302
|
|
|
303
|
+
def remove_tip(self, pipette_id: str) -> None:
|
|
304
|
+
"""See documentation on abstract base class."""
|
|
305
|
+
hw_mount = self._get_hw_mount(pipette_id)
|
|
306
|
+
self._hardware_api.remove_tip(hw_mount)
|
|
307
|
+
self._hardware_api.set_current_tiprack_diameter(hw_mount, 0)
|
|
308
|
+
|
|
281
309
|
async def get_tip_presence(self, pipette_id: str) -> TipPresenceStatus:
|
|
282
|
-
"""
|
|
310
|
+
"""See documentation on abstract base class."""
|
|
283
311
|
try:
|
|
284
312
|
ot3api = ensure_ot3_hardware(hardware_api=self._hardware_api)
|
|
285
313
|
|
|
286
|
-
hw_mount = self.
|
|
314
|
+
hw_mount = self._get_hw_mount(pipette_id)
|
|
287
315
|
|
|
288
316
|
status = await ot3api.get_tip_presence_status(hw_mount)
|
|
289
317
|
return TipPresenceStatus.from_hw_state(status)
|
|
@@ -297,11 +325,7 @@ class HardwareTipHandler(TipHandler):
|
|
|
297
325
|
expected: TipPresenceStatus,
|
|
298
326
|
follow_singular_sensor: Optional[InstrumentProbeType] = None,
|
|
299
327
|
) -> None:
|
|
300
|
-
"""
|
|
301
|
-
|
|
302
|
-
This function will raise an exception if the specified tip presence status
|
|
303
|
-
isn't matched.
|
|
304
|
-
"""
|
|
328
|
+
"""See documentation on abstract base class."""
|
|
305
329
|
nozzle_configuration = (
|
|
306
330
|
self._state_view.pipettes.state.nozzle_configuration_by_id[pipette_id]
|
|
307
331
|
)
|
|
@@ -328,7 +352,7 @@ class HardwareTipHandler(TipHandler):
|
|
|
328
352
|
return
|
|
329
353
|
try:
|
|
330
354
|
ot3api = ensure_ot3_hardware(hardware_api=self._hardware_api)
|
|
331
|
-
hw_mount = self.
|
|
355
|
+
hw_mount = self._get_hw_mount(pipette_id)
|
|
332
356
|
await ot3api.verify_tip_presence(
|
|
333
357
|
hw_mount, expected.to_hw_state(), follow_singular_sensor
|
|
334
358
|
)
|
|
@@ -346,6 +370,9 @@ class HardwareTipHandler(TipHandler):
|
|
|
346
370
|
wrapping=[PythonException(e)],
|
|
347
371
|
)
|
|
348
372
|
|
|
373
|
+
def _get_hw_mount(self, pipette_id: str) -> Mount:
|
|
374
|
+
return self._state_view.pipettes.get_mount(pipette_id).to_hw_mount()
|
|
375
|
+
|
|
349
376
|
|
|
350
377
|
class VirtualTipHandler(TipHandler):
|
|
351
378
|
"""Pick up and drop tips, using a virtual pipette."""
|
|
@@ -385,7 +412,7 @@ class VirtualTipHandler(TipHandler):
|
|
|
385
412
|
front_right_nozzle: Optional[str] = None,
|
|
386
413
|
back_left_nozzle: Optional[str] = None,
|
|
387
414
|
) -> Dict[str, str]:
|
|
388
|
-
"""
|
|
415
|
+
"""See documentation on abstract base class."""
|
|
389
416
|
if self._state_view.pipettes.get_attached_tip(pipette_id):
|
|
390
417
|
raise CommandPreconditionViolated(
|
|
391
418
|
message=f"Cannot configure nozzle layout of {str(self)} while it has tips attached."
|
|
@@ -409,12 +436,19 @@ class VirtualTipHandler(TipHandler):
|
|
|
409
436
|
expected_has_tip=True,
|
|
410
437
|
)
|
|
411
438
|
|
|
412
|
-
|
|
413
|
-
"""
|
|
439
|
+
def cache_tip(self, pipette_id: str, tip: TipGeometry) -> None:
|
|
440
|
+
"""See documentation on abstract base class.
|
|
441
|
+
|
|
442
|
+
This should not be called when using virtual pipettes.
|
|
443
|
+
"""
|
|
444
|
+
assert False, "TipHandler.cache_tip should not be used with virtual pipettes"
|
|
445
|
+
|
|
446
|
+
def remove_tip(self, pipette_id: str) -> None:
|
|
447
|
+
"""See documentation on abstract base class.
|
|
414
448
|
|
|
415
449
|
This should not be called when using virtual pipettes.
|
|
416
450
|
"""
|
|
417
|
-
assert False, "TipHandler.
|
|
451
|
+
assert False, "TipHandler.remove_tip should not be used with virtual pipettes"
|
|
418
452
|
|
|
419
453
|
async def verify_tip_presence(
|
|
420
454
|
self,
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
"""Protocol engine notes module."""
|
|
2
2
|
|
|
3
|
-
from .notes import
|
|
3
|
+
from .notes import (
|
|
4
|
+
NoteKind,
|
|
5
|
+
CommandNote,
|
|
6
|
+
CommandNoteAdder,
|
|
7
|
+
CommandNoteTracker,
|
|
8
|
+
make_error_recovery_debug_note,
|
|
9
|
+
)
|
|
4
10
|
|
|
5
|
-
__all__ = [
|
|
11
|
+
__all__ = [
|
|
12
|
+
"NoteKind",
|
|
13
|
+
"CommandNote",
|
|
14
|
+
"CommandNoteAdder",
|
|
15
|
+
"CommandNoteTracker",
|
|
16
|
+
"make_error_recovery_debug_note",
|
|
17
|
+
]
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"""Definitions of data and interface shapes for notes."""
|
|
2
|
-
from typing import Union, Literal, Protocol, List
|
|
2
|
+
from typing import Union, Literal, Protocol, List, TYPE_CHECKING
|
|
3
3
|
from pydantic import BaseModel, Field
|
|
4
4
|
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from opentrons.protocol_engine.error_recovery_policy import ErrorRecoveryType
|
|
7
|
+
|
|
5
8
|
NoteKind = Union[Literal["warning", "information"], str]
|
|
6
9
|
|
|
7
10
|
|
|
@@ -26,6 +29,20 @@ class CommandNote(BaseModel):
|
|
|
26
29
|
)
|
|
27
30
|
|
|
28
31
|
|
|
32
|
+
def make_error_recovery_debug_note(type: "ErrorRecoveryType") -> CommandNote:
|
|
33
|
+
"""Return a note for debugging error recovery.
|
|
34
|
+
|
|
35
|
+
This is intended to be read by developers and support people, not computers.
|
|
36
|
+
"""
|
|
37
|
+
message = f"Handling this command failure with {type.name}."
|
|
38
|
+
return CommandNote.construct(
|
|
39
|
+
noteKind="debugErrorRecovery",
|
|
40
|
+
shortMessage=message,
|
|
41
|
+
longMessage=message,
|
|
42
|
+
source="execution",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
29
46
|
class CommandNoteAdder(Protocol):
|
|
30
47
|
"""The shape of a function that something can use to add a command note."""
|
|
31
48
|
|