opentrons 8.7.0a9__py3-none-any.whl → 8.8.0a8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opentrons/_version.py +2 -2
- opentrons/cli/analyze.py +4 -1
- opentrons/config/__init__.py +7 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +126 -49
- opentrons/drivers/heater_shaker/abstract.py +5 -0
- opentrons/drivers/heater_shaker/driver.py +10 -0
- opentrons/drivers/heater_shaker/simulator.py +4 -0
- opentrons/drivers/thermocycler/abstract.py +6 -0
- opentrons/drivers/thermocycler/driver.py +61 -10
- opentrons/drivers/thermocycler/simulator.py +6 -0
- 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/api.py +24 -5
- opentrons/hardware_control/backends/controller.py +8 -2
- opentrons/hardware_control/backends/flex_protocol.py +1 -0
- opentrons/hardware_control/backends/ot3controller.py +35 -2
- opentrons/hardware_control/backends/ot3simulator.py +3 -1
- opentrons/hardware_control/backends/ot3utils.py +37 -0
- opentrons/hardware_control/backends/simulator.py +2 -1
- opentrons/hardware_control/backends/subsystem_manager.py +5 -2
- opentrons/hardware_control/emulation/abstract_emulator.py +6 -4
- opentrons/hardware_control/emulation/connection_handler.py +8 -5
- opentrons/hardware_control/emulation/heater_shaker.py +12 -3
- opentrons/hardware_control/emulation/settings.py +1 -1
- opentrons/hardware_control/emulation/thermocycler.py +67 -15
- opentrons/hardware_control/module_control.py +105 -10
- opentrons/hardware_control/modules/__init__.py +3 -0
- opentrons/hardware_control/modules/absorbance_reader.py +11 -4
- opentrons/hardware_control/modules/flex_stacker.py +38 -9
- opentrons/hardware_control/modules/heater_shaker.py +42 -5
- opentrons/hardware_control/modules/magdeck.py +8 -4
- opentrons/hardware_control/modules/mod_abc.py +14 -6
- opentrons/hardware_control/modules/tempdeck.py +25 -5
- opentrons/hardware_control/modules/thermocycler.py +68 -11
- opentrons/hardware_control/modules/types.py +20 -1
- opentrons/hardware_control/modules/utils.py +11 -4
- opentrons/hardware_control/motion_utilities.py +6 -6
- opentrons/hardware_control/nozzle_manager.py +3 -0
- opentrons/hardware_control/ot3api.py +92 -17
- opentrons/hardware_control/poller.py +22 -8
- opentrons/hardware_control/protocols/liquid_handler.py +12 -4
- opentrons/hardware_control/scripts/update_module_fw.py +5 -0
- opentrons/hardware_control/types.py +43 -2
- opentrons/legacy_commands/commands.py +58 -5
- opentrons/legacy_commands/module_commands.py +52 -0
- opentrons/legacy_commands/protocol_commands.py +53 -1
- opentrons/legacy_commands/types.py +155 -1
- opentrons/motion_planning/deck_conflict.py +17 -12
- opentrons/motion_planning/waypoints.py +15 -29
- opentrons/protocol_api/__init__.py +5 -1
- opentrons/protocol_api/_transfer_liquid_validation.py +17 -2
- opentrons/protocol_api/_types.py +8 -1
- opentrons/protocol_api/core/common.py +3 -1
- opentrons/protocol_api/core/engine/_default_labware_versions.py +33 -11
- opentrons/protocol_api/core/engine/deck_conflict.py +3 -1
- opentrons/protocol_api/core/engine/instrument.py +109 -26
- opentrons/protocol_api/core/engine/labware.py +8 -1
- opentrons/protocol_api/core/engine/module_core.py +95 -4
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +4 -18
- opentrons/protocol_api/core/engine/protocol.py +51 -2
- opentrons/protocol_api/core/engine/stringify.py +2 -0
- opentrons/protocol_api/core/engine/tasks.py +48 -0
- opentrons/protocol_api/core/engine/well.py +8 -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 +33 -2
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +23 -1
- opentrons/protocol_api/core/legacy/legacy_well_core.py +4 -0
- opentrons/protocol_api/core/legacy/tasks.py +19 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +19 -2
- opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +14 -2
- opentrons/protocol_api/core/legacy_simulator/tasks.py +19 -0
- opentrons/protocol_api/core/module.py +58 -2
- opentrons/protocol_api/core/protocol.py +23 -2
- opentrons/protocol_api/core/tasks.py +31 -0
- opentrons/protocol_api/core/well.py +4 -0
- opentrons/protocol_api/instrument_context.py +388 -2
- opentrons/protocol_api/labware.py +10 -2
- opentrons/protocol_api/module_contexts.py +170 -6
- opentrons/protocol_api/protocol_context.py +87 -21
- opentrons/protocol_api/robot_context.py +41 -25
- opentrons/protocol_api/tasks.py +48 -0
- opentrons/protocol_api/validation.py +49 -3
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/__init__.py +6 -2
- opentrons/protocol_engine/actions/actions.py +31 -9
- opentrons/protocol_engine/clients/sync_client.py +42 -7
- opentrons/protocol_engine/commands/__init__.py +56 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +2 -15
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +2 -15
- opentrons/protocol_engine/commands/absorbance_reader/read.py +22 -23
- opentrons/protocol_engine/commands/aspirate.py +1 -0
- 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 +2 -0
- opentrons/protocol_engine/commands/command_unions.py +62 -0
- opentrons/protocol_engine/commands/create_timer.py +83 -0
- opentrons/protocol_engine/commands/dispense.py +1 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +56 -19
- opentrons/protocol_engine/commands/drop_tip.py +32 -8
- 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/__init__.py +14 -0
- opentrons/protocol_engine/commands/heater_shaker/common.py +20 -0
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +5 -4
- opentrons/protocol_engine/commands/heater_shaker/set_shake_speed.py +136 -0
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +31 -5
- 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 +31 -2
- opentrons/protocol_engine/commands/pick_up_tip.py +21 -11
- opentrons/protocol_engine/commands/pipetting_common.py +48 -3
- opentrons/protocol_engine/commands/set_tip_state.py +97 -0
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +38 -7
- opentrons/protocol_engine/commands/thermocycler/__init__.py +16 -0
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +6 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +8 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +44 -7
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +43 -14
- opentrons/protocol_engine/commands/thermocycler/start_run_extended_profile.py +191 -0
- opentrons/protocol_engine/commands/touch_tip.py +1 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +6 -22
- opentrons/protocol_engine/commands/wait_for_tasks.py +98 -0
- opentrons/protocol_engine/create_protocol_engine.py +12 -0
- opentrons/protocol_engine/engine_support.py +3 -0
- opentrons/protocol_engine/errors/__init__.py +12 -0
- opentrons/protocol_engine/errors/exceptions.py +119 -0
- opentrons/protocol_engine/execution/__init__.py +4 -0
- opentrons/protocol_engine/execution/command_executor.py +62 -1
- opentrons/protocol_engine/execution/create_queue_worker.py +9 -2
- opentrons/protocol_engine/execution/labware_movement.py +13 -15
- opentrons/protocol_engine/execution/movement.py +2 -0
- opentrons/protocol_engine/execution/pipetting.py +26 -25
- opentrons/protocol_engine/execution/queue_worker.py +4 -0
- opentrons/protocol_engine/execution/run_control.py +8 -0
- opentrons/protocol_engine/execution/task_handler.py +157 -0
- opentrons/protocol_engine/protocol_engine.py +137 -36
- opentrons/protocol_engine/resources/__init__.py +4 -0
- opentrons/protocol_engine/resources/camera_provider.py +110 -0
- opentrons/protocol_engine/resources/concurrency_provider.py +27 -0
- opentrons/protocol_engine/resources/deck_configuration_provider.py +7 -0
- opentrons/protocol_engine/resources/file_provider.py +133 -58
- opentrons/protocol_engine/resources/labware_validation.py +10 -6
- opentrons/protocol_engine/slot_standardization.py +2 -0
- opentrons/protocol_engine/state/_well_math.py +60 -18
- opentrons/protocol_engine/state/addressable_areas.py +2 -0
- opentrons/protocol_engine/state/camera.py +54 -0
- opentrons/protocol_engine/state/commands.py +37 -14
- opentrons/protocol_engine/state/geometry.py +276 -379
- opentrons/protocol_engine/state/labware.py +62 -108
- opentrons/protocol_engine/state/labware_origin_math/errors.py +94 -0
- opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +1336 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +37 -0
- opentrons/protocol_engine/state/modules.py +30 -8
- opentrons/protocol_engine/state/motion.py +60 -18
- opentrons/protocol_engine/state/preconditions.py +59 -0
- opentrons/protocol_engine/state/state.py +44 -0
- opentrons/protocol_engine/state/state_summary.py +4 -0
- opentrons/protocol_engine/state/tasks.py +139 -0
- opentrons/protocol_engine/state/tips.py +177 -258
- opentrons/protocol_engine/state/update_types.py +26 -9
- opentrons/protocol_engine/types/__init__.py +23 -4
- opentrons/protocol_engine/types/command_preconditions.py +18 -0
- opentrons/protocol_engine/types/deck_configuration.py +5 -1
- opentrons/protocol_engine/types/instrument.py +8 -1
- opentrons/protocol_engine/types/labware.py +1 -13
- opentrons/protocol_engine/types/location.py +26 -2
- opentrons/protocol_engine/types/module.py +11 -1
- opentrons/protocol_engine/types/tasks.py +38 -0
- opentrons/protocol_engine/types/tip.py +9 -0
- opentrons/protocol_runner/create_simulating_orchestrator.py +29 -2
- opentrons/protocol_runner/protocol_runner.py +14 -1
- opentrons/protocol_runner/run_orchestrator.py +49 -2
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +2 -2
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/types.py +2 -1
- opentrons/simulate.py +51 -15
- opentrons/system/camera.py +334 -4
- opentrons/system/ffmpeg.py +110 -0
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/METADATA +4 -4
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/RECORD +189 -161
- opentrons/protocol_engine/state/_labware_origin_math.py +0 -636
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/WHEEL +0 -0
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/entry_points.txt +0 -0
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/licenses/LICENSE +0 -0
|
@@ -112,6 +112,38 @@ DEFAULT_LABWARE_VERSIONS: DefaultLabwareVersions = {
|
|
|
112
112
|
"thermoscientificnunc_96_wellplate_2000ul": 3,
|
|
113
113
|
"usascientific_96_wellplate_2.4ml_deep": 3,
|
|
114
114
|
},
|
|
115
|
+
APIVersion(2, 27): {
|
|
116
|
+
"agilent_1_reservoir_290ml": 4,
|
|
117
|
+
"axygen_1_reservoir_90ml": 3,
|
|
118
|
+
"biorad_96_wellplate_200ul_pcr": 5,
|
|
119
|
+
"corning_12_wellplate_6.9ml_flat": 5,
|
|
120
|
+
"corning_24_wellplate_3.4ml_flat": 5,
|
|
121
|
+
"corning_384_wellplate_112ul_flat": 5,
|
|
122
|
+
"corning_48_wellplate_1.6ml_flat": 6,
|
|
123
|
+
"corning_6_wellplate_16.8ml_flat": 5,
|
|
124
|
+
"corning_96_wellplate_360ul_flat": 5,
|
|
125
|
+
"nest_12_reservoir_15ml": 3,
|
|
126
|
+
"nest_1_reservoir_195ml": 4,
|
|
127
|
+
"nest_1_reservoir_290ml": 4,
|
|
128
|
+
"nest_96_wellplate_100ul_pcr_full_skirt": 5,
|
|
129
|
+
"nest_96_wellplate_200ul_flat": 5,
|
|
130
|
+
"nest_96_wellplate_2ml_deep": 5,
|
|
131
|
+
"opentrons_10_tuberack_falcon_4x50ml_6x15ml_conical": 3,
|
|
132
|
+
"opentrons_15_tuberack_falcon_15ml_conical": 3,
|
|
133
|
+
"opentrons_24_aluminumblock_nest_0.5ml_screwcap": 4,
|
|
134
|
+
"opentrons_24_aluminumblock_nest_1.5ml_screwcap": 3,
|
|
135
|
+
"opentrons_24_aluminumblock_nest_1.5ml_snapcap": 3,
|
|
136
|
+
"opentrons_24_aluminumblock_nest_2ml_screwcap": 3,
|
|
137
|
+
"opentrons_24_aluminumblock_nest_2ml_snapcap": 3,
|
|
138
|
+
"opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap": 3,
|
|
139
|
+
"opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap": 3,
|
|
140
|
+
"opentrons_24_tuberack_nest_0.5ml_screwcap": 4,
|
|
141
|
+
"opentrons_6_tuberack_nest_50ml_conical": 3,
|
|
142
|
+
"opentrons_96_aluminumblock_generic_pcr_strip_200ul": 4,
|
|
143
|
+
"opentrons_tough_universal_lid": 2,
|
|
144
|
+
"usascientific_12_reservoir_22ml": 4,
|
|
145
|
+
"usascientific_96_wellplate_2.4ml_deep": 4,
|
|
146
|
+
},
|
|
115
147
|
}
|
|
116
148
|
|
|
117
149
|
|
|
@@ -139,17 +171,7 @@ KNOWN_EXCEPTIONS_FOR_TESTS: set[str] = {
|
|
|
139
171
|
"schema3test_flex_tiprack_lid",
|
|
140
172
|
"schema3test_tough_pcr_auto_sealing_lid",
|
|
141
173
|
"schema3test_universal_flat_adapter",
|
|
142
|
-
|
|
143
|
-
# https://github.com/Opentrons/opentrons/pull/18266 + https://github.com/Opentrons/opentrons/pull/18284,
|
|
144
|
-
# but the second punch took a while. We should merge the second punch after v8.6.0
|
|
145
|
-
# and remove these exceptions as part of that.
|
|
146
|
-
"agilent_1_reservoir_290ml",
|
|
147
|
-
"corning_384_wellplate_112ul_flat",
|
|
148
|
-
"nest_1_reservoir_290ml",
|
|
149
|
-
"opentrons_24_aluminumblock_nest_0.5ml_screwcap",
|
|
150
|
-
"opentrons_24_tuberack_nest_0.5ml_screwcap",
|
|
151
|
-
"opentrons_96_aluminumblock_generic_pcr_strip_200ul",
|
|
152
|
-
"usascientific_12_reservoir_22ml",
|
|
174
|
+
"schema3test_96_wellplate_360ul_flat",
|
|
153
175
|
}
|
|
154
176
|
|
|
155
177
|
|
|
@@ -26,6 +26,7 @@ from opentrons.protocol_engine import (
|
|
|
26
26
|
OnLabwareLocation,
|
|
27
27
|
AddressableAreaLocation,
|
|
28
28
|
InStackerHopperLocation,
|
|
29
|
+
WASTE_CHUTE_LOCATION,
|
|
29
30
|
OFF_DECK_LOCATION,
|
|
30
31
|
SYSTEM_LOCATION,
|
|
31
32
|
)
|
|
@@ -241,7 +242,6 @@ def _map_labware(
|
|
|
241
242
|
Tuple[Union[DeckSlotName, StagingSlotName], wrapped_deck_conflict.DeckItem]
|
|
242
243
|
]:
|
|
243
244
|
location_from_engine = engine_state.labware.get_location(labware_id=labware_id)
|
|
244
|
-
|
|
245
245
|
if isinstance(location_from_engine, AddressableAreaLocation):
|
|
246
246
|
# This will be guaranteed to be either deck slot name or staging slot name
|
|
247
247
|
slot: Union[DeckSlotName, StagingSlotName]
|
|
@@ -299,10 +299,12 @@ def _map_labware(
|
|
|
299
299
|
location_from_engine == OFF_DECK_LOCATION
|
|
300
300
|
or location_from_engine == SYSTEM_LOCATION
|
|
301
301
|
or isinstance(location_from_engine, InStackerHopperLocation)
|
|
302
|
+
or location_from_engine == WASTE_CHUTE_LOCATION
|
|
302
303
|
):
|
|
303
304
|
# This labware is off-deck. Exclude it from conflict checking.
|
|
304
305
|
# todo(mm, 2023-02-23): Move this logic into wrapped_deck_conflict.
|
|
305
306
|
return None
|
|
307
|
+
return None
|
|
306
308
|
|
|
307
309
|
|
|
308
310
|
def _map_module(
|
|
@@ -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 "
|
|
@@ -23,6 +23,7 @@ from opentrons.protocol_engine.clients import SyncClient as ProtocolEngineClient
|
|
|
23
23
|
from opentrons.protocol_engine.types import (
|
|
24
24
|
LabwareOffsetCreate,
|
|
25
25
|
LabwareOffsetVector,
|
|
26
|
+
TipRackWellState,
|
|
26
27
|
)
|
|
27
28
|
from opentrons.types import DeckSlotName, NozzleMapInterface, Point, StagingSlotName
|
|
28
29
|
|
|
@@ -165,7 +166,13 @@ class LabwareCore(AbstractLabware[WellCore]):
|
|
|
165
166
|
|
|
166
167
|
def reset_tips(self) -> None:
|
|
167
168
|
if self.is_tip_rack():
|
|
168
|
-
self._engine_client.
|
|
169
|
+
self._engine_client.execute_command(
|
|
170
|
+
cmd.SetTipStateParams(
|
|
171
|
+
labwareId=self._labware_id,
|
|
172
|
+
wellNames=list(self._definition.wells),
|
|
173
|
+
tipWellState=TipRackWellState.CLEAN,
|
|
174
|
+
)
|
|
175
|
+
)
|
|
169
176
|
else:
|
|
170
177
|
raise TypeError(f"{self.get_display_name()} is not a tip rack.")
|
|
171
178
|
|
|
@@ -51,6 +51,7 @@ from ..module import (
|
|
|
51
51
|
from .exceptions import InvalidMagnetEngageHeightError
|
|
52
52
|
|
|
53
53
|
from .labware import LabwareCore
|
|
54
|
+
from .tasks import EngineTaskCore
|
|
54
55
|
from . import load_labware_params
|
|
55
56
|
|
|
56
57
|
if TYPE_CHECKING:
|
|
@@ -175,13 +176,17 @@ class TemperatureModuleCore(ModuleCore, AbstractTemperatureModuleCore[LabwareCor
|
|
|
175
176
|
|
|
176
177
|
_sync_module_hardware: SynchronousAdapter[hw_modules.TempDeck]
|
|
177
178
|
|
|
178
|
-
def set_target_temperature(self, celsius: float) ->
|
|
179
|
+
def set_target_temperature(self, celsius: float) -> EngineTaskCore:
|
|
179
180
|
"""Set the Temperature Module's target temperature in °C."""
|
|
180
|
-
self._engine_client.
|
|
181
|
+
result = self._engine_client.execute_command_without_recovery(
|
|
181
182
|
cmd.temperature_module.SetTargetTemperatureParams(
|
|
182
183
|
moduleId=self.module_id, celsius=celsius
|
|
183
184
|
)
|
|
184
185
|
)
|
|
186
|
+
temperature_task = EngineTaskCore(
|
|
187
|
+
engine_client=self._engine_client, task_id=result.taskId
|
|
188
|
+
)
|
|
189
|
+
return temperature_task
|
|
185
190
|
|
|
186
191
|
def wait_for_target_temperature(self, celsius: Optional[float] = None) -> None:
|
|
187
192
|
"""Wait until the module's target temperature is reached.
|
|
@@ -317,6 +322,7 @@ class ThermocyclerModuleCore(ModuleCore, AbstractThermocyclerCore[LabwareCore]):
|
|
|
317
322
|
def set_target_block_temperature(
|
|
318
323
|
self,
|
|
319
324
|
celsius: float,
|
|
325
|
+
ramp_rate: Optional[float],
|
|
320
326
|
hold_time_seconds: Optional[float] = None,
|
|
321
327
|
block_max_volume: Optional[float] = None,
|
|
322
328
|
) -> None:
|
|
@@ -327,9 +333,30 @@ class ThermocyclerModuleCore(ModuleCore, AbstractThermocyclerCore[LabwareCore]):
|
|
|
327
333
|
celsius=celsius,
|
|
328
334
|
blockMaxVolumeUl=block_max_volume,
|
|
329
335
|
holdTimeSeconds=hold_time_seconds,
|
|
336
|
+
ramp_rate=ramp_rate,
|
|
330
337
|
)
|
|
331
338
|
)
|
|
332
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
|
+
)
|
|
355
|
+
block_temperature_task = EngineTaskCore(
|
|
356
|
+
engine_client=self._engine_client, task_id=result.taskId
|
|
357
|
+
)
|
|
358
|
+
return block_temperature_task
|
|
359
|
+
|
|
333
360
|
def wait_for_block_temperature(self) -> None:
|
|
334
361
|
"""Wait for target block temperature to be reached."""
|
|
335
362
|
self._engine_client.execute_command(
|
|
@@ -344,6 +371,18 @@ class ThermocyclerModuleCore(ModuleCore, AbstractThermocyclerCore[LabwareCore]):
|
|
|
344
371
|
)
|
|
345
372
|
)
|
|
346
373
|
|
|
374
|
+
def start_set_target_lid_temperature(self, celsius: float) -> EngineTaskCore:
|
|
375
|
+
"""Start setting the target temperature for the heated lid, in °C."""
|
|
376
|
+
result = self._engine_client.execute_command_without_recovery(
|
|
377
|
+
cmd.thermocycler.SetTargetLidTemperatureParams(
|
|
378
|
+
moduleId=self.module_id, celsius=celsius
|
|
379
|
+
)
|
|
380
|
+
)
|
|
381
|
+
lid_temperature_task = EngineTaskCore(
|
|
382
|
+
engine_client=self._engine_client, task_id=result.taskId
|
|
383
|
+
)
|
|
384
|
+
return lid_temperature_task
|
|
385
|
+
|
|
347
386
|
def wait_for_lid_temperature(self) -> None:
|
|
348
387
|
"""Wait for target lid temperature to be reached."""
|
|
349
388
|
self._engine_client.execute_command(
|
|
@@ -361,6 +400,7 @@ class ThermocyclerModuleCore(ModuleCore, AbstractThermocyclerCore[LabwareCore]):
|
|
|
361
400
|
cmd.thermocycler.RunProfileStepParams(
|
|
362
401
|
celsius=step["temperature"],
|
|
363
402
|
holdSeconds=step["hold_time_seconds"],
|
|
403
|
+
rampRate=step["ramp_rate"],
|
|
364
404
|
)
|
|
365
405
|
for step in steps
|
|
366
406
|
]
|
|
@@ -389,6 +429,7 @@ class ThermocyclerModuleCore(ModuleCore, AbstractThermocyclerCore[LabwareCore]):
|
|
|
389
429
|
cmd.thermocycler.ProfileStep(
|
|
390
430
|
celsius=step["temperature"],
|
|
391
431
|
holdSeconds=step["hold_time_seconds"],
|
|
432
|
+
rampRate=step["ramp_rate"],
|
|
392
433
|
)
|
|
393
434
|
for step in steps
|
|
394
435
|
],
|
|
@@ -416,6 +457,42 @@ class ThermocyclerModuleCore(ModuleCore, AbstractThermocyclerCore[LabwareCore]):
|
|
|
416
457
|
else:
|
|
417
458
|
return self._execute_profile_pre_221(steps, repetitions, block_max_volume)
|
|
418
459
|
|
|
460
|
+
def start_execute_profile(
|
|
461
|
+
self,
|
|
462
|
+
steps: List[ThermocyclerStep],
|
|
463
|
+
repetitions: int,
|
|
464
|
+
block_max_volume: Optional[float] = None,
|
|
465
|
+
) -> EngineTaskCore:
|
|
466
|
+
"""Start the execution of a hermocycler profile and return a task."""
|
|
467
|
+
self._repetitions = repetitions
|
|
468
|
+
self._step_count = len(steps)
|
|
469
|
+
engine_steps: List[
|
|
470
|
+
Union[cmd.thermocycler.ProfileStep, cmd.thermocycler.ProfileCycle]
|
|
471
|
+
] = [
|
|
472
|
+
cmd.thermocycler.ProfileCycle(
|
|
473
|
+
repetitions=repetitions,
|
|
474
|
+
steps=[
|
|
475
|
+
cmd.thermocycler.ProfileStep(
|
|
476
|
+
celsius=step["temperature"],
|
|
477
|
+
holdSeconds=step["hold_time_seconds"],
|
|
478
|
+
rampRate=step["ramp_rate"],
|
|
479
|
+
)
|
|
480
|
+
for step in steps
|
|
481
|
+
],
|
|
482
|
+
)
|
|
483
|
+
]
|
|
484
|
+
result = self._engine_client.execute_command_without_recovery(
|
|
485
|
+
cmd.thermocycler.StartRunExtendedProfileParams(
|
|
486
|
+
moduleId=self.module_id,
|
|
487
|
+
profileElements=engine_steps,
|
|
488
|
+
blockMaxVolumeUl=block_max_volume,
|
|
489
|
+
)
|
|
490
|
+
)
|
|
491
|
+
start_execute_profile_result = EngineTaskCore(
|
|
492
|
+
engine_client=self._engine_client, task_id=result.taskId
|
|
493
|
+
)
|
|
494
|
+
return start_execute_profile_result
|
|
495
|
+
|
|
419
496
|
def deactivate_lid(self) -> None:
|
|
420
497
|
"""Turn off the heated lid."""
|
|
421
498
|
self._engine_client.execute_command(
|
|
@@ -507,13 +584,17 @@ class HeaterShakerModuleCore(ModuleCore, AbstractHeaterShakerCore[LabwareCore]):
|
|
|
507
584
|
|
|
508
585
|
_sync_module_hardware: SynchronousAdapter[hw_modules.HeaterShaker]
|
|
509
586
|
|
|
510
|
-
def set_target_temperature(self, celsius: float) ->
|
|
587
|
+
def set_target_temperature(self, celsius: float) -> EngineTaskCore:
|
|
511
588
|
"""Set the labware plate's target temperature in °C."""
|
|
512
|
-
self._engine_client.
|
|
589
|
+
result = self._engine_client.execute_command_without_recovery(
|
|
513
590
|
cmd.heater_shaker.SetTargetTemperatureParams(
|
|
514
591
|
moduleId=self.module_id, celsius=celsius
|
|
515
592
|
)
|
|
516
593
|
)
|
|
594
|
+
temperature_task = EngineTaskCore(
|
|
595
|
+
engine_client=self._engine_client, task_id=result.taskId
|
|
596
|
+
)
|
|
597
|
+
return temperature_task
|
|
517
598
|
|
|
518
599
|
def wait_for_target_temperature(self) -> None:
|
|
519
600
|
"""Wait for the labware plate's target temperature to be reached."""
|
|
@@ -529,6 +610,16 @@ class HeaterShakerModuleCore(ModuleCore, AbstractHeaterShakerCore[LabwareCore]):
|
|
|
529
610
|
)
|
|
530
611
|
)
|
|
531
612
|
|
|
613
|
+
def set_shake_speed(self, rpm: int) -> EngineTaskCore:
|
|
614
|
+
"""Set the shaker's target shake speed and wait for it to spin up."""
|
|
615
|
+
result = self._engine_client.execute_command_without_recovery(
|
|
616
|
+
cmd.heater_shaker.SetShakeSpeedParams(moduleId=self.module_id, rpm=rpm)
|
|
617
|
+
)
|
|
618
|
+
shake_task = EngineTaskCore(
|
|
619
|
+
engine_client=self._engine_client, task_id=result.taskId
|
|
620
|
+
)
|
|
621
|
+
return shake_task
|
|
622
|
+
|
|
532
623
|
def open_labware_latch(self) -> None:
|
|
533
624
|
"""Open the labware latch."""
|
|
534
625
|
self._engine_client.execute_command(
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""A Protocol-Engine-friendly wrapper for opentrons.motion_planning.deck_conflict."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
import logging
|
|
4
5
|
from typing import (
|
|
5
|
-
Optional,
|
|
6
6
|
Tuple,
|
|
7
7
|
Union,
|
|
8
8
|
List,
|
|
@@ -12,7 +12,6 @@ from opentrons_shared_data.errors.exceptions import MotionPlanningFailureError
|
|
|
12
12
|
from opentrons.protocol_engine.errors import LocationIsStagingSlotError
|
|
13
13
|
from opentrons_shared_data.module import FLEX_TC_LID_COLLISION_ZONE
|
|
14
14
|
|
|
15
|
-
from opentrons.hardware_control import CriticalPoint
|
|
16
15
|
from opentrons.motion_planning import adjacent_slots_getters
|
|
17
16
|
|
|
18
17
|
from opentrons.protocol_engine import (
|
|
@@ -101,7 +100,9 @@ def check_safe_for_pipette_movement( # noqa: C901
|
|
|
101
100
|
)
|
|
102
101
|
primary_nozzle = engine_state.pipettes.get_primary_nozzle(pipette_id)
|
|
103
102
|
|
|
104
|
-
destination_cp =
|
|
103
|
+
destination_cp = engine_state.motion.get_critical_point_for_wells_in_labware(
|
|
104
|
+
labware_id
|
|
105
|
+
)
|
|
105
106
|
pipette_bounds_at_well_location = (
|
|
106
107
|
engine_state.pipettes.get_pipette_bounds_at_specified_move_to_position(
|
|
107
108
|
pipette_id=pipette_id,
|
|
@@ -189,21 +190,6 @@ def check_safe_for_pipette_movement( # noqa: C901
|
|
|
189
190
|
)
|
|
190
191
|
|
|
191
192
|
|
|
192
|
-
def _get_critical_point_to_use(
|
|
193
|
-
engine_state: StateView, labware_id: str
|
|
194
|
-
) -> Optional[CriticalPoint]:
|
|
195
|
-
"""Return the critical point to use when accessing the given labware."""
|
|
196
|
-
# TODO (spp, 2024-09-17): looks like Y_CENTER of column is the same as its XY_CENTER.
|
|
197
|
-
# I'm using this if-else ladder to be consistent with what we do in
|
|
198
|
-
# `MotionPlanning.get_movement_waypoints_to_well()`.
|
|
199
|
-
# We should probably use only XY_CENTER in both places.
|
|
200
|
-
if engine_state.labware.get_should_center_column_on_target_well(labware_id):
|
|
201
|
-
return CriticalPoint.Y_CENTER
|
|
202
|
-
elif engine_state.labware.get_should_center_pipette_on_target_well(labware_id):
|
|
203
|
-
return CriticalPoint.XY_CENTER
|
|
204
|
-
return None
|
|
205
|
-
|
|
206
|
-
|
|
207
193
|
def _slot_has_potential_colliding_object(
|
|
208
194
|
engine_state: StateView,
|
|
209
195
|
pipette_bounds: Tuple[Point, Point, Point, Point],
|