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
|
@@ -262,33 +262,32 @@ class GeometryView:
|
|
|
262
262
|
return min_travel_z
|
|
263
263
|
|
|
264
264
|
def get_labware_parent_nominal_position(self, labware_id: str) -> Point:
|
|
265
|
-
"""Get the position of the labware's uncalibrated parent (deck
|
|
265
|
+
"""Get the position of the labware's uncalibrated parent slot (deck, module, or another labware)."""
|
|
266
266
|
try:
|
|
267
267
|
addressable_area_name = self.get_ancestor_slot_name(labware_id).id
|
|
268
268
|
except errors.LocationIsStagingSlotError:
|
|
269
269
|
addressable_area_name = self._get_staging_slot_name(labware_id)
|
|
270
270
|
except errors.LocationIsLidDockSlotError:
|
|
271
271
|
addressable_area_name = self._get_lid_dock_slot_name(labware_id)
|
|
272
|
-
|
|
272
|
+
slot_pos = self._addressable_areas.get_addressable_area_position(
|
|
273
273
|
addressable_area_name
|
|
274
274
|
)
|
|
275
|
+
labware_data = self._labware.get(labware_id)
|
|
275
276
|
|
|
276
|
-
|
|
277
|
-
child_definition=self._labware.get_definition(labware_id),
|
|
278
|
-
parent=self._labware.get(labware_id).location,
|
|
279
|
-
)
|
|
277
|
+
offset = self._get_labware_position_offset(labware_id, labware_data.location)
|
|
280
278
|
|
|
281
279
|
return Point(
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
280
|
+
slot_pos.x + offset.x,
|
|
281
|
+
slot_pos.y + offset.y,
|
|
282
|
+
slot_pos.z + offset.z,
|
|
285
283
|
)
|
|
286
284
|
|
|
287
|
-
def
|
|
288
|
-
self,
|
|
285
|
+
def _get_labware_position_offset(
|
|
286
|
+
self, labware_id: str, labware_location: LabwareLocation
|
|
289
287
|
) -> LabwareOffsetVector:
|
|
290
|
-
"""Gets the offset vector of a labware
|
|
288
|
+
"""Gets the offset vector of a labware on the given location.
|
|
291
289
|
|
|
290
|
+
NOTE: Not to be confused with LPC offset.
|
|
292
291
|
- For labware on Deck Slot: returns an offset of (0, 0, 0)
|
|
293
292
|
- For labware on a Module: returns the nominal offset for the labware's position
|
|
294
293
|
when placed on the specified module (using slot-transformed labwareOffset
|
|
@@ -299,42 +298,40 @@ class GeometryView:
|
|
|
299
298
|
on modules as well as stacking overlaps.
|
|
300
299
|
Does not include module calibration offset or LPC offset.
|
|
301
300
|
"""
|
|
302
|
-
if isinstance(
|
|
301
|
+
if isinstance(labware_location, (AddressableAreaLocation, DeckSlotLocation)):
|
|
303
302
|
return LabwareOffsetVector(x=0, y=0, z=0)
|
|
304
|
-
elif isinstance(
|
|
305
|
-
module_id =
|
|
306
|
-
|
|
303
|
+
elif isinstance(labware_location, ModuleLocation):
|
|
304
|
+
module_id = labware_location.moduleId
|
|
305
|
+
module_offset = self._modules.get_nominal_module_offset(
|
|
307
306
|
module_id=module_id, addressable_areas=self._addressable_areas
|
|
308
307
|
)
|
|
309
308
|
module_model = self._modules.get_connected_model(module_id)
|
|
310
309
|
stacking_overlap = self._labware.get_module_overlap_offsets(
|
|
311
|
-
|
|
310
|
+
labware_id, module_model
|
|
312
311
|
)
|
|
313
312
|
return LabwareOffsetVector(
|
|
314
|
-
x=
|
|
315
|
-
y=
|
|
316
|
-
z=
|
|
317
|
-
)
|
|
318
|
-
elif isinstance(parent, OnLabwareLocation):
|
|
319
|
-
on_labware = self._labware.get(parent.labwareId)
|
|
320
|
-
on_labware_dimensions = self._labware.get_dimensions(
|
|
321
|
-
labware_id=on_labware.id
|
|
313
|
+
x=module_offset.x - stacking_overlap.x,
|
|
314
|
+
y=module_offset.y - stacking_overlap.y,
|
|
315
|
+
z=module_offset.z - stacking_overlap.z,
|
|
322
316
|
)
|
|
317
|
+
elif isinstance(labware_location, OnLabwareLocation):
|
|
318
|
+
on_labware = self._labware.get(labware_location.labwareId)
|
|
319
|
+
on_labware_dimensions = self._labware.get_dimensions(on_labware.id)
|
|
323
320
|
stacking_overlap = self._labware.get_labware_overlap_offsets(
|
|
324
|
-
|
|
321
|
+
labware_id=labware_id, below_labware_name=on_labware.loadName
|
|
325
322
|
)
|
|
326
323
|
labware_offset = LabwareOffsetVector(
|
|
327
324
|
x=stacking_overlap.x,
|
|
328
325
|
y=stacking_overlap.y,
|
|
329
326
|
z=on_labware_dimensions.z - stacking_overlap.z,
|
|
330
327
|
)
|
|
331
|
-
return labware_offset + self.
|
|
332
|
-
|
|
328
|
+
return labware_offset + self._get_labware_position_offset(
|
|
329
|
+
on_labware.id, on_labware.location
|
|
333
330
|
)
|
|
334
331
|
else:
|
|
335
332
|
raise errors.LabwareNotOnDeckError(
|
|
336
|
-
"Cannot access labware since it is not on the deck. "
|
|
337
|
-
"Either it has been loaded off-deck or its been moved off-deck."
|
|
333
|
+
f"Cannot access labware {labware_id} since it is not on the deck. "
|
|
334
|
+
f"Either it has been loaded off-deck or its been moved off-deck."
|
|
338
335
|
)
|
|
339
336
|
|
|
340
337
|
def _normalize_module_calibration_offset(
|
|
@@ -712,12 +709,10 @@ class GeometryView:
|
|
|
712
709
|
assert isinstance(labware_location, AddressableAreaLocation)
|
|
713
710
|
return labware_location.addressableAreaName
|
|
714
711
|
|
|
715
|
-
def get_ancestor_slot_name(
|
|
716
|
-
self, labware_id: str
|
|
717
|
-
) -> Union[DeckSlotName, StagingSlotName]:
|
|
712
|
+
def get_ancestor_slot_name(self, labware_id: str) -> DeckSlotName:
|
|
718
713
|
"""Get the slot name of the labware or the module that the labware is on."""
|
|
719
714
|
labware = self._labware.get(labware_id)
|
|
720
|
-
slot_name:
|
|
715
|
+
slot_name: DeckSlotName
|
|
721
716
|
|
|
722
717
|
if isinstance(labware.location, DeckSlotLocation):
|
|
723
718
|
slot_name = labware.location.slotName
|
|
@@ -729,14 +724,18 @@ class GeometryView:
|
|
|
729
724
|
slot_name = self.get_ancestor_slot_name(below_labware_id)
|
|
730
725
|
elif isinstance(labware.location, AddressableAreaLocation):
|
|
731
726
|
area_name = labware.location.addressableAreaName
|
|
727
|
+
# TODO we might want to eventually return some sort of staging slot name when we're ready to work through
|
|
728
|
+
# the linting nightmare it will create
|
|
732
729
|
if self._labware.is_absorbance_reader_lid(labware_id):
|
|
733
730
|
raise errors.LocationIsLidDockSlotError(
|
|
734
731
|
"Cannot get ancestor slot name for labware on lid dock slot."
|
|
735
732
|
)
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
733
|
+
if fixture_validation.is_staging_slot(area_name):
|
|
734
|
+
raise errors.LocationIsStagingSlotError(
|
|
735
|
+
"Cannot get ancestor slot name for labware on staging slot."
|
|
736
|
+
)
|
|
737
|
+
raise errors.LocationIs
|
|
738
|
+
slot_name = DeckSlotName.from_primitive(area_name)
|
|
740
739
|
elif labware.location == OFF_DECK_LOCATION:
|
|
741
740
|
raise errors.LabwareNotOnDeckError(
|
|
742
741
|
f"Labware {labware_id} does not have a slot associated with it"
|
|
@@ -769,7 +768,7 @@ class GeometryView:
|
|
|
769
768
|
|
|
770
769
|
def get_labware_grip_point(
|
|
771
770
|
self,
|
|
772
|
-
|
|
771
|
+
labware_id: str,
|
|
773
772
|
location: Union[
|
|
774
773
|
DeckSlotLocation, ModuleLocation, OnLabwareLocation, AddressableAreaLocation
|
|
775
774
|
],
|
|
@@ -785,7 +784,7 @@ class GeometryView:
|
|
|
785
784
|
z-position of labware bottom + grip height from labware bottom.
|
|
786
785
|
"""
|
|
787
786
|
grip_height_from_labware_bottom = (
|
|
788
|
-
self._labware.get_grip_height_from_labware_bottom(
|
|
787
|
+
self._labware.get_grip_height_from_labware_bottom(labware_id)
|
|
789
788
|
)
|
|
790
789
|
location_name: str
|
|
791
790
|
|
|
@@ -811,9 +810,7 @@ class GeometryView:
|
|
|
811
810
|
).slotName.id
|
|
812
811
|
else: # OnLabwareLocation
|
|
813
812
|
location_name = self.get_ancestor_slot_name(location.labwareId).id
|
|
814
|
-
labware_offset = self.
|
|
815
|
-
child_definition=labware_definition, parent=location
|
|
816
|
-
)
|
|
813
|
+
labware_offset = self._get_labware_position_offset(labware_id, location)
|
|
817
814
|
# Get the calibrated offset if the on labware location is on top of a module, otherwise return empty one
|
|
818
815
|
cal_offset = self._get_calibrated_module_offset(location)
|
|
819
816
|
offset = LabwareOffsetVector(
|
|
@@ -832,9 +829,7 @@ class GeometryView:
|
|
|
832
829
|
)
|
|
833
830
|
|
|
834
831
|
def get_extra_waypoints(
|
|
835
|
-
self,
|
|
836
|
-
location: Optional[CurrentPipetteLocation],
|
|
837
|
-
to_slot: Union[DeckSlotName, StagingSlotName],
|
|
832
|
+
self, location: Optional[CurrentPipetteLocation], to_slot: DeckSlotName
|
|
838
833
|
) -> List[Tuple[float, float]]:
|
|
839
834
|
"""Get extra waypoints for movement if thermocycler needs to be dodged."""
|
|
840
835
|
if location is not None:
|
|
@@ -893,10 +888,8 @@ class GeometryView:
|
|
|
893
888
|
return maybe_labware or maybe_module or maybe_fixture or None
|
|
894
889
|
|
|
895
890
|
@staticmethod
|
|
896
|
-
def get_slot_column(slot_name:
|
|
891
|
+
def get_slot_column(slot_name: DeckSlotName) -> int:
|
|
897
892
|
"""Get the column number for the specified slot."""
|
|
898
|
-
if isinstance(slot_name, StagingSlotName):
|
|
899
|
-
return 4
|
|
900
893
|
row_col_name = slot_name.to_ot3_equivalent()
|
|
901
894
|
slot_name_match = WELL_NAME_PATTERN.match(row_col_name.value)
|
|
902
895
|
assert (
|
|
@@ -1177,13 +1170,7 @@ class GeometryView:
|
|
|
1177
1170
|
)
|
|
1178
1171
|
|
|
1179
1172
|
assert isinstance(
|
|
1180
|
-
ancestor,
|
|
1181
|
-
(
|
|
1182
|
-
DeckSlotLocation,
|
|
1183
|
-
ModuleLocation,
|
|
1184
|
-
OnLabwareLocation,
|
|
1185
|
-
AddressableAreaLocation,
|
|
1186
|
-
),
|
|
1173
|
+
ancestor, (DeckSlotLocation, ModuleLocation, OnLabwareLocation)
|
|
1187
1174
|
), "No gripper offsets for off-deck labware"
|
|
1188
1175
|
return (
|
|
1189
1176
|
direct_parent_offset.pickUpOffset
|
|
@@ -1208,7 +1195,6 @@ class GeometryView:
|
|
|
1208
1195
|
extra_offset = LabwareOffsetVector(x=0, y=0, z=0)
|
|
1209
1196
|
if (
|
|
1210
1197
|
isinstance(ancestor, ModuleLocation)
|
|
1211
|
-
# todo(mm, 2024-11-06): Do not access private module state; only use public ModuleView methods.
|
|
1212
1198
|
and self._modules._state.requested_model_by_id[ancestor.moduleId]
|
|
1213
1199
|
== ModuleModel.THERMOCYCLER_MODULE_V2
|
|
1214
1200
|
and labware_validation.validate_definition_is_lid(current_labware)
|
|
@@ -1231,13 +1217,7 @@ class GeometryView:
|
|
|
1231
1217
|
)
|
|
1232
1218
|
|
|
1233
1219
|
assert isinstance(
|
|
1234
|
-
ancestor,
|
|
1235
|
-
(
|
|
1236
|
-
DeckSlotLocation,
|
|
1237
|
-
ModuleLocation,
|
|
1238
|
-
OnLabwareLocation,
|
|
1239
|
-
AddressableAreaLocation,
|
|
1240
|
-
),
|
|
1220
|
+
ancestor, (DeckSlotLocation, ModuleLocation, OnLabwareLocation)
|
|
1241
1221
|
), "No gripper offsets for off-deck labware"
|
|
1242
1222
|
return (
|
|
1243
1223
|
direct_parent_offset.dropOffset
|
|
@@ -1247,23 +1227,6 @@ class GeometryView:
|
|
|
1247
1227
|
+ extra_offset
|
|
1248
1228
|
)
|
|
1249
1229
|
|
|
1250
|
-
# todo(mm, 2024-11-05): This may be incorrect because it does not take the following
|
|
1251
|
-
# offsets into account, which *are* taken into account for the actual gripper movement:
|
|
1252
|
-
#
|
|
1253
|
-
# * The pickup offset in the definition of the parent of the gripped labware.
|
|
1254
|
-
# * The "additional offset" or "user offset", e.g. the `pickUpOffset` and `dropOffset`
|
|
1255
|
-
# params in the `moveLabware` command.
|
|
1256
|
-
#
|
|
1257
|
-
# And this *does* take these extra offsets into account:
|
|
1258
|
-
#
|
|
1259
|
-
# * The labware's Labware Position Check offset
|
|
1260
|
-
#
|
|
1261
|
-
# For robustness, we should combine this with `get_gripper_labware_movement_waypoints()`.
|
|
1262
|
-
#
|
|
1263
|
-
# We should also be more explicit about which offsets act to move the gripper paddles
|
|
1264
|
-
# relative to the gripped labware, and which offsets act to change how the gripped
|
|
1265
|
-
# labware sits atop its parent. Those have different effects on how far the gripped
|
|
1266
|
-
# labware juts beyond the paddles while it's in transit.
|
|
1267
1230
|
def check_gripper_labware_tip_collision(
|
|
1268
1231
|
self,
|
|
1269
1232
|
gripper_homed_position_z: float,
|
|
@@ -1271,22 +1234,18 @@ class GeometryView:
|
|
|
1271
1234
|
current_location: OnDeckLabwareLocation,
|
|
1272
1235
|
) -> None:
|
|
1273
1236
|
"""Check for potential collision of tips against labware to be lifted."""
|
|
1274
|
-
|
|
1237
|
+
# TODO(cb, 2024-01-22): Remove the 1 and 8 channel special case once we are doing X axis validation
|
|
1275
1238
|
pipettes = self._pipettes.get_all()
|
|
1276
1239
|
for pipette in pipettes:
|
|
1277
|
-
# TODO(cb, 2024-01-22): Remove the 1 and 8 channel special case once we are doing X axis validation
|
|
1278
1240
|
if self._pipettes.get_channels(pipette.id) in [1, 8]:
|
|
1279
1241
|
return
|
|
1280
1242
|
|
|
1281
1243
|
tip = self._pipettes.get_attached_tip(pipette.id)
|
|
1282
1244
|
if tip:
|
|
1283
|
-
# NOTE: This call to get_labware_highest_z() uses the labware's LPC offset,
|
|
1284
|
-
# which is an inconsistency between this and the actual gripper movement.
|
|
1285
|
-
# See the todo comment above this function.
|
|
1286
1245
|
labware_top_z_when_gripped = gripper_homed_position_z + (
|
|
1287
1246
|
self.get_labware_highest_z(labware_id=labware_id)
|
|
1288
1247
|
- self.get_labware_grip_point(
|
|
1289
|
-
|
|
1248
|
+
labware_id=labware_id, location=current_location
|
|
1290
1249
|
).z
|
|
1291
1250
|
)
|
|
1292
1251
|
# TODO(cb, 2024-01-18): Utilizing the nozzle map and labware X coordinates verify if collisions will occur on the X axis (analysis will use hard coded data to measure from the gripper critical point to the pipette mount)
|
|
@@ -1294,7 +1253,7 @@ class GeometryView:
|
|
|
1294
1253
|
_PIPETTE_HOMED_POSITION_Z - tip.length
|
|
1295
1254
|
) < labware_top_z_when_gripped:
|
|
1296
1255
|
raise LabwareMovementNotAllowedError(
|
|
1297
|
-
f"Cannot move labware '{
|
|
1256
|
+
f"Cannot move labware '{self._labware.get(labware_id).loadName}' when {int(tip.volume)} µL tips are attached."
|
|
1298
1257
|
)
|
|
1299
1258
|
return
|
|
1300
1259
|
|
|
@@ -1334,7 +1293,6 @@ class GeometryView:
|
|
|
1334
1293
|
DeckSlotLocation,
|
|
1335
1294
|
ModuleLocation,
|
|
1336
1295
|
AddressableAreaLocation,
|
|
1337
|
-
OnLabwareLocation,
|
|
1338
1296
|
),
|
|
1339
1297
|
), "No gripper offsets for off-deck labware"
|
|
1340
1298
|
|
|
@@ -1348,11 +1306,11 @@ class GeometryView:
|
|
|
1348
1306
|
module_loc = self._modules.get_location(parent_location.moduleId)
|
|
1349
1307
|
slot_name = module_loc.slotName
|
|
1350
1308
|
|
|
1351
|
-
slot_based_offset = self._labware.
|
|
1309
|
+
slot_based_offset = self._labware.get_labware_gripper_offsets(
|
|
1352
1310
|
labware_id=labware_id, slot_name=slot_name.to_ot3_equivalent()
|
|
1353
1311
|
)
|
|
1354
1312
|
|
|
1355
|
-
return slot_based_offset or self._labware.
|
|
1313
|
+
return slot_based_offset or self._labware.get_labware_gripper_offsets(
|
|
1356
1314
|
labware_id=labware_id, slot_name=None
|
|
1357
1315
|
)
|
|
1358
1316
|
|
|
@@ -13,7 +13,6 @@ from typing import (
|
|
|
13
13
|
NamedTuple,
|
|
14
14
|
cast,
|
|
15
15
|
Union,
|
|
16
|
-
overload,
|
|
17
16
|
)
|
|
18
17
|
|
|
19
18
|
from opentrons.protocol_engine.state import update_types
|
|
@@ -82,10 +81,6 @@ _RIGHT_SIDE_SLOTS = {
|
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
|
|
85
|
-
# The max height of the labware that can fit in a plate reader
|
|
86
|
-
_PLATE_READER_MAX_LABWARE_Z_MM = 16
|
|
87
|
-
|
|
88
|
-
|
|
89
84
|
class LabwareLoadParams(NamedTuple):
|
|
90
85
|
"""Parameters required to load a labware in Protocol Engine."""
|
|
91
86
|
|
|
@@ -232,11 +227,10 @@ class LabwareStore(HasState[LabwareState], HandlesActions):
|
|
|
232
227
|
if labware_location_update.new_location:
|
|
233
228
|
new_location = labware_location_update.new_location
|
|
234
229
|
|
|
235
|
-
if isinstance(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
or fixture_validation.is_trash(new_location.addressableAreaName)
|
|
230
|
+
if isinstance(
|
|
231
|
+
new_location, AddressableAreaLocation
|
|
232
|
+
) and fixture_validation.is_gripper_waste_chute(
|
|
233
|
+
new_location.addressableAreaName
|
|
240
234
|
):
|
|
241
235
|
# If a labware has been moved into a waste chute it's been chuted away and is now technically off deck
|
|
242
236
|
new_location = OFF_DECK_LOCATION
|
|
@@ -631,26 +625,10 @@ class LabwareView(HasState[LabwareState]):
|
|
|
631
625
|
definition = self.get_definition(labware_id)
|
|
632
626
|
return definition.parameters.loadName
|
|
633
627
|
|
|
634
|
-
|
|
635
|
-
def get_dimensions(self, *, labware_definition: LabwareDefinition) -> Dimensions:
|
|
636
|
-
pass
|
|
637
|
-
|
|
638
|
-
@overload
|
|
639
|
-
def get_dimensions(self, *, labware_id: str) -> Dimensions:
|
|
640
|
-
pass
|
|
641
|
-
|
|
642
|
-
def get_dimensions(
|
|
643
|
-
self,
|
|
644
|
-
*,
|
|
645
|
-
labware_definition: LabwareDefinition | None = None,
|
|
646
|
-
labware_id: str | None = None,
|
|
647
|
-
) -> Dimensions:
|
|
628
|
+
def get_dimensions(self, labware_id: str) -> Dimensions:
|
|
648
629
|
"""Get the labware's dimensions."""
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
labware_definition = self.get_definition(labware_id)
|
|
652
|
-
|
|
653
|
-
dims = labware_definition.dimensions
|
|
630
|
+
definition = self.get_definition(labware_id)
|
|
631
|
+
dims = definition.dimensions
|
|
654
632
|
|
|
655
633
|
return Dimensions(
|
|
656
634
|
x=dims.xDimension,
|
|
@@ -659,9 +637,10 @@ class LabwareView(HasState[LabwareState]):
|
|
|
659
637
|
)
|
|
660
638
|
|
|
661
639
|
def get_labware_overlap_offsets(
|
|
662
|
-
self,
|
|
640
|
+
self, labware_id: str, below_labware_name: str
|
|
663
641
|
) -> OverlapOffset:
|
|
664
642
|
"""Get the labware's overlap with requested labware's load name."""
|
|
643
|
+
definition = self.get_definition(labware_id)
|
|
665
644
|
if below_labware_name in definition.stackingOffsetWithLabware.keys():
|
|
666
645
|
stacking_overlap = definition.stackingOffsetWithLabware.get(
|
|
667
646
|
below_labware_name, OverlapOffset(x=0, y=0, z=0)
|
|
@@ -675,9 +654,10 @@ class LabwareView(HasState[LabwareState]):
|
|
|
675
654
|
)
|
|
676
655
|
|
|
677
656
|
def get_module_overlap_offsets(
|
|
678
|
-
self,
|
|
657
|
+
self, labware_id: str, module_model: ModuleModel
|
|
679
658
|
) -> OverlapOffset:
|
|
680
659
|
"""Get the labware's overlap with requested module model."""
|
|
660
|
+
definition = self.get_definition(labware_id)
|
|
681
661
|
stacking_overlap = definition.stackingOffsetWithModule.get(
|
|
682
662
|
str(module_model.value)
|
|
683
663
|
)
|
|
@@ -837,24 +817,6 @@ class LabwareView(HasState[LabwareState]):
|
|
|
837
817
|
f"Labware {labware.loadName} is already present at {location}."
|
|
838
818
|
)
|
|
839
819
|
|
|
840
|
-
def raise_if_labware_incompatible_with_plate_reader(
|
|
841
|
-
self,
|
|
842
|
-
labware_definition: LabwareDefinition,
|
|
843
|
-
) -> None:
|
|
844
|
-
"""Raise an error if the labware is not compatible with the plate reader."""
|
|
845
|
-
load_name = labware_definition.parameters.loadName
|
|
846
|
-
number_of_wells = len(labware_definition.wells)
|
|
847
|
-
if number_of_wells != 96:
|
|
848
|
-
raise errors.LabwareMovementNotAllowedError(
|
|
849
|
-
f"Cannot move '{load_name}' into plate reader because the"
|
|
850
|
-
f" labware contains {number_of_wells} wells where 96 wells is expected."
|
|
851
|
-
)
|
|
852
|
-
elif labware_definition.dimensions.zDimension > _PLATE_READER_MAX_LABWARE_Z_MM:
|
|
853
|
-
raise errors.LabwareMovementNotAllowedError(
|
|
854
|
-
f"Cannot move '{load_name}' into plate reader because the"
|
|
855
|
-
f" maximum allowed labware height is {_PLATE_READER_MAX_LABWARE_Z_MM}mm."
|
|
856
|
-
)
|
|
857
|
-
|
|
858
820
|
def raise_if_labware_cannot_be_stacked( # noqa: C901
|
|
859
821
|
self, top_labware_definition: LabwareDefinition, bottom_labware_id: str
|
|
860
822
|
) -> None:
|
|
@@ -938,60 +900,22 @@ class LabwareView(HasState[LabwareState]):
|
|
|
938
900
|
else None
|
|
939
901
|
)
|
|
940
902
|
|
|
941
|
-
def
|
|
942
|
-
"""Return the special labware definition for the plate reader lid.
|
|
943
|
-
|
|
944
|
-
See todo comments in `create_protocol_engine().
|
|
945
|
-
"""
|
|
946
|
-
# NOTE: This needs to stay in sync with create_protocol_engine().
|
|
947
|
-
return self._state.definitions_by_uri[
|
|
948
|
-
"opentrons/opentrons_flex_lid_absorbance_plate_reader_module/1"
|
|
949
|
-
]
|
|
950
|
-
|
|
951
|
-
@overload
|
|
952
|
-
def get_child_gripper_offsets(
|
|
903
|
+
def get_labware_gripper_offsets(
|
|
953
904
|
self,
|
|
954
|
-
|
|
955
|
-
labware_definition: LabwareDefinition,
|
|
956
|
-
slot_name: Optional[DeckSlotName],
|
|
957
|
-
) -> Optional[LabwareMovementOffsetData]:
|
|
958
|
-
pass
|
|
959
|
-
|
|
960
|
-
@overload
|
|
961
|
-
def get_child_gripper_offsets(
|
|
962
|
-
self, *, labware_id: str, slot_name: Optional[DeckSlotName]
|
|
963
|
-
) -> Optional[LabwareMovementOffsetData]:
|
|
964
|
-
pass
|
|
965
|
-
|
|
966
|
-
def get_child_gripper_offsets(
|
|
967
|
-
self,
|
|
968
|
-
*,
|
|
969
|
-
labware_definition: Optional[LabwareDefinition] = None,
|
|
970
|
-
labware_id: Optional[str] = None,
|
|
905
|
+
labware_id: str,
|
|
971
906
|
slot_name: Optional[DeckSlotName],
|
|
972
907
|
) -> Optional[LabwareMovementOffsetData]:
|
|
973
|
-
"""Get the
|
|
974
|
-
|
|
975
|
-
Params:
|
|
976
|
-
labware_id: The ID of a parent labware (atop which another labware, the child, will be stacked).
|
|
977
|
-
slot_name: The ancestor slot that the parent labware is ultimately loaded into,
|
|
978
|
-
perhaps after going through a module in the middle.
|
|
908
|
+
"""Get the labware's gripper offsets of the specified type.
|
|
979
909
|
|
|
980
910
|
Returns:
|
|
981
|
-
If `slot_name` is provided, returns the gripper offsets that the
|
|
911
|
+
If `slot_name` is provided, returns the gripper offsets that the labware definition
|
|
982
912
|
specifies just for that slot, or `None` if the labware definition doesn't have an
|
|
983
913
|
exact match.
|
|
984
914
|
|
|
985
|
-
If `slot_name` is `None`, returns the gripper offsets that the
|
|
915
|
+
If `slot_name` is `None`, returns the gripper offsets that the labware
|
|
986
916
|
definition designates as "default," or `None` if it doesn't designate any as such.
|
|
987
917
|
"""
|
|
988
|
-
|
|
989
|
-
labware_definition = self.get_definition(labware_id)
|
|
990
|
-
else:
|
|
991
|
-
# Should be ensured by our @overloads.
|
|
992
|
-
assert labware_definition is not None
|
|
993
|
-
|
|
994
|
-
parsed_offsets = labware_definition.gripperOffsets
|
|
918
|
+
parsed_offsets = self.get_definition(labware_id).gripperOffsets
|
|
995
919
|
offset_key = slot_name.id if slot_name else "default"
|
|
996
920
|
|
|
997
921
|
if parsed_offsets is None or offset_key not in parsed_offsets:
|
|
@@ -1006,22 +930,20 @@ class LabwareView(HasState[LabwareState]):
|
|
|
1006
930
|
),
|
|
1007
931
|
)
|
|
1008
932
|
|
|
1009
|
-
def get_grip_force(self,
|
|
933
|
+
def get_grip_force(self, labware_id: str) -> float:
|
|
1010
934
|
"""Get the recommended grip force for gripping labware using gripper."""
|
|
1011
|
-
recommended_force =
|
|
935
|
+
recommended_force = self.get_definition(labware_id).gripForce
|
|
1012
936
|
return (
|
|
1013
937
|
recommended_force if recommended_force is not None else LABWARE_GRIP_FORCE
|
|
1014
938
|
)
|
|
1015
939
|
|
|
1016
|
-
def get_grip_height_from_labware_bottom(
|
|
1017
|
-
self, labware_definition: LabwareDefinition
|
|
1018
|
-
) -> float:
|
|
940
|
+
def get_grip_height_from_labware_bottom(self, labware_id: str) -> float:
|
|
1019
941
|
"""Get the recommended grip height from labware bottom, if present."""
|
|
1020
|
-
recommended_height =
|
|
942
|
+
recommended_height = self.get_definition(labware_id).gripHeightFromLabwareBottom
|
|
1021
943
|
return (
|
|
1022
944
|
recommended_height
|
|
1023
945
|
if recommended_height is not None
|
|
1024
|
-
else self.get_dimensions(
|
|
946
|
+
else self.get_dimensions(labware_id).z / 2
|
|
1025
947
|
)
|
|
1026
948
|
|
|
1027
949
|
@staticmethod
|
|
@@ -1064,7 +986,7 @@ class LabwareView(HasState[LabwareState]):
|
|
|
1064
986
|
def _max_z_of_well(well_defn: WellDefinition) -> float:
|
|
1065
987
|
return well_defn.z + well_defn.depth
|
|
1066
988
|
|
|
1067
|
-
def get_well_bbox(self,
|
|
989
|
+
def get_well_bbox(self, labware_id: str) -> Dimensions:
|
|
1068
990
|
"""Get the bounding box implied by the wells.
|
|
1069
991
|
|
|
1070
992
|
The bounding box of the labware that is implied by the wells is that required
|
|
@@ -1075,13 +997,14 @@ class LabwareView(HasState[LabwareState]):
|
|
|
1075
997
|
This is used for the specific purpose of finding the reasonable uncertainty bounds of
|
|
1076
998
|
where and how a gripper will interact with a labware.
|
|
1077
999
|
"""
|
|
1000
|
+
defn = self.get_definition(labware_id)
|
|
1078
1001
|
max_x: Optional[float] = None
|
|
1079
1002
|
min_x: Optional[float] = None
|
|
1080
1003
|
max_y: Optional[float] = None
|
|
1081
1004
|
min_y: Optional[float] = None
|
|
1082
1005
|
max_z: Optional[float] = None
|
|
1083
1006
|
|
|
1084
|
-
for well in
|
|
1007
|
+
for well in defn.wells.values():
|
|
1085
1008
|
well_max_x = self._max_x_of_well(well)
|
|
1086
1009
|
well_min_x = self._min_x_of_well(well)
|
|
1087
1010
|
well_max_y = self._max_y_of_well(well)
|
|
@@ -9,9 +9,6 @@ AbsorbanceReaderLidId = NewType("AbsorbanceReaderLidId", str)
|
|
|
9
9
|
AbsorbanceReaderMeasureMode = NewType("AbsorbanceReaderMeasureMode", str)
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
# todo(mm, 2024-11-08): frozen=True is getting pretty painful because ModuleStore has
|
|
13
|
-
# no type-safe way to modify just a single attribute. Consider unfreezing this
|
|
14
|
-
# (taking care to ensure that consumers of ModuleView still only get a read-only view).
|
|
15
12
|
@dataclass(frozen=True)
|
|
16
13
|
class AbsorbanceReaderSubState:
|
|
17
14
|
"""Absorbance-Plate-Reader-specific state."""
|
|
@@ -24,6 +21,7 @@ class AbsorbanceReaderSubState:
|
|
|
24
21
|
configured_wavelengths: Optional[List[int]]
|
|
25
22
|
measure_mode: Optional[AbsorbanceReaderMeasureMode]
|
|
26
23
|
reference_wavelength: Optional[int]
|
|
24
|
+
lid_id: Optional[str]
|
|
27
25
|
|
|
28
26
|
def raise_if_lid_status_not_expected(self, lid_on_expected: bool) -> None:
|
|
29
27
|
"""Raise if the lid status is not correct."""
|