opentrons 8.3.2__py2.py3-none-any.whl → 8.4.0__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/ot2/mark_bad_calibration.py +2 -0
- opentrons/calibration_storage/ot2/tip_length.py +6 -6
- opentrons/config/advanced_settings.py +9 -11
- opentrons/config/feature_flags.py +0 -4
- opentrons/config/reset.py +7 -2
- opentrons/drivers/asyncio/communication/__init__.py +2 -0
- opentrons/drivers/asyncio/communication/async_serial.py +4 -0
- opentrons/drivers/asyncio/communication/errors.py +41 -8
- opentrons/drivers/asyncio/communication/serial_connection.py +36 -10
- opentrons/drivers/flex_stacker/__init__.py +9 -3
- opentrons/drivers/flex_stacker/abstract.py +140 -15
- opentrons/drivers/flex_stacker/driver.py +593 -47
- opentrons/drivers/flex_stacker/errors.py +64 -0
- opentrons/drivers/flex_stacker/simulator.py +222 -24
- opentrons/drivers/flex_stacker/types.py +211 -15
- opentrons/drivers/flex_stacker/utils.py +19 -0
- opentrons/execute.py +4 -2
- opentrons/hardware_control/api.py +5 -0
- opentrons/hardware_control/backends/flex_protocol.py +4 -0
- opentrons/hardware_control/backends/ot3controller.py +12 -1
- opentrons/hardware_control/backends/ot3simulator.py +3 -0
- opentrons/hardware_control/backends/subsystem_manager.py +8 -4
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +10 -6
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +59 -6
- opentrons/hardware_control/modules/__init__.py +12 -1
- opentrons/hardware_control/modules/absorbance_reader.py +11 -9
- opentrons/hardware_control/modules/flex_stacker.py +498 -0
- opentrons/hardware_control/modules/heater_shaker.py +12 -10
- opentrons/hardware_control/modules/magdeck.py +5 -1
- opentrons/hardware_control/modules/tempdeck.py +5 -1
- opentrons/hardware_control/modules/thermocycler.py +15 -14
- opentrons/hardware_control/modules/types.py +191 -1
- opentrons/hardware_control/modules/utils.py +3 -0
- opentrons/hardware_control/motion_utilities.py +20 -0
- opentrons/hardware_control/ot3api.py +145 -15
- opentrons/hardware_control/protocols/liquid_handler.py +47 -1
- opentrons/hardware_control/types.py +6 -0
- opentrons/legacy_commands/commands.py +102 -5
- opentrons/legacy_commands/helpers.py +74 -1
- opentrons/legacy_commands/types.py +33 -2
- opentrons/protocol_api/__init__.py +2 -0
- opentrons/protocol_api/_liquid.py +39 -8
- opentrons/protocol_api/_liquid_properties.py +20 -19
- opentrons/protocol_api/_transfer_liquid_validation.py +91 -0
- opentrons/protocol_api/core/common.py +3 -1
- opentrons/protocol_api/core/engine/deck_conflict.py +11 -1
- opentrons/protocol_api/core/engine/instrument.py +1356 -107
- opentrons/protocol_api/core/engine/labware.py +8 -4
- opentrons/protocol_api/core/engine/load_labware_params.py +68 -10
- opentrons/protocol_api/core/engine/module_core.py +118 -2
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +6 -14
- opentrons/protocol_api/core/engine/protocol.py +253 -11
- opentrons/protocol_api/core/engine/stringify.py +19 -8
- opentrons/protocol_api/core/engine/transfer_components_executor.py +858 -0
- opentrons/protocol_api/core/engine/well.py +73 -5
- opentrons/protocol_api/core/instrument.py +71 -21
- opentrons/protocol_api/core/labware.py +6 -2
- opentrons/protocol_api/core/legacy/labware_offset_provider.py +7 -3
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +76 -49
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +8 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +36 -0
- opentrons/protocol_api/core/legacy/legacy_well_core.py +27 -2
- opentrons/protocol_api/core/legacy/load_info.py +4 -12
- opentrons/protocol_api/core/legacy/module_geometry.py +6 -1
- opentrons/protocol_api/core/legacy/well_geometry.py +3 -3
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +73 -23
- opentrons/protocol_api/core/module.py +43 -0
- opentrons/protocol_api/core/protocol.py +33 -0
- opentrons/protocol_api/core/well.py +23 -2
- opentrons/protocol_api/instrument_context.py +454 -150
- opentrons/protocol_api/labware.py +98 -50
- opentrons/protocol_api/module_contexts.py +140 -0
- opentrons/protocol_api/protocol_context.py +163 -19
- opentrons/protocol_api/validation.py +51 -41
- opentrons/protocol_engine/__init__.py +21 -2
- opentrons/protocol_engine/actions/actions.py +5 -5
- opentrons/protocol_engine/clients/sync_client.py +6 -0
- opentrons/protocol_engine/commands/__init__.py +66 -36
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +0 -1
- opentrons/protocol_engine/commands/air_gap_in_place.py +3 -2
- opentrons/protocol_engine/commands/aspirate.py +6 -2
- opentrons/protocol_engine/commands/aspirate_in_place.py +3 -1
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +210 -0
- opentrons/protocol_engine/commands/blow_out.py +2 -0
- opentrons/protocol_engine/commands/blow_out_in_place.py +4 -1
- opentrons/protocol_engine/commands/command_unions.py +102 -33
- opentrons/protocol_engine/commands/configure_for_volume.py +3 -0
- opentrons/protocol_engine/commands/dispense.py +3 -1
- opentrons/protocol_engine/commands/dispense_in_place.py +3 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
- opentrons/protocol_engine/commands/drop_tip.py +23 -1
- opentrons/protocol_engine/commands/flex_stacker/__init__.py +106 -0
- opentrons/protocol_engine/commands/flex_stacker/close_latch.py +72 -0
- opentrons/protocol_engine/commands/flex_stacker/common.py +15 -0
- opentrons/protocol_engine/commands/flex_stacker/empty.py +161 -0
- opentrons/protocol_engine/commands/flex_stacker/fill.py +164 -0
- opentrons/protocol_engine/commands/flex_stacker/open_latch.py +70 -0
- opentrons/protocol_engine/commands/flex_stacker/prepare_shuttle.py +112 -0
- opentrons/protocol_engine/commands/flex_stacker/retrieve.py +394 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +190 -0
- opentrons/protocol_engine/commands/flex_stacker/store.py +291 -0
- opentrons/protocol_engine/commands/generate_command_schema.py +31 -2
- opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
- opentrons/protocol_engine/commands/liquid_probe.py +27 -13
- opentrons/protocol_engine/commands/load_labware.py +42 -39
- opentrons/protocol_engine/commands/load_lid.py +21 -13
- opentrons/protocol_engine/commands/load_lid_stack.py +130 -47
- opentrons/protocol_engine/commands/load_module.py +18 -17
- opentrons/protocol_engine/commands/load_pipette.py +3 -0
- opentrons/protocol_engine/commands/move_labware.py +139 -20
- opentrons/protocol_engine/commands/move_to_well.py +5 -11
- opentrons/protocol_engine/commands/pick_up_tip.py +5 -2
- opentrons/protocol_engine/commands/pipetting_common.py +159 -8
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +15 -5
- opentrons/protocol_engine/commands/{evotip_dispense.py → pressure_dispense.py} +33 -34
- opentrons/protocol_engine/commands/reload_labware.py +6 -19
- opentrons/protocol_engine/commands/{evotip_seal_pipette.py → seal_pipette_to_tip.py} +97 -76
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +3 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +6 -1
- opentrons/protocol_engine/commands/{evotip_unseal_pipette.py → unseal_pipette_from_tip.py} +31 -40
- opentrons/protocol_engine/errors/__init__.py +10 -0
- opentrons/protocol_engine/errors/exceptions.py +62 -0
- opentrons/protocol_engine/execution/equipment.py +123 -106
- opentrons/protocol_engine/execution/labware_movement.py +8 -6
- opentrons/protocol_engine/execution/pipetting.py +235 -25
- opentrons/protocol_engine/execution/tip_handler.py +82 -32
- opentrons/protocol_engine/labware_offset_standardization.py +194 -0
- opentrons/protocol_engine/protocol_engine.py +22 -13
- opentrons/protocol_engine/resources/deck_configuration_provider.py +98 -2
- opentrons/protocol_engine/resources/deck_data_provider.py +1 -1
- opentrons/protocol_engine/resources/labware_data_provider.py +32 -12
- opentrons/protocol_engine/resources/labware_validation.py +7 -5
- opentrons/protocol_engine/slot_standardization.py +11 -23
- opentrons/protocol_engine/state/addressable_areas.py +84 -46
- opentrons/protocol_engine/state/frustum_helpers.py +36 -14
- opentrons/protocol_engine/state/geometry.py +892 -227
- opentrons/protocol_engine/state/labware.py +252 -55
- opentrons/protocol_engine/state/module_substates/__init__.py +4 -0
- opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +68 -0
- opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +22 -0
- opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +13 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +20 -0
- opentrons/protocol_engine/state/modules.py +210 -67
- opentrons/protocol_engine/state/pipettes.py +54 -0
- opentrons/protocol_engine/state/state.py +1 -1
- opentrons/protocol_engine/state/tips.py +14 -0
- opentrons/protocol_engine/state/update_types.py +180 -25
- opentrons/protocol_engine/state/wells.py +55 -9
- opentrons/protocol_engine/types/__init__.py +300 -0
- opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
- opentrons/protocol_engine/types/command_annotations.py +53 -0
- opentrons/protocol_engine/types/deck_configuration.py +72 -0
- opentrons/protocol_engine/types/execution.py +96 -0
- opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
- opentrons/protocol_engine/types/instrument.py +47 -0
- opentrons/protocol_engine/types/instrument_sensors.py +47 -0
- opentrons/protocol_engine/types/labware.py +111 -0
- opentrons/protocol_engine/types/labware_movement.py +22 -0
- opentrons/protocol_engine/types/labware_offset_location.py +111 -0
- opentrons/protocol_engine/types/labware_offset_vector.py +33 -0
- opentrons/protocol_engine/types/liquid.py +40 -0
- opentrons/protocol_engine/types/liquid_class.py +59 -0
- opentrons/protocol_engine/types/liquid_handling.py +13 -0
- opentrons/protocol_engine/types/liquid_level_detection.py +131 -0
- opentrons/protocol_engine/types/location.py +194 -0
- opentrons/protocol_engine/types/module.py +301 -0
- opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
- opentrons/protocol_engine/types/run_time_parameters.py +133 -0
- opentrons/protocol_engine/types/tip.py +18 -0
- opentrons/protocol_engine/types/util.py +21 -0
- opentrons/protocol_engine/types/well_position.py +124 -0
- opentrons/protocol_reader/extract_labware_definitions.py +7 -3
- opentrons/protocol_reader/file_format_validator.py +5 -3
- opentrons/protocol_runner/json_translator.py +4 -2
- opentrons/protocol_runner/legacy_command_mapper.py +6 -2
- opentrons/protocol_runner/run_orchestrator.py +4 -1
- opentrons/protocols/advanced_control/transfers/common.py +48 -1
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +204 -0
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/instrument.py +16 -3
- opentrons/protocols/labware.py +27 -23
- opentrons/protocols/models/__init__.py +0 -21
- opentrons/simulate.py +4 -2
- opentrons/types.py +20 -7
- opentrons/util/logging_config.py +94 -25
- opentrons/util/logging_queue_handler.py +61 -0
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/METADATA +4 -4
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/RECORD +192 -151
- opentrons/calibration_storage/ot2/models/defaults.py +0 -0
- opentrons/calibration_storage/ot3/models/defaults.py +0 -0
- opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
- opentrons/protocol_engine/types.py +0 -1311
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/LICENSE +0 -0
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/WHEEL +0 -0
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
NUMBER_OF_ZONES = 10
|
|
2
|
+
NUMBER_OF_BINS = 128
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def validate_histogram_frame(data: bytes, next_frame_id: int) -> bool:
|
|
6
|
+
"""Validate Histogram frame, Raise error if invalid."""
|
|
7
|
+
start_delimn = data[0]
|
|
8
|
+
assert (
|
|
9
|
+
start_delimn == 0x81 # histogram start byte
|
|
10
|
+
), f"Invalid delimn, {hex(start_delimn)} != 0x81."
|
|
11
|
+
frame_id = data[4]
|
|
12
|
+
assert (
|
|
13
|
+
next_frame_id == frame_id
|
|
14
|
+
), f"Invalid frame id, expected {next_frame_id} got {frame_id}."
|
|
15
|
+
frame_len = data[5]
|
|
16
|
+
assert (
|
|
17
|
+
frame_len == 128 # len is always 128
|
|
18
|
+
), f"Invalid frame length, expected 128 got {frame_len}."
|
|
19
|
+
return True
|
opentrons/execute.py
CHANGED
|
@@ -23,7 +23,9 @@ from typing import (
|
|
|
23
23
|
Union,
|
|
24
24
|
)
|
|
25
25
|
|
|
26
|
-
from opentrons_shared_data.labware.labware_definition import
|
|
26
|
+
from opentrons_shared_data.labware.labware_definition import (
|
|
27
|
+
labware_definition_type_adapter,
|
|
28
|
+
)
|
|
27
29
|
from opentrons_shared_data.robot.types import RobotType
|
|
28
30
|
|
|
29
31
|
from opentrons import protocol_api, __version__, should_use_ot3
|
|
@@ -560,7 +562,7 @@ def _create_live_context_pe(
|
|
|
560
562
|
# Non-async would use call_soon_threadsafe(), which makes the waiting harder.
|
|
561
563
|
async def add_all_extra_labware() -> None:
|
|
562
564
|
for labware_definition_dict in extra_labware.values():
|
|
563
|
-
labware_definition =
|
|
565
|
+
labware_definition = labware_definition_type_adapter.validate_python(
|
|
564
566
|
labware_definition_dict
|
|
565
567
|
)
|
|
566
568
|
pe.add_labware_definition(labware_definition)
|
|
@@ -58,6 +58,7 @@ from .types import (
|
|
|
58
58
|
SubSystem,
|
|
59
59
|
SubSystemState,
|
|
60
60
|
HardwareFeatureFlags,
|
|
61
|
+
TipScrapeType,
|
|
61
62
|
)
|
|
62
63
|
from . import modules
|
|
63
64
|
from .robot_calibration import (
|
|
@@ -1040,6 +1041,7 @@ class API(
|
|
|
1040
1041
|
mount: top_types.Mount,
|
|
1041
1042
|
volume: Optional[float] = None,
|
|
1042
1043
|
rate: float = 1.0,
|
|
1044
|
+
correction_volume: float = 0.0,
|
|
1043
1045
|
) -> None:
|
|
1044
1046
|
"""
|
|
1045
1047
|
Aspirate a volume of liquid (in microliters/uL) using this pipette.
|
|
@@ -1074,6 +1076,8 @@ class API(
|
|
|
1074
1076
|
volume: Optional[float] = None,
|
|
1075
1077
|
rate: float = 1.0,
|
|
1076
1078
|
push_out: Optional[float] = None,
|
|
1079
|
+
correction_volume: float = 0.0,
|
|
1080
|
+
is_full_dispense: bool = False,
|
|
1077
1081
|
) -> None:
|
|
1078
1082
|
"""
|
|
1079
1083
|
Dispense a volume of liquid in microliters(uL) using this pipette.
|
|
@@ -1253,6 +1257,7 @@ class API(
|
|
|
1253
1257
|
mount: top_types.Mount,
|
|
1254
1258
|
home_after: bool = True,
|
|
1255
1259
|
ignore_plunger: bool = False,
|
|
1260
|
+
scrape_type: TipScrapeType = TipScrapeType.NONE,
|
|
1256
1261
|
) -> None:
|
|
1257
1262
|
spec, _ = self.plan_check_drop_tip(mount, home_after)
|
|
1258
1263
|
|
|
@@ -462,3 +462,7 @@ class FlexBackend(Protocol):
|
|
|
462
462
|
|
|
463
463
|
async def get_hepa_uv_state(self) -> Optional[HepaUVState]:
|
|
464
464
|
...
|
|
465
|
+
|
|
466
|
+
async def increase_evo_disp_count(self, mount: OT3Mount) -> None:
|
|
467
|
+
"""Tell a pipette to increase it's evo-tip-dispense-count in eeprom."""
|
|
468
|
+
...
|
|
@@ -216,6 +216,7 @@ from .types import HWStopCondition
|
|
|
216
216
|
from .flex_protocol import FlexBackend
|
|
217
217
|
from .status_bar_state import StatusBarStateController
|
|
218
218
|
from opentrons_hardware.sensors.types import SensorDataType
|
|
219
|
+
from opentrons_hardware.sensors.utils import send_evo_dispense_count_increase
|
|
219
220
|
|
|
220
221
|
log = logging.getLogger(__name__)
|
|
221
222
|
|
|
@@ -1397,7 +1398,11 @@ class OT3Controller(FlexBackend):
|
|
|
1397
1398
|
return
|
|
1398
1399
|
|
|
1399
1400
|
if hasattr(self, "_event_watcher"):
|
|
1400
|
-
if
|
|
1401
|
+
if (
|
|
1402
|
+
loop.is_running()
|
|
1403
|
+
and self._event_watcher
|
|
1404
|
+
and not self._event_watcher.closed
|
|
1405
|
+
):
|
|
1401
1406
|
self._event_watcher.close()
|
|
1402
1407
|
|
|
1403
1408
|
messenger = getattr(self, "_messenger", None)
|
|
@@ -1824,3 +1829,9 @@ class OT3Controller(FlexBackend):
|
|
|
1824
1829
|
"""This is something we only use in the simulator.
|
|
1825
1830
|
It is required so that PE simulations using ot3api don't break."""
|
|
1826
1831
|
pass
|
|
1832
|
+
|
|
1833
|
+
async def increase_evo_disp_count(self, mount: OT3Mount) -> None:
|
|
1834
|
+
"""Tell a pipette to increase it's evo-tip-dispense-count in eeprom."""
|
|
1835
|
+
await send_evo_dispense_count_increase(
|
|
1836
|
+
self._messenger, sensor_node_for_pipette(OT3Mount(mount.value))
|
|
1837
|
+
)
|
|
@@ -871,3 +871,6 @@ class OT3Simulator(FlexBackend):
|
|
|
871
871
|
"""This is something we only use in the simulator.
|
|
872
872
|
It is required so that PE simulations using ot3api don't break."""
|
|
873
873
|
self._sim_tip_state[mount] = status
|
|
874
|
+
|
|
875
|
+
async def increase_evo_disp_count(self, mount: OT3Mount) -> None:
|
|
876
|
+
pass
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Coordinate subsystem detection and updates.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
import asyncio
|
|
5
6
|
from contextlib import contextmanager, ExitStack
|
|
6
7
|
from dataclasses import dataclass
|
|
@@ -57,7 +58,7 @@ class SubsystemManager:
|
|
|
57
58
|
_expected_core_targets: Set[FirmwareTarget]
|
|
58
59
|
_present_tools: tools.types.ToolSummary
|
|
59
60
|
_tool_task_condition: asyncio.Condition
|
|
60
|
-
_tool_task_state: Union[bool,
|
|
61
|
+
_tool_task_state: Union[bool, BaseException]
|
|
61
62
|
_updates_required: Dict[FirmwareTarget, FirmwareUpdateRequirements]
|
|
62
63
|
_updates_ongoing: Dict[SubSystem, UpdateStatus]
|
|
63
64
|
_update_bag: FirmwareUpdate
|
|
@@ -369,7 +370,8 @@ class SubsystemManager:
|
|
|
369
370
|
async def _tool_detection_task_main(self) -> None:
|
|
370
371
|
try:
|
|
371
372
|
await self._tool_detection_task_protected()
|
|
372
|
-
except
|
|
373
|
+
except BaseException as e:
|
|
374
|
+
log.exception("Tool reader task failed")
|
|
373
375
|
async with self._tool_task_condition:
|
|
374
376
|
self._tool_task_state = e
|
|
375
377
|
self._tool_task_condition.notify_all()
|
|
@@ -390,11 +392,12 @@ class SubsystemManager:
|
|
|
390
392
|
tool_nodes.add(NodeId.pipette_right)
|
|
391
393
|
if update.gripper != ToolType.nothing_attached:
|
|
392
394
|
tool_nodes.add(NodeId.gripper)
|
|
393
|
-
|
|
395
|
+
base_can_nodes: List[NodeId] = [
|
|
394
396
|
NodeId.pipette_left,
|
|
395
397
|
NodeId.pipette_right,
|
|
396
398
|
NodeId.gripper,
|
|
397
|
-
|
|
399
|
+
]
|
|
400
|
+
base_nodes: Set[FirmwareTarget] = {n for n in base_can_nodes}
|
|
398
401
|
try:
|
|
399
402
|
self._network_info.mark_absent(base_nodes - tool_nodes)
|
|
400
403
|
await self._probe_network_and_cache_fw_updates(
|
|
@@ -412,6 +415,7 @@ class SubsystemManager:
|
|
|
412
415
|
)
|
|
413
416
|
self._present_tools = await self._tool_detector.resolve(to_resolve, 10.0)
|
|
414
417
|
log.info(f"Present tools are now {self._present_tools}")
|
|
418
|
+
await network.log_motor_usage_data(self._can_messenger)
|
|
415
419
|
async with self._tool_task_condition:
|
|
416
420
|
self._tool_task_state = True
|
|
417
421
|
self._tool_task_condition.notify_all()
|
|
@@ -9,12 +9,12 @@ from opentrons.calibration_storage import types, helpers
|
|
|
9
9
|
from opentrons.types import Mount, Point
|
|
10
10
|
from opentrons.hardware_control.types import OT3Mount
|
|
11
11
|
|
|
12
|
-
from opentrons_shared_data.labware.labware_definition import
|
|
12
|
+
from opentrons_shared_data.labware.labware_definition import LabwareDefinition2
|
|
13
13
|
|
|
14
14
|
if typing.TYPE_CHECKING:
|
|
15
15
|
from opentrons_shared_data.pipette.types import LabwareUri
|
|
16
16
|
from opentrons_shared_data.labware.types import (
|
|
17
|
-
|
|
17
|
+
LabwareDefinition2 as TypeDictLabwareDef2,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
# These type aliases aid typechecking in tests that work the same on this and
|
|
@@ -119,12 +119,16 @@ def save_pipette_offset_calibration(
|
|
|
119
119
|
# TODO (lc 09-26-2022) We should ensure that only LabwareDefinition models are passed
|
|
120
120
|
# into this function instead of a mixture of TypeDicts and BaseModels
|
|
121
121
|
def load_tip_length_for_pipette(
|
|
122
|
-
pipette_id: str, tiprack: typing.Union["
|
|
122
|
+
pipette_id: str, tiprack: typing.Union["TypeDictLabwareDef2", LabwareDefinition2]
|
|
123
123
|
) -> TipLengthCalibration:
|
|
124
|
-
if isinstance(tiprack,
|
|
124
|
+
if isinstance(tiprack, LabwareDefinition2):
|
|
125
125
|
tiprack = typing.cast(
|
|
126
|
-
"
|
|
127
|
-
tiprack.model_dump(
|
|
126
|
+
"TypeDictLabwareDef2",
|
|
127
|
+
tiprack.model_dump(
|
|
128
|
+
exclude_none=True,
|
|
129
|
+
exclude_unset=True
|
|
130
|
+
# todo(mm, 2025-02-13): Do we need by_alias=True here?
|
|
131
|
+
),
|
|
128
132
|
)
|
|
129
133
|
|
|
130
134
|
tip_length_data = calibration_storage.load_tip_length_calibration(
|
|
@@ -32,6 +32,7 @@ from opentrons.hardware_control.types import (
|
|
|
32
32
|
HardwareAction,
|
|
33
33
|
Axis,
|
|
34
34
|
OT3Mount,
|
|
35
|
+
TipScrapeType,
|
|
35
36
|
)
|
|
36
37
|
from opentrons.hardware_control.constants import (
|
|
37
38
|
SHAKE_OFF_TIPS_SPEED,
|
|
@@ -78,6 +79,8 @@ class TipActionMoveSpec:
|
|
|
78
79
|
speed: Optional[
|
|
79
80
|
float
|
|
80
81
|
] # allow speed for a movement to default to its axes' speed settings
|
|
82
|
+
scrape_axis: Optional[Axis] = None
|
|
83
|
+
# add a scrape motion in the middle of a tip drop
|
|
81
84
|
|
|
82
85
|
|
|
83
86
|
@dataclass(frozen=True)
|
|
@@ -502,10 +505,19 @@ class OT3PipetteHandler:
|
|
|
502
505
|
self._ihp_log.debug(f"{action} on {target.name}")
|
|
503
506
|
|
|
504
507
|
def plunger_position(
|
|
505
|
-
self,
|
|
508
|
+
self,
|
|
509
|
+
instr: Pipette,
|
|
510
|
+
ul: float,
|
|
511
|
+
action: "UlPerMmAction",
|
|
512
|
+
correction_volume: float = 0.0,
|
|
506
513
|
) -> float:
|
|
507
|
-
|
|
508
|
-
|
|
514
|
+
if ul == 0:
|
|
515
|
+
position = instr.plunger_positions.bottom
|
|
516
|
+
else:
|
|
517
|
+
multiplier = 1.0 + (correction_volume / ul)
|
|
518
|
+
mm_dist_from_bottom = ul / instr.ul_per_mm(ul, action)
|
|
519
|
+
mm_dist_from_bottom_corrected = mm_dist_from_bottom * multiplier
|
|
520
|
+
position = instr.plunger_positions.bottom - mm_dist_from_bottom_corrected
|
|
509
521
|
return round(position, 6)
|
|
510
522
|
|
|
511
523
|
def plunger_speed(
|
|
@@ -531,6 +543,7 @@ class OT3PipetteHandler:
|
|
|
531
543
|
mount: OT3Mount,
|
|
532
544
|
volume: Optional[float],
|
|
533
545
|
rate: float,
|
|
546
|
+
correction_volume: float = 0.0,
|
|
534
547
|
) -> Optional[LiquidActionSpec]:
|
|
535
548
|
"""Check preconditions for aspirate, parse args, and calculate positions.
|
|
536
549
|
|
|
@@ -566,7 +579,10 @@ class OT3PipetteHandler:
|
|
|
566
579
|
), "Cannot aspirate more than pipette max volume"
|
|
567
580
|
|
|
568
581
|
dist = self.plunger_position(
|
|
569
|
-
instrument,
|
|
582
|
+
instr=instrument,
|
|
583
|
+
ul=instrument.current_volume + asp_vol,
|
|
584
|
+
action="aspirate",
|
|
585
|
+
correction_volume=correction_volume,
|
|
570
586
|
)
|
|
571
587
|
speed = self.plunger_speed(
|
|
572
588
|
instrument, instrument.aspirate_flow_rate * rate, "aspirate"
|
|
@@ -591,6 +607,8 @@ class OT3PipetteHandler:
|
|
|
591
607
|
volume: Optional[float],
|
|
592
608
|
rate: float,
|
|
593
609
|
push_out: Optional[float],
|
|
610
|
+
is_full_dispense: bool,
|
|
611
|
+
correction_volume: float = 0.0,
|
|
594
612
|
) -> Optional[LiquidActionSpec]:
|
|
595
613
|
"""Check preconditions for dispense, parse args, and calculate positions.
|
|
596
614
|
|
|
@@ -627,7 +645,21 @@ class OT3PipetteHandler:
|
|
|
627
645
|
# of the OT-2 version of this class. Protocol Engine does its own clamping,
|
|
628
646
|
# so we don't expect this to trigger in practice.
|
|
629
647
|
disp_vol = min(instrument.current_volume, disp_vol)
|
|
630
|
-
|
|
648
|
+
|
|
649
|
+
# TODO (Ryan): Remove this check in the future.
|
|
650
|
+
# we moved this logic up to protocol_engine but replacing with this check to make sure
|
|
651
|
+
# we don't accidentally call this incorrectly from somewhere else.
|
|
652
|
+
if not is_full_dispense and numpy.isclose(
|
|
653
|
+
instrument.current_volume - disp_vol, 0
|
|
654
|
+
):
|
|
655
|
+
raise CommandPreconditionViolated(
|
|
656
|
+
message="Command created a full-dispense without the full dispense argument",
|
|
657
|
+
detail={
|
|
658
|
+
"command": "dispense",
|
|
659
|
+
"current-volume": str(instrument.current_volume),
|
|
660
|
+
"dispense-volume": str(disp_vol),
|
|
661
|
+
},
|
|
662
|
+
)
|
|
631
663
|
|
|
632
664
|
if disp_vol == 0:
|
|
633
665
|
return None
|
|
@@ -659,7 +691,10 @@ class OT3PipetteHandler:
|
|
|
659
691
|
)
|
|
660
692
|
|
|
661
693
|
dist = self.plunger_position(
|
|
662
|
-
instrument,
|
|
694
|
+
instr=instrument,
|
|
695
|
+
ul=instrument.current_volume - disp_vol,
|
|
696
|
+
action="dispense",
|
|
697
|
+
correction_volume=correction_volume,
|
|
663
698
|
)
|
|
664
699
|
speed = self.plunger_speed(
|
|
665
700
|
instrument, instrument.dispense_flow_rate * rate, "dispense"
|
|
@@ -889,6 +924,7 @@ class OT3PipetteHandler:
|
|
|
889
924
|
def plan_lt_drop_tip(
|
|
890
925
|
self,
|
|
891
926
|
mount: OT3Mount,
|
|
927
|
+
scrape_tips: TipScrapeType = TipScrapeType.NONE,
|
|
892
928
|
) -> TipActionSpec:
|
|
893
929
|
instrument = self.get_pipette(mount)
|
|
894
930
|
config = instrument.drop_configurations.plunger_eject
|
|
@@ -896,6 +932,20 @@ class OT3PipetteHandler:
|
|
|
896
932
|
raise CommandPreconditionViolated(
|
|
897
933
|
f"No plunger-eject drop tip configurations for {instrument.name} on {mount.name}"
|
|
898
934
|
)
|
|
935
|
+
scrape_move: Optional[TipActionMoveSpec] = None
|
|
936
|
+
match scrape_tips:
|
|
937
|
+
case TipScrapeType.LEFT_ONE_COL:
|
|
938
|
+
scrape_move = TipActionMoveSpec(
|
|
939
|
+
distance=-11, currents=None, speed=None, scrape_axis=Axis.X
|
|
940
|
+
)
|
|
941
|
+
case TipScrapeType.RIGHT_ONE_COL:
|
|
942
|
+
scrape_move = TipActionMoveSpec(
|
|
943
|
+
distance=11, currents=None, speed=None, scrape_axis=Axis.X
|
|
944
|
+
)
|
|
945
|
+
case TipScrapeType.NONE:
|
|
946
|
+
scrape_move = None
|
|
947
|
+
case _:
|
|
948
|
+
scrape_move = None
|
|
899
949
|
drop_seq = [
|
|
900
950
|
TipActionMoveSpec(
|
|
901
951
|
distance=instrument.plunger_positions.drop_tip,
|
|
@@ -914,6 +964,9 @@ class OT3PipetteHandler:
|
|
|
914
964
|
},
|
|
915
965
|
),
|
|
916
966
|
]
|
|
967
|
+
if scrape_move:
|
|
968
|
+
# Add the scrape move before the plunger moves back up
|
|
969
|
+
drop_seq.insert(1, scrape_move)
|
|
917
970
|
|
|
918
971
|
return TipActionSpec(
|
|
919
972
|
tip_action_moves=drop_seq,
|
|
@@ -4,6 +4,7 @@ from .magdeck import MagDeck
|
|
|
4
4
|
from .thermocycler import Thermocycler
|
|
5
5
|
from .heater_shaker import HeaterShaker
|
|
6
6
|
from .absorbance_reader import AbsorbanceReader
|
|
7
|
+
from .flex_stacker import FlexStacker
|
|
7
8
|
from .update import update_firmware
|
|
8
9
|
from .utils import MODULE_TYPE_BY_NAME, build
|
|
9
10
|
from .types import (
|
|
@@ -19,8 +20,13 @@ from .types import (
|
|
|
19
20
|
MagneticStatus,
|
|
20
21
|
HeaterShakerStatus,
|
|
21
22
|
AbsorbanceReaderStatus,
|
|
23
|
+
PlatformState,
|
|
24
|
+
StackerAxisState,
|
|
25
|
+
FlexStackerStatus,
|
|
22
26
|
SpeedStatus,
|
|
23
27
|
LiveData,
|
|
28
|
+
ModuleData,
|
|
29
|
+
ModuleDataValidator,
|
|
24
30
|
)
|
|
25
31
|
from .errors import (
|
|
26
32
|
UpdateError,
|
|
@@ -51,8 +57,13 @@ __all__ = [
|
|
|
51
57
|
"HeaterShakerStatus",
|
|
52
58
|
"SpeedStatus",
|
|
53
59
|
"LiveData",
|
|
60
|
+
"ModuleData",
|
|
61
|
+
"ModuleDataValidator",
|
|
54
62
|
"AbsorbanceReader",
|
|
55
63
|
"AbsorbanceReaderStatus",
|
|
56
64
|
"AbsorbanceReaderDisconnectedError",
|
|
57
|
-
"
|
|
65
|
+
"FlexStacker",
|
|
66
|
+
"FlexStackerStatus",
|
|
67
|
+
"PlatformState",
|
|
68
|
+
"StackerAxisState",
|
|
58
69
|
]
|
|
@@ -24,6 +24,7 @@ from opentrons.hardware_control.modules.types import (
|
|
|
24
24
|
ModuleType,
|
|
25
25
|
AbsorbanceReaderStatus,
|
|
26
26
|
LiveData,
|
|
27
|
+
AbsorbanceReaderData,
|
|
27
28
|
UploadFunction,
|
|
28
29
|
)
|
|
29
30
|
from opentrons.hardware_control.modules.errors import AbsorbanceReaderDisconnectedError
|
|
@@ -243,17 +244,18 @@ class AbsorbanceReader(mod_abc.AbstractModule):
|
|
|
243
244
|
def live_data(self) -> LiveData:
|
|
244
245
|
"""Return a dict of the module's dynamic information"""
|
|
245
246
|
conf = self._measurement_config.data if self._measurement_config else dict()
|
|
247
|
+
data: AbsorbanceReaderData = {
|
|
248
|
+
"uptime": self.uptime,
|
|
249
|
+
"deviceStatus": self.status.value,
|
|
250
|
+
"lidStatus": self.lid_status.value,
|
|
251
|
+
"platePresence": self.plate_presence.value,
|
|
252
|
+
"measureMode": conf.get("measureMode", ""),
|
|
253
|
+
"sampleWavelengths": conf.get("sampleWavelengths", []),
|
|
254
|
+
"referenceWavelength": conf.get("referenceWavelength", 0),
|
|
255
|
+
}
|
|
246
256
|
return {
|
|
247
257
|
"status": self.status.value,
|
|
248
|
-
"data":
|
|
249
|
-
"uptime": self.uptime,
|
|
250
|
-
"deviceStatus": self.status.value,
|
|
251
|
-
"lidStatus": self.lid_status.value,
|
|
252
|
-
"platePresence": self.plate_presence.value,
|
|
253
|
-
"measureMode": conf.get("measureMode", ""),
|
|
254
|
-
"sampleWavelengths": conf.get("sampleWavelengths", []),
|
|
255
|
-
"referenceWavelength": conf.get("referenceWavelength", 0),
|
|
256
|
-
},
|
|
258
|
+
"data": data,
|
|
257
259
|
}
|
|
258
260
|
|
|
259
261
|
@property
|