opentrons 8.4.0a3__py2.py3-none-any.whl → 8.4.0a5__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/legacy_commands/commands.py +83 -2
- opentrons/legacy_commands/helpers.py +59 -1
- opentrons/legacy_commands/types.py +30 -0
- opentrons/protocol_api/core/engine/instrument.py +182 -115
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +6 -14
- opentrons/protocol_api/core/engine/transfer_components_executor.py +30 -25
- opentrons/protocol_api/core/instrument.py +8 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +9 -30
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +8 -4
- opentrons/protocol_api/core/well.py +1 -1
- opentrons/protocol_api/instrument_context.py +144 -73
- opentrons/protocol_api/labware.py +26 -44
- opentrons/protocol_api/protocol_context.py +18 -16
- opentrons/protocol_engine/commands/__init__.py +38 -38
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +38 -65
- opentrons/protocol_engine/commands/command_unions.py +33 -33
- opentrons/protocol_engine/commands/dispense_while_tracking.py +36 -72
- opentrons/protocol_engine/commands/labware_handling_common.py +6 -1
- opentrons/protocol_engine/commands/liquid_probe.py +1 -2
- opentrons/protocol_engine/commands/move_to_well.py +5 -11
- opentrons/protocol_engine/commands/{evotip_dispense.py → pressure_dispense.py} +27 -27
- opentrons/protocol_engine/commands/{evotip_seal_pipette.py → seal_pipette_to_tip.py} +32 -27
- opentrons/protocol_engine/commands/{evotip_unseal_pipette.py → unseal_pipette_from_tip.py} +22 -22
- opentrons/protocol_engine/execution/pipetting.py +1 -0
- opentrons/protocol_engine/labware_offset_standardization.py +22 -1
- opentrons/protocol_engine/resources/deck_configuration_provider.py +8 -4
- opentrons/protocol_engine/state/frustum_helpers.py +12 -4
- opentrons/protocol_engine/state/geometry.py +121 -72
- opentrons/protocol_engine/state/update_types.py +1 -1
- opentrons/protocol_engine/state/wells.py +1 -1
- opentrons/protocol_engine/types/__init__.py +6 -0
- opentrons/protocol_engine/types/well_position.py +18 -1
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +1 -1
- opentrons/protocols/labware.py +23 -18
- opentrons/util/logging_config.py +94 -25
- opentrons/util/logging_queue_handler.py +61 -0
- {opentrons-8.4.0a3.dist-info → opentrons-8.4.0a5.dist-info}/METADATA +4 -4
- {opentrons-8.4.0a3.dist-info → opentrons-8.4.0a5.dist-info}/RECORD +42 -41
- {opentrons-8.4.0a3.dist-info → opentrons-8.4.0a5.dist-info}/LICENSE +0 -0
- {opentrons-8.4.0a3.dist-info → opentrons-8.4.0a5.dist-info}/WHEEL +0 -0
- {opentrons-8.4.0a3.dist-info → opentrons-8.4.0a5.dist-info}/entry_points.txt +0 -0
- {opentrons-8.4.0a3.dist-info → opentrons-8.4.0a5.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
from contextlib import contextmanager
|
|
5
|
+
from itertools import dropwhile
|
|
5
6
|
from typing import (
|
|
6
7
|
Optional,
|
|
7
8
|
TYPE_CHECKING,
|
|
@@ -11,6 +12,7 @@ from typing import (
|
|
|
11
12
|
Tuple,
|
|
12
13
|
NamedTuple,
|
|
13
14
|
Generator,
|
|
15
|
+
Literal,
|
|
14
16
|
)
|
|
15
17
|
from opentrons.types import (
|
|
16
18
|
Location,
|
|
@@ -48,8 +50,17 @@ from opentrons.protocol_engine.types import (
|
|
|
48
50
|
AddressableOffsetVector,
|
|
49
51
|
LiquidClassRecord,
|
|
50
52
|
NextTipInfo,
|
|
53
|
+
PickUpTipWellLocation,
|
|
54
|
+
LiquidHandlingWellLocation,
|
|
55
|
+
)
|
|
56
|
+
from opentrons.protocol_engine.types import (
|
|
57
|
+
LiquidTrackingType,
|
|
58
|
+
WellLocationFunction,
|
|
59
|
+
)
|
|
60
|
+
from opentrons.protocol_engine.types.automatic_tip_selection import (
|
|
61
|
+
NoTipAvailable,
|
|
62
|
+
NoTipReason,
|
|
51
63
|
)
|
|
52
|
-
from opentrons.protocol_engine.types.liquid_level_detection import LiquidTrackingType
|
|
53
64
|
from opentrons.protocol_engine.errors.exceptions import TipNotAttachedError
|
|
54
65
|
from opentrons.protocol_engine.clients import SyncClient as EngineClient
|
|
55
66
|
from opentrons.protocols.api_support.definitions import MAX_SUPPORTED_VERSION
|
|
@@ -59,6 +70,7 @@ from opentrons_shared_data.pipette.types import (
|
|
|
59
70
|
)
|
|
60
71
|
from opentrons_shared_data.errors.exceptions import (
|
|
61
72
|
UnsupportedHardwareCommand,
|
|
73
|
+
CommandPreconditionViolated,
|
|
62
74
|
)
|
|
63
75
|
from opentrons_shared_data.liquid_classes.liquid_class_definition import BlowoutLocation
|
|
64
76
|
from opentrons.protocol_api._nozzle_layout import NozzleLayout
|
|
@@ -222,10 +234,11 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
222
234
|
(
|
|
223
235
|
well_location,
|
|
224
236
|
dynamic_liquid_tracking,
|
|
225
|
-
) = self._engine_client.state.geometry.
|
|
237
|
+
) = self._engine_client.state.geometry.get_relative_well_location(
|
|
226
238
|
labware_id=labware_id,
|
|
227
239
|
well_name=well_name,
|
|
228
240
|
absolute_point=location.point,
|
|
241
|
+
location_type=WellLocationFunction.LIQUID_HANDLING,
|
|
229
242
|
meniscus_tracking=meniscus_tracking,
|
|
230
243
|
)
|
|
231
244
|
pipette_movement_conflict.check_safe_for_pipette_movement(
|
|
@@ -235,8 +248,8 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
235
248
|
well_name=well_name,
|
|
236
249
|
well_location=well_location,
|
|
237
250
|
)
|
|
251
|
+
assert isinstance(well_location, LiquidHandlingWellLocation)
|
|
238
252
|
if dynamic_liquid_tracking:
|
|
239
|
-
|
|
240
253
|
self._engine_client.execute_command(
|
|
241
254
|
cmd.AspirateWhileTrackingParams(
|
|
242
255
|
pipetteId=self._pipette_id,
|
|
@@ -334,12 +347,14 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
334
347
|
(
|
|
335
348
|
well_location,
|
|
336
349
|
dynamic_liquid_tracking,
|
|
337
|
-
) = self._engine_client.state.geometry.
|
|
350
|
+
) = self._engine_client.state.geometry.get_relative_well_location(
|
|
338
351
|
labware_id=labware_id,
|
|
339
352
|
well_name=well_name,
|
|
340
353
|
absolute_point=location.point,
|
|
354
|
+
location_type=WellLocationFunction.LIQUID_HANDLING,
|
|
341
355
|
meniscus_tracking=meniscus_tracking,
|
|
342
356
|
)
|
|
357
|
+
assert isinstance(well_location, LiquidHandlingWellLocation)
|
|
343
358
|
pipette_movement_conflict.check_safe_for_pipette_movement(
|
|
344
359
|
engine_state=self._engine_client.state,
|
|
345
360
|
pipette_id=self._pipette_id,
|
|
@@ -425,13 +440,16 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
425
440
|
well_name = well_core.get_name()
|
|
426
441
|
labware_id = well_core.labware_id
|
|
427
442
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
443
|
+
(
|
|
444
|
+
well_location,
|
|
445
|
+
_,
|
|
446
|
+
) = self._engine_client.state.geometry.get_relative_well_location(
|
|
447
|
+
labware_id=labware_id,
|
|
448
|
+
well_name=well_name,
|
|
449
|
+
absolute_point=location.point,
|
|
450
|
+
location_type=WellLocationFunction.BASE,
|
|
434
451
|
)
|
|
452
|
+
|
|
435
453
|
pipette_movement_conflict.check_safe_for_pipette_movement(
|
|
436
454
|
engine_state=self._engine_client.state,
|
|
437
455
|
pipette_id=self._pipette_id,
|
|
@@ -439,6 +457,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
439
457
|
well_name=well_name,
|
|
440
458
|
well_location=well_location,
|
|
441
459
|
)
|
|
460
|
+
assert isinstance(well_location, WellLocation)
|
|
442
461
|
self._engine_client.execute_command(
|
|
443
462
|
cmd.BlowOutParams(
|
|
444
463
|
pipetteId=self._pipette_id,
|
|
@@ -533,12 +552,14 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
533
552
|
well_name = well_core.get_name()
|
|
534
553
|
labware_id = well_core.labware_id
|
|
535
554
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
555
|
+
(
|
|
556
|
+
well_location,
|
|
557
|
+
_,
|
|
558
|
+
) = self._engine_client.state.geometry.get_relative_well_location(
|
|
559
|
+
labware_id=labware_id,
|
|
560
|
+
well_name=well_name,
|
|
561
|
+
absolute_point=location.point,
|
|
562
|
+
location_type=WellLocationFunction.PICK_UP_TIP,
|
|
542
563
|
)
|
|
543
564
|
pipette_movement_conflict.check_safe_for_tip_pickup_and_return(
|
|
544
565
|
engine_state=self._engine_client.state,
|
|
@@ -552,7 +573,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
552
573
|
well_name=well_name,
|
|
553
574
|
well_location=well_location,
|
|
554
575
|
)
|
|
555
|
-
|
|
576
|
+
assert isinstance(well_location, PickUpTipWellLocation)
|
|
556
577
|
self._engine_client.execute_command(
|
|
557
578
|
cmd.PickUpTipParams(
|
|
558
579
|
pipetteId=self._pipette_id,
|
|
@@ -590,12 +611,14 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
590
611
|
scrape_tips = False
|
|
591
612
|
|
|
592
613
|
if location is not None:
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
614
|
+
(
|
|
615
|
+
relative_well_location,
|
|
616
|
+
_,
|
|
617
|
+
) = self._engine_client.state.geometry.get_relative_well_location(
|
|
618
|
+
labware_id=labware_id,
|
|
619
|
+
well_name=well_name,
|
|
620
|
+
absolute_point=location.point,
|
|
621
|
+
location_type=WellLocationFunction.DROP_TIP,
|
|
599
622
|
)
|
|
600
623
|
|
|
601
624
|
well_location = DropTipWellLocation(
|
|
@@ -725,20 +748,33 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
725
748
|
force_direct: bool,
|
|
726
749
|
minimum_z_height: Optional[float],
|
|
727
750
|
speed: Optional[float],
|
|
751
|
+
check_for_movement_conflicts: bool = True,
|
|
728
752
|
) -> None:
|
|
729
753
|
if well_core is not None:
|
|
730
754
|
if isinstance(location, (TrashBin, WasteChute)):
|
|
731
755
|
raise ValueError("Trash Bin and Waste Chute have no Wells.")
|
|
732
756
|
labware_id = well_core.labware_id
|
|
733
757
|
well_name = well_core.get_name()
|
|
734
|
-
|
|
735
|
-
|
|
758
|
+
(
|
|
759
|
+
well_location,
|
|
760
|
+
_,
|
|
761
|
+
) = self._engine_client.state.geometry.get_relative_well_location(
|
|
762
|
+
labware_id=labware_id,
|
|
763
|
+
well_name=well_name,
|
|
764
|
+
absolute_point=location.point,
|
|
765
|
+
location_type=WellLocationFunction.LIQUID_HANDLING,
|
|
766
|
+
)
|
|
767
|
+
assert isinstance(well_location, LiquidHandlingWellLocation)
|
|
768
|
+
if well_location.volumeOffset and well_location.volumeOffset != 0:
|
|
769
|
+
raise ValueError("volume offset not supported with move_to")
|
|
770
|
+
if check_for_movement_conflicts:
|
|
771
|
+
pipette_movement_conflict.check_safe_for_pipette_movement(
|
|
772
|
+
engine_state=self._engine_client.state,
|
|
773
|
+
pipette_id=self._pipette_id,
|
|
736
774
|
labware_id=labware_id,
|
|
737
775
|
well_name=well_name,
|
|
738
|
-
|
|
776
|
+
well_location=well_location,
|
|
739
777
|
)
|
|
740
|
-
)
|
|
741
|
-
|
|
742
778
|
self._engine_client.execute_command(
|
|
743
779
|
cmd.MoveToWellParams(
|
|
744
780
|
pipetteId=self._pipette_id,
|
|
@@ -779,16 +815,18 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
779
815
|
) -> None:
|
|
780
816
|
labware_id = well_core.labware_id
|
|
781
817
|
well_name = well_core.get_name()
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
818
|
+
(
|
|
819
|
+
well_location,
|
|
820
|
+
_,
|
|
821
|
+
) = self._engine_client.state.geometry.get_relative_well_location(
|
|
822
|
+
labware_id=labware_id,
|
|
823
|
+
well_name=well_name,
|
|
824
|
+
absolute_point=location.point,
|
|
825
|
+
location_type=WellLocationFunction.PICK_UP_TIP,
|
|
788
826
|
)
|
|
789
|
-
|
|
827
|
+
assert isinstance(well_location, PickUpTipWellLocation)
|
|
790
828
|
self._engine_client.execute_command(
|
|
791
|
-
cmd.
|
|
829
|
+
cmd.SealPipetteToTipParams(
|
|
792
830
|
pipetteId=self._pipette_id,
|
|
793
831
|
labwareId=labware_id,
|
|
794
832
|
wellName=well_name,
|
|
@@ -801,12 +839,14 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
801
839
|
labware_id = well_core.labware_id
|
|
802
840
|
|
|
803
841
|
if location is not None:
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
842
|
+
(
|
|
843
|
+
relative_well_location,
|
|
844
|
+
_,
|
|
845
|
+
) = self._engine_client.state.geometry.get_relative_well_location(
|
|
846
|
+
labware_id=labware_id,
|
|
847
|
+
well_name=well_name,
|
|
848
|
+
absolute_point=location.point,
|
|
849
|
+
location_type=WellLocationFunction.BASE,
|
|
810
850
|
)
|
|
811
851
|
|
|
812
852
|
well_location = DropTipWellLocation(
|
|
@@ -824,7 +864,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
824
864
|
well_location=well_location,
|
|
825
865
|
)
|
|
826
866
|
self._engine_client.execute_command(
|
|
827
|
-
cmd.
|
|
867
|
+
cmd.UnsealPipetteFromTipParams(
|
|
828
868
|
pipetteId=self._pipette_id,
|
|
829
869
|
labwareId=labware_id,
|
|
830
870
|
wellName=well_name,
|
|
@@ -860,10 +900,11 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
860
900
|
(
|
|
861
901
|
well_location,
|
|
862
902
|
dynamic_tracking,
|
|
863
|
-
) = self._engine_client.state.geometry.
|
|
903
|
+
) = self._engine_client.state.geometry.get_relative_well_location(
|
|
864
904
|
labware_id=labware_id,
|
|
865
905
|
well_name=well_name,
|
|
866
906
|
absolute_point=location.point,
|
|
907
|
+
location_type=WellLocationFunction.LIQUID_HANDLING,
|
|
867
908
|
)
|
|
868
909
|
pipette_movement_conflict.check_safe_for_pipette_movement(
|
|
869
910
|
engine_state=self._engine_client.state,
|
|
@@ -872,8 +913,9 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
872
913
|
well_name=well_name,
|
|
873
914
|
well_location=well_location,
|
|
874
915
|
)
|
|
916
|
+
assert isinstance(well_location, LiquidHandlingWellLocation)
|
|
875
917
|
self._engine_client.execute_command(
|
|
876
|
-
cmd.
|
|
918
|
+
cmd.PressureDispenseParams(
|
|
877
919
|
pipetteId=self._pipette_id,
|
|
878
920
|
labwareId=labware_id,
|
|
879
921
|
wellName=well_name,
|
|
@@ -1115,9 +1157,11 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1115
1157
|
tiprack=tiprack_uri,
|
|
1116
1158
|
aspirate=transfer_properties.aspirate.as_shared_data_model(),
|
|
1117
1159
|
singleDispense=transfer_properties.dispense.as_shared_data_model(),
|
|
1118
|
-
multiDispense=
|
|
1119
|
-
|
|
1120
|
-
|
|
1160
|
+
multiDispense=(
|
|
1161
|
+
transfer_properties.multi_dispense.as_shared_data_model()
|
|
1162
|
+
if transfer_properties.multi_dispense
|
|
1163
|
+
else None
|
|
1164
|
+
),
|
|
1121
1165
|
)
|
|
1122
1166
|
result = self._engine_client.execute_command_without_recovery(
|
|
1123
1167
|
cmd.LoadLiquidClassParams(
|
|
@@ -1127,19 +1171,39 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1127
1171
|
return result.liquidClassId
|
|
1128
1172
|
|
|
1129
1173
|
def get_next_tip(
|
|
1130
|
-
self, tip_racks: List[LabwareCore], starting_well: Optional[
|
|
1174
|
+
self, tip_racks: List[LabwareCore], starting_well: Optional[WellCore]
|
|
1131
1175
|
) -> Optional[NextTipInfo]:
|
|
1132
1176
|
"""Get the next tip to pick up."""
|
|
1177
|
+
if starting_well is not None:
|
|
1178
|
+
# Drop tip racks until the one with the starting tip is reached (if any)
|
|
1179
|
+
valid_tip_racks = list(
|
|
1180
|
+
dropwhile(
|
|
1181
|
+
lambda tr: starting_well.labware_id != tr.labware_id, tip_racks
|
|
1182
|
+
)
|
|
1183
|
+
)
|
|
1184
|
+
else:
|
|
1185
|
+
valid_tip_racks = tip_racks
|
|
1186
|
+
|
|
1133
1187
|
result = self._engine_client.execute_command_without_recovery(
|
|
1134
1188
|
cmd.GetNextTipParams(
|
|
1135
1189
|
pipetteId=self._pipette_id,
|
|
1136
|
-
labwareIds=[tip_rack.labware_id for tip_rack in
|
|
1137
|
-
startingTipWell=starting_well
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1190
|
+
labwareIds=[tip_rack.labware_id for tip_rack in valid_tip_racks],
|
|
1191
|
+
startingTipWell=starting_well.get_name()
|
|
1192
|
+
if starting_well is not None
|
|
1193
|
+
else None,
|
|
1194
|
+
)
|
|
1195
|
+
)
|
|
1196
|
+
next_tip_info = result.nextTipInfo
|
|
1197
|
+
if isinstance(next_tip_info, NoTipAvailable):
|
|
1198
|
+
if next_tip_info.noTipReason == NoTipReason.STARTING_TIP_WITH_PARTIAL:
|
|
1199
|
+
raise CommandPreconditionViolated(
|
|
1200
|
+
"Automatic tip tracking is not available when using a partial pipette"
|
|
1201
|
+
" nozzle configuration and InstrumentContext.starting_tip."
|
|
1202
|
+
" Switch to a full configuration or set starting_tip to None."
|
|
1203
|
+
)
|
|
1204
|
+
return None
|
|
1205
|
+
else:
|
|
1206
|
+
return next_tip_info
|
|
1143
1207
|
|
|
1144
1208
|
def transfer_with_liquid_class( # noqa: C901
|
|
1145
1209
|
self,
|
|
@@ -1149,6 +1213,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1149
1213
|
dest: List[Tuple[Location, WellCore]],
|
|
1150
1214
|
new_tip: TransferTipPolicyV2,
|
|
1151
1215
|
tip_racks: List[Tuple[Location, LabwareCore]],
|
|
1216
|
+
starting_tip: Optional[WellCore],
|
|
1152
1217
|
trash_location: Union[Location, TrashBin, WasteChute],
|
|
1153
1218
|
return_tip: bool,
|
|
1154
1219
|
) -> None:
|
|
@@ -1234,11 +1299,12 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1234
1299
|
def _pick_up_tip() -> WellCore:
|
|
1235
1300
|
next_tip = self.get_next_tip(
|
|
1236
1301
|
tip_racks=[core for loc, core in tip_racks],
|
|
1237
|
-
starting_well=
|
|
1302
|
+
starting_well=starting_tip,
|
|
1238
1303
|
)
|
|
1239
1304
|
if next_tip is None:
|
|
1240
1305
|
raise RuntimeError(
|
|
1241
|
-
f"No tip available among
|
|
1306
|
+
f"No tip available among the tipracks assigned for {self.get_pipette_name()}:"
|
|
1307
|
+
f" {[f'{tip_rack[1].get_display_name()} in {tip_rack[1].get_deck_slot()}' for tip_rack in tip_racks]}"
|
|
1242
1308
|
)
|
|
1243
1309
|
(
|
|
1244
1310
|
tiprack_loc,
|
|
@@ -1325,9 +1391,11 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1325
1391
|
transfer_properties=transfer_props,
|
|
1326
1392
|
transfer_type=tx_comps_executor.TransferType.ONE_TO_ONE,
|
|
1327
1393
|
tip_contents=post_asp_tip_contents,
|
|
1328
|
-
add_final_air_gap=
|
|
1329
|
-
|
|
1330
|
-
|
|
1394
|
+
add_final_air_gap=(
|
|
1395
|
+
False
|
|
1396
|
+
if is_last_step and new_tip == TransferTipPolicyV2.NEVER
|
|
1397
|
+
else True
|
|
1398
|
+
),
|
|
1331
1399
|
trash_location=trash_location,
|
|
1332
1400
|
)
|
|
1333
1401
|
prev_src = step_source
|
|
@@ -1341,8 +1409,9 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1341
1409
|
volume: float,
|
|
1342
1410
|
source: Tuple[Location, WellCore],
|
|
1343
1411
|
dest: List[Tuple[Location, WellCore]],
|
|
1344
|
-
new_tip: TransferTipPolicyV2,
|
|
1412
|
+
new_tip: Literal[TransferTipPolicyV2.NEVER, TransferTipPolicyV2.ONCE],
|
|
1345
1413
|
tip_racks: List[Tuple[Location, LabwareCore]],
|
|
1414
|
+
starting_tip: Optional[WellCore],
|
|
1346
1415
|
trash_location: Union[Location, TrashBin, WasteChute],
|
|
1347
1416
|
return_tip: bool,
|
|
1348
1417
|
) -> None:
|
|
@@ -1356,8 +1425,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1356
1425
|
dest: List of destination wells, with each well represented as a tuple of
|
|
1357
1426
|
types.Location and WellCore.
|
|
1358
1427
|
types.Location is only necessary for saving the last accessed location.
|
|
1359
|
-
new_tip: Whether the transfer should use a new tip 'once'
|
|
1360
|
-
or 'per source'.
|
|
1428
|
+
new_tip: Whether the transfer should use a new tip 'once' or 'never'.
|
|
1361
1429
|
tiprack_uri: The URI of the tiprack that the transfer settings are for.
|
|
1362
1430
|
tip_drop_location: Location where the tip will be dropped (if appropriate).
|
|
1363
1431
|
|
|
@@ -1373,6 +1441,8 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1373
1441
|
raise RuntimeError(
|
|
1374
1442
|
"No tipracks found for pipette in order to perform transfer"
|
|
1375
1443
|
)
|
|
1444
|
+
assert new_tip in [TransferTipPolicyV2.NEVER, TransferTipPolicyV2.ONCE]
|
|
1445
|
+
|
|
1376
1446
|
tiprack_uri_for_transfer_props = tip_racks[0][1].get_uri()
|
|
1377
1447
|
working_volume = min(
|
|
1378
1448
|
self.get_max_volume(),
|
|
@@ -1424,6 +1494,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1424
1494
|
dest=dest,
|
|
1425
1495
|
new_tip=new_tip,
|
|
1426
1496
|
tip_racks=tip_racks,
|
|
1497
|
+
starting_tip=starting_tip,
|
|
1427
1498
|
trash_location=trash_location,
|
|
1428
1499
|
return_tip=return_tip,
|
|
1429
1500
|
)
|
|
@@ -1474,11 +1545,12 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1474
1545
|
def _pick_up_tip() -> WellCore:
|
|
1475
1546
|
next_tip = self.get_next_tip(
|
|
1476
1547
|
tip_racks=[core for loc, core in tip_racks],
|
|
1477
|
-
starting_well=
|
|
1548
|
+
starting_well=starting_tip,
|
|
1478
1549
|
)
|
|
1479
1550
|
if next_tip is None:
|
|
1480
1551
|
raise RuntimeError(
|
|
1481
|
-
f"No tip available among
|
|
1552
|
+
f"No tip available among the tipracks assigned for {self.get_pipette_name()}:"
|
|
1553
|
+
f" {[f'{tip_rack[1].get_display_name()} in {tip_rack[1].get_deck_slot()}' for tip_rack in tip_racks]}"
|
|
1482
1554
|
)
|
|
1483
1555
|
(
|
|
1484
1556
|
tiprack_loc,
|
|
@@ -1498,7 +1570,6 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1498
1570
|
)
|
|
1499
1571
|
return tip_well
|
|
1500
1572
|
|
|
1501
|
-
tip_used = False
|
|
1502
1573
|
if new_tip != TransferTipPolicyV2.NEVER:
|
|
1503
1574
|
last_tip_picked_up_from = _pick_up_tip()
|
|
1504
1575
|
|
|
@@ -1543,16 +1614,6 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1543
1614
|
)
|
|
1544
1615
|
)
|
|
1545
1616
|
|
|
1546
|
-
if new_tip == TransferTipPolicyV2.ALWAYS and tip_used:
|
|
1547
|
-
_drop_tip()
|
|
1548
|
-
last_tip_picked_up_from = _pick_up_tip()
|
|
1549
|
-
tip_contents = [
|
|
1550
|
-
tx_comps_executor.LiquidAndAirGapPair(
|
|
1551
|
-
liquid=0,
|
|
1552
|
-
air_gap=0,
|
|
1553
|
-
)
|
|
1554
|
-
]
|
|
1555
|
-
|
|
1556
1617
|
use_single_dispense = False
|
|
1557
1618
|
if total_aspirate_volume == volume and len(vol_dest_combo) == 1:
|
|
1558
1619
|
# We are only doing a single transfer. Either because this is the last
|
|
@@ -1569,7 +1630,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1569
1630
|
and not transfer_props.multi_dispense.retract.blowout.enabled
|
|
1570
1631
|
):
|
|
1571
1632
|
raise RuntimeError(
|
|
1572
|
-
"Distribute
|
|
1633
|
+
"Distribute uses a disposal volume but location for disposing of"
|
|
1573
1634
|
" the disposal volume cannot be found when blowout is disabled."
|
|
1574
1635
|
" Specify a blowout location and enable blowout when using a disposal volume."
|
|
1575
1636
|
)
|
|
@@ -1610,9 +1671,11 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1610
1671
|
transfer_properties=transfer_props,
|
|
1611
1672
|
transfer_type=tx_comps_executor.TransferType.ONE_TO_MANY,
|
|
1612
1673
|
tip_contents=tip_contents,
|
|
1613
|
-
add_final_air_gap=
|
|
1614
|
-
|
|
1615
|
-
|
|
1674
|
+
add_final_air_gap=(
|
|
1675
|
+
False
|
|
1676
|
+
if is_last_step and new_tip == TransferTipPolicyV2.NEVER
|
|
1677
|
+
else True
|
|
1678
|
+
),
|
|
1616
1679
|
trash_location=trash_location,
|
|
1617
1680
|
)
|
|
1618
1681
|
else:
|
|
@@ -1623,15 +1686,16 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1623
1686
|
transfer_properties=transfer_props,
|
|
1624
1687
|
transfer_type=tx_comps_executor.TransferType.ONE_TO_MANY,
|
|
1625
1688
|
tip_contents=tip_contents,
|
|
1626
|
-
add_final_air_gap=
|
|
1627
|
-
|
|
1628
|
-
|
|
1689
|
+
add_final_air_gap=(
|
|
1690
|
+
False
|
|
1691
|
+
if is_last_step and new_tip == TransferTipPolicyV2.NEVER
|
|
1692
|
+
else True
|
|
1693
|
+
),
|
|
1629
1694
|
trash_location=trash_location,
|
|
1630
1695
|
conditioning_volume=conditioning_vol,
|
|
1631
1696
|
disposal_volume=disposal_vol,
|
|
1632
1697
|
)
|
|
1633
1698
|
is_first_step = False
|
|
1634
|
-
tip_used = True
|
|
1635
1699
|
|
|
1636
1700
|
if new_tip != TransferTipPolicyV2.NEVER:
|
|
1637
1701
|
_drop_tip()
|
|
@@ -1663,8 +1727,9 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1663
1727
|
volume: float,
|
|
1664
1728
|
source: List[Tuple[Location, WellCore]],
|
|
1665
1729
|
dest: Tuple[Location, WellCore],
|
|
1666
|
-
new_tip: TransferTipPolicyV2,
|
|
1730
|
+
new_tip: Literal[TransferTipPolicyV2.NEVER, TransferTipPolicyV2.ONCE],
|
|
1667
1731
|
tip_racks: List[Tuple[Location, LabwareCore]],
|
|
1732
|
+
starting_tip: Optional[WellCore],
|
|
1668
1733
|
trash_location: Union[Location, TrashBin, WasteChute],
|
|
1669
1734
|
return_tip: bool,
|
|
1670
1735
|
) -> None:
|
|
@@ -1672,7 +1737,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1672
1737
|
raise RuntimeError(
|
|
1673
1738
|
"No tipracks found for pipette in order to perform transfer"
|
|
1674
1739
|
)
|
|
1675
|
-
|
|
1740
|
+
assert new_tip in [TransferTipPolicyV2.NEVER, TransferTipPolicyV2.ONCE]
|
|
1676
1741
|
tiprack_uri_for_transfer_props = tip_racks[0][1].get_uri()
|
|
1677
1742
|
try:
|
|
1678
1743
|
transfer_props = liquid_class.get_for(
|
|
@@ -1747,11 +1812,12 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1747
1812
|
def _pick_up_tip() -> WellCore:
|
|
1748
1813
|
next_tip = self.get_next_tip(
|
|
1749
1814
|
tip_racks=[core for loc, core in tip_racks],
|
|
1750
|
-
starting_well=
|
|
1815
|
+
starting_well=starting_tip,
|
|
1751
1816
|
)
|
|
1752
1817
|
if next_tip is None:
|
|
1753
1818
|
raise RuntimeError(
|
|
1754
|
-
f"No tip available among
|
|
1819
|
+
f"No tip available among the tipracks assigned for {self.get_pipette_name()}:"
|
|
1820
|
+
f" {[ f'{tip_rack[1].get_display_name()} in {tip_rack[1].get_deck_slot()}' for tip_rack in tip_racks]}"
|
|
1755
1821
|
)
|
|
1756
1822
|
(
|
|
1757
1823
|
tiprack_loc,
|
|
@@ -1774,7 +1840,6 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1774
1840
|
if new_tip == TransferTipPolicyV2.ONCE:
|
|
1775
1841
|
last_tip_picked_up_from = _pick_up_tip()
|
|
1776
1842
|
|
|
1777
|
-
prev_src: Optional[Tuple[Location, WellCore]] = None
|
|
1778
1843
|
tip_contents = [
|
|
1779
1844
|
tx_comps_executor.LiquidAndAirGapPair(
|
|
1780
1845
|
liquid=0,
|
|
@@ -1782,6 +1847,7 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1782
1847
|
)
|
|
1783
1848
|
]
|
|
1784
1849
|
next_step_volume, next_source = next(source_per_volume_step)
|
|
1850
|
+
is_first_step = True
|
|
1785
1851
|
is_last_step = False
|
|
1786
1852
|
while not is_last_step:
|
|
1787
1853
|
total_dispense_volume = 0.0
|
|
@@ -1796,31 +1862,29 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1796
1862
|
is_last_step = True
|
|
1797
1863
|
break
|
|
1798
1864
|
|
|
1799
|
-
if
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
with self.lpd_for_transfer(enable=False):
|
|
1811
|
-
for step_num, (step_volume, step_source) in enumerate(
|
|
1812
|
-
vol_aspirate_combo
|
|
1813
|
-
):
|
|
1865
|
+
if (
|
|
1866
|
+
self.get_liquid_presence_detection()
|
|
1867
|
+
and new_tip != TransferTipPolicyV2.NEVER
|
|
1868
|
+
and is_first_step
|
|
1869
|
+
):
|
|
1870
|
+
enable_lpd = True
|
|
1871
|
+
else:
|
|
1872
|
+
enable_lpd = False
|
|
1873
|
+
|
|
1874
|
+
for step_num, (step_volume, step_source) in enumerate(vol_aspirate_combo):
|
|
1875
|
+
with self.lpd_for_transfer(enable=enable_lpd):
|
|
1814
1876
|
tip_contents = self.aspirate_liquid_class(
|
|
1815
1877
|
volume=step_volume,
|
|
1816
1878
|
source=step_source,
|
|
1817
1879
|
transfer_properties=transfer_props,
|
|
1818
1880
|
transfer_type=tx_comps_executor.TransferType.MANY_TO_ONE,
|
|
1819
1881
|
tip_contents=tip_contents,
|
|
1820
|
-
volume_for_pipette_mode_configuration=
|
|
1821
|
-
|
|
1822
|
-
|
|
1882
|
+
volume_for_pipette_mode_configuration=(
|
|
1883
|
+
total_dispense_volume if step_num == 0 else None
|
|
1884
|
+
),
|
|
1823
1885
|
)
|
|
1886
|
+
is_first_step = False
|
|
1887
|
+
enable_lpd = False
|
|
1824
1888
|
tip_contents = self.dispense_liquid_class(
|
|
1825
1889
|
volume=total_dispense_volume,
|
|
1826
1890
|
dest=dest,
|
|
@@ -1828,12 +1892,13 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1828
1892
|
transfer_properties=transfer_props,
|
|
1829
1893
|
transfer_type=tx_comps_executor.TransferType.MANY_TO_ONE,
|
|
1830
1894
|
tip_contents=tip_contents,
|
|
1831
|
-
add_final_air_gap=
|
|
1832
|
-
|
|
1833
|
-
|
|
1895
|
+
add_final_air_gap=(
|
|
1896
|
+
False
|
|
1897
|
+
if is_last_step and new_tip == TransferTipPolicyV2.NEVER
|
|
1898
|
+
else True
|
|
1899
|
+
),
|
|
1834
1900
|
trash_location=trash_location,
|
|
1835
1901
|
)
|
|
1836
|
-
prev_src = next_source
|
|
1837
1902
|
if new_tip != TransferTipPolicyV2.NEVER:
|
|
1838
1903
|
_drop_tip()
|
|
1839
1904
|
|
|
@@ -1881,9 +1946,11 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
|
|
|
1881
1946
|
aspirate_props = transfer_properties.aspirate
|
|
1882
1947
|
tx_commons.check_valid_liquid_class_volume_parameters(
|
|
1883
1948
|
aspirate_volume=volume,
|
|
1884
|
-
air_gap=
|
|
1885
|
-
|
|
1886
|
-
|
|
1949
|
+
air_gap=(
|
|
1950
|
+
aspirate_props.retract.air_gap_by_volume.get_for_volume(volume)
|
|
1951
|
+
if conditioning_volume is None
|
|
1952
|
+
else 0
|
|
1953
|
+
),
|
|
1887
1954
|
disposal_volume=0, # Disposal volume is accounted for in aspirate vol
|
|
1888
1955
|
max_volume=self.get_working_volume(),
|
|
1889
1956
|
)
|
|
@@ -19,14 +19,9 @@ from opentrons.protocol_engine import (
|
|
|
19
19
|
StateView,
|
|
20
20
|
DeckSlotLocation,
|
|
21
21
|
OnLabwareLocation,
|
|
22
|
-
WellLocation,
|
|
23
|
-
LiquidHandlingWellLocation,
|
|
24
|
-
PickUpTipWellLocation,
|
|
25
22
|
DropTipWellLocation,
|
|
26
23
|
)
|
|
27
|
-
from opentrons.protocol_engine.types import
|
|
28
|
-
StagingSlotLocation,
|
|
29
|
-
)
|
|
24
|
+
from opentrons.protocol_engine.types import StagingSlotLocation, WellLocationType
|
|
30
25
|
from opentrons.types import DeckSlotName, StagingSlotName, Point
|
|
31
26
|
from . import point_calculations
|
|
32
27
|
|
|
@@ -69,12 +64,7 @@ def check_safe_for_pipette_movement( # noqa: C901
|
|
|
69
64
|
pipette_id: str,
|
|
70
65
|
labware_id: str,
|
|
71
66
|
well_name: str,
|
|
72
|
-
well_location:
|
|
73
|
-
WellLocation,
|
|
74
|
-
LiquidHandlingWellLocation,
|
|
75
|
-
PickUpTipWellLocation,
|
|
76
|
-
DropTipWellLocation,
|
|
77
|
-
],
|
|
67
|
+
well_location: WellLocationType,
|
|
78
68
|
) -> None:
|
|
79
69
|
"""Check if the labware is safe to move to with a pipette in partial tip configuration.
|
|
80
70
|
|
|
@@ -100,12 +90,14 @@ def check_safe_for_pipette_movement( # noqa: C901
|
|
|
100
90
|
partially_configured=True,
|
|
101
91
|
)
|
|
102
92
|
well_location_point = engine_state.geometry.get_well_position(
|
|
103
|
-
labware_id=labware_id,
|
|
93
|
+
labware_id=labware_id,
|
|
94
|
+
well_name=well_name,
|
|
95
|
+
well_location=well_location,
|
|
96
|
+
pipette_id=pipette_id,
|
|
104
97
|
)
|
|
105
98
|
primary_nozzle = engine_state.pipettes.get_primary_nozzle(pipette_id)
|
|
106
99
|
|
|
107
100
|
destination_cp = _get_critical_point_to_use(engine_state, labware_id)
|
|
108
|
-
|
|
109
101
|
pipette_bounds_at_well_location = (
|
|
110
102
|
engine_state.pipettes.get_pipette_bounds_at_specified_move_to_position(
|
|
111
103
|
pipette_id=pipette_id,
|