opentrons 8.2.0__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.
Potentially problematic release.
This version of opentrons might be problematic. Click here for more details.
- opentrons/drivers/absorbance_reader/async_byonoy.py +5 -6
- opentrons/hardware_control/backends/ot3utils.py +0 -1
- opentrons/hardware_control/modules/absorbance_reader.py +0 -2
- opentrons/hardware_control/ot3api.py +5 -5
- opentrons/hardware_control/protocols/position_estimator.py +1 -3
- opentrons/hardware_control/types.py +0 -2
- opentrons/legacy_commands/helpers.py +2 -8
- opentrons/protocol_api/core/engine/labware.py +2 -10
- opentrons/protocol_api/core/engine/module_core.py +1 -38
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +5 -12
- opentrons/protocol_api/core/engine/protocol.py +30 -5
- opentrons/protocol_api/core/labware.py +0 -4
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +0 -5
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +0 -1
- opentrons/protocol_api/core/protocol.py +0 -1
- opentrons/protocol_api/module_contexts.py +26 -69
- opentrons/protocol_api/protocol_context.py +2 -12
- opentrons/protocol_engine/actions/__init__.py +2 -0
- opentrons/protocol_engine/actions/actions.py +12 -0
- opentrons/protocol_engine/clients/sync_client.py +6 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +31 -18
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +7 -19
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +29 -17
- opentrons/protocol_engine/commands/absorbance_reader/read.py +0 -4
- opentrons/protocol_engine/commands/aspirate_in_place.py +3 -3
- opentrons/protocol_engine/commands/command.py +1 -3
- opentrons/protocol_engine/commands/dispense_in_place.py +1 -1
- opentrons/protocol_engine/commands/drop_tip.py +1 -2
- opentrons/protocol_engine/commands/drop_tip_in_place.py +2 -7
- opentrons/protocol_engine/commands/load_labware.py +0 -9
- opentrons/protocol_engine/commands/load_module.py +39 -0
- opentrons/protocol_engine/commands/move_labware.py +4 -49
- opentrons/protocol_engine/commands/pick_up_tip.py +1 -1
- opentrons/protocol_engine/commands/pipetting_common.py +1 -8
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +35 -49
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +1 -3
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +1 -5
- opentrons/protocol_engine/create_protocol_engine.py +1 -18
- opentrons/protocol_engine/errors/__init__.py +0 -2
- opentrons/protocol_engine/errors/error_occurrence.py +3 -8
- opentrons/protocol_engine/errors/exceptions.py +0 -13
- opentrons/protocol_engine/execution/labware_movement.py +21 -69
- opentrons/protocol_engine/execution/movement.py +4 -9
- opentrons/protocol_engine/protocol_engine.py +7 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +39 -0
- opentrons/protocol_engine/resources/file_provider.py +7 -11
- opentrons/protocol_engine/resources/fixture_validation.py +1 -6
- opentrons/protocol_engine/state/geometry.py +49 -91
- opentrons/protocol_engine/state/labware.py +25 -102
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +1 -3
- opentrons/protocol_engine/state/modules.py +80 -53
- opentrons/protocol_engine/state/motion.py +5 -17
- opentrons/protocol_engine/state/update_types.py +0 -16
- opentrons/protocol_runner/run_orchestrator.py +0 -15
- opentrons/protocols/parameters/csv_parameter_interface.py +1 -3
- opentrons/util/logging_config.py +1 -1
- {opentrons-8.2.0.dist-info → opentrons-8.2.0a0.dist-info}/METADATA +4 -4
- {opentrons-8.2.0.dist-info → opentrons-8.2.0a0.dist-info}/RECORD +62 -62
- {opentrons-8.2.0.dist-info → opentrons-8.2.0a0.dist-info}/LICENSE +0 -0
- {opentrons-8.2.0.dist-info → opentrons-8.2.0a0.dist-info}/WHEEL +0 -0
- {opentrons-8.2.0.dist-info → opentrons-8.2.0a0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.2.0.dist-info → opentrons-8.2.0a0.dist-info}/top_level.txt +0 -0
|
@@ -10,6 +10,7 @@ from ...errors.error_occurrence import ErrorOccurrence
|
|
|
10
10
|
from ...errors import CannotPerformModuleAction
|
|
11
11
|
from opentrons.protocol_engine.types import AddressableAreaLocation
|
|
12
12
|
|
|
13
|
+
from opentrons.protocol_engine.resources import labware_validation
|
|
13
14
|
from ...state.update_types import StateUpdate
|
|
14
15
|
|
|
15
16
|
|
|
@@ -52,35 +53,41 @@ class CloseLidImpl(AbstractCommandImpl[CloseLidParams, SuccessData[CloseLidResul
|
|
|
52
53
|
|
|
53
54
|
async def execute(self, params: CloseLidParams) -> SuccessData[CloseLidResult]:
|
|
54
55
|
"""Execute the close lid command."""
|
|
55
|
-
state_update = StateUpdate()
|
|
56
56
|
mod_substate = self._state_view.modules.get_absorbance_reader_substate(
|
|
57
57
|
module_id=params.moduleId
|
|
58
58
|
)
|
|
59
59
|
|
|
60
|
+
# lid should currently be on the module
|
|
61
|
+
assert mod_substate.lid_id is not None
|
|
62
|
+
loaded_lid = self._state_view.labware.get(mod_substate.lid_id)
|
|
63
|
+
assert labware_validation.is_absorbance_reader_lid(loaded_lid.loadName)
|
|
64
|
+
|
|
60
65
|
hardware_lid_status = AbsorbanceReaderLidStatus.OFF
|
|
66
|
+
# If the lid is closed, if the lid is open No-op out
|
|
61
67
|
if not self._state_view.config.use_virtual_modules:
|
|
62
68
|
abs_reader = self._equipment.get_module_hardware_api(mod_substate.module_id)
|
|
63
69
|
|
|
64
70
|
if abs_reader is not None:
|
|
65
|
-
|
|
71
|
+
result = await abs_reader.get_current_lid_status()
|
|
72
|
+
hardware_lid_status = result
|
|
66
73
|
else:
|
|
67
74
|
raise CannotPerformModuleAction(
|
|
68
75
|
"Could not reach the Hardware API for Opentrons Plate Reader Module."
|
|
69
76
|
)
|
|
70
77
|
|
|
78
|
+
# If the lid is already ON, no-op losing lid
|
|
71
79
|
if hardware_lid_status is AbsorbanceReaderLidStatus.ON:
|
|
72
|
-
# The lid is already
|
|
73
|
-
|
|
74
|
-
|
|
80
|
+
# The lid is already On, so we can no-op and return the lids current location data
|
|
81
|
+
assert isinstance(loaded_lid.location, AddressableAreaLocation)
|
|
82
|
+
new_location = loaded_lid.location
|
|
83
|
+
new_offset_id = self._equipment.find_applicable_labware_offset_id(
|
|
84
|
+
labware_definition_uri=loaded_lid.definitionUri,
|
|
85
|
+
labware_location=loaded_lid.location,
|
|
75
86
|
)
|
|
76
87
|
else:
|
|
77
88
|
# Allow propagation of ModuleNotAttachedError.
|
|
78
89
|
_ = self._equipment.get_module_hardware_api(mod_substate.module_id)
|
|
79
90
|
|
|
80
|
-
lid_definition = (
|
|
81
|
-
self._state_view.labware.get_absorbance_reader_lid_definition()
|
|
82
|
-
)
|
|
83
|
-
|
|
84
91
|
current_location = self._state_view.modules.absorbance_reader_dock_location(
|
|
85
92
|
params.moduleId
|
|
86
93
|
)
|
|
@@ -100,29 +107,35 @@ class CloseLidImpl(AbstractCommandImpl[CloseLidParams, SuccessData[CloseLidResul
|
|
|
100
107
|
)
|
|
101
108
|
)
|
|
102
109
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
lid_gripper_offsets = self._state_view.labware.get_child_gripper_offsets(
|
|
106
|
-
labware_definition=lid_definition,
|
|
107
|
-
slot_name=None,
|
|
110
|
+
lid_gripper_offsets = self._state_view.labware.get_labware_gripper_offsets(
|
|
111
|
+
loaded_lid.id, None
|
|
108
112
|
)
|
|
109
113
|
if lid_gripper_offsets is None:
|
|
110
114
|
raise ValueError(
|
|
111
115
|
"Gripper Offset values for Absorbance Reader Lid labware must not be None."
|
|
112
116
|
)
|
|
113
117
|
|
|
118
|
+
# Skips gripper moves when using virtual gripper
|
|
114
119
|
await self._labware_movement.move_labware_with_gripper(
|
|
115
|
-
|
|
120
|
+
labware_id=loaded_lid.id,
|
|
116
121
|
current_location=current_location,
|
|
117
122
|
new_location=new_location,
|
|
118
123
|
user_offset_data=lid_gripper_offsets,
|
|
119
124
|
post_drop_slide_offset=None,
|
|
120
125
|
)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
|
|
127
|
+
new_offset_id = self._equipment.find_applicable_labware_offset_id(
|
|
128
|
+
labware_definition_uri=loaded_lid.definitionUri,
|
|
129
|
+
labware_location=new_location,
|
|
124
130
|
)
|
|
125
131
|
|
|
132
|
+
state_update = StateUpdate()
|
|
133
|
+
state_update.set_labware_location(
|
|
134
|
+
labware_id=loaded_lid.id,
|
|
135
|
+
new_location=new_location,
|
|
136
|
+
new_offset_id=new_offset_id,
|
|
137
|
+
)
|
|
138
|
+
|
|
126
139
|
return SuccessData(
|
|
127
140
|
public=CloseLidResult(),
|
|
128
141
|
state_update=state_update,
|
|
@@ -10,7 +10,6 @@ from opentrons.protocol_engine.types import ABSMeasureMode
|
|
|
10
10
|
|
|
11
11
|
from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
12
12
|
from ...errors.error_occurrence import ErrorOccurrence
|
|
13
|
-
from ...errors import InvalidWavelengthError
|
|
14
13
|
|
|
15
14
|
if TYPE_CHECKING:
|
|
16
15
|
from opentrons.protocol_engine.state.state import StateView
|
|
@@ -70,41 +69,30 @@ class InitializeImpl(
|
|
|
70
69
|
unsupported_wavelengths = sample_wavelengths.difference(
|
|
71
70
|
supported_wavelengths
|
|
72
71
|
)
|
|
73
|
-
sample_wl_str = ", ".join([str(w) + "nm" for w in sample_wavelengths])
|
|
74
|
-
supported_wl_str = ", ".join([str(w) + "nm" for w in supported_wavelengths])
|
|
75
|
-
unsupported_wl_str = ", ".join(
|
|
76
|
-
[str(w) + "nm" for w in unsupported_wavelengths]
|
|
77
|
-
)
|
|
78
72
|
if unsupported_wavelengths:
|
|
79
|
-
raise
|
|
80
|
-
f"Unsupported wavelengths: {unsupported_wl_str}. "
|
|
81
|
-
f" Use one of {supported_wl_str} instead."
|
|
82
|
-
)
|
|
73
|
+
raise ValueError(f"Unsupported wavelengths: {unsupported_wavelengths}")
|
|
83
74
|
|
|
84
75
|
if params.measureMode == "single":
|
|
85
76
|
if sample_wavelengths_len != 1:
|
|
86
77
|
raise ValueError(
|
|
87
|
-
f"
|
|
88
|
-
f" {sample_wl_str} provided instead."
|
|
78
|
+
f"single requires one sample wavelength, provided {sample_wavelengths}"
|
|
89
79
|
)
|
|
90
80
|
if (
|
|
91
81
|
reference_wavelength is not None
|
|
92
82
|
and reference_wavelength not in supported_wavelengths
|
|
93
83
|
):
|
|
94
|
-
raise
|
|
95
|
-
f"Reference wavelength {reference_wavelength}
|
|
96
|
-
f" Use one of {supported_wl_str} instead."
|
|
84
|
+
raise ValueError(
|
|
85
|
+
f"Reference wavelength {reference_wavelength} not supported {supported_wavelengths}"
|
|
97
86
|
)
|
|
98
87
|
|
|
99
88
|
if params.measureMode == "multi":
|
|
100
89
|
if sample_wavelengths_len < 1 or sample_wavelengths_len > 6:
|
|
101
90
|
raise ValueError(
|
|
102
|
-
f"
|
|
103
|
-
f" {sample_wl_str} provided instead."
|
|
91
|
+
f"multi requires 1-6 sample wavelengths, provided {sample_wavelengths}"
|
|
104
92
|
)
|
|
105
93
|
if reference_wavelength is not None:
|
|
106
|
-
raise
|
|
107
|
-
"Reference wavelength cannot be used with
|
|
94
|
+
raise RuntimeError(
|
|
95
|
+
"Reference wavelength cannot be used with multi mode."
|
|
108
96
|
)
|
|
109
97
|
|
|
110
98
|
await abs_reader.set_sample_wavelength(
|
|
@@ -9,6 +9,7 @@ from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, Succe
|
|
|
9
9
|
from ...errors.error_occurrence import ErrorOccurrence
|
|
10
10
|
from ...errors import CannotPerformModuleAction
|
|
11
11
|
|
|
12
|
+
from opentrons.protocol_engine.resources import labware_validation
|
|
12
13
|
from opentrons.protocol_engine.types import AddressableAreaLocation
|
|
13
14
|
|
|
14
15
|
from opentrons.drivers.types import AbsorbanceReaderLidStatus
|
|
@@ -53,35 +54,39 @@ class OpenLidImpl(AbstractCommandImpl[OpenLidParams, SuccessData[OpenLidResult]]
|
|
|
53
54
|
|
|
54
55
|
async def execute(self, params: OpenLidParams) -> SuccessData[OpenLidResult]:
|
|
55
56
|
"""Move the absorbance reader lid from the module to the lid dock."""
|
|
56
|
-
state_update = StateUpdate()
|
|
57
57
|
mod_substate = self._state_view.modules.get_absorbance_reader_substate(
|
|
58
58
|
module_id=params.moduleId
|
|
59
59
|
)
|
|
60
|
+
# lid should currently be on the module
|
|
61
|
+
assert mod_substate.lid_id is not None
|
|
62
|
+
loaded_lid = self._state_view.labware.get(mod_substate.lid_id)
|
|
63
|
+
assert labware_validation.is_absorbance_reader_lid(loaded_lid.loadName)
|
|
60
64
|
|
|
61
65
|
hardware_lid_status = AbsorbanceReaderLidStatus.ON
|
|
66
|
+
# If the lid is closed, if the lid is open No-op out
|
|
62
67
|
if not self._state_view.config.use_virtual_modules:
|
|
63
68
|
abs_reader = self._equipment.get_module_hardware_api(mod_substate.module_id)
|
|
64
69
|
|
|
65
70
|
if abs_reader is not None:
|
|
66
|
-
|
|
71
|
+
result = await abs_reader.get_current_lid_status()
|
|
72
|
+
hardware_lid_status = result
|
|
67
73
|
else:
|
|
68
74
|
raise CannotPerformModuleAction(
|
|
69
75
|
"Could not reach the Hardware API for Opentrons Plate Reader Module."
|
|
70
76
|
)
|
|
71
77
|
|
|
78
|
+
# If the lid is already OFF, no-op the lid removal
|
|
72
79
|
if hardware_lid_status is AbsorbanceReaderLidStatus.OFF:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
assert isinstance(loaded_lid.location, AddressableAreaLocation)
|
|
81
|
+
new_location = loaded_lid.location
|
|
82
|
+
new_offset_id = self._equipment.find_applicable_labware_offset_id(
|
|
83
|
+
labware_definition_uri=loaded_lid.definitionUri,
|
|
84
|
+
labware_location=loaded_lid.location,
|
|
76
85
|
)
|
|
77
86
|
else:
|
|
78
87
|
# Allow propagation of ModuleNotAttachedError.
|
|
79
88
|
_ = self._equipment.get_module_hardware_api(mod_substate.module_id)
|
|
80
89
|
|
|
81
|
-
lid_definition = (
|
|
82
|
-
self._state_view.labware.get_absorbance_reader_lid_definition()
|
|
83
|
-
)
|
|
84
|
-
|
|
85
90
|
absorbance_model = self._state_view.modules.get_requested_model(
|
|
86
91
|
params.moduleId
|
|
87
92
|
)
|
|
@@ -101,28 +106,35 @@ class OpenLidImpl(AbstractCommandImpl[OpenLidParams, SuccessData[OpenLidResult]]
|
|
|
101
106
|
mod_substate.module_id
|
|
102
107
|
)
|
|
103
108
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
lid_gripper_offsets = self._state_view.labware.get_child_gripper_offsets(
|
|
107
|
-
labware_definition=lid_definition,
|
|
108
|
-
slot_name=None,
|
|
109
|
+
lid_gripper_offsets = self._state_view.labware.get_labware_gripper_offsets(
|
|
110
|
+
loaded_lid.id, None
|
|
109
111
|
)
|
|
110
112
|
if lid_gripper_offsets is None:
|
|
111
113
|
raise ValueError(
|
|
112
114
|
"Gripper Offset values for Absorbance Reader Lid labware must not be None."
|
|
113
115
|
)
|
|
114
116
|
|
|
117
|
+
# Skips gripper moves when using virtual gripper
|
|
115
118
|
await self._labware_movement.move_labware_with_gripper(
|
|
116
|
-
|
|
119
|
+
labware_id=loaded_lid.id,
|
|
117
120
|
current_location=current_location,
|
|
118
121
|
new_location=new_location,
|
|
119
122
|
user_offset_data=lid_gripper_offsets,
|
|
120
123
|
post_drop_slide_offset=None,
|
|
121
124
|
)
|
|
122
|
-
|
|
123
|
-
|
|
125
|
+
new_offset_id = self._equipment.find_applicable_labware_offset_id(
|
|
126
|
+
labware_definition_uri=loaded_lid.definitionUri,
|
|
127
|
+
labware_location=new_location,
|
|
124
128
|
)
|
|
125
129
|
|
|
130
|
+
state_update = StateUpdate()
|
|
131
|
+
|
|
132
|
+
state_update.set_labware_location(
|
|
133
|
+
labware_id=loaded_lid.id,
|
|
134
|
+
new_location=new_location,
|
|
135
|
+
new_offset_id=new_offset_id,
|
|
136
|
+
)
|
|
137
|
+
|
|
126
138
|
return SuccessData(
|
|
127
139
|
public=OpenLidResult(),
|
|
128
140
|
state_update=state_update,
|
|
@@ -80,10 +80,6 @@ class ReadAbsorbanceImpl(
|
|
|
80
80
|
raise CannotPerformModuleAction(
|
|
81
81
|
"Cannot perform Read action on Absorbance Reader without calling `.initialize(...)` first."
|
|
82
82
|
)
|
|
83
|
-
if abs_reader_substate.is_lid_on is False:
|
|
84
|
-
raise CannotPerformModuleAction(
|
|
85
|
-
"Absorbance Plate Reader can't read a plate with the lid open. Call `close_lid()` first."
|
|
86
|
-
)
|
|
87
83
|
|
|
88
84
|
# TODO: we need to return a file ID and increase the file count even when a moduel is not attached
|
|
89
85
|
if (
|
|
@@ -83,11 +83,10 @@ class AspirateInPlaceImplementation(
|
|
|
83
83
|
TipNotAttachedError: if no tip is attached to the pipette.
|
|
84
84
|
PipetteNotReadyToAspirateError: pipette plunger is not ready.
|
|
85
85
|
"""
|
|
86
|
-
state_update = StateUpdate()
|
|
87
|
-
|
|
88
86
|
ready_to_aspirate = self._pipetting.get_is_ready_to_aspirate(
|
|
89
87
|
pipette_id=params.pipetteId,
|
|
90
88
|
)
|
|
89
|
+
|
|
91
90
|
if not ready_to_aspirate:
|
|
92
91
|
raise PipetteNotReadyToAspirateError(
|
|
93
92
|
"Pipette cannot aspirate in place because of a previous blow out."
|
|
@@ -95,10 +94,11 @@ class AspirateInPlaceImplementation(
|
|
|
95
94
|
" so the plunger can be reset in a known safe position."
|
|
96
95
|
)
|
|
97
96
|
|
|
97
|
+
state_update = StateUpdate()
|
|
98
98
|
current_location = self._state_view.pipettes.get_current_location()
|
|
99
|
-
current_position = await self._gantry_mover.get_position(params.pipetteId)
|
|
100
99
|
|
|
101
100
|
try:
|
|
101
|
+
current_position = await self._gantry_mover.get_position(params.pipetteId)
|
|
102
102
|
volume = await self._pipetting.aspirate_in_place(
|
|
103
103
|
pipette_id=params.pipetteId,
|
|
104
104
|
volume=params.volume,
|
|
@@ -185,9 +185,7 @@ class BaseCommand(
|
|
|
185
185
|
)
|
|
186
186
|
error: Union[
|
|
187
187
|
_ErrorT,
|
|
188
|
-
# ErrorOccurrence here is
|
|
189
|
-
# _ErrorT, or defined errors that don't parse into _ErrorT because, for example,
|
|
190
|
-
# they are from an older software version that was missing some fields.
|
|
188
|
+
# ErrorOccurrence here is for undefined errors not captured by _ErrorT.
|
|
191
189
|
ErrorOccurrence,
|
|
192
190
|
None,
|
|
193
191
|
] = Field(
|
|
@@ -76,8 +76,8 @@ class DispenseInPlaceImplementation(
|
|
|
76
76
|
"""Dispense without moving the pipette."""
|
|
77
77
|
state_update = StateUpdate()
|
|
78
78
|
current_location = self._state_view.pipettes.get_current_location()
|
|
79
|
-
current_position = await self._gantry_mover.get_position(params.pipetteId)
|
|
80
79
|
try:
|
|
80
|
+
current_position = await self._gantry_mover.get_position(params.pipetteId)
|
|
81
81
|
volume = await self._pipetting.dispense_in_place(
|
|
82
82
|
pipette_id=params.pipetteId,
|
|
83
83
|
volume=params.volume,
|
|
@@ -145,7 +145,6 @@ class DropTipImplementation(AbstractCommandImpl[DropTipParams, _ExecuteReturn]):
|
|
|
145
145
|
error=exception,
|
|
146
146
|
)
|
|
147
147
|
],
|
|
148
|
-
errorInfo={"retryLocation": position},
|
|
149
148
|
)
|
|
150
149
|
state_update_if_false_positive = update_types.StateUpdate()
|
|
151
150
|
state_update_if_false_positive.update_pipette_tip_state(
|
|
@@ -166,7 +165,7 @@ class DropTipImplementation(AbstractCommandImpl[DropTipParams, _ExecuteReturn]):
|
|
|
166
165
|
)
|
|
167
166
|
|
|
168
167
|
|
|
169
|
-
class DropTip(BaseCommand[DropTipParams, DropTipResult,
|
|
168
|
+
class DropTip(BaseCommand[DropTipParams, DropTipResult, ErrorOccurrence]):
|
|
170
169
|
"""Drop tip command model."""
|
|
171
170
|
|
|
172
171
|
commandType: DropTipCommandType = "dropTip"
|
|
@@ -18,7 +18,7 @@ from ..resources.model_utils import ModelUtils
|
|
|
18
18
|
from ..state import update_types
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
|
-
from ..execution import TipHandler
|
|
21
|
+
from ..execution import TipHandler
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
DropTipInPlaceCommandType = Literal["dropTipInPlace"]
|
|
@@ -57,19 +57,15 @@ class DropTipInPlaceImplementation(
|
|
|
57
57
|
self,
|
|
58
58
|
tip_handler: TipHandler,
|
|
59
59
|
model_utils: ModelUtils,
|
|
60
|
-
gantry_mover: GantryMover,
|
|
61
60
|
**kwargs: object,
|
|
62
61
|
) -> None:
|
|
63
62
|
self._tip_handler = tip_handler
|
|
64
63
|
self._model_utils = model_utils
|
|
65
|
-
self._gantry_mover = gantry_mover
|
|
66
64
|
|
|
67
65
|
async def execute(self, params: DropTipInPlaceParams) -> _ExecuteReturn:
|
|
68
66
|
"""Drop a tip using the requested pipette."""
|
|
69
67
|
state_update = update_types.StateUpdate()
|
|
70
68
|
|
|
71
|
-
retry_location = await self._gantry_mover.get_position(params.pipetteId)
|
|
72
|
-
|
|
73
69
|
try:
|
|
74
70
|
await self._tip_handler.drop_tip(
|
|
75
71
|
pipette_id=params.pipetteId, home_after=params.homeAfter
|
|
@@ -89,7 +85,6 @@ class DropTipInPlaceImplementation(
|
|
|
89
85
|
error=exception,
|
|
90
86
|
)
|
|
91
87
|
],
|
|
92
|
-
errorInfo={"retryLocation": retry_location},
|
|
93
88
|
)
|
|
94
89
|
return DefinedErrorData(
|
|
95
90
|
public=error,
|
|
@@ -104,7 +99,7 @@ class DropTipInPlaceImplementation(
|
|
|
104
99
|
|
|
105
100
|
|
|
106
101
|
class DropTipInPlace(
|
|
107
|
-
BaseCommand[DropTipInPlaceParams, DropTipInPlaceResult,
|
|
102
|
+
BaseCommand[DropTipInPlaceParams, DropTipInPlaceResult, ErrorOccurrence]
|
|
108
103
|
):
|
|
109
104
|
"""Drop tip in place command model."""
|
|
110
105
|
|
|
@@ -10,8 +10,6 @@ from ..errors import LabwareIsNotAllowedInLocationError
|
|
|
10
10
|
from ..resources import labware_validation, fixture_validation
|
|
11
11
|
from ..types import (
|
|
12
12
|
LabwareLocation,
|
|
13
|
-
ModuleLocation,
|
|
14
|
-
ModuleModel,
|
|
15
13
|
OnLabwareLocation,
|
|
16
14
|
DeckSlotLocation,
|
|
17
15
|
AddressableAreaLocation,
|
|
@@ -162,13 +160,6 @@ class LoadLabwareImplementation(
|
|
|
162
160
|
top_labware_definition=loaded_labware.definition,
|
|
163
161
|
bottom_labware_id=verified_location.labwareId,
|
|
164
162
|
)
|
|
165
|
-
# Validate labware for the absorbance reader
|
|
166
|
-
elif isinstance(params.location, ModuleLocation):
|
|
167
|
-
module = self._state_view.modules.get(params.location.moduleId)
|
|
168
|
-
if module is not None and module.model == ModuleModel.ABSORBANCE_READER_V1:
|
|
169
|
-
self._state_view.labware.raise_if_labware_incompatible_with_plate_reader(
|
|
170
|
-
loaded_labware.definition
|
|
171
|
-
)
|
|
172
163
|
|
|
173
164
|
return SuccessData(
|
|
174
165
|
public=LoadLabwareResult(
|
|
@@ -5,6 +5,7 @@ from typing_extensions import Literal
|
|
|
5
5
|
from pydantic import BaseModel, Field
|
|
6
6
|
|
|
7
7
|
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
8
|
+
from ..errors import ModuleNotLoadedError
|
|
8
9
|
from ..errors.error_occurrence import ErrorOccurrence
|
|
9
10
|
from ..types import (
|
|
10
11
|
DeckSlotLocation,
|
|
@@ -16,6 +17,7 @@ from opentrons.types import DeckSlotName
|
|
|
16
17
|
|
|
17
18
|
from opentrons.protocol_engine.resources import deck_configuration_provider
|
|
18
19
|
|
|
20
|
+
from opentrons.drivers.types import AbsorbanceReaderLidStatus
|
|
19
21
|
|
|
20
22
|
if TYPE_CHECKING:
|
|
21
23
|
from ..state.state import StateView
|
|
@@ -150,6 +152,43 @@ class LoadModuleImplementation(
|
|
|
150
152
|
module_id=params.moduleId,
|
|
151
153
|
)
|
|
152
154
|
|
|
155
|
+
# Handle lid position update for loaded Plate Reader module on deck
|
|
156
|
+
if (
|
|
157
|
+
not self._state_view.config.use_virtual_modules
|
|
158
|
+
and params.model == ModuleModel.ABSORBANCE_READER_V1
|
|
159
|
+
and params.moduleId is not None
|
|
160
|
+
):
|
|
161
|
+
try:
|
|
162
|
+
abs_reader = self._equipment.get_module_hardware_api(
|
|
163
|
+
self._state_view.modules.get_absorbance_reader_substate(
|
|
164
|
+
params.moduleId
|
|
165
|
+
).module_id
|
|
166
|
+
)
|
|
167
|
+
except ModuleNotLoadedError:
|
|
168
|
+
abs_reader = None
|
|
169
|
+
|
|
170
|
+
if abs_reader is not None:
|
|
171
|
+
result = await abs_reader.get_current_lid_status()
|
|
172
|
+
if (
|
|
173
|
+
isinstance(result, AbsorbanceReaderLidStatus)
|
|
174
|
+
and result is not AbsorbanceReaderLidStatus.ON
|
|
175
|
+
):
|
|
176
|
+
reader_area = self._state_view.modules.ensure_and_convert_module_fixture_location(
|
|
177
|
+
params.location.slotName,
|
|
178
|
+
self._state_view.config.deck_type,
|
|
179
|
+
params.model,
|
|
180
|
+
)
|
|
181
|
+
lid_labware = self._state_view.labware.get_by_addressable_area(
|
|
182
|
+
reader_area
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
if lid_labware is not None:
|
|
186
|
+
self._state_view.labware._state.labware_by_id[
|
|
187
|
+
lid_labware.id
|
|
188
|
+
].location = self._state_view.modules.absorbance_reader_dock_location(
|
|
189
|
+
params.moduleId
|
|
190
|
+
)
|
|
191
|
+
|
|
153
192
|
return SuccessData(
|
|
154
193
|
public=LoadModuleResult(
|
|
155
194
|
moduleId=loaded_module.module_id,
|
|
@@ -13,22 +13,16 @@ from typing_extensions import Literal
|
|
|
13
13
|
from opentrons.protocol_engine.resources.model_utils import ModelUtils
|
|
14
14
|
from opentrons.types import Point
|
|
15
15
|
from ..types import (
|
|
16
|
-
ModuleModel,
|
|
17
16
|
CurrentWell,
|
|
18
17
|
LabwareLocation,
|
|
19
18
|
DeckSlotLocation,
|
|
20
|
-
ModuleLocation,
|
|
21
19
|
OnLabwareLocation,
|
|
22
20
|
AddressableAreaLocation,
|
|
23
21
|
LabwareMovementStrategy,
|
|
24
22
|
LabwareOffsetVector,
|
|
25
23
|
LabwareMovementOffsetData,
|
|
26
24
|
)
|
|
27
|
-
from ..errors import
|
|
28
|
-
LabwareMovementNotAllowedError,
|
|
29
|
-
NotSupportedOnRobotType,
|
|
30
|
-
LabwareOffsetDoesNotExistError,
|
|
31
|
-
)
|
|
25
|
+
from ..errors import LabwareMovementNotAllowedError, NotSupportedOnRobotType
|
|
32
26
|
from ..resources import labware_validation, fixture_validation
|
|
33
27
|
from .command import (
|
|
34
28
|
AbstractCommandImpl,
|
|
@@ -136,7 +130,6 @@ class MoveLabwareImplementation(AbstractCommandImpl[MoveLabwareParams, _ExecuteR
|
|
|
136
130
|
)
|
|
137
131
|
definition_uri = current_labware.definitionUri
|
|
138
132
|
post_drop_slide_offset: Optional[Point] = None
|
|
139
|
-
trash_lid_drop_offset: Optional[LabwareOffsetVector] = None
|
|
140
133
|
|
|
141
134
|
if self._state_view.labware.is_fixed_trash(params.labwareId):
|
|
142
135
|
raise LabwareMovementNotAllowedError(
|
|
@@ -145,11 +138,9 @@ class MoveLabwareImplementation(AbstractCommandImpl[MoveLabwareParams, _ExecuteR
|
|
|
145
138
|
|
|
146
139
|
if isinstance(params.newLocation, AddressableAreaLocation):
|
|
147
140
|
area_name = params.newLocation.addressableAreaName
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
and not fixture_validation.is_trash(area_name)
|
|
152
|
-
):
|
|
141
|
+
if not fixture_validation.is_gripper_waste_chute(
|
|
142
|
+
area_name
|
|
143
|
+
) and not fixture_validation.is_deck_slot(area_name):
|
|
153
144
|
raise LabwareMovementNotAllowedError(
|
|
154
145
|
f"Cannot move {current_labware.loadName} to addressable area {area_name}"
|
|
155
146
|
)
|
|
@@ -171,32 +162,6 @@ class MoveLabwareImplementation(AbstractCommandImpl[MoveLabwareParams, _ExecuteR
|
|
|
171
162
|
y=0,
|
|
172
163
|
z=0,
|
|
173
164
|
)
|
|
174
|
-
elif fixture_validation.is_trash(area_name):
|
|
175
|
-
# When dropping labware in the trash bins we want to ensure they are lids
|
|
176
|
-
# and enforce a y-axis drop offset to ensure they fall within the trash bin
|
|
177
|
-
if labware_validation.validate_definition_is_lid(
|
|
178
|
-
self._state_view.labware.get_definition(params.labwareId)
|
|
179
|
-
):
|
|
180
|
-
lid_disposable_offfets = (
|
|
181
|
-
current_labware_definition.gripperOffsets.get(
|
|
182
|
-
"lidDisposalOffsets"
|
|
183
|
-
)
|
|
184
|
-
)
|
|
185
|
-
if lid_disposable_offfets is not None:
|
|
186
|
-
trash_lid_drop_offset = LabwareOffsetVector(
|
|
187
|
-
x=lid_disposable_offfets.dropOffset.x,
|
|
188
|
-
y=lid_disposable_offfets.dropOffset.y,
|
|
189
|
-
z=lid_disposable_offfets.dropOffset.z,
|
|
190
|
-
)
|
|
191
|
-
else:
|
|
192
|
-
raise LabwareOffsetDoesNotExistError(
|
|
193
|
-
f"Labware Definition {current_labware.loadName} does not contain required field 'lidDisposalOffsets' of 'gripperOffsets'."
|
|
194
|
-
)
|
|
195
|
-
else:
|
|
196
|
-
raise LabwareMovementNotAllowedError(
|
|
197
|
-
"Can only move labware with allowed role 'Lid' to a Trash Bin."
|
|
198
|
-
)
|
|
199
|
-
|
|
200
165
|
elif isinstance(params.newLocation, DeckSlotLocation):
|
|
201
166
|
self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration(
|
|
202
167
|
params.newLocation.slotName.id
|
|
@@ -223,13 +188,6 @@ class MoveLabwareImplementation(AbstractCommandImpl[MoveLabwareParams, _ExecuteR
|
|
|
223
188
|
raise LabwareMovementNotAllowedError(
|
|
224
189
|
"Cannot move a labware onto itself."
|
|
225
190
|
)
|
|
226
|
-
# Validate labware for the absorbance reader
|
|
227
|
-
elif isinstance(available_new_location, ModuleLocation):
|
|
228
|
-
module = self._state_view.modules.get(available_new_location.moduleId)
|
|
229
|
-
if module is not None and module.model == ModuleModel.ABSORBANCE_READER_V1:
|
|
230
|
-
self._state_view.labware.raise_if_labware_incompatible_with_plate_reader(
|
|
231
|
-
current_labware_definition
|
|
232
|
-
)
|
|
233
191
|
|
|
234
192
|
# Allow propagation of ModuleNotLoadedError.
|
|
235
193
|
new_offset_id = self._equipment.find_applicable_labware_offset_id(
|
|
@@ -274,9 +232,6 @@ class MoveLabwareImplementation(AbstractCommandImpl[MoveLabwareParams, _ExecuteR
|
|
|
274
232
|
dropOffset=params.dropOffset or LabwareOffsetVector(x=0, y=0, z=0),
|
|
275
233
|
)
|
|
276
234
|
|
|
277
|
-
if trash_lid_drop_offset:
|
|
278
|
-
user_offset_data.dropOffset += trash_lid_drop_offset
|
|
279
|
-
|
|
280
235
|
try:
|
|
281
236
|
# Skips gripper moves when using virtual gripper
|
|
282
237
|
await self._labware_movement.move_labware_with_gripper(
|
|
@@ -82,7 +82,7 @@ class TipPhysicallyMissingError(ErrorOccurrence):
|
|
|
82
82
|
isDefined: bool = True
|
|
83
83
|
errorType: Literal["tipPhysicallyMissing"] = "tipPhysicallyMissing"
|
|
84
84
|
errorCode: str = ErrorCodes.TIP_PICKUP_FAILED.value.code
|
|
85
|
-
detail: str = "No
|
|
85
|
+
detail: str = "No tip detected."
|
|
86
86
|
|
|
87
87
|
|
|
88
88
|
_ExecuteReturn = Union[
|
|
@@ -148,12 +148,7 @@ class DestinationPositionResult(BaseModel):
|
|
|
148
148
|
|
|
149
149
|
|
|
150
150
|
class ErrorLocationInfo(TypedDict):
|
|
151
|
-
"""Holds a retry location for in-place error recovery.
|
|
152
|
-
|
|
153
|
-
This is appropriate to pass to a `moveToCoordinates` command,
|
|
154
|
-
assuming the pipette has not been configured with a different nozzle layout
|
|
155
|
-
in the meantime.
|
|
156
|
-
"""
|
|
151
|
+
"""Holds a retry location for in-place error recovery."""
|
|
157
152
|
|
|
158
153
|
retryLocation: Tuple[float, float, float]
|
|
159
154
|
|
|
@@ -206,5 +201,3 @@ class TipPhysicallyAttachedError(ErrorOccurrence):
|
|
|
206
201
|
|
|
207
202
|
errorCode: str = ErrorCodes.TIP_DROP_FAILED.value.code
|
|
208
203
|
detail: str = ErrorCodes.TIP_DROP_FAILED.value.detail
|
|
209
|
-
|
|
210
|
-
errorInfo: ErrorLocationInfo
|