opentrons 8.7.0a9__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.
- 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 +85 -17
- opentrons/hardware_control/poller.py +22 -8
- opentrons/hardware_control/protocols/liquid_handler.py +6 -2
- 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/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 +19 -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 +44 -0
- 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.0a7.dist-info}/METADATA +4 -4
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a7.dist-info}/RECORD +188 -160
- opentrons/protocol_engine/state/_labware_origin_math.py +0 -636
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a7.dist-info}/WHEEL +0 -0
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a7.dist-info}/entry_points.txt +0 -0
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a7.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,636 +0,0 @@
|
|
|
1
|
-
"""Utilities for calculating the labware origin offset position."""
|
|
2
|
-
import dataclasses
|
|
3
|
-
from typing import Union, overload
|
|
4
|
-
|
|
5
|
-
from typing_extensions import assert_type
|
|
6
|
-
|
|
7
|
-
from opentrons.types import Point
|
|
8
|
-
from opentrons_shared_data.labware.labware_definition import (
|
|
9
|
-
LabwareDefinition,
|
|
10
|
-
LabwareDefinition2,
|
|
11
|
-
LabwareDefinition3,
|
|
12
|
-
Extents,
|
|
13
|
-
AxisAlignedBoundingBox3D,
|
|
14
|
-
Vector3D,
|
|
15
|
-
)
|
|
16
|
-
from opentrons_shared_data.labware.types import (
|
|
17
|
-
SlotFootprintAsChildFeature,
|
|
18
|
-
LocatingFeatures,
|
|
19
|
-
SpringDirectionalForce,
|
|
20
|
-
SlotFootprintAsParentFeature,
|
|
21
|
-
)
|
|
22
|
-
from opentrons.protocol_engine.types import AddressableArea
|
|
23
|
-
from opentrons_shared_data.deck.types import DeckDefinitionV5, SlotDefV3
|
|
24
|
-
from ..types import (
|
|
25
|
-
LabwareParentDefinition,
|
|
26
|
-
ModuleDefinition,
|
|
27
|
-
ModuleModel,
|
|
28
|
-
DeckLocationDefinition,
|
|
29
|
-
LabwareLocation,
|
|
30
|
-
ModuleLocation,
|
|
31
|
-
DeckSlotLocation,
|
|
32
|
-
AddressableAreaLocation,
|
|
33
|
-
OnLabwareLocation,
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
_OFFSET_ON_TC_OT2 = Point(x=0, y=0, z=10.7)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@dataclasses.dataclass
|
|
40
|
-
class _Labware3SupportedParentDefinition:
|
|
41
|
-
features: LocatingFeatures
|
|
42
|
-
extents: Extents
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
@overload
|
|
46
|
-
def get_parent_placement_origin_to_lw_origin(
|
|
47
|
-
child_labware: LabwareDefinition,
|
|
48
|
-
parent_deck_item: ModuleDefinition,
|
|
49
|
-
module_parent_to_child_offset: Point,
|
|
50
|
-
deck_definition: DeckDefinitionV5,
|
|
51
|
-
is_topmost_labware: bool,
|
|
52
|
-
labware_location: ModuleLocation,
|
|
53
|
-
) -> Point:
|
|
54
|
-
...
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
@overload
|
|
58
|
-
def get_parent_placement_origin_to_lw_origin(
|
|
59
|
-
child_labware: LabwareDefinition,
|
|
60
|
-
parent_deck_item: DeckLocationDefinition,
|
|
61
|
-
module_parent_to_child_offset: None,
|
|
62
|
-
deck_definition: DeckDefinitionV5,
|
|
63
|
-
is_topmost_labware: bool,
|
|
64
|
-
labware_location: Union[DeckSlotLocation, AddressableAreaLocation],
|
|
65
|
-
) -> Point:
|
|
66
|
-
...
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
@overload
|
|
70
|
-
def get_parent_placement_origin_to_lw_origin(
|
|
71
|
-
child_labware: LabwareDefinition,
|
|
72
|
-
parent_deck_item: LabwareDefinition,
|
|
73
|
-
module_parent_to_child_offset: None,
|
|
74
|
-
deck_definition: DeckDefinitionV5,
|
|
75
|
-
is_topmost_labware: bool,
|
|
76
|
-
labware_location: OnLabwareLocation,
|
|
77
|
-
) -> Point:
|
|
78
|
-
...
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def get_parent_placement_origin_to_lw_origin(
|
|
82
|
-
child_labware: LabwareDefinition,
|
|
83
|
-
parent_deck_item: LabwareParentDefinition,
|
|
84
|
-
module_parent_to_child_offset: Union[Point, None],
|
|
85
|
-
deck_definition: DeckDefinitionV5,
|
|
86
|
-
is_topmost_labware: bool,
|
|
87
|
-
labware_location: LabwareLocation,
|
|
88
|
-
) -> Point:
|
|
89
|
-
"""Returns the offset from parent entity's placement origin to child labware origin.
|
|
90
|
-
|
|
91
|
-
Placement origin varies depending on the parent entity type (labware v3 are the back left bottom, and
|
|
92
|
-
labware v2, modules, & deck location types are the front left bottom).
|
|
93
|
-
|
|
94
|
-
Only parent-child specific offsets are calculated. Offsets that apply to a single entity
|
|
95
|
-
(ex., module cal) or the entire stackup (ex., LPC) are handled elsewhere.
|
|
96
|
-
"""
|
|
97
|
-
if isinstance(child_labware, LabwareDefinition2):
|
|
98
|
-
parent_deck_item_origin_to_child_labware_placement_origin = (
|
|
99
|
-
_get_parent_deck_item_origin_to_child_labware_placement_origin(
|
|
100
|
-
child_labware=child_labware,
|
|
101
|
-
parent_deck_item=parent_deck_item,
|
|
102
|
-
module_parent_to_child_offset=module_parent_to_child_offset,
|
|
103
|
-
deck_definition=deck_definition,
|
|
104
|
-
labware_location=labware_location,
|
|
105
|
-
)
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
# For v2 definitions, cornerOffsetFromSlot is the parent entity placement origin to child labware origin offset.
|
|
109
|
-
# For compatibility with historical (buggy?) behavior,
|
|
110
|
-
# we only consider it when the child labware is the topmost labware in a stackup.
|
|
111
|
-
parent_deck_item_to_child_labware_offset = (
|
|
112
|
-
Point.from_xyz_attrs(child_labware.cornerOffsetFromSlot)
|
|
113
|
-
if is_topmost_labware
|
|
114
|
-
else Point(0, 0, 0)
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
return (
|
|
118
|
-
parent_deck_item_origin_to_child_labware_placement_origin
|
|
119
|
-
+ parent_deck_item_to_child_labware_offset
|
|
120
|
-
)
|
|
121
|
-
else:
|
|
122
|
-
# For v3 definitions, get the vector from the back left bottom to the front right bottom.
|
|
123
|
-
assert_type(child_labware, LabwareDefinition3)
|
|
124
|
-
|
|
125
|
-
if isinstance(parent_deck_item, LabwareDefinition2):
|
|
126
|
-
raise NotImplementedError()
|
|
127
|
-
|
|
128
|
-
# TODO(jh, 06-25-25): This code is entirely temporary and only exists for the purposes of more useful
|
|
129
|
-
# snapshot testing. This code should exist in NO capacity after features are implemented outside of the
|
|
130
|
-
# module_parent_to_child_offset.
|
|
131
|
-
if _shim_does_locating_feature_pair_exist(
|
|
132
|
-
child_labware=child_labware,
|
|
133
|
-
parent_deck_item=_get_standardized_parent_deck_item(parent_deck_item),
|
|
134
|
-
):
|
|
135
|
-
parent_deck_item_origin_to_child_labware_placement_origin = (
|
|
136
|
-
_module_parent_to_child_offset(
|
|
137
|
-
module_parent_to_child_offset, labware_location
|
|
138
|
-
)
|
|
139
|
-
)
|
|
140
|
-
else:
|
|
141
|
-
parent_deck_item_origin_to_child_labware_placement_origin = (
|
|
142
|
-
_get_parent_deck_item_origin_to_child_labware_placement_origin(
|
|
143
|
-
child_labware=child_labware,
|
|
144
|
-
parent_deck_item=parent_deck_item,
|
|
145
|
-
module_parent_to_child_offset=module_parent_to_child_offset,
|
|
146
|
-
deck_definition=deck_definition,
|
|
147
|
-
labware_location=labware_location,
|
|
148
|
-
)
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
parent_deck_item_to_child_labware_feature_offset = (
|
|
152
|
-
_parent_deck_item_to_child_labware_feature_offset(
|
|
153
|
-
child_labware=child_labware,
|
|
154
|
-
parent_deck_item=_get_standardized_parent_deck_item(parent_deck_item),
|
|
155
|
-
)
|
|
156
|
-
) + _feature_exception_offsets(
|
|
157
|
-
deck_definition=deck_definition, parent_deck_item=parent_deck_item
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
return (
|
|
161
|
-
parent_deck_item_origin_to_child_labware_placement_origin
|
|
162
|
-
+ parent_deck_item_to_child_labware_feature_offset
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def _get_parent_deck_item_origin_to_child_labware_placement_origin(
|
|
167
|
-
child_labware: LabwareDefinition,
|
|
168
|
-
parent_deck_item: LabwareParentDefinition,
|
|
169
|
-
module_parent_to_child_offset: Union[Point, None],
|
|
170
|
-
deck_definition: DeckDefinitionV5,
|
|
171
|
-
labware_location: LabwareLocation,
|
|
172
|
-
) -> Point:
|
|
173
|
-
"""Get the offset vector from parent entity origin to child labware placement origin."""
|
|
174
|
-
if isinstance(labware_location, (DeckSlotLocation, AddressableAreaLocation)):
|
|
175
|
-
return Point(x=0, y=0, z=0)
|
|
176
|
-
|
|
177
|
-
elif isinstance(labware_location, ModuleLocation):
|
|
178
|
-
assert isinstance(parent_deck_item, ModuleDefinition)
|
|
179
|
-
|
|
180
|
-
child_labware_overlap_with_parent_deck_item = (
|
|
181
|
-
_get_child_labware_overlap_with_parent_module(
|
|
182
|
-
child_labware=child_labware,
|
|
183
|
-
parent_module_model=parent_deck_item.model,
|
|
184
|
-
deck_definition=deck_definition,
|
|
185
|
-
)
|
|
186
|
-
)
|
|
187
|
-
module_parent_to_child_offset = _module_parent_to_child_offset(
|
|
188
|
-
module_parent_to_child_offset, labware_location
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
return (
|
|
192
|
-
module_parent_to_child_offset - child_labware_overlap_with_parent_deck_item
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
elif isinstance(labware_location, OnLabwareLocation):
|
|
196
|
-
assert isinstance(parent_deck_item, (LabwareDefinition2, LabwareDefinition3))
|
|
197
|
-
|
|
198
|
-
# TODO(jh, 06-05-25): This logic is slightly duplicative of LabwareView get_dimensions. Can we unify?
|
|
199
|
-
if isinstance(parent_deck_item, LabwareDefinition2):
|
|
200
|
-
parent_deck_item_height = parent_deck_item.dimensions.zDimension
|
|
201
|
-
else:
|
|
202
|
-
assert_type(parent_deck_item, LabwareDefinition3)
|
|
203
|
-
parent_deck_item_height = (
|
|
204
|
-
parent_deck_item.extents.total.frontRightTop.z
|
|
205
|
-
- parent_deck_item.extents.total.backLeftBottom.z
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
child_labware_overlap_with_parent_deck_item = (
|
|
209
|
-
_get_child_labware_overlap_with_parent_labware(
|
|
210
|
-
child_labware=child_labware,
|
|
211
|
-
parent_labware_name=parent_deck_item.parameters.loadName,
|
|
212
|
-
)
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
return Point(
|
|
216
|
-
x=child_labware_overlap_with_parent_deck_item.x,
|
|
217
|
-
y=child_labware_overlap_with_parent_deck_item.y,
|
|
218
|
-
z=parent_deck_item_height - child_labware_overlap_with_parent_deck_item.z,
|
|
219
|
-
)
|
|
220
|
-
|
|
221
|
-
else:
|
|
222
|
-
raise TypeError(f"Unsupported labware location type: {labware_location}")
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
def _module_parent_to_child_offset(
|
|
226
|
-
module_parent_to_child_offset: Union[Point, None],
|
|
227
|
-
labware_location: LabwareLocation,
|
|
228
|
-
) -> Point:
|
|
229
|
-
"""Returns the module offset if applicable."""
|
|
230
|
-
if (
|
|
231
|
-
isinstance(labware_location, ModuleLocation)
|
|
232
|
-
and module_parent_to_child_offset is not None
|
|
233
|
-
):
|
|
234
|
-
return Point.from_xyz_attrs(module_parent_to_child_offset)
|
|
235
|
-
else:
|
|
236
|
-
return Point(0, 0, 0)
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
def _shim_does_locating_feature_pair_exist(
|
|
240
|
-
child_labware: LabwareDefinition3,
|
|
241
|
-
parent_deck_item: _Labware3SupportedParentDefinition,
|
|
242
|
-
) -> bool:
|
|
243
|
-
"""Temporary util."""
|
|
244
|
-
slot_footprint_exists = (
|
|
245
|
-
parent_deck_item.features.get("slotFootprintAsParent") is not None
|
|
246
|
-
and child_labware.features.get("slotFootprintAsChild") is not None
|
|
247
|
-
)
|
|
248
|
-
flex_tiprack_lid_exists = (
|
|
249
|
-
parent_deck_item.features.get("opentronsFlexTipRackLidAsParent") is not None
|
|
250
|
-
and child_labware.features.get("opentronsFlexTipRackLidAsChild") is not None
|
|
251
|
-
)
|
|
252
|
-
|
|
253
|
-
return slot_footprint_exists or flex_tiprack_lid_exists
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
def _get_standardized_parent_deck_item(
|
|
257
|
-
parent_deck_item: Union[
|
|
258
|
-
LabwareDefinition3, DeckLocationDefinition, ModuleDefinition
|
|
259
|
-
],
|
|
260
|
-
) -> _Labware3SupportedParentDefinition:
|
|
261
|
-
"""Returns a standardized parent deck item interface."""
|
|
262
|
-
if isinstance(parent_deck_item, ModuleDefinition):
|
|
263
|
-
slot_footprint_as_parent = _module_slot_footprint_as_parent(parent_deck_item)
|
|
264
|
-
if slot_footprint_as_parent is not None:
|
|
265
|
-
return _Labware3SupportedParentDefinition(
|
|
266
|
-
features={
|
|
267
|
-
**parent_deck_item.features,
|
|
268
|
-
"slotFootprintAsParent": slot_footprint_as_parent,
|
|
269
|
-
},
|
|
270
|
-
extents=parent_deck_item.extents,
|
|
271
|
-
)
|
|
272
|
-
else:
|
|
273
|
-
return _Labware3SupportedParentDefinition(
|
|
274
|
-
features=parent_deck_item.features, extents=parent_deck_item.extents
|
|
275
|
-
)
|
|
276
|
-
elif isinstance(parent_deck_item, AddressableArea):
|
|
277
|
-
extents = Extents(
|
|
278
|
-
total=AxisAlignedBoundingBox3D(
|
|
279
|
-
backLeftBottom=Vector3D(x=0, y=0, z=0),
|
|
280
|
-
frontRightTop=Vector3D(
|
|
281
|
-
x=parent_deck_item.bounding_box.x,
|
|
282
|
-
y=parent_deck_item.bounding_box.y * 1,
|
|
283
|
-
z=parent_deck_item.bounding_box.z,
|
|
284
|
-
),
|
|
285
|
-
)
|
|
286
|
-
)
|
|
287
|
-
|
|
288
|
-
slot_footprint_as_parent = _aa_slot_footprint_as_parent(parent_deck_item)
|
|
289
|
-
if slot_footprint_as_parent is not None:
|
|
290
|
-
return _Labware3SupportedParentDefinition(
|
|
291
|
-
features={
|
|
292
|
-
**parent_deck_item.features,
|
|
293
|
-
"slotFootprintAsParent": slot_footprint_as_parent,
|
|
294
|
-
},
|
|
295
|
-
extents=extents,
|
|
296
|
-
)
|
|
297
|
-
else:
|
|
298
|
-
return _Labware3SupportedParentDefinition(
|
|
299
|
-
parent_deck_item.features, extents=extents
|
|
300
|
-
)
|
|
301
|
-
elif isinstance(parent_deck_item, LabwareDefinition3):
|
|
302
|
-
return _Labware3SupportedParentDefinition(
|
|
303
|
-
features=parent_deck_item.features, extents=parent_deck_item.extents
|
|
304
|
-
)
|
|
305
|
-
# The slotDefV3 case.
|
|
306
|
-
else:
|
|
307
|
-
extents = Extents(
|
|
308
|
-
total=AxisAlignedBoundingBox3D(
|
|
309
|
-
backLeftBottom=Vector3D(x=0, y=0, z=0),
|
|
310
|
-
frontRightTop=Vector3D(
|
|
311
|
-
x=parent_deck_item["boundingBox"]["xDimension"],
|
|
312
|
-
y=parent_deck_item["boundingBox"]["yDimension"] * 1,
|
|
313
|
-
z=parent_deck_item["boundingBox"]["zDimension"],
|
|
314
|
-
),
|
|
315
|
-
)
|
|
316
|
-
)
|
|
317
|
-
slot_footprint_as_parent = _slot_def_slot_footprint_as_parent(parent_deck_item)
|
|
318
|
-
return _Labware3SupportedParentDefinition(
|
|
319
|
-
features={
|
|
320
|
-
**parent_deck_item["features"],
|
|
321
|
-
"slotFootprintAsParent": slot_footprint_as_parent,
|
|
322
|
-
},
|
|
323
|
-
extents=extents,
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
def _module_slot_footprint_as_parent(
|
|
328
|
-
parent_deck_item: ModuleDefinition,
|
|
329
|
-
) -> SlotFootprintAsParentFeature | None:
|
|
330
|
-
"""Returns the slot footprint as parent feature if inherently supported by the module definition.
|
|
331
|
-
|
|
332
|
-
This utility is a normalization shim until labwareOffset + labwareInterfaceX/YDimension is deleted in module defs
|
|
333
|
-
and replaced with the same slotFootprintAsParent that exists in labware def v3.
|
|
334
|
-
"""
|
|
335
|
-
dimensions = parent_deck_item.dimensions
|
|
336
|
-
if (
|
|
337
|
-
dimensions.labwareInterfaceYDimension is None
|
|
338
|
-
or dimensions.labwareInterfaceXDimension is None
|
|
339
|
-
):
|
|
340
|
-
return None
|
|
341
|
-
else:
|
|
342
|
-
# Modules with springs would require special mating types and therefore are not handled here.
|
|
343
|
-
return SlotFootprintAsParentFeature(
|
|
344
|
-
z=0,
|
|
345
|
-
backLeft={"x": 0, "y": dimensions.labwareInterfaceYDimension},
|
|
346
|
-
frontRight={"x": dimensions.labwareInterfaceXDimension, "y": 0},
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
def _aa_slot_footprint_as_parent(
|
|
351
|
-
parent_deck_item: AddressableArea,
|
|
352
|
-
) -> SlotFootprintAsParentFeature | None:
|
|
353
|
-
"""Returns the slot footprint as parent feature for addressable areas.
|
|
354
|
-
|
|
355
|
-
This utility is a normalization shim until bounding box in deck defs and
|
|
356
|
-
replaced with the same slotFootprintAsParent that exists in labware def v3.
|
|
357
|
-
"""
|
|
358
|
-
bb = parent_deck_item.bounding_box
|
|
359
|
-
|
|
360
|
-
if parent_deck_item.mating_surface_unit_vector is not None:
|
|
361
|
-
if parent_deck_item.mating_surface_unit_vector == [-1, 1, -1]:
|
|
362
|
-
return SlotFootprintAsParentFeature(
|
|
363
|
-
z=0,
|
|
364
|
-
backLeft={"x": 0, "y": bb.y},
|
|
365
|
-
frontRight={"x": bb.x, "y": 0},
|
|
366
|
-
springDirectionalForce="backLeftBottom",
|
|
367
|
-
)
|
|
368
|
-
else:
|
|
369
|
-
raise NotImplementedError(
|
|
370
|
-
"Slot footprint as parent does not support mating surface unit vector."
|
|
371
|
-
)
|
|
372
|
-
else:
|
|
373
|
-
return SlotFootprintAsParentFeature(
|
|
374
|
-
z=0,
|
|
375
|
-
backLeft={"x": 0, "y": bb.y},
|
|
376
|
-
frontRight={"x": bb.x, "y": 0},
|
|
377
|
-
)
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
def _slot_def_slot_footprint_as_parent(
|
|
381
|
-
parent_deck_item: SlotDefV3,
|
|
382
|
-
) -> SlotFootprintAsParentFeature:
|
|
383
|
-
"""Returns the slot footprint as parent feature for slot definitions.
|
|
384
|
-
|
|
385
|
-
This utility is a normalization shim until bounding box in deck defs and
|
|
386
|
-
replaced with the same slotFootprintAsParent that exists in labware def v3.
|
|
387
|
-
"""
|
|
388
|
-
bb = parent_deck_item["boundingBox"]
|
|
389
|
-
return SlotFootprintAsParentFeature(
|
|
390
|
-
z=0,
|
|
391
|
-
backLeft={"x": 0, "y": bb["yDimension"]},
|
|
392
|
-
frontRight={"x": bb["xDimension"], "y": 0},
|
|
393
|
-
springDirectionalForce="backLeftBottom",
|
|
394
|
-
)
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
def _parent_deck_item_to_child_labware_feature_offset(
|
|
398
|
-
child_labware: LabwareDefinition3,
|
|
399
|
-
parent_deck_item: _Labware3SupportedParentDefinition,
|
|
400
|
-
) -> Point:
|
|
401
|
-
"""Get the offset vector from the parent entity origin to the child labware origin."""
|
|
402
|
-
if (
|
|
403
|
-
parent_deck_item.features.get("opentronsFlexTipRackLidAsParent") is not None
|
|
404
|
-
and child_labware.features.get("opentronsFlexTipRackLidAsChild") is not None
|
|
405
|
-
):
|
|
406
|
-
# TODO(jh, 07-29-25): Support center X/Y calculation after addressing grip point
|
|
407
|
-
# calculations. See #18929 discussion.
|
|
408
|
-
return _parent_origin_to_flex_tip_rack_lid_feature(
|
|
409
|
-
parent_deck_item
|
|
410
|
-
) + _flex_tip_rack_lid_feature_to_child_origin(child_labware)
|
|
411
|
-
elif (
|
|
412
|
-
parent_deck_item.features.get("slotFootprintAsParent") is not None
|
|
413
|
-
and child_labware.features.get("slotFootprintAsChild") is not None
|
|
414
|
-
):
|
|
415
|
-
spring_force = _get_spring_force(child_labware, parent_deck_item)
|
|
416
|
-
|
|
417
|
-
if spring_force is not None:
|
|
418
|
-
if spring_force == "backLeftBottom":
|
|
419
|
-
return _parent_origin_to_slot_back_left_bottom(
|
|
420
|
-
parent_deck_item
|
|
421
|
-
) + _slot_back_left_bottom_to_child_origin(child_labware)
|
|
422
|
-
else:
|
|
423
|
-
raise NotImplementedError(f"Spring force: {spring_force}")
|
|
424
|
-
else:
|
|
425
|
-
return _parent_origin_to_slot_bottom_center(
|
|
426
|
-
parent_deck_item
|
|
427
|
-
) + slot_bottom_center_to_child_origin(child_labware)
|
|
428
|
-
else:
|
|
429
|
-
# TODO(jh, 06-25-25): This is a temporary shim to unblock FE usage with LW Def3 and more accurately diff
|
|
430
|
-
# ongoing positioning snapshot changes, but we should throw an error after adding all locating features
|
|
431
|
-
# if no appropriate LF pair is found.
|
|
432
|
-
return Point(0, 0, 0)
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
def _get_spring_force(
|
|
436
|
-
child_labware: LabwareDefinition3,
|
|
437
|
-
parent_deck_item: _Labware3SupportedParentDefinition,
|
|
438
|
-
) -> SpringDirectionalForce | None:
|
|
439
|
-
"""Returns whether the parent-child stackup has a spring that affects positioning."""
|
|
440
|
-
assert parent_deck_item.features.get("slotFootprintAsParent") is not None
|
|
441
|
-
assert child_labware.features.get("slotFootprintAsChild") is not None
|
|
442
|
-
|
|
443
|
-
parent_spring_force = parent_deck_item.features["slotFootprintAsParent"].get(
|
|
444
|
-
"springDirectionalForce"
|
|
445
|
-
)
|
|
446
|
-
child_spring_force = child_labware.features["slotFootprintAsChild"].get(
|
|
447
|
-
"springDirectionalForce"
|
|
448
|
-
)
|
|
449
|
-
|
|
450
|
-
if parent_spring_force is not None and child_spring_force is not None:
|
|
451
|
-
if parent_spring_force != child_spring_force:
|
|
452
|
-
raise ValueError(
|
|
453
|
-
f"Parent spring force: {parent_spring_force} does not match child spring force: {child_spring_force}"
|
|
454
|
-
)
|
|
455
|
-
|
|
456
|
-
return parent_spring_force or child_spring_force
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
def _parent_origin_to_flex_tip_rack_lid_feature(
|
|
460
|
-
parent_deck_item: _Labware3SupportedParentDefinition,
|
|
461
|
-
) -> Point:
|
|
462
|
-
"""Returns the offset from a deck item's origin to the Flex tip rack lid locating feature."""
|
|
463
|
-
flex_tip_rack_lid_as_parent = parent_deck_item.features.get(
|
|
464
|
-
"opentronsFlexTipRackLidAsParent"
|
|
465
|
-
)
|
|
466
|
-
assert flex_tip_rack_lid_as_parent is not None
|
|
467
|
-
|
|
468
|
-
return Point(x=0, y=0, z=flex_tip_rack_lid_as_parent["matingZ"])
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
def _parent_origin_to_slot_bottom_center(
|
|
472
|
-
parent_deck_item: _Labware3SupportedParentDefinition,
|
|
473
|
-
) -> Point:
|
|
474
|
-
"""Returns the offset from a deck item's origin to the bottom center of the slot that it provides."""
|
|
475
|
-
slot_footprint_as_parent = parent_deck_item.features.get("slotFootprintAsParent")
|
|
476
|
-
assert slot_footprint_as_parent is not None
|
|
477
|
-
|
|
478
|
-
x = (
|
|
479
|
-
slot_footprint_as_parent["frontRight"]["x"]
|
|
480
|
-
+ slot_footprint_as_parent["backLeft"]["x"]
|
|
481
|
-
) / 2
|
|
482
|
-
y = (
|
|
483
|
-
slot_footprint_as_parent["frontRight"]["y"]
|
|
484
|
-
+ slot_footprint_as_parent["backLeft"]["y"]
|
|
485
|
-
) / 2
|
|
486
|
-
z = slot_footprint_as_parent["z"]
|
|
487
|
-
|
|
488
|
-
return Point(x, y, z)
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
def _parent_origin_to_slot_back_left_bottom(
|
|
492
|
-
parent_deck_item: _Labware3SupportedParentDefinition,
|
|
493
|
-
) -> Point:
|
|
494
|
-
"""Returns the offset from a deck item's origin to the back left bottom of the slot that it provides."""
|
|
495
|
-
slot_footprint_as_parent = parent_deck_item.features.get("slotFootprintAsParent")
|
|
496
|
-
assert slot_footprint_as_parent is not None
|
|
497
|
-
|
|
498
|
-
x = slot_footprint_as_parent["backLeft"]["x"]
|
|
499
|
-
y = slot_footprint_as_parent["backLeft"]["y"]
|
|
500
|
-
z = slot_footprint_as_parent["z"]
|
|
501
|
-
|
|
502
|
-
return Point(x, y, z)
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
def _flex_tip_rack_lid_feature_to_child_origin(
|
|
506
|
-
child_labware: LabwareDefinition3,
|
|
507
|
-
) -> Point:
|
|
508
|
-
"""Returns the offset from a Flex tip rack lid locating feature to the child origin."""
|
|
509
|
-
flex_tip_rack_lid_as_child = child_labware.features.get(
|
|
510
|
-
"opentronsFlexTipRackLidAsChild"
|
|
511
|
-
)
|
|
512
|
-
assert flex_tip_rack_lid_as_child is not None
|
|
513
|
-
|
|
514
|
-
return Point(x=0, y=0, z=flex_tip_rack_lid_as_child["matingZ"])
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
def slot_bottom_center_to_child_origin(
|
|
518
|
-
child_labware: LabwareDefinition3,
|
|
519
|
-
) -> Point:
|
|
520
|
-
"""Returns offset from a parent slot's bottom center to the child origin."""
|
|
521
|
-
slot_footprint_as_child = child_labware.features.get("slotFootprintAsChild")
|
|
522
|
-
assert slot_footprint_as_child is not None
|
|
523
|
-
|
|
524
|
-
x = (
|
|
525
|
-
slot_footprint_as_child["frontRight"]["x"]
|
|
526
|
-
+ slot_footprint_as_child["backLeft"]["x"]
|
|
527
|
-
) / 2
|
|
528
|
-
y = (
|
|
529
|
-
slot_footprint_as_child["frontRight"]["y"]
|
|
530
|
-
+ slot_footprint_as_child["backLeft"]["y"]
|
|
531
|
-
) / 2
|
|
532
|
-
z = slot_footprint_as_child["z"]
|
|
533
|
-
|
|
534
|
-
return Point(x, y, z) * -1
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
def _slot_back_left_bottom_to_child_origin(
|
|
538
|
-
child_labware: LabwareDefinition3,
|
|
539
|
-
) -> Point:
|
|
540
|
-
"""Returns offset from a parent slot's back left bottom to the child's origin."""
|
|
541
|
-
slot_footprint_as_child = child_labware.features.get("slotFootprintAsChild")
|
|
542
|
-
assert slot_footprint_as_child is not None
|
|
543
|
-
|
|
544
|
-
x = slot_footprint_as_child["backLeft"]["x"]
|
|
545
|
-
y = slot_footprint_as_child["backLeft"]["y"]
|
|
546
|
-
z = slot_footprint_as_child["z"]
|
|
547
|
-
|
|
548
|
-
return Point(x, y, z) * -1
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
def _child_back_left_bottom_position(child_labware: LabwareDefinition3) -> Point:
|
|
552
|
-
"""Get the back left bottom position from a v3 labware definition."""
|
|
553
|
-
footprint_as_child = _get_labware_footprint_as_child(child_labware)
|
|
554
|
-
|
|
555
|
-
return Point(
|
|
556
|
-
x=footprint_as_child["backLeft"]["x"],
|
|
557
|
-
y=footprint_as_child["frontRight"]["y"],
|
|
558
|
-
z=footprint_as_child["z"],
|
|
559
|
-
)
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
def _get_child_labware_overlap_with_parent_labware(
|
|
563
|
-
child_labware: LabwareDefinition, parent_labware_name: str
|
|
564
|
-
) -> Point:
|
|
565
|
-
"""Get the child labware's overlap with the parent labware's load name."""
|
|
566
|
-
overlap = child_labware.stackingOffsetWithLabware.get(parent_labware_name)
|
|
567
|
-
|
|
568
|
-
if overlap is None:
|
|
569
|
-
overlap = child_labware.stackingOffsetWithLabware.get("default")
|
|
570
|
-
|
|
571
|
-
if overlap is None:
|
|
572
|
-
raise ValueError(
|
|
573
|
-
f"No default labware overlap specified for parent labware: {parent_labware_name}"
|
|
574
|
-
)
|
|
575
|
-
else:
|
|
576
|
-
return Point.from_xyz_attrs(overlap)
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
def _get_child_labware_overlap_with_parent_module(
|
|
580
|
-
child_labware: LabwareDefinition,
|
|
581
|
-
parent_module_model: ModuleModel,
|
|
582
|
-
deck_definition: DeckDefinitionV5,
|
|
583
|
-
) -> Point:
|
|
584
|
-
"""Get the child labware's overlap with the parent module model."""
|
|
585
|
-
child_labware_overlap = child_labware.stackingOffsetWithModule.get(
|
|
586
|
-
str(parent_module_model.value)
|
|
587
|
-
)
|
|
588
|
-
if not child_labware_overlap:
|
|
589
|
-
if _is_thermocycler_on_ot2(parent_module_model, deck_definition):
|
|
590
|
-
return _OFFSET_ON_TC_OT2
|
|
591
|
-
else:
|
|
592
|
-
return Point(x=0, y=0, z=0)
|
|
593
|
-
|
|
594
|
-
return Point.from_xyz_attrs(child_labware_overlap)
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
def _feature_exception_offsets(
|
|
598
|
-
parent_deck_item: LabwareParentDefinition,
|
|
599
|
-
deck_definition: DeckDefinitionV5,
|
|
600
|
-
) -> Point:
|
|
601
|
-
"""These offsets are intended for legacy reasons only and should generally be avoided post labware schema 2.
|
|
602
|
-
|
|
603
|
-
If you need to make exceptions for a parent-child stackup, use the `custom` locating feature.
|
|
604
|
-
"""
|
|
605
|
-
if isinstance(parent_deck_item, ModuleDefinition) and _is_thermocycler_on_ot2(
|
|
606
|
-
parent_deck_item.model, deck_definition
|
|
607
|
-
):
|
|
608
|
-
return _OFFSET_ON_TC_OT2
|
|
609
|
-
else:
|
|
610
|
-
return Point(x=0, y=0, z=0)
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
def _is_thermocycler_on_ot2(
|
|
614
|
-
parent_module_model: ModuleModel,
|
|
615
|
-
deck_definition: DeckDefinitionV5,
|
|
616
|
-
) -> bool:
|
|
617
|
-
"""Whether the given parent module is a thermocycler with the current deck being an OT2 deck."""
|
|
618
|
-
robot_model = deck_definition["robot"]["model"]
|
|
619
|
-
return (
|
|
620
|
-
parent_module_model
|
|
621
|
-
in [ModuleModel.THERMOCYCLER_MODULE_V1, ModuleModel.THERMOCYCLER_MODULE_V2]
|
|
622
|
-
and robot_model == "OT-2 Standard"
|
|
623
|
-
)
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
def _get_labware_footprint_as_child(
|
|
627
|
-
labware: LabwareDefinition3,
|
|
628
|
-
) -> SlotFootprintAsChildFeature:
|
|
629
|
-
"""Get the SlotFootprintAsChildFeature for labware definitions."""
|
|
630
|
-
footprint_as_child = labware.features.get("slotFootprintAsChild")
|
|
631
|
-
if footprint_as_child is None:
|
|
632
|
-
raise ValueError(
|
|
633
|
-
f"Expected labware {labware.metadata.displayName} to have a SlotFootprintAsChild feature"
|
|
634
|
-
)
|
|
635
|
-
else:
|
|
636
|
-
return footprint_as_child
|
|
File without changes
|
|
File without changes
|
|
File without changes
|