opentrons 8.7.0a7__py3-none-any.whl → 8.8.0a7__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/_version.py +2 -2
- opentrons/cli/analyze.py +4 -1
- opentrons/config/__init__.py +7 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +8 -5
- opentrons/drivers/flex_stacker/driver.py +6 -1
- opentrons/drivers/vacuum_module/__init__.py +5 -0
- opentrons/drivers/vacuum_module/abstract.py +93 -0
- opentrons/drivers/vacuum_module/driver.py +208 -0
- opentrons/drivers/vacuum_module/errors.py +39 -0
- opentrons/drivers/vacuum_module/simulator.py +85 -0
- opentrons/drivers/vacuum_module/types.py +79 -0
- opentrons/execute.py +3 -0
- opentrons/hardware_control/backends/flex_protocol.py +2 -0
- opentrons/hardware_control/backends/ot3controller.py +35 -2
- opentrons/hardware_control/backends/ot3simulator.py +2 -0
- opentrons/hardware_control/backends/ot3utils.py +37 -0
- opentrons/hardware_control/module_control.py +23 -2
- opentrons/hardware_control/modules/mod_abc.py +1 -1
- opentrons/hardware_control/modules/types.py +1 -1
- opentrons/hardware_control/motion_utilities.py +6 -6
- opentrons/hardware_control/ot3api.py +62 -13
- opentrons/hardware_control/protocols/gripper_controller.py +1 -0
- opentrons/hardware_control/protocols/liquid_handler.py +6 -2
- opentrons/hardware_control/types.py +12 -0
- opentrons/legacy_commands/commands.py +58 -5
- opentrons/legacy_commands/module_commands.py +29 -0
- opentrons/legacy_commands/protocol_commands.py +33 -1
- opentrons/legacy_commands/types.py +75 -1
- opentrons/protocol_api/_transfer_liquid_validation.py +17 -2
- opentrons/protocol_api/_types.py +2 -0
- opentrons/protocol_api/core/engine/_default_labware_versions.py +1 -0
- opentrons/protocol_api/core/engine/deck_conflict.py +3 -1
- opentrons/protocol_api/core/engine/instrument.py +109 -26
- opentrons/protocol_api/core/engine/module_core.py +27 -3
- opentrons/protocol_api/core/engine/protocol.py +33 -1
- opentrons/protocol_api/core/engine/stringify.py +2 -0
- opentrons/protocol_api/core/instrument.py +19 -2
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +19 -2
- opentrons/protocol_api/core/legacy/legacy_module_core.py +15 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +12 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +19 -2
- opentrons/protocol_api/core/module.py +25 -2
- opentrons/protocol_api/core/protocol.py +12 -0
- opentrons/protocol_api/instrument_context.py +388 -2
- opentrons/protocol_api/labware.py +5 -2
- opentrons/protocol_api/module_contexts.py +133 -30
- opentrons/protocol_api/protocol_context.py +61 -17
- opentrons/protocol_api/robot_context.py +3 -4
- opentrons/protocol_api/validation.py +43 -2
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/__init__.py +2 -0
- opentrons/protocol_engine/actions/actions.py +9 -0
- opentrons/protocol_engine/commands/__init__.py +14 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +22 -23
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +52 -19
- opentrons/protocol_engine/commands/capture_image.py +302 -0
- opentrons/protocol_engine/commands/command.py +1 -0
- opentrons/protocol_engine/commands/command_unions.py +13 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +56 -19
- opentrons/protocol_engine/commands/flex_stacker/common.py +35 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +7 -0
- opentrons/protocol_engine/commands/heater_shaker/set_shake_speed.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/move_labware.py +3 -4
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +1 -1
- opentrons/protocol_engine/commands/movement_common.py +29 -2
- opentrons/protocol_engine/commands/pipetting_common.py +48 -3
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +12 -9
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +17 -12
- opentrons/protocol_engine/commands/thermocycler/start_run_extended_profile.py +1 -1
- opentrons/protocol_engine/create_protocol_engine.py +12 -0
- opentrons/protocol_engine/engine_support.py +3 -0
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/exceptions.py +64 -0
- opentrons/protocol_engine/execution/__init__.py +2 -0
- opentrons/protocol_engine/execution/command_executor.py +54 -1
- opentrons/protocol_engine/execution/create_queue_worker.py +4 -1
- opentrons/protocol_engine/execution/labware_movement.py +13 -4
- opentrons/protocol_engine/execution/pipetting.py +19 -25
- opentrons/protocol_engine/protocol_engine.py +62 -2
- opentrons/protocol_engine/resources/__init__.py +2 -0
- opentrons/protocol_engine/resources/camera_provider.py +110 -0
- opentrons/protocol_engine/resources/file_provider.py +133 -58
- opentrons/protocol_engine/slot_standardization.py +2 -0
- opentrons/protocol_engine/state/camera.py +54 -0
- opentrons/protocol_engine/state/commands.py +24 -4
- opentrons/protocol_engine/state/geometry.py +68 -10
- opentrons/protocol_engine/state/labware.py +10 -6
- opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +6 -1
- opentrons/protocol_engine/state/modules.py +9 -0
- opentrons/protocol_engine/state/preconditions.py +59 -0
- opentrons/protocol_engine/state/state.py +30 -0
- opentrons/protocol_engine/state/state_summary.py +2 -0
- opentrons/protocol_engine/state/update_types.py +10 -0
- opentrons/protocol_engine/types/__init__.py +14 -1
- opentrons/protocol_engine/types/command_preconditions.py +18 -0
- opentrons/protocol_engine/types/location.py +26 -2
- opentrons/protocol_engine/types/module.py +1 -1
- opentrons/protocol_runner/protocol_runner.py +14 -1
- opentrons/protocol_runner/run_orchestrator.py +31 -0
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +2 -2
- opentrons/simulate.py +3 -0
- opentrons/system/camera.py +333 -3
- opentrons/system/ffmpeg.py +110 -0
- {opentrons-8.7.0a7.dist-info → opentrons-8.8.0a7.dist-info}/METADATA +4 -4
- {opentrons-8.7.0a7.dist-info → opentrons-8.8.0a7.dist-info}/RECORD +109 -97
- {opentrons-8.7.0a7.dist-info → opentrons-8.8.0a7.dist-info}/WHEEL +0 -0
- {opentrons-8.7.0a7.dist-info → opentrons-8.8.0a7.dist-info}/entry_points.txt +0 -0
- {opentrons-8.7.0a7.dist-info → opentrons-8.8.0a7.dist-info}/licenses/LICENSE +0 -0
|
@@ -203,7 +203,10 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
203
203
|
flow_rate: float,
|
|
204
204
|
in_place: bool,
|
|
205
205
|
meniscus_tracking: Optional[MeniscusTrackingTarget] = None,
|
|
206
|
+
end_location: Optional[Location] = None,
|
|
207
|
+
end_meniscus_tracking: Optional[MeniscusTrackingTarget] = None,
|
|
206
208
|
correction_volume: Optional[float] = None,
|
|
209
|
+
movement_delay: Optional[float] = None,
|
|
207
210
|
) -> None:
|
|
208
211
|
"""Aspirate a given volume of liquid from the specified location.
|
|
209
212
|
Args:
|
|
@@ -215,8 +218,9 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
215
218
|
in_place: whether this is a in-place command.
|
|
216
219
|
meniscus_tracking: Optional data about where to aspirate from.
|
|
217
220
|
"""
|
|
218
|
-
if meniscus_tracking == MeniscusTrackingTarget.START:
|
|
221
|
+
if meniscus_tracking == MeniscusTrackingTarget.START and end_location is None:
|
|
219
222
|
raise ValueError("Cannot aspirate at the starting liquid height.")
|
|
223
|
+
final_location = location
|
|
220
224
|
if well_core is None:
|
|
221
225
|
if not in_place:
|
|
222
226
|
self._engine_client.execute_command(
|
|
@@ -262,16 +266,34 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
262
266
|
well_location=well_location,
|
|
263
267
|
)
|
|
264
268
|
assert isinstance(well_location, LiquidHandlingWellLocation)
|
|
265
|
-
|
|
269
|
+
# the dynamic liquid tracking flag is for the prototype dynamic tracking method
|
|
270
|
+
if dynamic_liquid_tracking or end_location is not None:
|
|
271
|
+
# Keep this part when above TODO is done
|
|
272
|
+
if end_location is None:
|
|
273
|
+
end_location = location
|
|
274
|
+
(
|
|
275
|
+
end_well_location,
|
|
276
|
+
_,
|
|
277
|
+
) = self._engine_client.state.geometry.get_relative_well_location(
|
|
278
|
+
labware_id=labware_id,
|
|
279
|
+
well_name=well_name,
|
|
280
|
+
absolute_point=end_location.point,
|
|
281
|
+
location_type=WellLocationFunction.LIQUID_HANDLING,
|
|
282
|
+
meniscus_tracking=end_meniscus_tracking,
|
|
283
|
+
)
|
|
284
|
+
final_location = end_location
|
|
285
|
+
assert isinstance(end_well_location, LiquidHandlingWellLocation)
|
|
266
286
|
self._engine_client.execute_command(
|
|
267
287
|
cmd.AspirateWhileTrackingParams(
|
|
268
288
|
pipetteId=self._pipette_id,
|
|
269
289
|
labwareId=labware_id,
|
|
270
290
|
wellName=well_name,
|
|
271
|
-
|
|
291
|
+
trackFromLocation=well_location,
|
|
292
|
+
trackToLocation=end_well_location,
|
|
272
293
|
volume=volume,
|
|
273
294
|
flowRate=flow_rate,
|
|
274
295
|
correctionVolume=correction_volume,
|
|
296
|
+
movement_delay=movement_delay,
|
|
275
297
|
)
|
|
276
298
|
)
|
|
277
299
|
else:
|
|
@@ -287,7 +309,9 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
287
309
|
)
|
|
288
310
|
)
|
|
289
311
|
|
|
290
|
-
self._protocol_core.set_last_location(
|
|
312
|
+
self._protocol_core.set_last_location(
|
|
313
|
+
location=final_location, mount=self.get_mount()
|
|
314
|
+
)
|
|
291
315
|
|
|
292
316
|
def dispense(
|
|
293
317
|
self,
|
|
@@ -299,7 +323,10 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
299
323
|
in_place: bool,
|
|
300
324
|
push_out: Optional[float],
|
|
301
325
|
meniscus_tracking: Optional[MeniscusTrackingTarget] = None,
|
|
326
|
+
end_location: Optional[Location] = None,
|
|
327
|
+
end_meniscus_tracking: Optional[MeniscusTrackingTarget] = None,
|
|
302
328
|
correction_volume: Optional[float] = None,
|
|
329
|
+
movement_delay: Optional[float] = None,
|
|
303
330
|
) -> None:
|
|
304
331
|
"""Dispense a given volume of liquid into the specified location.
|
|
305
332
|
Args:
|
|
@@ -320,7 +347,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
320
347
|
# Newer API versions raise an error if you try to dispense more than
|
|
321
348
|
# you can. Let the error come from Protocol Engine's validation.
|
|
322
349
|
pass
|
|
323
|
-
|
|
350
|
+
final_location = location
|
|
324
351
|
if well_core is None:
|
|
325
352
|
if not in_place:
|
|
326
353
|
if isinstance(location, (TrashBin, WasteChute)):
|
|
@@ -375,17 +402,34 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
375
402
|
well_name=well_name,
|
|
376
403
|
well_location=well_location,
|
|
377
404
|
)
|
|
378
|
-
|
|
405
|
+
# the dynamic liquid tracking flag is for the prototype dynamic tracking method
|
|
406
|
+
if dynamic_liquid_tracking or end_location is not None:
|
|
407
|
+
if end_location is None:
|
|
408
|
+
end_location = location
|
|
409
|
+
final_location = end_location
|
|
410
|
+
(
|
|
411
|
+
end_well_location,
|
|
412
|
+
_,
|
|
413
|
+
) = self._engine_client.state.geometry.get_relative_well_location(
|
|
414
|
+
labware_id=labware_id,
|
|
415
|
+
well_name=well_name,
|
|
416
|
+
absolute_point=end_location.point,
|
|
417
|
+
location_type=WellLocationFunction.LIQUID_HANDLING,
|
|
418
|
+
meniscus_tracking=end_meniscus_tracking,
|
|
419
|
+
)
|
|
420
|
+
assert isinstance(end_well_location, LiquidHandlingWellLocation)
|
|
379
421
|
self._engine_client.execute_command(
|
|
380
422
|
cmd.DispenseWhileTrackingParams(
|
|
381
423
|
pipetteId=self._pipette_id,
|
|
382
424
|
labwareId=labware_id,
|
|
383
425
|
wellName=well_name,
|
|
384
|
-
|
|
426
|
+
trackFromLocation=well_location,
|
|
427
|
+
trackToLocation=end_well_location,
|
|
385
428
|
volume=volume,
|
|
386
429
|
flowRate=flow_rate,
|
|
387
430
|
pushOut=push_out,
|
|
388
431
|
correctionVolume=correction_volume,
|
|
432
|
+
movement_delay=movement_delay,
|
|
389
433
|
)
|
|
390
434
|
)
|
|
391
435
|
else:
|
|
@@ -402,7 +446,9 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
402
446
|
)
|
|
403
447
|
)
|
|
404
448
|
|
|
405
|
-
self._protocol_core.set_last_location(
|
|
449
|
+
self._protocol_core.set_last_location(
|
|
450
|
+
location=final_location, mount=self.get_mount()
|
|
451
|
+
)
|
|
406
452
|
|
|
407
453
|
def blow_out(
|
|
408
454
|
self,
|
|
@@ -1300,6 +1346,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1300
1346
|
trash_location: Union[Location, TrashBin, WasteChute],
|
|
1301
1347
|
return_tip: bool,
|
|
1302
1348
|
keep_last_tip: bool,
|
|
1349
|
+
tips: Optional[List[WellCore]],
|
|
1303
1350
|
) -> None:
|
|
1304
1351
|
"""Execute transfer using liquid class properties.
|
|
1305
1352
|
|
|
@@ -1322,10 +1369,12 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1322
1369
|
return_tip: If `True`, return tips to the tip rack location they were picked up from,
|
|
1323
1370
|
otherwise drop in `trash_location`
|
|
1324
1371
|
keep_last_tip: When set to `True`, do not drop the final tip used in the transfer.
|
|
1372
|
+
tips: If provided, transfer will pick up the tips in the order given. If this
|
|
1373
|
+
is less than the amount of tips needed, an error will be raised.
|
|
1325
1374
|
"""
|
|
1326
|
-
if not tip_racks:
|
|
1375
|
+
if not tip_racks and not tips:
|
|
1327
1376
|
raise RuntimeError(
|
|
1328
|
-
"No
|
|
1377
|
+
"No tip racks or tips found for pipette in order to perform transfer"
|
|
1329
1378
|
)
|
|
1330
1379
|
tiprack_uri_for_transfer_props = tip_racks[0][1].get_uri()
|
|
1331
1380
|
transfer_props = self._get_transfer_properties_for_tip_rack(
|
|
@@ -1367,7 +1416,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1367
1416
|
|
|
1368
1417
|
if new_tip == TransferTipPolicyV2.ONCE:
|
|
1369
1418
|
self._pick_up_tip_for_liquid_class(
|
|
1370
|
-
tip_racks, starting_tip, tiprack_uri_for_transfer_props
|
|
1419
|
+
tip_racks, starting_tip, tiprack_uri_for_transfer_props, tips
|
|
1371
1420
|
)
|
|
1372
1421
|
|
|
1373
1422
|
prev_src: Optional[Tuple[Location, WellCore]] = None
|
|
@@ -1407,7 +1456,10 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1407
1456
|
if prev_src is not None and prev_dest is not None:
|
|
1408
1457
|
self._drop_tip_for_liquid_class(trash_location, return_tip)
|
|
1409
1458
|
self._pick_up_tip_for_liquid_class(
|
|
1410
|
-
tip_racks,
|
|
1459
|
+
tip_racks,
|
|
1460
|
+
starting_tip,
|
|
1461
|
+
tiprack_uri_for_transfer_props,
|
|
1462
|
+
tips,
|
|
1411
1463
|
)
|
|
1412
1464
|
post_disp_tip_contents = [
|
|
1413
1465
|
tx_comps_executor.LiquidAndAirGapPair(
|
|
@@ -1464,6 +1516,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1464
1516
|
trash_location: Union[Location, TrashBin, WasteChute],
|
|
1465
1517
|
return_tip: bool,
|
|
1466
1518
|
keep_last_tip: bool,
|
|
1519
|
+
tips: Optional[List[WellCore]],
|
|
1467
1520
|
) -> None:
|
|
1468
1521
|
"""Execute a distribution using liquid class properties.
|
|
1469
1522
|
|
|
@@ -1487,6 +1540,8 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1487
1540
|
return_tip: If `True`, return tips to the tip rack location they were picked up from,
|
|
1488
1541
|
otherwise drop in `trash_location`
|
|
1489
1542
|
keep_last_tip: When set to `True`, do not drop the final tip used in the distribute.
|
|
1543
|
+
tips: If provided, transfer will pick up the tips in the order given. If this
|
|
1544
|
+
is less than the amount of tips needed, an error will be raised.
|
|
1490
1545
|
|
|
1491
1546
|
This method distributes the liquid in the source well into multiple destinations.
|
|
1492
1547
|
It can accomplish this by either doing a multi-dispense (aspirate once and then
|
|
@@ -1498,7 +1553,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1498
1553
|
"""
|
|
1499
1554
|
if not tip_racks:
|
|
1500
1555
|
raise RuntimeError(
|
|
1501
|
-
"No
|
|
1556
|
+
"No tip racks found for pipette in order to perform transfer"
|
|
1502
1557
|
)
|
|
1503
1558
|
assert new_tip in [
|
|
1504
1559
|
TransferTipPolicyV2.NEVER,
|
|
@@ -1546,6 +1601,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1546
1601
|
trash_location=trash_location,
|
|
1547
1602
|
return_tip=return_tip,
|
|
1548
1603
|
keep_last_tip=keep_last_tip,
|
|
1604
|
+
tips=tips,
|
|
1549
1605
|
)
|
|
1550
1606
|
|
|
1551
1607
|
# TODO: use the ID returned by load_liquid_class in command annotations
|
|
@@ -1576,7 +1632,10 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1576
1632
|
|
|
1577
1633
|
if new_tip != TransferTipPolicyV2.NEVER:
|
|
1578
1634
|
self._pick_up_tip_for_liquid_class(
|
|
1579
|
-
tip_racks,
|
|
1635
|
+
tip_racks,
|
|
1636
|
+
starting_tip,
|
|
1637
|
+
tiprack_uri_for_transfer_props,
|
|
1638
|
+
tips,
|
|
1580
1639
|
)
|
|
1581
1640
|
|
|
1582
1641
|
tip_contents = [
|
|
@@ -1644,7 +1703,10 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1644
1703
|
if not is_first_step and new_tip == TransferTipPolicyV2.ALWAYS:
|
|
1645
1704
|
self._drop_tip_for_liquid_class(trash_location, return_tip)
|
|
1646
1705
|
self._pick_up_tip_for_liquid_class(
|
|
1647
|
-
tip_racks,
|
|
1706
|
+
tip_racks,
|
|
1707
|
+
starting_tip,
|
|
1708
|
+
tiprack_uri_for_transfer_props,
|
|
1709
|
+
tips,
|
|
1648
1710
|
)
|
|
1649
1711
|
tip_contents = [
|
|
1650
1712
|
tx_comps_executor.LiquidAndAirGapPair(
|
|
@@ -1750,6 +1812,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1750
1812
|
trash_location: Union[Location, TrashBin, WasteChute],
|
|
1751
1813
|
return_tip: bool,
|
|
1752
1814
|
keep_last_tip: bool,
|
|
1815
|
+
tips: Optional[List[WellCore]],
|
|
1753
1816
|
) -> None:
|
|
1754
1817
|
"""Execute consolidate using liquid class properties.
|
|
1755
1818
|
|
|
@@ -1774,10 +1837,12 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1774
1837
|
return_tip: If `True`, return tips to the tip rack location they were picked up from,
|
|
1775
1838
|
otherwise drop in `trash_location`
|
|
1776
1839
|
keep_last_tip: When set to `True`, do not drop the final tip used in the consolidate.
|
|
1840
|
+
tips: If provided, transfer will pick up the tips in the order given. If this
|
|
1841
|
+
is less than the amount of tips needed, an error will be raised.
|
|
1777
1842
|
"""
|
|
1778
1843
|
if not tip_racks:
|
|
1779
1844
|
raise RuntimeError(
|
|
1780
|
-
"No
|
|
1845
|
+
"No tip racks found for pipette in order to perform transfer"
|
|
1781
1846
|
)
|
|
1782
1847
|
# NOTE: Tip option of "always" in consolidate is equivalent to "after every dispense",
|
|
1783
1848
|
# or more specifically, "before the next chunk of aspirates".
|
|
@@ -1828,7 +1893,10 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1828
1893
|
|
|
1829
1894
|
if new_tip in [TransferTipPolicyV2.ONCE, TransferTipPolicyV2.ALWAYS]:
|
|
1830
1895
|
self._pick_up_tip_for_liquid_class(
|
|
1831
|
-
tip_racks,
|
|
1896
|
+
tip_racks,
|
|
1897
|
+
starting_tip,
|
|
1898
|
+
tiprack_uri_for_transfer_props,
|
|
1899
|
+
tips,
|
|
1832
1900
|
)
|
|
1833
1901
|
|
|
1834
1902
|
aspirate_air_gap_by_volume = transfer_props.aspirate.retract.air_gap_by_volume
|
|
@@ -1861,7 +1929,10 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1861
1929
|
if not is_first_step and new_tip == TransferTipPolicyV2.ALWAYS:
|
|
1862
1930
|
self._drop_tip_for_liquid_class(trash_location, return_tip)
|
|
1863
1931
|
self._pick_up_tip_for_liquid_class(
|
|
1864
|
-
tip_racks,
|
|
1932
|
+
tip_racks,
|
|
1933
|
+
starting_tip,
|
|
1934
|
+
tiprack_uri_for_transfer_props,
|
|
1935
|
+
tips,
|
|
1865
1936
|
)
|
|
1866
1937
|
tip_contents = [
|
|
1867
1938
|
tx_comps_executor.LiquidAndAirGapPair(
|
|
@@ -1957,22 +2028,34 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1957
2028
|
tip_racks: List[Tuple[Location, LabwareCore]],
|
|
1958
2029
|
starting_tip: Optional[WellCore],
|
|
1959
2030
|
tiprack_uri_for_transfer_props: str,
|
|
2031
|
+
selected_tips: Optional[List[WellCore]],
|
|
1960
2032
|
) -> None:
|
|
1961
2033
|
"""Resolve next tip and pick it up, for use in liquid class transfer code."""
|
|
1962
|
-
next_tip
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2034
|
+
next_tip: Optional[NextTipInfo]
|
|
2035
|
+
if selected_tips is not None:
|
|
2036
|
+
try:
|
|
2037
|
+
tip_core = selected_tips.pop(0)
|
|
2038
|
+
except IndexError:
|
|
2039
|
+
raise RuntimeError("No more selected tips available for liquid class.")
|
|
2040
|
+
next_tip = NextTipInfo(
|
|
2041
|
+
labwareId=tip_core.labware_id, tipStartingWell=tip_core.get_name()
|
|
2042
|
+
)
|
|
2043
|
+
else:
|
|
2044
|
+
next_tip = self.get_next_tip(
|
|
2045
|
+
tip_racks=[core for loc, core in tip_racks],
|
|
2046
|
+
starting_well=starting_tip,
|
|
1970
2047
|
)
|
|
2048
|
+
if next_tip is None:
|
|
2049
|
+
raise RuntimeError(
|
|
2050
|
+
f"No tip available among the tipracks assigned for {self.get_pipette_name()}:"
|
|
2051
|
+
f" {[f'{tip_rack[1].get_display_name()} in {tip_rack[1].get_deck_slot()}' for tip_rack in tip_racks]}"
|
|
2052
|
+
)
|
|
1971
2053
|
(
|
|
1972
2054
|
tiprack_loc,
|
|
1973
2055
|
tiprack_uri,
|
|
1974
2056
|
tip_well,
|
|
1975
2057
|
) = self._get_location_and_well_core_from_next_tip_info(next_tip, tip_racks)
|
|
2058
|
+
|
|
1976
2059
|
if tiprack_uri != tiprack_uri_for_transfer_props:
|
|
1977
2060
|
raise RuntimeError(
|
|
1978
2061
|
f"Tiprack {tiprack_uri} does not match the tiprack designated "
|
|
@@ -325,9 +325,9 @@ class ThermocyclerModuleCore(ModuleCore, AbstractThermocyclerCore[LabwareCore]):
|
|
|
325
325
|
ramp_rate: Optional[float],
|
|
326
326
|
hold_time_seconds: Optional[float] = None,
|
|
327
327
|
block_max_volume: Optional[float] = None,
|
|
328
|
-
) ->
|
|
328
|
+
) -> None:
|
|
329
329
|
"""Set the target temperature for the well block, in °C."""
|
|
330
|
-
|
|
330
|
+
self._engine_client.execute_command(
|
|
331
331
|
cmd.thermocycler.SetTargetBlockTemperatureParams(
|
|
332
332
|
moduleId=self.module_id,
|
|
333
333
|
celsius=celsius,
|
|
@@ -336,6 +336,22 @@ class ThermocyclerModuleCore(ModuleCore, AbstractThermocyclerCore[LabwareCore]):
|
|
|
336
336
|
ramp_rate=ramp_rate,
|
|
337
337
|
)
|
|
338
338
|
)
|
|
339
|
+
|
|
340
|
+
def start_set_target_block_temperature(
|
|
341
|
+
self,
|
|
342
|
+
celsius: float,
|
|
343
|
+
ramp_rate: Optional[float],
|
|
344
|
+
block_max_volume: Optional[float] = None,
|
|
345
|
+
) -> EngineTaskCore:
|
|
346
|
+
"""Start setting the target temperature for the well block, in °C."""
|
|
347
|
+
result = self._engine_client.execute_command_without_recovery(
|
|
348
|
+
cmd.thermocycler.SetTargetBlockTemperatureParams(
|
|
349
|
+
moduleId=self.module_id,
|
|
350
|
+
celsius=celsius,
|
|
351
|
+
blockMaxVolumeUl=block_max_volume,
|
|
352
|
+
ramp_rate=ramp_rate,
|
|
353
|
+
)
|
|
354
|
+
)
|
|
339
355
|
block_temperature_task = EngineTaskCore(
|
|
340
356
|
engine_client=self._engine_client, task_id=result.taskId
|
|
341
357
|
)
|
|
@@ -347,8 +363,16 @@ class ThermocyclerModuleCore(ModuleCore, AbstractThermocyclerCore[LabwareCore]):
|
|
|
347
363
|
cmd.thermocycler.WaitForBlockTemperatureParams(moduleId=self.module_id)
|
|
348
364
|
)
|
|
349
365
|
|
|
350
|
-
def set_target_lid_temperature(self, celsius: float) ->
|
|
366
|
+
def set_target_lid_temperature(self, celsius: float) -> None:
|
|
351
367
|
"""Set the target temperature for the heated lid, in °C."""
|
|
368
|
+
self._engine_client.execute_command(
|
|
369
|
+
cmd.thermocycler.SetTargetLidTemperatureParams(
|
|
370
|
+
moduleId=self.module_id, celsius=celsius
|
|
371
|
+
)
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
def start_set_target_lid_temperature(self, celsius: float) -> EngineTaskCore:
|
|
375
|
+
"""Start setting the target temperature for the heated lid, in °C."""
|
|
352
376
|
result = self._engine_client.execute_command_without_recovery(
|
|
353
377
|
cmd.thermocycler.SetTargetLidTemperatureParams(
|
|
354
378
|
moduleId=self.module_id, celsius=celsius
|
|
@@ -49,6 +49,7 @@ from opentrons.protocol_engine.types import (
|
|
|
49
49
|
OFF_DECK_LOCATION,
|
|
50
50
|
SYSTEM_LOCATION,
|
|
51
51
|
LoadableLabwareLocation,
|
|
52
|
+
WASTE_CHUTE_LOCATION,
|
|
52
53
|
NonStackedLocation,
|
|
53
54
|
)
|
|
54
55
|
from opentrons.protocol_engine.clients import SyncClient as ProtocolEngineClient
|
|
@@ -1168,9 +1169,38 @@ class ProtocolCore(
|
|
|
1168
1169
|
return self._module_cores_by_id[labware_location.moduleId]
|
|
1169
1170
|
elif isinstance(labware_location, OnLabwareLocation):
|
|
1170
1171
|
return self._labware_cores_by_id[labware_location.labwareId]
|
|
1171
|
-
|
|
1172
|
+
elif labware_location == WASTE_CHUTE_LOCATION:
|
|
1173
|
+
return OffDeckType.WASTE_CHUTE
|
|
1172
1174
|
return OffDeckType.OFF_DECK
|
|
1173
1175
|
|
|
1176
|
+
def capture_image(
|
|
1177
|
+
self,
|
|
1178
|
+
filename: Optional[str] = None,
|
|
1179
|
+
resolution: Optional[Tuple[int, int]] = None,
|
|
1180
|
+
zoom: Optional[float] = None,
|
|
1181
|
+
contrast: Optional[float] = None,
|
|
1182
|
+
brightness: Optional[float] = None,
|
|
1183
|
+
saturation: Optional[float] = None,
|
|
1184
|
+
) -> None:
|
|
1185
|
+
"""Capture an image using a camera.
|
|
1186
|
+
Args:
|
|
1187
|
+
resolution: Width by height resolution in pixels for the image to be captured with.
|
|
1188
|
+
zoom: Multiplier to use when cropping and scaling a captured image. Scale is 1.0 to 2.0.
|
|
1189
|
+
contrast: The contrast to use when processing an image. Scale is 0% to 100%
|
|
1190
|
+
brightness: The brightness to use when processing an image. Scale is 0% to 100%.
|
|
1191
|
+
saturation: The saturation to use when processing an image. Scale is 0% to 100%.
|
|
1192
|
+
"""
|
|
1193
|
+
self._engine_client.execute_command(
|
|
1194
|
+
cmd.CaptureImageParams(
|
|
1195
|
+
fileName=filename,
|
|
1196
|
+
resolution=resolution,
|
|
1197
|
+
zoom=zoom,
|
|
1198
|
+
contrast=contrast,
|
|
1199
|
+
brightness=brightness,
|
|
1200
|
+
saturation=saturation,
|
|
1201
|
+
)
|
|
1202
|
+
)
|
|
1203
|
+
|
|
1174
1204
|
def _convert_labware_location(
|
|
1175
1205
|
self,
|
|
1176
1206
|
location: Union[
|
|
@@ -1205,6 +1235,8 @@ class ProtocolCore(
|
|
|
1205
1235
|
return ModuleLocation(moduleId=location.module_id)
|
|
1206
1236
|
elif location is OffDeckType.OFF_DECK:
|
|
1207
1237
|
return OFF_DECK_LOCATION
|
|
1238
|
+
elif location is OffDeckType.WASTE_CHUTE:
|
|
1239
|
+
return AddressableAreaLocation(addressableAreaName="gripperWasteChute")
|
|
1208
1240
|
elif isinstance(location, DeckSlotName):
|
|
1209
1241
|
return DeckSlotLocation(slotName=location)
|
|
1210
1242
|
elif isinstance(location, StagingSlotName):
|
|
@@ -60,6 +60,8 @@ def _labware_location_string(
|
|
|
60
60
|
return (
|
|
61
61
|
f"stored in {_module_in_location_string(location.moduleId, engine_client)}"
|
|
62
62
|
)
|
|
63
|
+
elif location == "wasteChuteLocation":
|
|
64
|
+
return "in waste chute"
|
|
63
65
|
|
|
64
66
|
|
|
65
67
|
def _labware_name(engine_client: SyncClient, labware_id: str) -> str:
|
|
@@ -48,7 +48,10 @@ class AbstractInstrument(ABC, Generic[WellCoreType, LabwareCoreType]):
|
|
|
48
48
|
flow_rate: float,
|
|
49
49
|
in_place: bool,
|
|
50
50
|
meniscus_tracking: Optional[types.MeniscusTrackingTarget] = None,
|
|
51
|
+
end_location: Optional[types.Location] = None,
|
|
52
|
+
end_meniscus_tracking: Optional[types.MeniscusTrackingTarget] = None,
|
|
51
53
|
correction_volume: Optional[float] = None,
|
|
54
|
+
movement_delay: Optional[float] = None,
|
|
52
55
|
) -> None:
|
|
53
56
|
"""Aspirate a given volume of liquid from the specified location.
|
|
54
57
|
Args:
|
|
@@ -74,7 +77,10 @@ class AbstractInstrument(ABC, Generic[WellCoreType, LabwareCoreType]):
|
|
|
74
77
|
in_place: bool,
|
|
75
78
|
push_out: Optional[float],
|
|
76
79
|
meniscus_tracking: Optional[types.MeniscusTrackingTarget] = None,
|
|
80
|
+
end_location: Optional[types.Location] = None,
|
|
81
|
+
end_meniscus_tracking: Optional[types.MeniscusTrackingTarget] = None,
|
|
77
82
|
correction_volume: Optional[float] = None,
|
|
83
|
+
movement_delay: Optional[float] = None,
|
|
78
84
|
) -> None:
|
|
79
85
|
"""Dispense a given volume of liquid into the specified location.
|
|
80
86
|
Args:
|
|
@@ -378,6 +384,7 @@ class AbstractInstrument(ABC, Generic[WellCoreType, LabwareCoreType]):
|
|
|
378
384
|
trash_location: Union[types.Location, TrashBin, WasteChute],
|
|
379
385
|
return_tip: bool,
|
|
380
386
|
keep_last_tip: bool,
|
|
387
|
+
tips: Optional[List[WellCoreType]],
|
|
381
388
|
) -> None:
|
|
382
389
|
"""Transfer a liquid from source to dest according to liquid class properties."""
|
|
383
390
|
...
|
|
@@ -389,12 +396,17 @@ class AbstractInstrument(ABC, Generic[WellCoreType, LabwareCoreType]):
|
|
|
389
396
|
volume: float,
|
|
390
397
|
source: Tuple[types.Location, WellCoreType],
|
|
391
398
|
dest: List[Tuple[types.Location, WellCoreType]],
|
|
392
|
-
new_tip: Literal[
|
|
399
|
+
new_tip: Literal[
|
|
400
|
+
TransferTipPolicyV2.NEVER,
|
|
401
|
+
TransferTipPolicyV2.ONCE,
|
|
402
|
+
TransferTipPolicyV2.ALWAYS,
|
|
403
|
+
],
|
|
393
404
|
tip_racks: List[Tuple[types.Location, LabwareCoreType]],
|
|
394
405
|
starting_tip: Optional[WellCoreType],
|
|
395
406
|
trash_location: Union[types.Location, TrashBin, WasteChute],
|
|
396
407
|
return_tip: bool,
|
|
397
408
|
keep_last_tip: bool,
|
|
409
|
+
tips: Optional[List[WellCoreType]],
|
|
398
410
|
) -> None:
|
|
399
411
|
"""
|
|
400
412
|
Distribute a liquid from single source to multiple destinations
|
|
@@ -409,12 +421,17 @@ class AbstractInstrument(ABC, Generic[WellCoreType, LabwareCoreType]):
|
|
|
409
421
|
volume: float,
|
|
410
422
|
source: List[Tuple[types.Location, WellCoreType]],
|
|
411
423
|
dest: Union[Tuple[types.Location, WellCoreType], TrashBin, WasteChute],
|
|
412
|
-
new_tip: Literal[
|
|
424
|
+
new_tip: Literal[
|
|
425
|
+
TransferTipPolicyV2.NEVER,
|
|
426
|
+
TransferTipPolicyV2.ONCE,
|
|
427
|
+
TransferTipPolicyV2.ALWAYS,
|
|
428
|
+
],
|
|
413
429
|
tip_racks: List[Tuple[types.Location, LabwareCoreType]],
|
|
414
430
|
starting_tip: Optional[WellCoreType],
|
|
415
431
|
trash_location: Union[types.Location, TrashBin, WasteChute],
|
|
416
432
|
return_tip: bool,
|
|
417
433
|
keep_last_tip: bool,
|
|
434
|
+
tips: Optional[List[WellCoreType]],
|
|
418
435
|
) -> None:
|
|
419
436
|
"""
|
|
420
437
|
Consolidate liquid from multiple sources to a single destination
|
|
@@ -93,7 +93,10 @@ class LegacyInstrumentCore(AbstractInstrument[LegacyWellCore, LegacyLabwareCore]
|
|
|
93
93
|
flow_rate: float,
|
|
94
94
|
in_place: bool,
|
|
95
95
|
meniscus_tracking: Optional[types.MeniscusTrackingTarget] = None,
|
|
96
|
+
end_location: Optional[types.Location] = None,
|
|
97
|
+
end_meniscus_tracking: Optional[types.MeniscusTrackingTarget] = None,
|
|
96
98
|
correction_volume: Optional[float] = None,
|
|
99
|
+
movement_delay: Optional[float] = None,
|
|
97
100
|
) -> None:
|
|
98
101
|
"""Aspirate a given volume of liquid from the specified location.
|
|
99
102
|
Args:
|
|
@@ -139,7 +142,10 @@ class LegacyInstrumentCore(AbstractInstrument[LegacyWellCore, LegacyLabwareCore]
|
|
|
139
142
|
in_place: bool,
|
|
140
143
|
push_out: Optional[float],
|
|
141
144
|
meniscus_tracking: Optional[types.MeniscusTrackingTarget] = None,
|
|
145
|
+
end_location: Optional[types.Location] = None,
|
|
146
|
+
end_meniscus_tracking: Optional[types.MeniscusTrackingTarget] = None,
|
|
142
147
|
correction_volume: Optional[float] = None,
|
|
148
|
+
movement_delay: Optional[float] = None,
|
|
143
149
|
) -> None:
|
|
144
150
|
"""Dispense a given volume of liquid into the specified location.
|
|
145
151
|
Args:
|
|
@@ -622,6 +628,7 @@ class LegacyInstrumentCore(AbstractInstrument[LegacyWellCore, LegacyLabwareCore]
|
|
|
622
628
|
trash_location: Union[types.Location, TrashBin, WasteChute],
|
|
623
629
|
return_tip: bool,
|
|
624
630
|
keep_last_tip: bool,
|
|
631
|
+
tips: Optional[List[LegacyWellCore]],
|
|
625
632
|
) -> None:
|
|
626
633
|
"""This will never be called because it was added in API 2.23"""
|
|
627
634
|
assert False, "transfer_liquid is not supported in legacy context"
|
|
@@ -632,12 +639,17 @@ class LegacyInstrumentCore(AbstractInstrument[LegacyWellCore, LegacyLabwareCore]
|
|
|
632
639
|
volume: float,
|
|
633
640
|
source: Tuple[types.Location, LegacyWellCore],
|
|
634
641
|
dest: List[Tuple[types.Location, LegacyWellCore]],
|
|
635
|
-
new_tip: Literal[
|
|
642
|
+
new_tip: Literal[
|
|
643
|
+
TransferTipPolicyV2.NEVER,
|
|
644
|
+
TransferTipPolicyV2.ONCE,
|
|
645
|
+
TransferTipPolicyV2.ALWAYS,
|
|
646
|
+
],
|
|
636
647
|
tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
|
|
637
648
|
starting_tip: Optional[LegacyWellCore],
|
|
638
649
|
trash_location: Union[types.Location, TrashBin, WasteChute],
|
|
639
650
|
return_tip: bool,
|
|
640
651
|
keep_last_tip: bool,
|
|
652
|
+
tips: Optional[List[LegacyWellCore]],
|
|
641
653
|
) -> None:
|
|
642
654
|
"""This will never be called because it was added in API 2.23"""
|
|
643
655
|
assert False, "distribute_liquid is not supported in legacy context"
|
|
@@ -648,12 +660,17 @@ class LegacyInstrumentCore(AbstractInstrument[LegacyWellCore, LegacyLabwareCore]
|
|
|
648
660
|
volume: float,
|
|
649
661
|
source: List[Tuple[types.Location, LegacyWellCore]],
|
|
650
662
|
dest: Union[Tuple[types.Location, LegacyWellCore], TrashBin, WasteChute],
|
|
651
|
-
new_tip: Literal[
|
|
663
|
+
new_tip: Literal[
|
|
664
|
+
TransferTipPolicyV2.NEVER,
|
|
665
|
+
TransferTipPolicyV2.ONCE,
|
|
666
|
+
TransferTipPolicyV2.ALWAYS,
|
|
667
|
+
],
|
|
652
668
|
tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
|
|
653
669
|
starting_tip: Optional[LegacyWellCore],
|
|
654
670
|
trash_location: Union[types.Location, TrashBin, WasteChute],
|
|
655
671
|
return_tip: bool,
|
|
656
672
|
keep_last_tip: bool,
|
|
673
|
+
tips: Optional[List[LegacyWellCore]],
|
|
657
674
|
) -> None:
|
|
658
675
|
"""This will never be called because it was added in API 2.23."""
|
|
659
676
|
assert False, "consolidate_liquid is not supported in legacy context"
|
|
@@ -268,7 +268,7 @@ class LegacyThermocyclerCore(
|
|
|
268
268
|
ramp_rate: Optional[float],
|
|
269
269
|
hold_time_seconds: Optional[float] = None,
|
|
270
270
|
block_max_volume: Optional[float] = None,
|
|
271
|
-
) ->
|
|
271
|
+
) -> None:
|
|
272
272
|
"""Set the target temperature for the well block, in °C."""
|
|
273
273
|
self._sync_module_hardware.set_target_block_temperature(
|
|
274
274
|
celsius=celsius,
|
|
@@ -276,16 +276,27 @@ class LegacyThermocyclerCore(
|
|
|
276
276
|
volume=block_max_volume,
|
|
277
277
|
ramp_rate=ramp_rate,
|
|
278
278
|
)
|
|
279
|
-
return LegacyTaskCore()
|
|
280
279
|
|
|
281
280
|
def wait_for_block_temperature(self) -> None:
|
|
282
281
|
"""Wait for target block temperature to be reached."""
|
|
283
282
|
self._sync_module_hardware.wait_for_block_target()
|
|
284
283
|
|
|
285
|
-
def set_target_lid_temperature(self, celsius: float) ->
|
|
284
|
+
def set_target_lid_temperature(self, celsius: float) -> None:
|
|
286
285
|
"""Set the target temperature for the heated lid, in °C."""
|
|
287
286
|
self._sync_module_hardware.set_target_lid_temperature(celsius=celsius)
|
|
288
|
-
|
|
287
|
+
|
|
288
|
+
def start_set_target_lid_temperature(self, celsius: float) -> LegacyTaskCore:
|
|
289
|
+
"""Set the target temperature for the heated lid, in °C."""
|
|
290
|
+
assert False, "start_set_target_lid_temperature only supported on engine core"
|
|
291
|
+
|
|
292
|
+
def start_set_target_block_temperature(
|
|
293
|
+
self,
|
|
294
|
+
celsius: float,
|
|
295
|
+
ramp_rate: Optional[float],
|
|
296
|
+
block_max_volume: Optional[float] = None,
|
|
297
|
+
) -> LegacyTaskCore:
|
|
298
|
+
"""Set the target temperature for the heated block, in °C."""
|
|
299
|
+
assert False, "start_set_target_block_temperature only supported on engine core"
|
|
289
300
|
|
|
290
301
|
def wait_for_lid_temperature(self) -> None:
|
|
291
302
|
"""Wait for target lid temperature to be reached."""
|
|
@@ -613,6 +613,18 @@ class LegacyProtocolCore(
|
|
|
613
613
|
"""Get labware parent location."""
|
|
614
614
|
assert False, "get_labware_location only supported on engine core"
|
|
615
615
|
|
|
616
|
+
def capture_image(
|
|
617
|
+
self,
|
|
618
|
+
filename: Optional[str] = None,
|
|
619
|
+
resolution: Optional[Tuple[int, int]] = None,
|
|
620
|
+
zoom: Optional[float] = None,
|
|
621
|
+
contrast: Optional[float] = None,
|
|
622
|
+
brightness: Optional[float] = None,
|
|
623
|
+
saturation: Optional[float] = None,
|
|
624
|
+
) -> None:
|
|
625
|
+
"Capture an image using a camera."
|
|
626
|
+
assert False, "capture_image only supported on engine core"
|
|
627
|
+
|
|
616
628
|
def wait_for_tasks(self, task: Sequence[LegacyTaskCore]) -> None:
|
|
617
629
|
"""Wait for list of tasks to complete before executing subsequent commands."""
|
|
618
630
|
assert False, "wait_for_tasks only supported on engine core"
|