opentrons 8.1.0a0__py2.py3-none-any.whl → 8.2.0a0__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/cli/analyze.py +71 -7
- opentrons/config/__init__.py +9 -0
- opentrons/config/advanced_settings.py +22 -0
- opentrons/config/defaults_ot3.py +14 -36
- opentrons/config/feature_flags.py +4 -0
- opentrons/config/types.py +6 -17
- opentrons/drivers/absorbance_reader/abstract.py +27 -3
- opentrons/drivers/absorbance_reader/async_byonoy.py +207 -154
- opentrons/drivers/absorbance_reader/driver.py +24 -15
- opentrons/drivers/absorbance_reader/hid_protocol.py +79 -50
- opentrons/drivers/absorbance_reader/simulator.py +32 -6
- opentrons/drivers/types.py +23 -1
- opentrons/execute.py +2 -2
- opentrons/hardware_control/api.py +18 -10
- opentrons/hardware_control/backends/controller.py +3 -2
- opentrons/hardware_control/backends/flex_protocol.py +11 -5
- opentrons/hardware_control/backends/ot3controller.py +18 -50
- opentrons/hardware_control/backends/ot3simulator.py +7 -6
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +22 -82
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -2
- opentrons/hardware_control/module_control.py +43 -2
- opentrons/hardware_control/modules/__init__.py +7 -1
- opentrons/hardware_control/modules/absorbance_reader.py +230 -83
- opentrons/hardware_control/modules/errors.py +7 -0
- opentrons/hardware_control/modules/heater_shaker.py +8 -3
- opentrons/hardware_control/modules/magdeck.py +12 -3
- opentrons/hardware_control/modules/mod_abc.py +27 -2
- opentrons/hardware_control/modules/tempdeck.py +15 -7
- opentrons/hardware_control/modules/thermocycler.py +69 -3
- opentrons/hardware_control/modules/types.py +11 -5
- opentrons/hardware_control/modules/update.py +11 -5
- opentrons/hardware_control/modules/utils.py +3 -1
- opentrons/hardware_control/ot3_calibration.py +6 -6
- opentrons/hardware_control/ot3api.py +126 -89
- opentrons/hardware_control/poller.py +15 -11
- opentrons/hardware_control/protocols/__init__.py +1 -7
- opentrons/hardware_control/protocols/instrument_configurer.py +14 -2
- opentrons/hardware_control/protocols/liquid_handler.py +5 -0
- opentrons/motion_planning/__init__.py +2 -0
- opentrons/motion_planning/waypoints.py +32 -0
- opentrons/protocol_api/__init__.py +2 -1
- opentrons/protocol_api/_liquid.py +87 -1
- opentrons/protocol_api/_parameter_context.py +10 -1
- opentrons/protocol_api/core/engine/deck_conflict.py +0 -297
- opentrons/protocol_api/core/engine/instrument.py +29 -25
- opentrons/protocol_api/core/engine/labware.py +10 -2
- opentrons/protocol_api/core/engine/module_core.py +129 -17
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +355 -0
- opentrons/protocol_api/core/engine/protocol.py +55 -2
- opentrons/protocol_api/core/instrument.py +2 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +5 -2
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/module.py +22 -4
- opentrons/protocol_api/core/protocol.py +5 -2
- opentrons/protocol_api/instrument_context.py +52 -20
- opentrons/protocol_api/labware.py +13 -1
- opentrons/protocol_api/module_contexts.py +68 -13
- opentrons/protocol_api/protocol_context.py +38 -4
- opentrons/protocol_api/validation.py +5 -3
- opentrons/protocol_engine/__init__.py +10 -9
- opentrons/protocol_engine/actions/__init__.py +5 -0
- opentrons/protocol_engine/actions/actions.py +42 -25
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/sync_client.py +7 -1
- opentrons/protocol_engine/clients/transports.py +1 -1
- opentrons/protocol_engine/commands/__init__.py +0 -4
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +41 -11
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +161 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +53 -9
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +160 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +196 -0
- opentrons/protocol_engine/commands/aspirate.py +29 -16
- opentrons/protocol_engine/commands/aspirate_in_place.py +32 -15
- opentrons/protocol_engine/commands/blow_out.py +63 -14
- opentrons/protocol_engine/commands/blow_out_in_place.py +55 -13
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +2 -5
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +3 -4
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +2 -5
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +6 -4
- opentrons/protocol_engine/commands/command.py +28 -17
- opentrons/protocol_engine/commands/command_unions.py +37 -24
- opentrons/protocol_engine/commands/comment.py +5 -3
- opentrons/protocol_engine/commands/configure_for_volume.py +11 -14
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +9 -15
- opentrons/protocol_engine/commands/custom.py +5 -3
- opentrons/protocol_engine/commands/dispense.py +42 -20
- opentrons/protocol_engine/commands/dispense_in_place.py +32 -14
- opentrons/protocol_engine/commands/drop_tip.py +68 -15
- opentrons/protocol_engine/commands/drop_tip_in_place.py +52 -11
- opentrons/protocol_engine/commands/get_tip_presence.py +5 -3
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +8 -6
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +8 -4
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +6 -4
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +6 -6
- opentrons/protocol_engine/commands/home.py +11 -5
- opentrons/protocol_engine/commands/liquid_probe.py +146 -88
- opentrons/protocol_engine/commands/load_labware.py +19 -5
- opentrons/protocol_engine/commands/load_liquid.py +18 -7
- opentrons/protocol_engine/commands/load_module.py +43 -6
- opentrons/protocol_engine/commands/load_pipette.py +18 -17
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +6 -6
- opentrons/protocol_engine/commands/magnetic_module/engage.py +6 -4
- opentrons/protocol_engine/commands/move_labware.py +106 -19
- opentrons/protocol_engine/commands/move_relative.py +15 -3
- opentrons/protocol_engine/commands/move_to_addressable_area.py +29 -4
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +13 -4
- opentrons/protocol_engine/commands/move_to_coordinates.py +11 -5
- opentrons/protocol_engine/commands/move_to_well.py +37 -10
- opentrons/protocol_engine/commands/pick_up_tip.py +50 -29
- opentrons/protocol_engine/commands/pipetting_common.py +39 -15
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +62 -15
- opentrons/protocol_engine/commands/reload_labware.py +13 -4
- opentrons/protocol_engine/commands/retract_axis.py +6 -3
- opentrons/protocol_engine/commands/save_position.py +2 -3
- opentrons/protocol_engine/commands/set_rail_lights.py +5 -3
- opentrons/protocol_engine/commands/set_status_bar.py +5 -3
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +6 -4
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +3 -4
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +6 -6
- opentrons/protocol_engine/commands/thermocycler/__init__.py +19 -0
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +8 -8
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +8 -4
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +165 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +6 -6
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +3 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +3 -4
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +6 -4
- opentrons/protocol_engine/commands/touch_tip.py +19 -7
- opentrons/protocol_engine/commands/unsafe/__init__.py +30 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +6 -4
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -4
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +5 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +194 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +75 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +5 -3
- opentrons/protocol_engine/commands/verify_tip_presence.py +5 -5
- opentrons/protocol_engine/commands/wait_for_duration.py +5 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +5 -3
- opentrons/protocol_engine/create_protocol_engine.py +41 -8
- opentrons/protocol_engine/engine_support.py +2 -1
- opentrons/protocol_engine/error_recovery_policy.py +14 -3
- opentrons/protocol_engine/errors/__init__.py +18 -0
- opentrons/protocol_engine/errors/exceptions.py +114 -2
- opentrons/protocol_engine/execution/__init__.py +2 -0
- opentrons/protocol_engine/execution/command_executor.py +22 -13
- opentrons/protocol_engine/execution/create_queue_worker.py +5 -1
- opentrons/protocol_engine/execution/door_watcher.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +2 -1
- opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
- opentrons/protocol_engine/execution/gantry_mover.py +4 -2
- opentrons/protocol_engine/execution/hardware_stopper.py +3 -3
- opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +1 -4
- opentrons/protocol_engine/execution/labware_movement.py +6 -3
- opentrons/protocol_engine/execution/movement.py +8 -3
- opentrons/protocol_engine/execution/pipetting.py +7 -4
- opentrons/protocol_engine/execution/queue_worker.py +6 -2
- opentrons/protocol_engine/execution/run_control.py +1 -1
- opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +1 -1
- opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +2 -1
- opentrons/protocol_engine/execution/tip_handler.py +77 -43
- opentrons/protocol_engine/notes/__init__.py +14 -2
- opentrons/protocol_engine/notes/notes.py +18 -1
- opentrons/protocol_engine/plugins.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +54 -31
- opentrons/protocol_engine/resources/__init__.py +2 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +58 -5
- opentrons/protocol_engine/resources/file_provider.py +157 -0
- opentrons/protocol_engine/resources/fixture_validation.py +5 -0
- opentrons/protocol_engine/resources/labware_validation.py +10 -0
- opentrons/protocol_engine/state/__init__.py +0 -70
- opentrons/protocol_engine/state/addressable_areas.py +1 -1
- opentrons/protocol_engine/state/command_history.py +21 -2
- opentrons/protocol_engine/state/commands.py +110 -31
- opentrons/protocol_engine/state/files.py +59 -0
- opentrons/protocol_engine/state/frustum_helpers.py +440 -0
- opentrons/protocol_engine/state/geometry.py +359 -15
- opentrons/protocol_engine/state/labware.py +166 -63
- opentrons/protocol_engine/state/liquids.py +1 -1
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +19 -3
- opentrons/protocol_engine/state/modules.py +167 -85
- opentrons/protocol_engine/state/motion.py +16 -9
- opentrons/protocol_engine/state/pipettes.py +157 -317
- opentrons/protocol_engine/state/state.py +30 -1
- opentrons/protocol_engine/state/state_summary.py +3 -0
- opentrons/protocol_engine/state/tips.py +69 -114
- opentrons/protocol_engine/state/update_types.py +408 -0
- opentrons/protocol_engine/state/wells.py +236 -0
- opentrons/protocol_engine/types.py +90 -0
- opentrons/protocol_reader/file_format_validator.py +83 -15
- opentrons/protocol_runner/json_translator.py +21 -5
- opentrons/protocol_runner/legacy_command_mapper.py +27 -6
- opentrons/protocol_runner/legacy_context_plugin.py +27 -71
- opentrons/protocol_runner/protocol_runner.py +6 -3
- opentrons/protocol_runner/run_orchestrator.py +26 -6
- opentrons/protocols/advanced_control/mix.py +3 -5
- opentrons/protocols/advanced_control/transfers.py +125 -56
- opentrons/protocols/api_support/constants.py +1 -1
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/labware_like.py +4 -4
- opentrons/protocols/api_support/tip_tracker.py +2 -2
- opentrons/protocols/api_support/types.py +15 -2
- opentrons/protocols/api_support/util.py +30 -42
- opentrons/protocols/duration/errors.py +1 -1
- opentrons/protocols/duration/estimator.py +50 -29
- opentrons/protocols/execution/dev_types.py +2 -2
- opentrons/protocols/execution/execute_json_v4.py +15 -10
- opentrons/protocols/execution/execute_python.py +8 -3
- opentrons/protocols/geometry/planning.py +12 -12
- opentrons/protocols/labware.py +17 -33
- opentrons/simulate.py +3 -3
- opentrons/types.py +30 -3
- opentrons/util/logging_config.py +34 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/METADATA +5 -4
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/RECORD +227 -215
- opentrons/protocol_engine/commands/absorbance_reader/measure.py +0 -94
- opentrons/protocol_engine/commands/configuring_common.py +0 -26
- opentrons/protocol_runner/thread_async_queue.py +0 -174
- /opentrons/protocol_engine/state/{abstract_store.py → _abstract_store.py} +0 -0
- /opentrons/protocol_engine/state/{move_types.py → _move_types.py} +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/LICENSE +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/WHEEL +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/top_level.txt +0 -0
|
@@ -4,11 +4,14 @@ from pydantic import BaseModel, Field
|
|
|
4
4
|
from typing import Optional, Type, Dict, TYPE_CHECKING
|
|
5
5
|
from typing_extensions import Literal
|
|
6
6
|
|
|
7
|
+
from opentrons.protocol_engine.state.update_types import StateUpdate
|
|
8
|
+
|
|
7
9
|
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
8
10
|
from ..errors.error_occurrence import ErrorOccurrence
|
|
9
11
|
|
|
10
12
|
if TYPE_CHECKING:
|
|
11
|
-
from ..state import StateView
|
|
13
|
+
from ..state.state import StateView
|
|
14
|
+
from ..resources import ModelUtils
|
|
12
15
|
|
|
13
16
|
LoadLiquidCommandType = Literal["loadLiquid"]
|
|
14
17
|
|
|
@@ -37,16 +40,17 @@ class LoadLiquidResult(BaseModel):
|
|
|
37
40
|
|
|
38
41
|
|
|
39
42
|
class LoadLiquidImplementation(
|
|
40
|
-
AbstractCommandImpl[LoadLiquidParams, SuccessData[LoadLiquidResult
|
|
43
|
+
AbstractCommandImpl[LoadLiquidParams, SuccessData[LoadLiquidResult]]
|
|
41
44
|
):
|
|
42
45
|
"""Load liquid command implementation."""
|
|
43
46
|
|
|
44
|
-
def __init__(
|
|
47
|
+
def __init__(
|
|
48
|
+
self, state_view: StateView, model_utils: ModelUtils, **kwargs: object
|
|
49
|
+
) -> None:
|
|
45
50
|
self._state_view = state_view
|
|
51
|
+
self._model_utils = model_utils
|
|
46
52
|
|
|
47
|
-
async def execute(
|
|
48
|
-
self, params: LoadLiquidParams
|
|
49
|
-
) -> SuccessData[LoadLiquidResult, None]:
|
|
53
|
+
async def execute(self, params: LoadLiquidParams) -> SuccessData[LoadLiquidResult]:
|
|
50
54
|
"""Load data necessary for a liquid."""
|
|
51
55
|
self._state_view.liquid.validate_liquid_id(params.liquidId)
|
|
52
56
|
|
|
@@ -54,7 +58,14 @@ class LoadLiquidImplementation(
|
|
|
54
58
|
labware_id=params.labwareId, wells=params.volumeByWell
|
|
55
59
|
)
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
state_update = StateUpdate()
|
|
62
|
+
state_update.set_liquid_loaded(
|
|
63
|
+
labware_id=params.labwareId,
|
|
64
|
+
volumes=params.volumeByWell,
|
|
65
|
+
last_loaded=self._model_utils.get_timestamp(),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
return SuccessData(public=LoadLiquidResult(), state_update=state_update)
|
|
58
69
|
|
|
59
70
|
|
|
60
71
|
class LoadLiquid(BaseCommand[LoadLiquidParams, LoadLiquidResult, ErrorOccurrence]):
|
|
@@ -5,6 +5,7 @@ from typing_extensions import Literal
|
|
|
5
5
|
from pydantic import BaseModel, Field
|
|
6
6
|
|
|
7
7
|
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
8
|
+
from ..errors import ModuleNotLoadedError
|
|
8
9
|
from ..errors.error_occurrence import ErrorOccurrence
|
|
9
10
|
from ..types import (
|
|
10
11
|
DeckSlotLocation,
|
|
@@ -16,8 +17,10 @@ from opentrons.types import DeckSlotName
|
|
|
16
17
|
|
|
17
18
|
from opentrons.protocol_engine.resources import deck_configuration_provider
|
|
18
19
|
|
|
20
|
+
from opentrons.drivers.types import AbsorbanceReaderLidStatus
|
|
21
|
+
|
|
19
22
|
if TYPE_CHECKING:
|
|
20
|
-
from ..state import StateView
|
|
23
|
+
from ..state.state import StateView
|
|
21
24
|
from ..execution import EquipmentHandler
|
|
22
25
|
|
|
23
26
|
|
|
@@ -103,7 +106,7 @@ class LoadModuleResult(BaseModel):
|
|
|
103
106
|
|
|
104
107
|
|
|
105
108
|
class LoadModuleImplementation(
|
|
106
|
-
AbstractCommandImpl[LoadModuleParams, SuccessData[LoadModuleResult
|
|
109
|
+
AbstractCommandImpl[LoadModuleParams, SuccessData[LoadModuleResult]]
|
|
107
110
|
):
|
|
108
111
|
"""The implementation of the load module command."""
|
|
109
112
|
|
|
@@ -113,9 +116,7 @@ class LoadModuleImplementation(
|
|
|
113
116
|
self._equipment = equipment
|
|
114
117
|
self._state_view = state_view
|
|
115
118
|
|
|
116
|
-
async def execute(
|
|
117
|
-
self, params: LoadModuleParams
|
|
118
|
-
) -> SuccessData[LoadModuleResult, None]:
|
|
119
|
+
async def execute(self, params: LoadModuleParams) -> SuccessData[LoadModuleResult]:
|
|
119
120
|
"""Check that the requested module is attached and assign its identifier."""
|
|
120
121
|
module_type = params.model.as_type()
|
|
121
122
|
self._ensure_module_location(params.location.slotName, module_type)
|
|
@@ -151,6 +152,43 @@ class LoadModuleImplementation(
|
|
|
151
152
|
module_id=params.moduleId,
|
|
152
153
|
)
|
|
153
154
|
|
|
155
|
+
# Handle lid position update for loaded Plate Reader module on deck
|
|
156
|
+
if (
|
|
157
|
+
not self._state_view.config.use_virtual_modules
|
|
158
|
+
and params.model == ModuleModel.ABSORBANCE_READER_V1
|
|
159
|
+
and params.moduleId is not None
|
|
160
|
+
):
|
|
161
|
+
try:
|
|
162
|
+
abs_reader = self._equipment.get_module_hardware_api(
|
|
163
|
+
self._state_view.modules.get_absorbance_reader_substate(
|
|
164
|
+
params.moduleId
|
|
165
|
+
).module_id
|
|
166
|
+
)
|
|
167
|
+
except ModuleNotLoadedError:
|
|
168
|
+
abs_reader = None
|
|
169
|
+
|
|
170
|
+
if abs_reader is not None:
|
|
171
|
+
result = await abs_reader.get_current_lid_status()
|
|
172
|
+
if (
|
|
173
|
+
isinstance(result, AbsorbanceReaderLidStatus)
|
|
174
|
+
and result is not AbsorbanceReaderLidStatus.ON
|
|
175
|
+
):
|
|
176
|
+
reader_area = self._state_view.modules.ensure_and_convert_module_fixture_location(
|
|
177
|
+
params.location.slotName,
|
|
178
|
+
self._state_view.config.deck_type,
|
|
179
|
+
params.model,
|
|
180
|
+
)
|
|
181
|
+
lid_labware = self._state_view.labware.get_by_addressable_area(
|
|
182
|
+
reader_area
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
if lid_labware is not None:
|
|
186
|
+
self._state_view.labware._state.labware_by_id[
|
|
187
|
+
lid_labware.id
|
|
188
|
+
].location = self._state_view.modules.absorbance_reader_dock_location(
|
|
189
|
+
params.moduleId
|
|
190
|
+
)
|
|
191
|
+
|
|
154
192
|
return SuccessData(
|
|
155
193
|
public=LoadModuleResult(
|
|
156
194
|
moduleId=loaded_module.module_id,
|
|
@@ -158,7 +196,6 @@ class LoadModuleImplementation(
|
|
|
158
196
|
model=loaded_module.definition.model,
|
|
159
197
|
definition=loaded_module.definition,
|
|
160
198
|
),
|
|
161
|
-
private=None,
|
|
162
199
|
)
|
|
163
200
|
|
|
164
201
|
def _ensure_module_location(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Load pipette command request, result, and implementation models."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
+
from opentrons.protocol_engine.state.update_types import StateUpdate
|
|
4
5
|
from opentrons_shared_data.pipette.pipette_load_name_conversions import (
|
|
5
6
|
convert_to_pipette_name_type,
|
|
6
7
|
)
|
|
@@ -16,23 +17,16 @@ from opentrons.types import MountType
|
|
|
16
17
|
|
|
17
18
|
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
18
19
|
from ..errors.error_occurrence import ErrorOccurrence
|
|
19
|
-
from .configuring_common import PipetteConfigUpdateResultMixin
|
|
20
20
|
from ..errors import InvalidSpecificationForRobotTypeError, InvalidLoadPipetteSpecsError
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
23
23
|
from ..execution import EquipmentHandler
|
|
24
|
-
from ..state import StateView
|
|
24
|
+
from ..state.state import StateView
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
LoadPipetteCommandType = Literal["loadPipette"]
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
class LoadPipettePrivateResult(PipetteConfigUpdateResultMixin):
|
|
31
|
-
"""The not-to-be-exposed results of a load pipette call."""
|
|
32
|
-
|
|
33
|
-
...
|
|
34
|
-
|
|
35
|
-
|
|
36
30
|
class LoadPipetteParams(BaseModel):
|
|
37
31
|
"""Payload needed to load a pipette on to a mount."""
|
|
38
32
|
|
|
@@ -72,9 +66,7 @@ class LoadPipetteResult(BaseModel):
|
|
|
72
66
|
|
|
73
67
|
|
|
74
68
|
class LoadPipetteImplementation(
|
|
75
|
-
AbstractCommandImpl[
|
|
76
|
-
LoadPipetteParams, SuccessData[LoadPipetteResult, LoadPipettePrivateResult]
|
|
77
|
-
]
|
|
69
|
+
AbstractCommandImpl[LoadPipetteParams, SuccessData[LoadPipetteResult]]
|
|
78
70
|
):
|
|
79
71
|
"""Load pipette command implementation."""
|
|
80
72
|
|
|
@@ -86,7 +78,7 @@ class LoadPipetteImplementation(
|
|
|
86
78
|
|
|
87
79
|
async def execute(
|
|
88
80
|
self, params: LoadPipetteParams
|
|
89
|
-
) -> SuccessData[LoadPipetteResult
|
|
81
|
+
) -> SuccessData[LoadPipetteResult]:
|
|
90
82
|
"""Check that requested pipette is attached and assign its identifier."""
|
|
91
83
|
pipette_generation = convert_to_pipette_name_type(
|
|
92
84
|
params.pipetteName.value
|
|
@@ -123,13 +115,22 @@ class LoadPipetteImplementation(
|
|
|
123
115
|
tip_overlap_version=params.tipOverlapNotAfterVersion,
|
|
124
116
|
)
|
|
125
117
|
|
|
118
|
+
state_update = StateUpdate()
|
|
119
|
+
state_update.set_load_pipette(
|
|
120
|
+
pipette_id=loaded_pipette.pipette_id,
|
|
121
|
+
pipette_name=params.pipetteName,
|
|
122
|
+
mount=params.mount,
|
|
123
|
+
liquid_presence_detection=params.liquidPresenceDetection,
|
|
124
|
+
)
|
|
125
|
+
state_update.update_pipette_config(
|
|
126
|
+
pipette_id=loaded_pipette.pipette_id,
|
|
127
|
+
serial_number=loaded_pipette.serial_number,
|
|
128
|
+
config=loaded_pipette.static_config,
|
|
129
|
+
)
|
|
130
|
+
|
|
126
131
|
return SuccessData(
|
|
127
132
|
public=LoadPipetteResult(pipetteId=loaded_pipette.pipette_id),
|
|
128
|
-
|
|
129
|
-
pipette_id=loaded_pipette.pipette_id,
|
|
130
|
-
serial_number=loaded_pipette.serial_number,
|
|
131
|
-
config=loaded_pipette.static_config,
|
|
132
|
-
),
|
|
133
|
+
state_update=state_update,
|
|
133
134
|
)
|
|
134
135
|
|
|
135
136
|
|
|
@@ -13,7 +13,7 @@ from ...errors.error_occurrence import ErrorOccurrence
|
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
15
|
from opentrons.protocol_engine.execution import EquipmentHandler
|
|
16
|
-
from opentrons.protocol_engine.state import StateView
|
|
16
|
+
from opentrons.protocol_engine.state.state import StateView
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
DisengageCommandType = Literal["magneticModule/disengage"]
|
|
@@ -38,7 +38,7 @@ class DisengageResult(BaseModel):
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
class DisengageImplementation(
|
|
41
|
-
AbstractCommandImpl[DisengageParams, SuccessData[DisengageResult
|
|
41
|
+
AbstractCommandImpl[DisengageParams, SuccessData[DisengageResult]]
|
|
42
42
|
):
|
|
43
43
|
"""The implementation of a Magnetic Module disengage command."""
|
|
44
44
|
|
|
@@ -51,9 +51,7 @@ class DisengageImplementation(
|
|
|
51
51
|
self._state_view = state_view
|
|
52
52
|
self._equipment = equipment
|
|
53
53
|
|
|
54
|
-
async def execute(
|
|
55
|
-
self, params: DisengageParams
|
|
56
|
-
) -> SuccessData[DisengageResult, None]:
|
|
54
|
+
async def execute(self, params: DisengageParams) -> SuccessData[DisengageResult]:
|
|
57
55
|
"""Execute a Magnetic Module disengage command.
|
|
58
56
|
|
|
59
57
|
Raises:
|
|
@@ -75,7 +73,9 @@ class DisengageImplementation(
|
|
|
75
73
|
if hardware_module is not None: # Not virtualizing modules.
|
|
76
74
|
await hardware_module.deactivate()
|
|
77
75
|
|
|
78
|
-
return SuccessData(
|
|
76
|
+
return SuccessData(
|
|
77
|
+
public=DisengageResult(),
|
|
78
|
+
)
|
|
79
79
|
|
|
80
80
|
|
|
81
81
|
class Disengage(BaseCommand[DisengageParams, DisengageResult, ErrorOccurrence]):
|
|
@@ -10,7 +10,7 @@ from ...errors.error_occurrence import ErrorOccurrence
|
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
12
|
from opentrons.protocol_engine.execution import EquipmentHandler
|
|
13
|
-
from opentrons.protocol_engine.state import StateView
|
|
13
|
+
from opentrons.protocol_engine.state.state import StateView
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
EngageCommandType = Literal["magneticModule/engage"]
|
|
@@ -54,7 +54,7 @@ class EngageResult(BaseModel):
|
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
class EngageImplementation(
|
|
57
|
-
AbstractCommandImpl[EngageParams, SuccessData[EngageResult
|
|
57
|
+
AbstractCommandImpl[EngageParams, SuccessData[EngageResult]]
|
|
58
58
|
):
|
|
59
59
|
"""The implementation of a Magnetic Module engage command."""
|
|
60
60
|
|
|
@@ -67,7 +67,7 @@ class EngageImplementation(
|
|
|
67
67
|
self._state_view = state_view
|
|
68
68
|
self._equipment = equipment
|
|
69
69
|
|
|
70
|
-
async def execute(self, params: EngageParams) -> SuccessData[EngageResult
|
|
70
|
+
async def execute(self, params: EngageParams) -> SuccessData[EngageResult]:
|
|
71
71
|
"""Execute a Magnetic Module engage command.
|
|
72
72
|
|
|
73
73
|
Raises:
|
|
@@ -95,7 +95,9 @@ class EngageImplementation(
|
|
|
95
95
|
if hardware_module is not None: # Not virtualizing modules.
|
|
96
96
|
await hardware_module.engage(height=hardware_height)
|
|
97
97
|
|
|
98
|
-
return SuccessData(
|
|
98
|
+
return SuccessData(
|
|
99
|
+
public=EngageResult(),
|
|
100
|
+
)
|
|
99
101
|
|
|
100
102
|
|
|
101
103
|
class Engage(BaseCommand[EngageParams, EngageResult, ErrorOccurrence]):
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
"""Models and implementation for the ``moveLabware`` command."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
|
+
from opentrons_shared_data.errors.exceptions import (
|
|
5
|
+
FailedGripperPickupError,
|
|
6
|
+
LabwareDroppedError,
|
|
7
|
+
StallOrCollisionDetectedError,
|
|
8
|
+
)
|
|
4
9
|
from pydantic import BaseModel, Field
|
|
5
10
|
from typing import TYPE_CHECKING, Optional, Type
|
|
6
11
|
from typing_extensions import Literal
|
|
7
12
|
|
|
13
|
+
from opentrons.protocol_engine.resources.model_utils import ModelUtils
|
|
8
14
|
from opentrons.types import Point
|
|
9
15
|
from ..types import (
|
|
16
|
+
CurrentWell,
|
|
10
17
|
LabwareLocation,
|
|
11
18
|
DeckSlotLocation,
|
|
12
19
|
OnLabwareLocation,
|
|
@@ -17,13 +24,20 @@ from ..types import (
|
|
|
17
24
|
)
|
|
18
25
|
from ..errors import LabwareMovementNotAllowedError, NotSupportedOnRobotType
|
|
19
26
|
from ..resources import labware_validation, fixture_validation
|
|
20
|
-
from .command import
|
|
27
|
+
from .command import (
|
|
28
|
+
AbstractCommandImpl,
|
|
29
|
+
BaseCommand,
|
|
30
|
+
BaseCommandCreate,
|
|
31
|
+
DefinedErrorData,
|
|
32
|
+
SuccessData,
|
|
33
|
+
)
|
|
21
34
|
from ..errors.error_occurrence import ErrorOccurrence
|
|
35
|
+
from ..state.update_types import StateUpdate
|
|
22
36
|
from opentrons_shared_data.gripper.constants import GRIPPER_PADDLE_WIDTH
|
|
23
37
|
|
|
24
38
|
if TYPE_CHECKING:
|
|
25
39
|
from ..execution import EquipmentHandler, RunControlHandler, LabwareMovementHandler
|
|
26
|
-
from ..state import StateView
|
|
40
|
+
from ..state.state import StateView
|
|
27
41
|
|
|
28
42
|
|
|
29
43
|
MoveLabwareCommandType = Literal["moveLabware"]
|
|
@@ -33,7 +47,6 @@ MoveLabwareCommandType = Literal["moveLabware"]
|
|
|
33
47
|
_TRASH_CHUTE_DROP_BUFFER_MM = 8
|
|
34
48
|
|
|
35
49
|
|
|
36
|
-
# TODO (spp, 2022-12-14): https://opentrons.atlassian.net/browse/RLAB-237
|
|
37
50
|
class MoveLabwareParams(BaseModel):
|
|
38
51
|
"""Input parameters for a ``moveLabware`` command."""
|
|
39
52
|
|
|
@@ -74,28 +87,42 @@ class MoveLabwareResult(BaseModel):
|
|
|
74
87
|
)
|
|
75
88
|
|
|
76
89
|
|
|
77
|
-
class
|
|
78
|
-
|
|
79
|
-
|
|
90
|
+
class GripperMovementError(ErrorOccurrence):
|
|
91
|
+
"""Returned when something physically goes wrong when the gripper moves labware.
|
|
92
|
+
|
|
93
|
+
When this error happens, the engine will leave the labware in its original place.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
isDefined: bool = True
|
|
97
|
+
|
|
98
|
+
errorType: Literal["gripperMovement"] = "gripperMovement"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
_ExecuteReturn = SuccessData[MoveLabwareResult] | DefinedErrorData[GripperMovementError]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class MoveLabwareImplementation(AbstractCommandImpl[MoveLabwareParams, _ExecuteReturn]):
|
|
80
105
|
"""The execution implementation for ``moveLabware`` commands."""
|
|
81
106
|
|
|
82
107
|
def __init__(
|
|
83
108
|
self,
|
|
109
|
+
model_utils: ModelUtils,
|
|
84
110
|
state_view: StateView,
|
|
85
111
|
equipment: EquipmentHandler,
|
|
86
112
|
labware_movement: LabwareMovementHandler,
|
|
87
113
|
run_control: RunControlHandler,
|
|
88
114
|
**kwargs: object,
|
|
89
115
|
) -> None:
|
|
116
|
+
self._model_utils = model_utils
|
|
90
117
|
self._state_view = state_view
|
|
91
118
|
self._equipment = equipment
|
|
92
119
|
self._labware_movement = labware_movement
|
|
93
120
|
self._run_control = run_control
|
|
94
121
|
|
|
95
|
-
async def execute( # noqa: C901
|
|
96
|
-
self, params: MoveLabwareParams
|
|
97
|
-
) -> SuccessData[MoveLabwareResult, None]:
|
|
122
|
+
async def execute(self, params: MoveLabwareParams) -> _ExecuteReturn: # noqa: C901
|
|
98
123
|
"""Move a loaded labware to a new location."""
|
|
124
|
+
state_update = StateUpdate()
|
|
125
|
+
|
|
99
126
|
# Allow propagation of LabwareNotLoadedError.
|
|
100
127
|
current_labware = self._state_view.labware.get(labware_id=params.labwareId)
|
|
101
128
|
current_labware_definition = self._state_view.labware.get_definition(
|
|
@@ -157,6 +184,10 @@ class MoveLabwareImplementation(
|
|
|
157
184
|
top_labware_definition=current_labware_definition,
|
|
158
185
|
bottom_labware_id=available_new_location.labwareId,
|
|
159
186
|
)
|
|
187
|
+
if params.labwareId == available_new_location.labwareId:
|
|
188
|
+
raise LabwareMovementNotAllowedError(
|
|
189
|
+
"Cannot move a labware onto itself."
|
|
190
|
+
)
|
|
160
191
|
|
|
161
192
|
# Allow propagation of ModuleNotLoadedError.
|
|
162
193
|
new_offset_id = self._equipment.find_applicable_labware_offset_id(
|
|
@@ -201,24 +232,80 @@ class MoveLabwareImplementation(
|
|
|
201
232
|
dropOffset=params.dropOffset or LabwareOffsetVector(x=0, y=0, z=0),
|
|
202
233
|
)
|
|
203
234
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
235
|
+
try:
|
|
236
|
+
# Skips gripper moves when using virtual gripper
|
|
237
|
+
await self._labware_movement.move_labware_with_gripper(
|
|
238
|
+
labware_id=params.labwareId,
|
|
239
|
+
current_location=validated_current_loc,
|
|
240
|
+
new_location=validated_new_loc,
|
|
241
|
+
user_offset_data=user_offset_data,
|
|
242
|
+
post_drop_slide_offset=post_drop_slide_offset,
|
|
243
|
+
)
|
|
244
|
+
except (
|
|
245
|
+
FailedGripperPickupError,
|
|
246
|
+
LabwareDroppedError,
|
|
247
|
+
StallOrCollisionDetectedError,
|
|
248
|
+
# todo(mm, 2024-09-26): Catch LabwareNotPickedUpError when that exists and
|
|
249
|
+
# move_labware_with_gripper() raises it.
|
|
250
|
+
) as exception:
|
|
251
|
+
gripper_movement_error: GripperMovementError | None = (
|
|
252
|
+
GripperMovementError(
|
|
253
|
+
id=self._model_utils.generate_id(),
|
|
254
|
+
createdAt=self._model_utils.get_timestamp(),
|
|
255
|
+
errorCode=exception.code.value.code,
|
|
256
|
+
detail=exception.code.value.detail,
|
|
257
|
+
wrappedErrors=[
|
|
258
|
+
ErrorOccurrence.from_failed(
|
|
259
|
+
id=self._model_utils.generate_id(),
|
|
260
|
+
createdAt=self._model_utils.get_timestamp(),
|
|
261
|
+
error=exception,
|
|
262
|
+
)
|
|
263
|
+
],
|
|
264
|
+
)
|
|
265
|
+
)
|
|
266
|
+
else:
|
|
267
|
+
gripper_movement_error = None
|
|
268
|
+
|
|
269
|
+
# All mounts will have been retracted as part of the gripper move.
|
|
270
|
+
state_update.clear_all_pipette_locations()
|
|
271
|
+
|
|
272
|
+
if gripper_movement_error:
|
|
273
|
+
return DefinedErrorData(
|
|
274
|
+
public=gripper_movement_error,
|
|
275
|
+
state_update=state_update,
|
|
276
|
+
)
|
|
277
|
+
|
|
212
278
|
elif params.strategy == LabwareMovementStrategy.MANUAL_MOVE_WITH_PAUSE:
|
|
213
279
|
# Pause to allow for manual labware movement
|
|
214
280
|
await self._run_control.wait_for_resume()
|
|
215
281
|
|
|
282
|
+
# We may have just moved the labware that contains the current well out from
|
|
283
|
+
# under the pipette. Clear the current location to reflect the fact that the
|
|
284
|
+
# pipette is no longer over any labware. This is necessary for safe path
|
|
285
|
+
# planning in case the next movement goes to the same labware (now in a new
|
|
286
|
+
# place).
|
|
287
|
+
pipette_location = self._state_view.pipettes.get_current_location()
|
|
288
|
+
if (
|
|
289
|
+
isinstance(pipette_location, CurrentWell)
|
|
290
|
+
and pipette_location.labware_id == params.labwareId
|
|
291
|
+
):
|
|
292
|
+
state_update.clear_all_pipette_locations()
|
|
293
|
+
|
|
294
|
+
state_update.set_labware_location(
|
|
295
|
+
labware_id=params.labwareId,
|
|
296
|
+
new_location=available_new_location,
|
|
297
|
+
new_offset_id=new_offset_id,
|
|
298
|
+
)
|
|
299
|
+
|
|
216
300
|
return SuccessData(
|
|
217
|
-
public=MoveLabwareResult(offsetId=new_offset_id),
|
|
301
|
+
public=MoveLabwareResult(offsetId=new_offset_id),
|
|
302
|
+
state_update=state_update,
|
|
218
303
|
)
|
|
219
304
|
|
|
220
305
|
|
|
221
|
-
class MoveLabware(
|
|
306
|
+
class MoveLabware(
|
|
307
|
+
BaseCommand[MoveLabwareParams, MoveLabwareResult, GripperMovementError]
|
|
308
|
+
):
|
|
222
309
|
"""A ``moveLabware`` command."""
|
|
223
310
|
|
|
224
311
|
commandType: MoveLabwareCommandType = "moveLabware"
|
|
@@ -4,6 +4,8 @@ from pydantic import BaseModel, Field
|
|
|
4
4
|
from typing import TYPE_CHECKING, Optional, Type
|
|
5
5
|
from typing_extensions import Literal
|
|
6
6
|
|
|
7
|
+
|
|
8
|
+
from ..state import update_types
|
|
7
9
|
from ..types import MovementAxis, DeckPoint
|
|
8
10
|
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
9
11
|
from ..errors.error_occurrence import ErrorOccurrence
|
|
@@ -37,7 +39,7 @@ class MoveRelativeResult(DestinationPositionResult):
|
|
|
37
39
|
|
|
38
40
|
|
|
39
41
|
class MoveRelativeImplementation(
|
|
40
|
-
AbstractCommandImpl[MoveRelativeParams, SuccessData[MoveRelativeResult
|
|
42
|
+
AbstractCommandImpl[MoveRelativeParams, SuccessData[MoveRelativeResult]]
|
|
41
43
|
):
|
|
42
44
|
"""Move relative command implementation."""
|
|
43
45
|
|
|
@@ -46,16 +48,26 @@ class MoveRelativeImplementation(
|
|
|
46
48
|
|
|
47
49
|
async def execute(
|
|
48
50
|
self, params: MoveRelativeParams
|
|
49
|
-
) -> SuccessData[MoveRelativeResult
|
|
51
|
+
) -> SuccessData[MoveRelativeResult]:
|
|
50
52
|
"""Move (jog) a given pipette a relative distance."""
|
|
53
|
+
state_update = update_types.StateUpdate()
|
|
54
|
+
|
|
51
55
|
x, y, z = await self._movement.move_relative(
|
|
52
56
|
pipette_id=params.pipetteId,
|
|
53
57
|
axis=params.axis,
|
|
54
58
|
distance=params.distance,
|
|
55
59
|
)
|
|
60
|
+
deck_point = DeckPoint.construct(x=x, y=y, z=z)
|
|
61
|
+
state_update.pipette_location = update_types.PipetteLocationUpdate(
|
|
62
|
+
pipette_id=params.pipetteId,
|
|
63
|
+
# TODO(jbl 2023-02-14): Need to investigate whether move relative should clear current location
|
|
64
|
+
new_location=update_types.NO_CHANGE,
|
|
65
|
+
new_deck_point=deck_point,
|
|
66
|
+
)
|
|
56
67
|
|
|
57
68
|
return SuccessData(
|
|
58
|
-
public=MoveRelativeResult(position=
|
|
69
|
+
public=MoveRelativeResult(position=deck_point),
|
|
70
|
+
state_update=state_update,
|
|
59
71
|
)
|
|
60
72
|
|
|
61
73
|
|
|
@@ -4,7 +4,10 @@ from pydantic import Field
|
|
|
4
4
|
from typing import TYPE_CHECKING, Optional, Type
|
|
5
5
|
from typing_extensions import Literal
|
|
6
6
|
|
|
7
|
+
from opentrons_shared_data.pipette.types import PipetteNameType
|
|
8
|
+
|
|
7
9
|
from ..errors import LocationNotAccessibleByPipetteError
|
|
10
|
+
from ..state import update_types
|
|
8
11
|
from ..types import DeckPoint, AddressableOffsetVector
|
|
9
12
|
from ..resources import fixture_validation
|
|
10
13
|
from .pipetting_common import (
|
|
@@ -17,7 +20,7 @@ from ..errors.error_occurrence import ErrorOccurrence
|
|
|
17
20
|
|
|
18
21
|
if TYPE_CHECKING:
|
|
19
22
|
from ..execution import MovementHandler
|
|
20
|
-
from ..state import StateView
|
|
23
|
+
from ..state.state import StateView
|
|
21
24
|
|
|
22
25
|
MoveToAddressableAreaCommandType = Literal["moveToAddressableArea"]
|
|
23
26
|
|
|
@@ -73,7 +76,7 @@ class MoveToAddressableAreaResult(DestinationPositionResult):
|
|
|
73
76
|
|
|
74
77
|
class MoveToAddressableAreaImplementation(
|
|
75
78
|
AbstractCommandImpl[
|
|
76
|
-
MoveToAddressableAreaParams, SuccessData[MoveToAddressableAreaResult
|
|
79
|
+
MoveToAddressableAreaParams, SuccessData[MoveToAddressableAreaResult]
|
|
77
80
|
]
|
|
78
81
|
):
|
|
79
82
|
"""Move to addressable area command implementation."""
|
|
@@ -86,11 +89,26 @@ class MoveToAddressableAreaImplementation(
|
|
|
86
89
|
|
|
87
90
|
async def execute(
|
|
88
91
|
self, params: MoveToAddressableAreaParams
|
|
89
|
-
) -> SuccessData[MoveToAddressableAreaResult
|
|
92
|
+
) -> SuccessData[MoveToAddressableAreaResult]:
|
|
90
93
|
"""Move the requested pipette to the requested addressable area."""
|
|
94
|
+
state_update = update_types.StateUpdate()
|
|
95
|
+
|
|
91
96
|
self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration(
|
|
92
97
|
params.addressableAreaName
|
|
93
98
|
)
|
|
99
|
+
loaded_pipette = self._state_view.pipettes.get(params.pipetteId)
|
|
100
|
+
if loaded_pipette.pipetteName in (
|
|
101
|
+
PipetteNameType.P10_SINGLE,
|
|
102
|
+
PipetteNameType.P10_MULTI,
|
|
103
|
+
PipetteNameType.P50_MULTI,
|
|
104
|
+
PipetteNameType.P50_SINGLE,
|
|
105
|
+
PipetteNameType.P300_SINGLE,
|
|
106
|
+
PipetteNameType.P300_MULTI,
|
|
107
|
+
PipetteNameType.P1000_SINGLE,
|
|
108
|
+
):
|
|
109
|
+
extra_z_offset: Optional[float] = 5.0
|
|
110
|
+
else:
|
|
111
|
+
extra_z_offset = None
|
|
94
112
|
|
|
95
113
|
if fixture_validation.is_staging_slot(params.addressableAreaName):
|
|
96
114
|
raise LocationNotAccessibleByPipetteError(
|
|
@@ -105,11 +123,18 @@ class MoveToAddressableAreaImplementation(
|
|
|
105
123
|
minimum_z_height=params.minimumZHeight,
|
|
106
124
|
speed=params.speed,
|
|
107
125
|
stay_at_highest_possible_z=params.stayAtHighestPossibleZ,
|
|
126
|
+
highest_possible_z_extra_offset=extra_z_offset,
|
|
127
|
+
)
|
|
128
|
+
deck_point = DeckPoint.construct(x=x, y=y, z=z)
|
|
129
|
+
state_update.set_pipette_location(
|
|
130
|
+
pipette_id=params.pipetteId,
|
|
131
|
+
new_addressable_area_name=params.addressableAreaName,
|
|
132
|
+
new_deck_point=deck_point,
|
|
108
133
|
)
|
|
109
134
|
|
|
110
135
|
return SuccessData(
|
|
111
136
|
public=MoveToAddressableAreaResult(position=DeckPoint(x=x, y=y, z=z)),
|
|
112
|
-
|
|
137
|
+
state_update=state_update,
|
|
113
138
|
)
|
|
114
139
|
|
|
115
140
|
|
|
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Optional, Type
|
|
|
5
5
|
from typing_extensions import Literal
|
|
6
6
|
|
|
7
7
|
from ..errors import LocationNotAccessibleByPipetteError
|
|
8
|
+
from ..state import update_types
|
|
8
9
|
from ..types import DeckPoint, AddressableOffsetVector
|
|
9
10
|
from ..resources import fixture_validation
|
|
10
11
|
from .pipetting_common import (
|
|
@@ -17,7 +18,7 @@ from ..errors.error_occurrence import ErrorOccurrence
|
|
|
17
18
|
|
|
18
19
|
if TYPE_CHECKING:
|
|
19
20
|
from ..execution import MovementHandler
|
|
20
|
-
from ..state import StateView
|
|
21
|
+
from ..state.state import StateView
|
|
21
22
|
|
|
22
23
|
MoveToAddressableAreaForDropTipCommandType = Literal["moveToAddressableAreaForDropTip"]
|
|
23
24
|
|
|
@@ -85,7 +86,7 @@ class MoveToAddressableAreaForDropTipResult(DestinationPositionResult):
|
|
|
85
86
|
class MoveToAddressableAreaForDropTipImplementation(
|
|
86
87
|
AbstractCommandImpl[
|
|
87
88
|
MoveToAddressableAreaForDropTipParams,
|
|
88
|
-
SuccessData[MoveToAddressableAreaForDropTipResult
|
|
89
|
+
SuccessData[MoveToAddressableAreaForDropTipResult],
|
|
89
90
|
]
|
|
90
91
|
):
|
|
91
92
|
"""Move to addressable area for drop tip command implementation."""
|
|
@@ -98,8 +99,10 @@ class MoveToAddressableAreaForDropTipImplementation(
|
|
|
98
99
|
|
|
99
100
|
async def execute(
|
|
100
101
|
self, params: MoveToAddressableAreaForDropTipParams
|
|
101
|
-
) -> SuccessData[MoveToAddressableAreaForDropTipResult
|
|
102
|
+
) -> SuccessData[MoveToAddressableAreaForDropTipResult]:
|
|
102
103
|
"""Move the requested pipette to the requested addressable area in preperation of a drop tip."""
|
|
104
|
+
state_update = update_types.StateUpdate()
|
|
105
|
+
|
|
103
106
|
self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration(
|
|
104
107
|
params.addressableAreaName
|
|
105
108
|
)
|
|
@@ -126,12 +129,18 @@ class MoveToAddressableAreaForDropTipImplementation(
|
|
|
126
129
|
speed=params.speed,
|
|
127
130
|
ignore_tip_configuration=params.ignoreTipConfiguration,
|
|
128
131
|
)
|
|
132
|
+
deck_point = DeckPoint.construct(x=x, y=y, z=z)
|
|
133
|
+
state_update.set_pipette_location(
|
|
134
|
+
pipette_id=params.pipetteId,
|
|
135
|
+
new_addressable_area_name=params.addressableAreaName,
|
|
136
|
+
new_deck_point=deck_point,
|
|
137
|
+
)
|
|
129
138
|
|
|
130
139
|
return SuccessData(
|
|
131
140
|
public=MoveToAddressableAreaForDropTipResult(
|
|
132
141
|
position=DeckPoint(x=x, y=y, z=z)
|
|
133
142
|
),
|
|
134
|
-
|
|
143
|
+
state_update=state_update,
|
|
135
144
|
)
|
|
136
145
|
|
|
137
146
|
|