Skip to content

Commit 2ca1ade

Browse files
committed
Merge branch 'edge' into RQA-3878-Tempdeck-PD-Cypress
Keeps things up to date
2 parents 75bb4fa + cb02084 commit 2ca1ade

File tree

222 files changed

+8370
-1605
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

222 files changed

+8370
-1605
lines changed

api-client/src/maintenance_runs/createMaintenanceRunLabwareDefinition.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@ import { POST, request } from '../request'
33
import type { ResponsePromise } from '../request'
44
import type { HostConfig } from '../types'
55
import type { LabwareDefinitionSummary } from './types'
6-
import type { LabwareDefinition2 } from '@opentrons/shared-data'
6+
import type {
7+
LabwareDefinition2,
8+
LabwareDefinition3,
9+
} from '@opentrons/shared-data'
710

811
export function createMaintenanceRunLabwareDefinition(
912
config: HostConfig,
1013
maintenanceRunId: string,
11-
data: LabwareDefinition2
14+
data: LabwareDefinition2 | LabwareDefinition3
1215
): ResponsePromise<LabwareDefinitionSummary> {
13-
return request<LabwareDefinitionSummary, { data: LabwareDefinition2 }>(
16+
return request<
17+
LabwareDefinitionSummary,
18+
{ data: LabwareDefinition2 | LabwareDefinition3 }
19+
>(
1420
POST,
1521
`/maintenance_runs/${maintenanceRunId}/labware_definitions`,
1622
{ data },

api/docs/v2/conf.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,10 @@
445445
("py:class", r".*protocol_api\.config.*"),
446446
("py:class", r".*opentrons_shared_data.*"),
447447
("py:class", r".*protocol_api._parameters.Parameters.*"),
448-
("py:class", r".*RobotContext"), # shh it's a secret (for now)
449-
("py:class", r'.*AbstractLabware|APIVersion|LabwareLike|LoadedCoreMap|ModuleTypes|NoneType|OffDeckType|ProtocolCore|WellCore'), # laundry list of not fully qualified things
448+
("py:class", r".*RobotContext"), # shh it's a secret (for now)
449+
("py:class", r".*FlexStackerContext"), # ssh it's a secret (for now)
450+
(
451+
"py:class",
452+
r".*AbstractLabware|APIVersion|LabwareLike|LoadedCoreMap|ModuleTypes|NoneType|OffDeckType|ProtocolCore|WellCore",
453+
), # laundry list of not fully qualified things
450454
]

api/src/opentrons/protocol_engine/commands/__init__.py

+28
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@
6161
AspirateCommandType,
6262
)
6363

64+
from .aspirate_while_tracking import (
65+
AspirateWhileTracking,
66+
AspirateWhileTrackingParams,
67+
AspirateWhileTrackingCreate,
68+
AspirateWhileTrackingResult,
69+
AspirateWhileTrackingCommandType,
70+
)
71+
6472
from .aspirate_in_place import (
6573
AspirateInPlace,
6674
AspirateInPlaceParams,
@@ -93,6 +101,14 @@
93101
DispenseCommandType,
94102
)
95103

104+
from .dispense_while_tracking import (
105+
DispenseWhileTracking,
106+
DispenseWhileTrackingParams,
107+
DispenseWhileTrackingCreate,
108+
DispenseWhileTrackingResult,
109+
DispenseWhileTrackingCommandType,
110+
)
111+
96112
from .dispense_in_place import (
97113
DispenseInPlace,
98114
DispenseInPlaceParams,
@@ -414,6 +430,12 @@
414430
"AspirateParams",
415431
"AspirateResult",
416432
"AspirateCommandType",
433+
# aspirate while tracking command models
434+
"AspirateWhileTracking",
435+
"AspirateWhileTrackingCreate",
436+
"AspirateWhileTrackingParams",
437+
"AspirateWhileTrackingResult",
438+
"AspirateWhileTrackingCommandType",
417439
# aspirate in place command models
418440
"AspirateInPlace",
419441
"AspirateInPlaceCreate",
@@ -438,6 +460,12 @@
438460
"DispenseParams",
439461
"DispenseResult",
440462
"DispenseCommandType",
463+
# dispense while tracking command models
464+
"DispenseWhileTracking",
465+
"DispenseWhileTrackingCreate",
466+
"DispenseWhileTrackingParams",
467+
"DispenseWhileTrackingResult",
468+
"DispenseWhileTrackingCommandType",
441469
# dispense in place command models
442470
"DispenseInPlace",
443471
"DispenseInPlaceCreate",

api/src/opentrons/protocol_engine/commands/aspirate.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@
4747

4848

4949
class AspirateParams(
50-
PipetteIdMixin, AspirateVolumeMixin, FlowRateMixin, LiquidHandlingWellLocationMixin
50+
PipetteIdMixin,
51+
AspirateVolumeMixin,
52+
FlowRateMixin,
53+
LiquidHandlingWellLocationMixin,
5154
):
5255
"""Parameters required to aspirate from a specific well."""
5356

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
"""Aspirate command request, result, and implementation models."""
2+
3+
from __future__ import annotations
4+
from typing import TYPE_CHECKING, Optional, Type, Union
5+
from typing_extensions import Literal
6+
7+
from .pipetting_common import (
8+
OverpressureError,
9+
PipetteIdMixin,
10+
AspirateVolumeMixin,
11+
FlowRateMixin,
12+
BaseLiquidHandlingResult,
13+
aspirate_while_tracking,
14+
)
15+
from .movement_common import (
16+
LiquidHandlingWellLocationMixin,
17+
DestinationPositionResult,
18+
StallOrCollisionError,
19+
)
20+
from .command import (
21+
AbstractCommandImpl,
22+
BaseCommand,
23+
BaseCommandCreate,
24+
DefinedErrorData,
25+
SuccessData,
26+
)
27+
from ..errors.exceptions import PipetteNotReadyToAspirateError
28+
from opentrons.hardware_control import HardwareControlAPI
29+
from ..state.update_types import CLEAR
30+
from ..types import CurrentWell, DeckPoint
31+
32+
if TYPE_CHECKING:
33+
from ..execution import PipettingHandler, GantryMover
34+
from ..resources import ModelUtils
35+
from ..state.state import StateView
36+
from ..notes import CommandNoteAdder
37+
38+
39+
AspirateWhileTrackingCommandType = Literal["aspirateWhileTracking"]
40+
41+
42+
class AspirateWhileTrackingParams(
43+
PipetteIdMixin,
44+
AspirateVolumeMixin,
45+
FlowRateMixin,
46+
LiquidHandlingWellLocationMixin,
47+
):
48+
"""Parameters required to aspirate from a specific well."""
49+
50+
pass
51+
52+
53+
class AspirateWhileTrackingResult(BaseLiquidHandlingResult, DestinationPositionResult):
54+
"""Result data from execution of an Aspirate command."""
55+
56+
pass
57+
58+
59+
_ExecuteReturn = Union[
60+
SuccessData[AspirateWhileTrackingResult],
61+
DefinedErrorData[OverpressureError] | DefinedErrorData[StallOrCollisionError],
62+
]
63+
64+
65+
class AspirateWhileTrackingImplementation(
66+
AbstractCommandImpl[AspirateWhileTrackingParams, _ExecuteReturn]
67+
):
68+
"""AspirateWhileTracking command implementation."""
69+
70+
def __init__(
71+
self,
72+
pipetting: PipettingHandler,
73+
state_view: StateView,
74+
hardware_api: HardwareControlAPI,
75+
command_note_adder: CommandNoteAdder,
76+
model_utils: ModelUtils,
77+
gantry_mover: GantryMover,
78+
**kwargs: object,
79+
) -> None:
80+
self._pipetting = pipetting
81+
self._state_view = state_view
82+
self._hardware_api = hardware_api
83+
self._command_note_adder = command_note_adder
84+
self._model_utils = model_utils
85+
self._gantry_mover = gantry_mover
86+
87+
async def execute(self, params: AspirateWhileTrackingParams) -> _ExecuteReturn:
88+
"""Move to and aspirate from the requested well.
89+
90+
Raises:
91+
TipNotAttachedError: if no tip is attached to the pipette.
92+
PipetteNotReadyToAspirateError: pipette plunger is not ready.
93+
"""
94+
ready_to_aspirate = self._pipetting.get_is_ready_to_aspirate(
95+
pipette_id=params.pipetteId,
96+
)
97+
if not ready_to_aspirate:
98+
raise PipetteNotReadyToAspirateError(
99+
"Pipette cannot aspirate while tracking because of a previous blow out."
100+
" The first aspirate following a blow-out must be from a specific well"
101+
" so the plunger can be reset in a known safe position."
102+
)
103+
104+
current_position = await self._gantry_mover.get_position(params.pipetteId)
105+
current_location = self._state_view.pipettes.get_current_location()
106+
107+
aspirate_result = await aspirate_while_tracking(
108+
pipette_id=params.pipetteId,
109+
labware_id=params.labwareId,
110+
well_name=params.wellName,
111+
volume=params.volume,
112+
flow_rate=params.flowRate,
113+
location_if_error={
114+
"retryLocation": (
115+
current_position.x,
116+
current_position.y,
117+
current_position.z,
118+
)
119+
},
120+
command_note_adder=self._command_note_adder,
121+
pipetting=self._pipetting,
122+
model_utils=self._model_utils,
123+
)
124+
position_after_aspirate = await self._gantry_mover.get_position(
125+
params.pipetteId
126+
)
127+
result_deck_point = DeckPoint.model_construct(
128+
x=position_after_aspirate.x,
129+
y=position_after_aspirate.y,
130+
z=position_after_aspirate.z,
131+
)
132+
if isinstance(aspirate_result, DefinedErrorData):
133+
if (
134+
isinstance(current_location, CurrentWell)
135+
and current_location.pipette_id == params.pipetteId
136+
):
137+
return DefinedErrorData(
138+
public=aspirate_result.public,
139+
state_update=aspirate_result.state_update.set_liquid_operated(
140+
labware_id=current_location.labware_id,
141+
well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
142+
current_location.labware_id,
143+
current_location.well_name,
144+
params.pipetteId,
145+
),
146+
volume_added=CLEAR,
147+
),
148+
state_update_if_false_positive=aspirate_result.state_update_if_false_positive,
149+
)
150+
else:
151+
return aspirate_result
152+
else:
153+
if (
154+
isinstance(current_location, CurrentWell)
155+
and current_location.pipette_id == params.pipetteId
156+
):
157+
return SuccessData(
158+
public=AspirateWhileTrackingResult(
159+
volume=aspirate_result.public.volume,
160+
position=result_deck_point,
161+
),
162+
state_update=aspirate_result.state_update.set_liquid_operated(
163+
labware_id=current_location.labware_id,
164+
well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
165+
current_location.labware_id,
166+
current_location.well_name,
167+
params.pipetteId,
168+
),
169+
volume_added=-aspirate_result.public.volume
170+
* self._state_view.geometry.get_nozzles_per_well(
171+
current_location.labware_id,
172+
current_location.well_name,
173+
params.pipetteId,
174+
),
175+
),
176+
)
177+
else:
178+
return SuccessData(
179+
public=AspirateWhileTrackingResult(
180+
volume=aspirate_result.public.volume,
181+
position=result_deck_point,
182+
),
183+
state_update=aspirate_result.state_update,
184+
)
185+
186+
187+
class AspirateWhileTracking(
188+
BaseCommand[
189+
AspirateWhileTrackingParams,
190+
AspirateWhileTrackingResult,
191+
OverpressureError | StallOrCollisionError,
192+
]
193+
):
194+
"""AspirateWhileTracking command model."""
195+
196+
commandType: AspirateWhileTrackingCommandType = "aspirateWhileTracking"
197+
params: AspirateWhileTrackingParams
198+
result: Optional[AspirateWhileTrackingResult] = None
199+
200+
_ImplementationCls: Type[
201+
AspirateWhileTrackingImplementation
202+
] = AspirateWhileTrackingImplementation
203+
204+
205+
class AspirateWhileTrackingCreate(BaseCommandCreate[AspirateWhileTrackingParams]):
206+
"""Create aspirateWhileTracking command request model."""
207+
208+
commandType: AspirateWhileTrackingCommandType = "aspirateWhileTracking"
209+
params: AspirateWhileTrackingParams
210+
211+
_CommandCls: Type[AspirateWhileTracking] = AspirateWhileTracking

0 commit comments

Comments
 (0)