opentrons 8.2.0a4__py2.py3-none-any.whl → 8.3.0a1__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/calibration_storage/deck_configuration.py +3 -3
- opentrons/calibration_storage/file_operators.py +3 -3
- opentrons/calibration_storage/helpers.py +3 -1
- opentrons/calibration_storage/ot2/models/v1.py +16 -29
- opentrons/calibration_storage/ot2/tip_length.py +7 -4
- opentrons/calibration_storage/ot3/models/v1.py +14 -23
- opentrons/cli/analyze.py +18 -6
- opentrons/config/defaults_ot3.py +1 -0
- opentrons/drivers/asyncio/communication/__init__.py +2 -0
- opentrons/drivers/asyncio/communication/errors.py +16 -3
- opentrons/drivers/asyncio/communication/serial_connection.py +24 -9
- opentrons/drivers/command_builder.py +2 -2
- opentrons/drivers/flex_stacker/__init__.py +9 -0
- opentrons/drivers/flex_stacker/abstract.py +89 -0
- opentrons/drivers/flex_stacker/driver.py +260 -0
- opentrons/drivers/flex_stacker/simulator.py +109 -0
- opentrons/drivers/flex_stacker/types.py +138 -0
- opentrons/drivers/heater_shaker/driver.py +18 -3
- opentrons/drivers/temp_deck/driver.py +13 -3
- opentrons/drivers/thermocycler/driver.py +17 -3
- opentrons/execute.py +3 -1
- opentrons/hardware_control/__init__.py +1 -2
- opentrons/hardware_control/api.py +28 -20
- opentrons/hardware_control/backends/flex_protocol.py +17 -7
- opentrons/hardware_control/backends/ot3controller.py +213 -63
- opentrons/hardware_control/backends/ot3simulator.py +18 -9
- opentrons/hardware_control/backends/ot3utils.py +43 -15
- opentrons/hardware_control/dev_types.py +4 -0
- opentrons/hardware_control/emulation/heater_shaker.py +4 -0
- opentrons/hardware_control/emulation/module_server/client.py +1 -1
- opentrons/hardware_control/emulation/module_server/server.py +5 -3
- opentrons/hardware_control/emulation/settings.py +3 -4
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +2 -1
- opentrons/hardware_control/instruments/ot2/pipette.py +15 -22
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +8 -1
- opentrons/hardware_control/instruments/ot3/gripper.py +2 -2
- opentrons/hardware_control/instruments/ot3/pipette.py +23 -22
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -1
- opentrons/hardware_control/modules/mod_abc.py +2 -2
- opentrons/hardware_control/motion_utilities.py +68 -0
- opentrons/hardware_control/nozzle_manager.py +39 -41
- opentrons/hardware_control/ot3_calibration.py +1 -1
- opentrons/hardware_control/ot3api.py +60 -23
- opentrons/hardware_control/protocols/gripper_controller.py +3 -0
- opentrons/hardware_control/protocols/hardware_manager.py +5 -1
- opentrons/hardware_control/protocols/liquid_handler.py +18 -0
- opentrons/hardware_control/protocols/motion_controller.py +6 -0
- opentrons/hardware_control/robot_calibration.py +1 -1
- opentrons/hardware_control/types.py +61 -0
- opentrons/protocol_api/__init__.py +20 -1
- opentrons/protocol_api/_liquid.py +24 -49
- opentrons/protocol_api/_liquid_properties.py +754 -0
- opentrons/protocol_api/_types.py +24 -0
- opentrons/protocol_api/core/common.py +2 -0
- opentrons/protocol_api/core/engine/instrument.py +82 -10
- opentrons/protocol_api/core/engine/labware.py +29 -7
- opentrons/protocol_api/core/engine/protocol.py +130 -5
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/well.py +4 -1
- opentrons/protocol_api/core/instrument.py +46 -4
- opentrons/protocol_api/core/labware.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +37 -3
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +32 -1
- opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +37 -3
- opentrons/protocol_api/core/protocol.py +34 -1
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/instrument_context.py +158 -44
- opentrons/protocol_api/labware.py +231 -7
- opentrons/protocol_api/module_contexts.py +21 -17
- opentrons/protocol_api/protocol_context.py +125 -4
- opentrons/protocol_api/robot_context.py +204 -32
- opentrons/protocol_api/validation.py +262 -3
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/actions.py +2 -3
- opentrons/protocol_engine/clients/sync_client.py +18 -0
- opentrons/protocol_engine/commands/__init__.py +81 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +0 -2
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +19 -5
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +0 -1
- opentrons/protocol_engine/commands/absorbance_reader/read.py +32 -9
- opentrons/protocol_engine/commands/air_gap_in_place.py +160 -0
- opentrons/protocol_engine/commands/aspirate.py +103 -53
- opentrons/protocol_engine/commands/aspirate_in_place.py +55 -51
- opentrons/protocol_engine/commands/blow_out.py +44 -39
- opentrons/protocol_engine/commands/blow_out_in_place.py +21 -32
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +13 -6
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +1 -1
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +3 -3
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +1 -1
- opentrons/protocol_engine/commands/command.py +73 -66
- opentrons/protocol_engine/commands/command_unions.py +101 -1
- opentrons/protocol_engine/commands/comment.py +1 -1
- opentrons/protocol_engine/commands/configure_for_volume.py +10 -3
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +6 -4
- opentrons/protocol_engine/commands/custom.py +6 -12
- opentrons/protocol_engine/commands/dispense.py +82 -48
- opentrons/protocol_engine/commands/dispense_in_place.py +71 -51
- opentrons/protocol_engine/commands/drop_tip.py +52 -31
- opentrons/protocol_engine/commands/drop_tip_in_place.py +13 -3
- opentrons/protocol_engine/commands/generate_command_schema.py +4 -11
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/home.py +13 -4
- opentrons/protocol_engine/commands/liquid_probe.py +67 -24
- opentrons/protocol_engine/commands/load_labware.py +29 -7
- opentrons/protocol_engine/commands/load_lid.py +146 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +189 -0
- opentrons/protocol_engine/commands/load_liquid.py +12 -4
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +31 -10
- opentrons/protocol_engine/commands/load_pipette.py +19 -8
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +1 -1
- opentrons/protocol_engine/commands/magnetic_module/engage.py +1 -1
- opentrons/protocol_engine/commands/move_labware.py +19 -6
- opentrons/protocol_engine/commands/move_relative.py +35 -25
- opentrons/protocol_engine/commands/move_to_addressable_area.py +40 -27
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +53 -32
- opentrons/protocol_engine/commands/move_to_coordinates.py +36 -22
- opentrons/protocol_engine/commands/move_to_well.py +40 -24
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +49 -27
- opentrons/protocol_engine/commands/pipetting_common.py +169 -87
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +24 -33
- opentrons/protocol_engine/commands/reload_labware.py +1 -1
- opentrons/protocol_engine/commands/retract_axis.py +1 -1
- opentrons/protocol_engine/commands/robot/__init__.py +69 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +86 -0
- opentrons/protocol_engine/commands/robot/common.py +18 -0
- opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
- opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
- opentrons/protocol_engine/commands/robot/move_to.py +94 -0
- opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +77 -0
- opentrons/protocol_engine/commands/save_position.py +14 -5
- opentrons/protocol_engine/commands/set_rail_lights.py +1 -1
- opentrons/protocol_engine/commands/set_status_bar.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +8 -2
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +9 -3
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +11 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/touch_tip.py +65 -16
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +4 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +1 -4
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +1 -4
- opentrons/protocol_engine/commands/verify_tip_presence.py +11 -4
- opentrons/protocol_engine/commands/wait_for_duration.py +10 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +10 -3
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/error_occurrence.py +19 -20
- opentrons/protocol_engine/errors/exceptions.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +73 -5
- opentrons/protocol_engine/execution/gantry_mover.py +364 -8
- opentrons/protocol_engine/execution/movement.py +27 -0
- opentrons/protocol_engine/execution/pipetting.py +5 -1
- opentrons/protocol_engine/execution/tip_handler.py +4 -6
- opentrons/protocol_engine/notes/notes.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +7 -6
- opentrons/protocol_engine/resources/labware_data_provider.py +1 -1
- opentrons/protocol_engine/resources/labware_validation.py +5 -0
- opentrons/protocol_engine/resources/module_data_provider.py +1 -1
- opentrons/protocol_engine/resources/pipette_data_provider.py +26 -0
- opentrons/protocol_engine/slot_standardization.py +9 -9
- opentrons/protocol_engine/state/_move_types.py +9 -5
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +25 -61
- opentrons/protocol_engine/state/command_history.py +12 -0
- opentrons/protocol_engine/state/commands.py +17 -13
- opentrons/protocol_engine/state/files.py +10 -12
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/frustum_helpers.py +57 -32
- opentrons/protocol_engine/state/geometry.py +47 -1
- opentrons/protocol_engine/state/labware.py +79 -25
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +16 -4
- opentrons/protocol_engine/state/modules.py +52 -70
- opentrons/protocol_engine/state/motion.py +6 -1
- opentrons/protocol_engine/state/pipettes.py +144 -58
- opentrons/protocol_engine/state/state.py +21 -2
- opentrons/protocol_engine/state/state_summary.py +4 -2
- opentrons/protocol_engine/state/tips.py +11 -44
- opentrons/protocol_engine/state/update_types.py +343 -48
- opentrons/protocol_engine/state/wells.py +19 -11
- opentrons/protocol_engine/types.py +176 -28
- opentrons/protocol_reader/extract_labware_definitions.py +5 -2
- opentrons/protocol_reader/file_format_validator.py +5 -5
- opentrons/protocol_runner/json_file_reader.py +9 -3
- opentrons/protocol_runner/json_translator.py +51 -25
- opentrons/protocol_runner/legacy_command_mapper.py +66 -64
- opentrons/protocol_runner/protocol_runner.py +35 -4
- opentrons/protocol_runner/python_protocol_wrappers.py +1 -1
- opentrons/protocol_runner/run_orchestrator.py +13 -3
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +1 -1
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +56 -0
- opentrons/protocols/advanced_control/{transfers.py → transfers/transfer.py} +10 -85
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/instrument.py +1 -1
- opentrons/protocols/api_support/util.py +10 -0
- opentrons/protocols/labware.py +39 -6
- opentrons/protocols/models/json_protocol.py +5 -9
- opentrons/simulate.py +3 -1
- opentrons/types.py +162 -2
- opentrons/util/logging_config.py +1 -1
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/METADATA +16 -15
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/RECORD +229 -202
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/WHEEL +1 -1
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/LICENSE +0 -0
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/entry_points.txt +0 -0
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
"""Utilities for calculating motion correctly."""
|
|
2
|
+
from logging import getLogger
|
|
3
|
+
|
|
2
4
|
from functools import lru_cache
|
|
3
5
|
from typing import Callable, Dict, Union, Optional, cast
|
|
4
6
|
from collections import OrderedDict
|
|
@@ -11,6 +13,7 @@ from opentrons.util import linal
|
|
|
11
13
|
|
|
12
14
|
from .types import Axis, OT3Mount
|
|
13
15
|
|
|
16
|
+
log = getLogger(__name__)
|
|
14
17
|
|
|
15
18
|
# TODO: The offset_for_mount function should be defined with an overload
|
|
16
19
|
# set, as with other functions in this module. Unfortunately, mypy < 0.920
|
|
@@ -36,6 +39,19 @@ from .types import Axis, OT3Mount
|
|
|
36
39
|
# ) -> Point:
|
|
37
40
|
# ...
|
|
38
41
|
|
|
42
|
+
EMPTY_ORDERED_DICT = OrderedDict(
|
|
43
|
+
(
|
|
44
|
+
(Axis.X, 0.0),
|
|
45
|
+
(Axis.Y, 0.0),
|
|
46
|
+
(Axis.Z_L, 0.0),
|
|
47
|
+
(Axis.Z_R, 0.0),
|
|
48
|
+
(Axis.Z_G, 0.0),
|
|
49
|
+
(Axis.P_L, 0.0),
|
|
50
|
+
(Axis.P_R, 0.0),
|
|
51
|
+
(Axis.Q, 0.0),
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
|
|
39
55
|
|
|
40
56
|
@lru_cache(4)
|
|
41
57
|
def offset_for_mount(
|
|
@@ -68,6 +84,7 @@ def target_position_from_absolute(
|
|
|
68
84
|
)
|
|
69
85
|
primary_cp = get_critical_point(mount)
|
|
70
86
|
primary_z = Axis.by_mount(mount)
|
|
87
|
+
|
|
71
88
|
target_position = OrderedDict(
|
|
72
89
|
(
|
|
73
90
|
(Axis.X, abs_position.x - offset.x - primary_cp.x),
|
|
@@ -97,6 +114,57 @@ def target_position_from_relative(
|
|
|
97
114
|
return target_position
|
|
98
115
|
|
|
99
116
|
|
|
117
|
+
def target_axis_map_from_absolute(
|
|
118
|
+
primary_mount: Union[OT3Mount, Mount],
|
|
119
|
+
axis_map: Dict[Axis, float],
|
|
120
|
+
get_critical_point: Callable[[Union[Mount, OT3Mount]], Point],
|
|
121
|
+
left_mount_offset: Point,
|
|
122
|
+
right_mount_offset: Point,
|
|
123
|
+
gripper_mount_offset: Optional[Point] = None,
|
|
124
|
+
) -> "OrderedDict[Axis, float]":
|
|
125
|
+
"""Create an absolute target position for all specified machine axes."""
|
|
126
|
+
keys_for_target_position = list(axis_map.keys())
|
|
127
|
+
|
|
128
|
+
offset = offset_for_mount(
|
|
129
|
+
primary_mount, left_mount_offset, right_mount_offset, gripper_mount_offset
|
|
130
|
+
)
|
|
131
|
+
primary_cp = get_critical_point(primary_mount)
|
|
132
|
+
primary_z = Axis.by_mount(primary_mount)
|
|
133
|
+
target_position = OrderedDict()
|
|
134
|
+
|
|
135
|
+
if Axis.X in keys_for_target_position:
|
|
136
|
+
target_position[Axis.X] = axis_map[Axis.X] - offset.x - primary_cp.x
|
|
137
|
+
if Axis.Y in keys_for_target_position:
|
|
138
|
+
target_position[Axis.Y] = axis_map[Axis.Y] - offset.y - primary_cp.y
|
|
139
|
+
if primary_z in keys_for_target_position:
|
|
140
|
+
# Since this function is intended to be used in conjunction with `API.move_axes`
|
|
141
|
+
# we must leave out the carriage offset subtraction from the target position as
|
|
142
|
+
# `move_axes` already does this calculation.
|
|
143
|
+
target_position[primary_z] = axis_map[primary_z] - primary_cp.z
|
|
144
|
+
|
|
145
|
+
target_position.update(
|
|
146
|
+
{ax: val for ax, val in axis_map.items() if ax not in Axis.gantry_axes()}
|
|
147
|
+
)
|
|
148
|
+
return target_position
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def target_axis_map_from_relative(
|
|
152
|
+
axis_map: Dict[Axis, float],
|
|
153
|
+
current_position: Dict[Axis, float],
|
|
154
|
+
) -> "OrderedDict[Axis, float]":
|
|
155
|
+
"""Create a target position for all specified machine axes."""
|
|
156
|
+
target_position = OrderedDict(
|
|
157
|
+
(
|
|
158
|
+
(ax, current_position[ax] + axis_map[ax])
|
|
159
|
+
for ax in EMPTY_ORDERED_DICT.keys()
|
|
160
|
+
if ax in axis_map.keys()
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
log.info(f"Current position {current_position} and axis map delta {axis_map}")
|
|
164
|
+
log.info(f"Relative move target {target_position}")
|
|
165
|
+
return target_position
|
|
166
|
+
|
|
167
|
+
|
|
100
168
|
def target_position_from_plunger(
|
|
101
169
|
mount: Union[Mount, OT3Mount],
|
|
102
170
|
delta: float,
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
from typing import Dict, List, Optional, Any, Sequence, Iterator, Tuple, cast
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
from collections import OrderedDict
|
|
4
|
-
from enum import Enum
|
|
5
4
|
from itertools import chain
|
|
6
5
|
|
|
7
6
|
from opentrons.hardware_control.types import CriticalPoint
|
|
8
|
-
from opentrons.types import
|
|
7
|
+
from opentrons.types import (
|
|
8
|
+
Point,
|
|
9
|
+
NozzleConfigurationType,
|
|
10
|
+
)
|
|
9
11
|
from opentrons_shared_data.pipette.pipette_definition import (
|
|
10
12
|
PipetteGeometryDefinition,
|
|
11
13
|
PipetteRowDefinition,
|
|
@@ -41,43 +43,6 @@ def _row_col_indices_for_nozzle(
|
|
|
41
43
|
)
|
|
42
44
|
|
|
43
45
|
|
|
44
|
-
class NozzleConfigurationType(Enum):
|
|
45
|
-
"""
|
|
46
|
-
Nozzle Configuration Type.
|
|
47
|
-
|
|
48
|
-
Represents the current nozzle
|
|
49
|
-
configuration stored in NozzleMap
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
COLUMN = "COLUMN"
|
|
53
|
-
ROW = "ROW"
|
|
54
|
-
SINGLE = "SINGLE"
|
|
55
|
-
FULL = "FULL"
|
|
56
|
-
SUBRECT = "SUBRECT"
|
|
57
|
-
|
|
58
|
-
@classmethod
|
|
59
|
-
def determine_nozzle_configuration(
|
|
60
|
-
cls,
|
|
61
|
-
physical_rows: "OrderedDict[str, List[str]]",
|
|
62
|
-
current_rows: "OrderedDict[str, List[str]]",
|
|
63
|
-
physical_cols: "OrderedDict[str, List[str]]",
|
|
64
|
-
current_cols: "OrderedDict[str, List[str]]",
|
|
65
|
-
) -> "NozzleConfigurationType":
|
|
66
|
-
"""
|
|
67
|
-
Determine the nozzle configuration based on the starting and
|
|
68
|
-
ending nozzle.
|
|
69
|
-
"""
|
|
70
|
-
if physical_rows == current_rows and physical_cols == current_cols:
|
|
71
|
-
return NozzleConfigurationType.FULL
|
|
72
|
-
if len(current_rows) == 1 and len(current_cols) == 1:
|
|
73
|
-
return NozzleConfigurationType.SINGLE
|
|
74
|
-
if len(current_rows) == 1:
|
|
75
|
-
return NozzleConfigurationType.ROW
|
|
76
|
-
if len(current_cols) == 1:
|
|
77
|
-
return NozzleConfigurationType.COLUMN
|
|
78
|
-
return NozzleConfigurationType.SUBRECT
|
|
79
|
-
|
|
80
|
-
|
|
81
46
|
@dataclass
|
|
82
47
|
class NozzleMap:
|
|
83
48
|
"""
|
|
@@ -113,6 +78,28 @@ class NozzleMap:
|
|
|
113
78
|
full_instrument_rows: Dict[str, List[str]]
|
|
114
79
|
#: A map of all the rows of an instrument
|
|
115
80
|
|
|
81
|
+
@classmethod
|
|
82
|
+
def determine_nozzle_configuration(
|
|
83
|
+
cls,
|
|
84
|
+
physical_rows: "OrderedDict[str, List[str]]",
|
|
85
|
+
current_rows: "OrderedDict[str, List[str]]",
|
|
86
|
+
physical_cols: "OrderedDict[str, List[str]]",
|
|
87
|
+
current_cols: "OrderedDict[str, List[str]]",
|
|
88
|
+
) -> "NozzleConfigurationType":
|
|
89
|
+
"""
|
|
90
|
+
Determine the nozzle configuration based on the starting and
|
|
91
|
+
ending nozzle.
|
|
92
|
+
"""
|
|
93
|
+
if physical_rows == current_rows and physical_cols == current_cols:
|
|
94
|
+
return NozzleConfigurationType.FULL
|
|
95
|
+
if len(current_rows) == 1 and len(current_cols) == 1:
|
|
96
|
+
return NozzleConfigurationType.SINGLE
|
|
97
|
+
if len(current_rows) == 1:
|
|
98
|
+
return NozzleConfigurationType.ROW
|
|
99
|
+
if len(current_cols) == 1:
|
|
100
|
+
return NozzleConfigurationType.COLUMN
|
|
101
|
+
return NozzleConfigurationType.SUBRECT
|
|
102
|
+
|
|
116
103
|
def __str__(self) -> str:
|
|
117
104
|
return f"back_left_nozzle: {self.back_left} front_right_nozzle: {self.front_right} configuration: {self.configuration}"
|
|
118
105
|
|
|
@@ -216,6 +203,16 @@ class NozzleMap:
|
|
|
216
203
|
"""The total number of active nozzles in the configuration, and thus the number of tips that will be picked up."""
|
|
217
204
|
return len(self.map_store)
|
|
218
205
|
|
|
206
|
+
@property
|
|
207
|
+
def physical_nozzle_count(self) -> int:
|
|
208
|
+
"""The number of physical nozzles, regardless of configuration."""
|
|
209
|
+
return len(self.full_instrument_map_store)
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def active_nozzles(self) -> list[str]:
|
|
213
|
+
"""An unstructured list of all nozzles active in the configuration."""
|
|
214
|
+
return list(self.map_store.keys())
|
|
215
|
+
|
|
219
216
|
@classmethod
|
|
220
217
|
def build( # noqa: C901
|
|
221
218
|
cls,
|
|
@@ -274,7 +271,7 @@ class NozzleMap:
|
|
|
274
271
|
)
|
|
275
272
|
|
|
276
273
|
if (
|
|
277
|
-
|
|
274
|
+
cls.determine_nozzle_configuration(
|
|
278
275
|
physical_rows, rows, physical_columns, columns
|
|
279
276
|
)
|
|
280
277
|
!= NozzleConfigurationType.FULL
|
|
@@ -289,6 +286,7 @@ class NozzleMap:
|
|
|
289
286
|
if valid_nozzle_maps.maps[map_key] == list(map_store.keys()):
|
|
290
287
|
validated_map_key = map_key
|
|
291
288
|
break
|
|
289
|
+
|
|
292
290
|
if validated_map_key is None:
|
|
293
291
|
raise IncompatibleNozzleConfiguration(
|
|
294
292
|
"Attempted Nozzle Configuration does not match any approved map layout for the current pipette."
|
|
@@ -302,7 +300,7 @@ class NozzleMap:
|
|
|
302
300
|
full_instrument_map_store=physical_nozzles,
|
|
303
301
|
full_instrument_rows=physical_rows,
|
|
304
302
|
columns=columns,
|
|
305
|
-
configuration=
|
|
303
|
+
configuration=cls.determine_nozzle_configuration(
|
|
306
304
|
physical_rows, rows, physical_columns, columns
|
|
307
305
|
),
|
|
308
306
|
)
|
|
@@ -968,7 +968,7 @@ def load_attitude_matrix(to_default: bool = True) -> DeckCalibration:
|
|
|
968
968
|
return DeckCalibration(
|
|
969
969
|
attitude=apply_machine_transform(calibration_data.attitude),
|
|
970
970
|
source=calibration_data.source,
|
|
971
|
-
status=types.CalibrationStatus(**calibration_data.status.
|
|
971
|
+
status=types.CalibrationStatus(**calibration_data.status.model_dump()),
|
|
972
972
|
belt_attitude=calibration_data.attitude,
|
|
973
973
|
last_modified=calibration_data.lastModified,
|
|
974
974
|
pipette_calibrated_with=calibration_data.pipetteCalibratedWith,
|
|
@@ -32,6 +32,7 @@ from opentrons_shared_data.pipette.types import (
|
|
|
32
32
|
)
|
|
33
33
|
from opentrons_shared_data.pipette import (
|
|
34
34
|
pipette_load_name_conversions as pipette_load_name,
|
|
35
|
+
pipette_definition,
|
|
35
36
|
)
|
|
36
37
|
from opentrons_shared_data.robot.types import RobotType
|
|
37
38
|
|
|
@@ -45,7 +46,6 @@ from opentrons.config.types import (
|
|
|
45
46
|
LiquidProbeSettings,
|
|
46
47
|
)
|
|
47
48
|
from opentrons.drivers.rpi_drivers.types import USBPort, PortGroup
|
|
48
|
-
from opentrons.hardware_control.nozzle_manager import NozzleConfigurationType
|
|
49
49
|
from opentrons_shared_data.errors.exceptions import (
|
|
50
50
|
EnumeratedError,
|
|
51
51
|
PythonException,
|
|
@@ -98,6 +98,7 @@ from .types import (
|
|
|
98
98
|
EstopState,
|
|
99
99
|
HardwareFeatureFlags,
|
|
100
100
|
FailedTipStateCheck,
|
|
101
|
+
PipetteSensorResponseQueue,
|
|
101
102
|
)
|
|
102
103
|
from .errors import (
|
|
103
104
|
UpdateOngoingError,
|
|
@@ -143,8 +144,6 @@ from .backends.types import HWStopCondition
|
|
|
143
144
|
from .backends.flex_protocol import FlexBackend
|
|
144
145
|
from .backends.ot3simulator import OT3Simulator
|
|
145
146
|
from .backends.errors import SubsystemUpdating
|
|
146
|
-
from opentrons_hardware.firmware_bindings.constants import SensorId
|
|
147
|
-
from opentrons_hardware.sensors.types import SensorDataType
|
|
148
147
|
|
|
149
148
|
mod_log = logging.getLogger(__name__)
|
|
150
149
|
|
|
@@ -299,8 +298,11 @@ class OT3API(
|
|
|
299
298
|
async def set_system_constraints_for_plunger_acceleration(
|
|
300
299
|
self, mount: OT3Mount, acceleration: float
|
|
301
300
|
) -> None:
|
|
301
|
+
high_speed_pipette = self._pipette_handler.get_pipette(
|
|
302
|
+
mount
|
|
303
|
+
).is_high_speed_pipette()
|
|
302
304
|
self._backend.update_constraints_for_plunger_acceleration(
|
|
303
|
-
mount, acceleration, self._gantry_load
|
|
305
|
+
mount, acceleration, self._gantry_load, high_speed_pipette
|
|
304
306
|
)
|
|
305
307
|
|
|
306
308
|
@contextlib.asynccontextmanager
|
|
@@ -353,7 +355,9 @@ class OT3API(
|
|
|
353
355
|
def _reset_last_mount(self) -> None:
|
|
354
356
|
self._last_moved_mount = None
|
|
355
357
|
|
|
356
|
-
def
|
|
358
|
+
def get_deck_from_machine(
|
|
359
|
+
self, machine_pos: Dict[Axis, float]
|
|
360
|
+
) -> Dict[Axis, float]:
|
|
357
361
|
return deck_from_machine(
|
|
358
362
|
machine_pos=machine_pos,
|
|
359
363
|
attitude=self._robot_calibration.deck_calibration.attitude,
|
|
@@ -633,10 +637,31 @@ class OT3API(
|
|
|
633
637
|
self._feature_flags.use_old_aspiration_functions,
|
|
634
638
|
)
|
|
635
639
|
self._pipette_handler.hardware_instruments[mount] = p
|
|
640
|
+
|
|
641
|
+
if config is not None:
|
|
642
|
+
self._set_pressure_sensor_available(mount, instrument_config=config)
|
|
643
|
+
|
|
636
644
|
# TODO (lc 12-5-2022) Properly support backwards compatibility
|
|
637
645
|
# when applicable
|
|
638
646
|
return skipped
|
|
639
647
|
|
|
648
|
+
def get_pressure_sensor_available(self, mount: OT3Mount) -> bool:
|
|
649
|
+
pip_axis = Axis.of_main_tool_actuator(mount)
|
|
650
|
+
return self._backend.get_pressure_sensor_available(pip_axis)
|
|
651
|
+
|
|
652
|
+
def _set_pressure_sensor_available(
|
|
653
|
+
self,
|
|
654
|
+
mount: OT3Mount,
|
|
655
|
+
instrument_config: pipette_definition.PipetteConfigurations,
|
|
656
|
+
) -> None:
|
|
657
|
+
pressure_sensor_available = (
|
|
658
|
+
"pressure" in instrument_config.available_sensors.sensors
|
|
659
|
+
)
|
|
660
|
+
pip_axis = Axis.of_main_tool_actuator(mount)
|
|
661
|
+
self._backend.set_pressure_sensor_available(
|
|
662
|
+
pipette_axis=pip_axis, available=pressure_sensor_available
|
|
663
|
+
)
|
|
664
|
+
|
|
640
665
|
async def cache_gripper(self, instrument_data: AttachedGripper) -> bool:
|
|
641
666
|
"""Set up gripper based on scanned information."""
|
|
642
667
|
grip_cal = load_gripper_calibration_offset(instrument_data.get("id"))
|
|
@@ -775,6 +800,8 @@ class OT3API(
|
|
|
775
800
|
"""
|
|
776
801
|
Function to update motor estimation for a set of axes
|
|
777
802
|
"""
|
|
803
|
+
await self._backend.update_motor_status()
|
|
804
|
+
|
|
778
805
|
if axes is None:
|
|
779
806
|
axes = [ax for ax in Axis]
|
|
780
807
|
|
|
@@ -943,8 +970,8 @@ class OT3API(
|
|
|
943
970
|
):
|
|
944
971
|
# move toward home until a safe distance
|
|
945
972
|
await self._backend.tip_action(
|
|
946
|
-
origin=
|
|
947
|
-
targets=[(
|
|
973
|
+
origin=current_pos_float,
|
|
974
|
+
targets=[(self._config.safe_home_distance, 400)],
|
|
948
975
|
)
|
|
949
976
|
|
|
950
977
|
# update current position
|
|
@@ -1021,14 +1048,14 @@ class OT3API(
|
|
|
1021
1048
|
|
|
1022
1049
|
async def _cache_current_position(self) -> Dict[Axis, float]:
|
|
1023
1050
|
"""Cache current position from backend and return in absolute deck coords."""
|
|
1024
|
-
self._current_position = self.
|
|
1051
|
+
self._current_position = self.get_deck_from_machine(
|
|
1025
1052
|
await self._backend.update_position()
|
|
1026
1053
|
)
|
|
1027
1054
|
return self._current_position
|
|
1028
1055
|
|
|
1029
1056
|
async def _cache_encoder_position(self) -> Dict[Axis, float]:
|
|
1030
1057
|
"""Cache encoder position from backend and return in absolute deck coords."""
|
|
1031
|
-
self._encoder_position = self.
|
|
1058
|
+
self._encoder_position = self.get_deck_from_machine(
|
|
1032
1059
|
await self._backend.update_encoder_position()
|
|
1033
1060
|
)
|
|
1034
1061
|
if self.has_gripper():
|
|
@@ -1228,7 +1255,9 @@ class OT3API(
|
|
|
1228
1255
|
message=f"{axis} is not present", detail={"axis": str(axis)}
|
|
1229
1256
|
)
|
|
1230
1257
|
|
|
1258
|
+
self._log.info(f"Attempting to move {position} with speed {speed}.")
|
|
1231
1259
|
if not self._backend.check_encoder_status(list(position.keys())):
|
|
1260
|
+
self._log.info("Calling home in move_axes")
|
|
1232
1261
|
await self.home()
|
|
1233
1262
|
self._assert_motor_ok(list(position.keys()))
|
|
1234
1263
|
|
|
@@ -1439,6 +1468,10 @@ class OT3API(
|
|
|
1439
1468
|
check_motion_bounds(to_check, target_position, bounds, check_bounds)
|
|
1440
1469
|
self._log.info(f"Move: deck {target_position} becomes machine {machine_pos}")
|
|
1441
1470
|
origin = await self._backend.update_position()
|
|
1471
|
+
|
|
1472
|
+
if self._gantry_load == GantryLoad.HIGH_THROUGHPUT:
|
|
1473
|
+
origin[Axis.Q] = self._backend.gear_motor_position or 0.0
|
|
1474
|
+
|
|
1442
1475
|
async with contextlib.AsyncExitStack() as stack:
|
|
1443
1476
|
if acquire_lock:
|
|
1444
1477
|
await stack.enter_async_context(self._motion_lock)
|
|
@@ -1640,7 +1673,12 @@ class OT3API(
|
|
|
1640
1673
|
await self._backend.disengage_axes(which)
|
|
1641
1674
|
|
|
1642
1675
|
async def engage_axes(self, which: List[Axis]) -> None:
|
|
1643
|
-
await self._backend.engage_axes(
|
|
1676
|
+
await self._backend.engage_axes(
|
|
1677
|
+
[axis for axis in which if self._backend.axis_is_present(axis)]
|
|
1678
|
+
)
|
|
1679
|
+
|
|
1680
|
+
def axis_is_present(self, axis: Axis) -> bool:
|
|
1681
|
+
return self._backend.axis_is_present(axis)
|
|
1644
1682
|
|
|
1645
1683
|
async def get_limit_switches(self) -> Dict[Axis, bool]:
|
|
1646
1684
|
res = await self._backend.get_limit_switches()
|
|
@@ -1826,7 +1864,7 @@ class OT3API(
|
|
|
1826
1864
|
if (
|
|
1827
1865
|
self.gantry_load == GantryLoad.HIGH_THROUGHPUT
|
|
1828
1866
|
and instrument.nozzle_manager.current_configuration.configuration
|
|
1829
|
-
== NozzleConfigurationType.FULL
|
|
1867
|
+
== top_types.NozzleConfigurationType.FULL
|
|
1830
1868
|
):
|
|
1831
1869
|
spec = self._pipette_handler.plan_ht_pick_up_tip(
|
|
1832
1870
|
instrument.nozzle_manager.current_configuration.tip_count
|
|
@@ -2156,8 +2194,8 @@ class OT3API(
|
|
|
2156
2194
|
# only move tip motors if they are not already below the sensor
|
|
2157
2195
|
if tip_motor_pos_float < tip_presence_check_target:
|
|
2158
2196
|
await self._backend.tip_action(
|
|
2159
|
-
origin=
|
|
2160
|
-
targets=[(
|
|
2197
|
+
origin=tip_motor_pos_float,
|
|
2198
|
+
targets=[(tip_presence_check_target, 400)],
|
|
2161
2199
|
)
|
|
2162
2200
|
try:
|
|
2163
2201
|
yield
|
|
@@ -2228,11 +2266,11 @@ class OT3API(
|
|
|
2228
2266
|
gear_origin_float = self._backend.gear_motor_position or 0.0
|
|
2229
2267
|
|
|
2230
2268
|
move_targets = [
|
|
2231
|
-
(
|
|
2269
|
+
(move_segment.distance, move_segment.speed or 400)
|
|
2232
2270
|
for move_segment in pipette_spec
|
|
2233
2271
|
]
|
|
2234
2272
|
await self._backend.tip_action(
|
|
2235
|
-
origin=
|
|
2273
|
+
origin=gear_origin_float, targets=move_targets
|
|
2236
2274
|
)
|
|
2237
2275
|
await self.home_gear_motors()
|
|
2238
2276
|
|
|
@@ -2557,7 +2595,7 @@ class OT3API(
|
|
|
2557
2595
|
mount: Union[top_types.Mount, OT3Mount],
|
|
2558
2596
|
critical_point: Optional[CriticalPoint] = None,
|
|
2559
2597
|
) -> float:
|
|
2560
|
-
carriage_pos = self.
|
|
2598
|
+
carriage_pos = self.get_deck_from_machine(self._backend.home_position())
|
|
2561
2599
|
pos_at_home = self._effector_pos_from_carriage_pos(
|
|
2562
2600
|
OT3Mount.from_mount(mount), carriage_pos, critical_point
|
|
2563
2601
|
)
|
|
@@ -2639,10 +2677,9 @@ class OT3API(
|
|
|
2639
2677
|
probe_settings: LiquidProbeSettings,
|
|
2640
2678
|
probe: InstrumentProbeType,
|
|
2641
2679
|
p_travel: float,
|
|
2680
|
+
z_offset_for_plunger_prep: float,
|
|
2642
2681
|
force_both_sensors: bool = False,
|
|
2643
|
-
response_queue: Optional[
|
|
2644
|
-
asyncio.Queue[Dict[SensorId, List[SensorDataType]]]
|
|
2645
|
-
] = None,
|
|
2682
|
+
response_queue: Optional[PipetteSensorResponseQueue] = None,
|
|
2646
2683
|
) -> float:
|
|
2647
2684
|
plunger_direction = -1 if probe_settings.aspirate_while_sensing else 1
|
|
2648
2685
|
end_z = await self._backend.liquid_probe(
|
|
@@ -2653,13 +2690,14 @@ class OT3API(
|
|
|
2653
2690
|
probe_settings.sensor_threshold_pascals,
|
|
2654
2691
|
probe_settings.plunger_impulse_time,
|
|
2655
2692
|
probe_settings.samples_for_baselining,
|
|
2693
|
+
z_offset_for_plunger_prep,
|
|
2656
2694
|
probe=probe,
|
|
2657
2695
|
force_both_sensors=force_both_sensors,
|
|
2658
2696
|
response_queue=response_queue,
|
|
2659
2697
|
)
|
|
2660
2698
|
machine_pos = await self._backend.update_position()
|
|
2661
2699
|
machine_pos[Axis.by_mount(mount)] = end_z
|
|
2662
|
-
deck_end_z = self.
|
|
2700
|
+
deck_end_z = self.get_deck_from_machine(machine_pos)[Axis.by_mount(mount)]
|
|
2663
2701
|
offset = offset_for_mount(
|
|
2664
2702
|
mount,
|
|
2665
2703
|
top_types.Point(*self._config.left_mount_offset),
|
|
@@ -2676,9 +2714,7 @@ class OT3API(
|
|
|
2676
2714
|
probe_settings: Optional[LiquidProbeSettings] = None,
|
|
2677
2715
|
probe: Optional[InstrumentProbeType] = None,
|
|
2678
2716
|
force_both_sensors: bool = False,
|
|
2679
|
-
response_queue: Optional[
|
|
2680
|
-
asyncio.Queue[Dict[SensorId, List[SensorDataType]]]
|
|
2681
|
-
] = None,
|
|
2717
|
+
response_queue: Optional[PipetteSensorResponseQueue] = None,
|
|
2682
2718
|
) -> float:
|
|
2683
2719
|
"""Search for and return liquid level height.
|
|
2684
2720
|
|
|
@@ -2804,6 +2840,7 @@ class OT3API(
|
|
|
2804
2840
|
probe_settings,
|
|
2805
2841
|
checked_probe,
|
|
2806
2842
|
plunger_travel_mm + sensor_baseline_plunger_move_mm,
|
|
2843
|
+
z_offset_for_plunger_prep,
|
|
2807
2844
|
force_both_sensors,
|
|
2808
2845
|
response_queue,
|
|
2809
2846
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import Dict, Optional
|
|
2
2
|
from typing_extensions import Protocol
|
|
3
3
|
|
|
4
|
-
from ..types import SubSystem, SubSystemState
|
|
4
|
+
from ..types import SubSystem, SubSystemState, Axis
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class HardwareManager(Protocol):
|
|
@@ -45,3 +45,7 @@ class HardwareManager(Protocol):
|
|
|
45
45
|
async def get_serial_number(self) -> Optional[str]:
|
|
46
46
|
"""Get the robot serial number, if provisioned. If not provisioned, will be None."""
|
|
47
47
|
...
|
|
48
|
+
|
|
49
|
+
def axis_is_present(self, axis: Axis) -> bool:
|
|
50
|
+
"""Get whether a motor axis is present on the machine."""
|
|
51
|
+
...
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
from typing_extensions import Protocol
|
|
3
3
|
|
|
4
|
+
from opentrons.types import Point
|
|
5
|
+
from opentrons.hardware_control.types import CriticalPoint
|
|
4
6
|
from .types import MountArgType, CalibrationType, ConfigType
|
|
5
7
|
|
|
6
8
|
from .instrument_configurer import InstrumentConfigurer
|
|
@@ -16,6 +18,22 @@ class LiquidHandler(
|
|
|
16
18
|
Calibratable[CalibrationType],
|
|
17
19
|
Protocol[CalibrationType, MountArgType, ConfigType],
|
|
18
20
|
):
|
|
21
|
+
def critical_point_for(
|
|
22
|
+
self,
|
|
23
|
+
mount: MountArgType,
|
|
24
|
+
cp_override: Optional[CriticalPoint] = None,
|
|
25
|
+
) -> Point:
|
|
26
|
+
"""
|
|
27
|
+
Determine the current critical point for the specified mount.
|
|
28
|
+
|
|
29
|
+
:param mount: A robot mount that the instrument is on.
|
|
30
|
+
:param cp_override: The critical point override to use.
|
|
31
|
+
|
|
32
|
+
If no critical point override is specified, the robot defaults to nozzle location `A1` or the mount critical point.
|
|
33
|
+
:return: Point.
|
|
34
|
+
"""
|
|
35
|
+
...
|
|
36
|
+
|
|
19
37
|
async def update_nozzle_configuration_for_mount(
|
|
20
38
|
self,
|
|
21
39
|
mount: MountArgType,
|
|
@@ -9,6 +9,12 @@ from .types import MountArgType
|
|
|
9
9
|
class MotionController(Protocol[MountArgType]):
|
|
10
10
|
"""Protocol specifying fundamental motion controls."""
|
|
11
11
|
|
|
12
|
+
def get_deck_from_machine(
|
|
13
|
+
self, machine_pos: Dict[Axis, float]
|
|
14
|
+
) -> Dict[Axis, float]:
|
|
15
|
+
"""Convert machine coordinates to deck coordinates."""
|
|
16
|
+
...
|
|
17
|
+
|
|
12
18
|
async def halt(self, disengage_before_stopping: bool = False) -> None:
|
|
13
19
|
"""Immediately stop motion.
|
|
14
20
|
|
|
@@ -154,7 +154,7 @@ def load_attitude_matrix() -> DeckCalibration:
|
|
|
154
154
|
return DeckCalibration(
|
|
155
155
|
attitude=calibration_data.attitude,
|
|
156
156
|
source=calibration_data.source,
|
|
157
|
-
status=types.CalibrationStatus(**calibration_data.status.
|
|
157
|
+
status=types.CalibrationStatus(**calibration_data.status.model_dump()),
|
|
158
158
|
last_modified=calibration_data.last_modified,
|
|
159
159
|
pipette_calibrated_with=calibration_data.pipette_calibrated_with,
|
|
160
160
|
tiprack=calibration_data.tiprack,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from asyncio import Queue
|
|
1
2
|
import enum
|
|
2
3
|
import logging
|
|
3
4
|
from dataclasses import dataclass
|
|
@@ -712,3 +713,63 @@ class FailedTipStateCheck(RuntimeError):
|
|
|
712
713
|
super().__init__(
|
|
713
714
|
f"Expected tip state {expected_state}, but received {actual_state}."
|
|
714
715
|
)
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
@enum.unique
|
|
719
|
+
class PipetteSensorId(int, enum.Enum):
|
|
720
|
+
"""Sensor IDs available.
|
|
721
|
+
|
|
722
|
+
Not to be confused with SensorType. This is the ID value that separate
|
|
723
|
+
two or more of the same type of sensor within a system.
|
|
724
|
+
|
|
725
|
+
Note that this is a copy of an enum defined in opentrons_hardware.firmware_bindings.constants. That version
|
|
726
|
+
is authoritative; this version is here because this data is exposed above the hardware control layer and
|
|
727
|
+
therefore needs a typing source here so that we don't create a dependency on the internal hardware package.
|
|
728
|
+
"""
|
|
729
|
+
|
|
730
|
+
S0 = 0x0
|
|
731
|
+
S1 = 0x1
|
|
732
|
+
UNUSED = 0x2
|
|
733
|
+
BOTH = 0x3
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
@enum.unique
|
|
737
|
+
class PipetteSensorType(int, enum.Enum):
|
|
738
|
+
"""Sensor types available.
|
|
739
|
+
|
|
740
|
+
Note that this is a copy of an enum defined in opentrons_hardware.firmware_bindings.constants. That version
|
|
741
|
+
is authoritative; this version is here because this data is exposed above the hardware control layer and
|
|
742
|
+
therefore needs a typing source here so that we don't create a dependency on the internal hardware package.
|
|
743
|
+
"""
|
|
744
|
+
|
|
745
|
+
tip = 0x00
|
|
746
|
+
capacitive = 0x01
|
|
747
|
+
environment = 0x02
|
|
748
|
+
pressure = 0x03
|
|
749
|
+
pressure_temperature = 0x04
|
|
750
|
+
humidity = 0x05
|
|
751
|
+
temperature = 0x06
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
@dataclass(frozen=True)
|
|
755
|
+
class PipetteSensorData:
|
|
756
|
+
"""Sensor data from a monitored sensor.
|
|
757
|
+
|
|
758
|
+
Note that this is a copy of an enum defined in opentrons_hardware.firmware_bindings.constants. That version
|
|
759
|
+
is authoritative; this version is here because this data is exposed above the hardware control layer and
|
|
760
|
+
therefore needs a typing source here so that we don't create a dependency on the internal hardware package.
|
|
761
|
+
"""
|
|
762
|
+
|
|
763
|
+
sensor_type: PipetteSensorType
|
|
764
|
+
_as_int: int
|
|
765
|
+
_as_float: float
|
|
766
|
+
|
|
767
|
+
def to_float(self) -> float:
|
|
768
|
+
return self._as_float
|
|
769
|
+
|
|
770
|
+
@property
|
|
771
|
+
def to_int(self) -> int:
|
|
772
|
+
return self._as_int
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
PipetteSensorResponseQueue = Queue[Dict[PipetteSensorId, List[PipetteSensorData]]]
|
|
@@ -30,7 +30,16 @@ from .module_contexts import (
|
|
|
30
30
|
)
|
|
31
31
|
from .disposal_locations import TrashBin, WasteChute
|
|
32
32
|
from ._liquid import Liquid, LiquidClass
|
|
33
|
-
from ._types import
|
|
33
|
+
from ._types import (
|
|
34
|
+
OFF_DECK,
|
|
35
|
+
PLUNGER_BLOWOUT,
|
|
36
|
+
PLUNGER_TOP,
|
|
37
|
+
PLUNGER_BOTTOM,
|
|
38
|
+
PLUNGER_DROPTIP,
|
|
39
|
+
ASPIRATE_ACTION,
|
|
40
|
+
DISPENSE_ACTION,
|
|
41
|
+
BLOWOUT_ACTION,
|
|
42
|
+
)
|
|
34
43
|
from ._nozzle_layout import (
|
|
35
44
|
COLUMN,
|
|
36
45
|
PARTIAL_COLUMN,
|
|
@@ -69,12 +78,22 @@ __all__ = [
|
|
|
69
78
|
"Liquid",
|
|
70
79
|
"LiquidClass",
|
|
71
80
|
"Parameters",
|
|
81
|
+
# Partial Tip types
|
|
72
82
|
"COLUMN",
|
|
73
83
|
"PARTIAL_COLUMN",
|
|
74
84
|
"SINGLE",
|
|
75
85
|
"ROW",
|
|
76
86
|
"ALL",
|
|
87
|
+
# Deck location types
|
|
77
88
|
"OFF_DECK",
|
|
89
|
+
# Pipette plunger types
|
|
90
|
+
"PLUNGER_BLOWOUT",
|
|
91
|
+
"PLUNGER_TOP",
|
|
92
|
+
"PLUNGER_BOTTOM",
|
|
93
|
+
"PLUNGER_DROPTIP",
|
|
94
|
+
"ASPIRATE_ACTION",
|
|
95
|
+
"DISPENSE_ACTION",
|
|
96
|
+
"BLOWOUT_ACTION",
|
|
78
97
|
"RuntimeParameterRequiredError",
|
|
79
98
|
"CSVParameter",
|
|
80
99
|
# For internal Opentrons use only:
|