Skip to content

Commit 61da984

Browse files
committed
pickup and drop offset adjustments as well as test fixture correction
1 parent 4e6c7c7 commit 61da984

File tree

6 files changed

+84
-24
lines changed

6 files changed

+84
-24
lines changed

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

+11-4
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@
2727
DefinedErrorData,
2828
)
2929
from ..resources import labware_validation
30-
from ..state.update_types import CLEAR
31-
from ..types import CurrentWell
30+
from ..errors import ProtocolEngineError
3231

3332
if TYPE_CHECKING:
3433
from ..execution import PipettingHandler, GantryMover, MovementHandler
@@ -101,7 +100,6 @@ async def execute(self, params: EvotipDispenseParams) -> _ExecuteReturn:
101100
if isinstance(move_result, DefinedErrorData):
102101
return move_result
103102

104-
current_location = self._state_view.pipettes.get_current_location()
105103
current_position = await self._gantry_mover.get_position(params.pipetteId)
106104
result = await dispense_in_place(
107105
pipette_id=params.pipetteId,
@@ -118,6 +116,11 @@ async def execute(self, params: EvotipDispenseParams) -> _ExecuteReturn:
118116
pipetting=self._pipetting,
119117
model_utils=self._model_utils,
120118
)
119+
if isinstance(result, DefinedErrorData):
120+
# TODO (chb, 2025-01-29): Remove this and the OverpressureError returns once disabled for this function
121+
raise ProtocolEngineError(
122+
message="Overpressure Error during Resin Tip Dispense Command."
123+
)
121124

122125
return SuccessData(
123126
public=EvotipDispenseResult(volume=result.public.volume),
@@ -126,7 +129,11 @@ async def execute(self, params: EvotipDispenseParams) -> _ExecuteReturn:
126129

127130

128131
class EvotipDispense(
129-
BaseCommand[EvotipDispenseParams, EvotipDispenseResult, StallOrCollisionError]
132+
BaseCommand[
133+
EvotipDispenseParams,
134+
EvotipDispenseResult,
135+
StallOrCollisionError,
136+
]
130137
):
131138
"""DispenseInPlace command model."""
132139

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

+1-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from opentrons.protocol_engine.errors import UnsupportedLabwareForActionError
1111
from ..resources import ModelUtils, labware_validation
12-
from ..types import PickUpTipWellLocation, TipGeometry, FluidKind, AspiratedFluid
12+
from ..types import PickUpTipWellLocation, FluidKind, AspiratedFluid
1313
from .pipetting_common import (
1414
PipetteIdMixin,
1515
)
@@ -39,7 +39,6 @@
3939
GantryMover,
4040
PipettingHandler,
4141
)
42-
from ..notes import CommandNoteAdder
4342

4443

4544
EvotipSealPipetteCommandType = Literal["evotipSealPipette"]
@@ -116,7 +115,6 @@ def __init__(
116115
movement: MovementHandler,
117116
hardware_api: HardwareControlAPI,
118117
gantry_mover: GantryMover,
119-
command_note_adder: CommandNoteAdder,
120118
pipetting: PipettingHandler,
121119
**kwargs: object,
122120
) -> None:
@@ -125,7 +123,6 @@ def __init__(
125123
self._model_utils = model_utils
126124
self._movement = movement
127125
self._gantry_mover = gantry_mover
128-
self._command_note_adder = command_note_adder
129126
self._pipetting = pipetting
130127
self._hardware_api = hardware_api
131128

api/tests/opentrons/protocol_engine/commands/test_evotip_dispense_in_place.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ async def test_overpressure_error(
207207

208208
if isinstance(location, CurrentWell):
209209
assert result == DefinedErrorData(
210-
public=OverpressureError.construct(
210+
public=OverpressureError.model_construct(
211211
id=error_id,
212212
createdAt=error_timestamp,
213213
wrappedErrors=[matchers.Anything()],
@@ -226,7 +226,7 @@ async def test_overpressure_error(
226226
)
227227
else:
228228
assert result == DefinedErrorData(
229-
public=OverpressureError.construct(
229+
public=OverpressureError.model_construct(
230230
id=error_id,
231231
createdAt=error_timestamp,
232232
wrappedErrors=[matchers.Anything()],

api/tests/opentrons/protocol_engine/commands/test_evotip_seal_pipette.py

+43-6
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,24 @@
3333
EvotipSealPipetteResult,
3434
EvotipSealPipetteImplementation,
3535
)
36+
from opentrons.protocol_engine.execution import (
37+
PipettingHandler,
38+
)
39+
from opentrons.hardware_control import HardwareControlAPI
40+
from opentrons.protocol_engine.resources import labware_validation
41+
import json
42+
from opentrons_shared_data import load_shared_data
3643

3744

3845
@pytest.fixture
3946
def evotips_definition() -> LabwareDefinition:
40-
return LabwareDefinition.parse_obj(
41-
load_definition("evotips_opentrons_96_labware", 1)
47+
# TODO (chb 2025-01-29): When we migrate all labware to v3 we can clean this up
48+
return LabwareDefinition.model_validate(
49+
json.loads(
50+
load_shared_data(
51+
f"labware/definitions/3/evotips_opentrons_96_labware/1.json"
52+
)
53+
)
4254
)
4355

4456

@@ -50,6 +62,8 @@ async def test_success(
5062
model_utils: ModelUtils,
5163
gantry_mover: GantryMover,
5264
evotips_definition: LabwareDefinition,
65+
hardware_api: HardwareControlAPI,
66+
pipetting: PipettingHandler,
5367
) -> None:
5468
"""A PickUpTip command should have an execution implementation."""
5569
subject = EvotipSealPipetteImplementation(
@@ -58,6 +72,8 @@ async def test_success(
5872
tip_handler=tip_handler,
5973
model_utils=model_utils,
6074
gantry_mover=gantry_mover,
75+
hardware_api=hardware_api,
76+
pipetting=pipetting,
6177
)
6278

6379
decoy.when(state_view.pipettes.get_mount("pipette-id")).then_return(MountType.LEFT)
@@ -136,6 +152,9 @@ async def test_no_tip_physically_missing_error(
136152
tip_handler: TipHandler,
137153
model_utils: ModelUtils,
138154
gantry_mover: GantryMover,
155+
hardware_api: HardwareControlAPI,
156+
pipetting: PipettingHandler,
157+
evotips_definition: LabwareDefinition,
139158
) -> None:
140159
"""It should not return a TipPhysicallyMissingError even though evotips do not sit high enough on the pipette to be detected by the tip sensor."""
141160
subject = EvotipSealPipetteImplementation(
@@ -144,6 +163,8 @@ async def test_no_tip_physically_missing_error(
144163
tip_handler=tip_handler,
145164
model_utils=model_utils,
146165
gantry_mover=gantry_mover,
166+
hardware_api=hardware_api,
167+
pipetting=pipetting,
147168
)
148169

149170
pipette_id = "pipette-id"
@@ -175,9 +196,16 @@ async def test_no_tip_physically_missing_error(
175196
await tip_handler.pick_up_tip(
176197
pipette_id=pipette_id, labware_id=labware_id, well_name=well_name
177198
)
178-
).then_raise(PickUpTipTipNotAttachedError(tip_geometry=sentinel.tip_geometry))
199+
).then_raise(
200+
PickUpTipTipNotAttachedError(
201+
tip_geometry=TipGeometry(length=42, diameter=5, volume=300)
202+
)
203+
)
179204
decoy.when(model_utils.generate_id()).then_return(error_id)
180205
decoy.when(model_utils.get_timestamp()).then_return(error_created_at)
206+
decoy.when(state_view.labware.get_definition(labware_id)).then_return(
207+
evotips_definition
208+
)
181209

182210
result = await subject.execute(
183211
EvotipSealPipetteParams(
@@ -186,7 +214,7 @@ async def test_no_tip_physically_missing_error(
186214
)
187215

188216
assert result == DefinedErrorData(
189-
public=TipPhysicallyMissingError.construct(
217+
public=StallOrCollisionError.model_construct(
190218
id=error_id, createdAt=error_created_at, wrappedErrors=[matchers.Anything()]
191219
),
192220
state_update=update_types.StateUpdate(
@@ -206,7 +234,8 @@ async def test_no_tip_physically_missing_error(
206234
),
207235
state_update_if_false_positive=update_types.StateUpdate(
208236
pipette_tip_state=update_types.PipetteTipStateUpdate(
209-
pipette_id="pipette-id", tip_geometry=sentinel.tip_geometry
237+
pipette_id="pipette-id",
238+
tip_geometry=TipGeometry(length=42, diameter=5, volume=300),
210239
),
211240
pipette_aspirated_fluid=update_types.PipetteEmptyFluidUpdate(
212241
pipette_id="pipette-id"
@@ -232,6 +261,9 @@ async def test_stall_error(
232261
tip_handler: TipHandler,
233262
model_utils: ModelUtils,
234263
gantry_mover: GantryMover,
264+
hardware_api: HardwareControlAPI,
265+
pipetting: PipettingHandler,
266+
evotips_definition: LabwareDefinition,
235267
) -> None:
236268
"""It should return a TipPhysicallyMissingError if the HW API indicates that."""
237269
subject = EvotipSealPipetteImplementation(
@@ -240,6 +272,8 @@ async def test_stall_error(
240272
tip_handler=tip_handler,
241273
model_utils=model_utils,
242274
gantry_mover=gantry_mover,
275+
hardware_api=hardware_api,
276+
pipetting=pipetting,
243277
)
244278

245279
pipette_id = "pipette-id"
@@ -270,6 +304,9 @@ async def test_stall_error(
270304

271305
decoy.when(model_utils.generate_id()).then_return(error_id)
272306
decoy.when(model_utils.get_timestamp()).then_return(error_created_at)
307+
decoy.when(state_view.labware.get_definition(labware_id)).then_return(
308+
evotips_definition
309+
)
273310

274311
result = await subject.execute(
275312
EvotipSealPipetteParams(
@@ -278,7 +315,7 @@ async def test_stall_error(
278315
)
279316

280317
assert result == DefinedErrorData(
281-
public=StallOrCollisionError.construct(
318+
public=StallOrCollisionError.model_construct(
282319
id=error_id, createdAt=error_created_at, wrappedErrors=[matchers.Anything()]
283320
),
284321
state_update=update_types.StateUpdate(

api/tests/opentrons/protocol_engine/commands/test_evotip_unseal_pipette.py

+13-8
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from opentrons.protocol_engine.resources.model_utils import ModelUtils
2929
from opentrons.protocol_engine.state import update_types
3030
from opentrons.protocol_engine.state.state import StateView
31-
from opentrons.protocol_engine.execution import MovementHandler, TipHandler
31+
from opentrons.protocol_engine.execution import MovementHandler, GantryMover, TipHandler
3232

3333

3434
from opentrons.types import Point
@@ -60,7 +60,7 @@ def mock_model_utils(decoy: Decoy) -> ModelUtils:
6060

6161
def test_drop_tip_params_defaults() -> None:
6262
"""A drop tip should use a `WellOrigin.DROP_TIP` by default."""
63-
default_params = EvotipUnsealPipetteParams.parse_obj(
63+
default_params = EvotipUnsealPipetteParams.model_validate(
6464
{"pipetteId": "abc", "labwareId": "def", "wellName": "ghj"}
6565
)
6666

@@ -71,7 +71,7 @@ def test_drop_tip_params_defaults() -> None:
7171

7272
def test_drop_tip_params_default_origin() -> None:
7373
"""A drop tip should drop a `WellOrigin.DROP_TIP` by default even if an offset is given."""
74-
default_params = EvotipUnsealPipetteParams.parse_obj(
74+
default_params = EvotipUnsealPipetteParams.model_validate(
7575
{
7676
"pipetteId": "abc",
7777
"labwareId": "def",
@@ -91,21 +91,22 @@ async def test_drop_tip_implementation(
9191
mock_movement_handler: MovementHandler,
9292
mock_tip_handler: TipHandler,
9393
mock_model_utils: ModelUtils,
94+
gantry_mover: GantryMover,
9495
) -> None:
9596
"""A DropTip command should have an execution implementation."""
9697
subject = EvotipUnsealPipetteImplementation(
9798
state_view=mock_state_view,
9899
movement=mock_movement_handler,
99100
tip_handler=mock_tip_handler,
100101
model_utils=mock_model_utils,
102+
gantry_mover=gantry_mover,
101103
)
102104

103105
params = EvotipUnsealPipetteParams(
104106
pipetteId="abc",
105107
labwareId="123",
106108
wellName="A3",
107109
wellLocation=DropTipWellLocation(offset=WellOffset(x=1, y=2, z=3)),
108-
homeAfter=True,
109110
)
110111

111112
decoy.when(
@@ -169,21 +170,21 @@ async def test_drop_tip_with_alternating_locations(
169170
mock_movement_handler: MovementHandler,
170171
mock_tip_handler: TipHandler,
171172
mock_model_utils: ModelUtils,
173+
gantry_mover: GantryMover,
172174
) -> None:
173175
"""It should drop tip at random location within the labware every time."""
174176
subject = EvotipUnsealPipetteImplementation(
175177
state_view=mock_state_view,
176178
movement=mock_movement_handler,
177179
tip_handler=mock_tip_handler,
178180
model_utils=mock_model_utils,
181+
gantry_mover=gantry_mover,
179182
)
180183
params = EvotipUnsealPipetteParams(
181184
pipetteId="abc",
182185
labwareId="123",
183186
wellName="A3",
184187
wellLocation=DropTipWellLocation(offset=WellOffset(x=1, y=2, z=3)),
185-
homeAfter=True,
186-
alternateDropLocation=True,
187188
)
188189
drop_location = DropTipWellLocation(
189190
origin=DropTipWellOrigin.DEFAULT, offset=WellOffset(x=10, y=20, z=30)
@@ -249,13 +250,15 @@ async def test_tip_attached_error(
249250
mock_movement_handler: MovementHandler,
250251
mock_tip_handler: TipHandler,
251252
mock_model_utils: ModelUtils,
253+
gantry_mover: GantryMover,
252254
) -> None:
253255
"""A Evotip Unseal command should have an execution implementation."""
254256
subject = EvotipUnsealPipetteImplementation(
255257
state_view=mock_state_view,
256258
movement=mock_movement_handler,
257259
tip_handler=mock_tip_handler,
258260
model_utils=mock_model_utils,
261+
gantry_mover=gantry_mover,
259262
)
260263

261264
params = EvotipUnsealPipetteParams(
@@ -303,7 +306,7 @@ async def test_tip_attached_error(
303306
result = await subject.execute(params)
304307

305308
assert result == DefinedErrorData(
306-
public=TipPhysicallyAttachedError.construct(
309+
public=StallOrCollisionError.model_construct(
307310
id="error-id",
308311
createdAt=datetime(year=1, month=2, day=3),
309312
wrappedErrors=[matchers.Anything()],
@@ -345,13 +348,15 @@ async def test_stall_error(
345348
mock_movement_handler: MovementHandler,
346349
mock_tip_handler: TipHandler,
347350
mock_model_utils: ModelUtils,
351+
gantry_mover: GantryMover,
348352
) -> None:
349353
"""A DropTip command should have an execution implementation."""
350354
subject = EvotipUnsealPipetteImplementation(
351355
state_view=mock_state_view,
352356
movement=mock_movement_handler,
353357
tip_handler=mock_tip_handler,
354358
model_utils=mock_model_utils,
359+
gantry_mover=gantry_mover,
355360
)
356361

357362
params = EvotipUnsealPipetteParams(
@@ -396,7 +401,7 @@ async def test_stall_error(
396401
result = await subject.execute(params)
397402

398403
assert result == DefinedErrorData(
399-
public=StallOrCollisionError.construct(
404+
public=StallOrCollisionError.model_construct(
400405
id="error-id",
401406
createdAt=datetime(year=1, month=2, day=3),
402407
wrappedErrors=[matchers.Anything()],

shared-data/labware/definitions/3/evotips_opentrons_96_labware/1.json

+14
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,20 @@
10251025
},
10261026
"gripHeightFromLabwareBottom": 14.5,
10271027
"gripForce": 15,
1028+
"gripperOffsets": {
1029+
"default": {
1030+
"pickUpOffset": {
1031+
"x": 0,
1032+
"y": 0,
1033+
"z": 15
1034+
},
1035+
"dropOffset": {
1036+
"x": 0,
1037+
"y": 0,
1038+
"z": 15
1039+
}
1040+
}
1041+
},
10281042
"stackingOffsetWithLabware": {
10291043
"nest_96_wellplate_2ml_deep": {
10301044
"x": 0,

0 commit comments

Comments
 (0)