Skip to content

Commit ac117dd

Browse files
jbleon95caila-marashaj
authored andcommitted
feat(api): wire up mmToEdge to liquid class transfer (#17293)
Wires up the liquid class touch tip property `mmToEdge` to the touch tip execution logic and updates transfer liquid to use this property.
1 parent 9d685e5 commit ac117dd

File tree

8 files changed

+97
-5
lines changed

8 files changed

+97
-5
lines changed

api/src/opentrons/protocol_api/core/engine/instrument.py

+6
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ def touch_tip(
393393
radius: float,
394394
z_offset: float,
395395
speed: float,
396+
mm_from_edge: Optional[float] = None,
396397
) -> None:
397398
"""Touch pipette tip to edges of the well
398399
@@ -402,7 +403,11 @@ def touch_tip(
402403
radius: Percentage modifier for well radius to touch.
403404
z_offset: Vertical offset for pipette tip during touch tip.
404405
speed: Speed for the touch tip movements.
406+
mm_from_edge: Offset from the edge of the well to move to. Requires a radius of 1.
405407
"""
408+
if mm_from_edge is not None and radius != 1.0:
409+
raise ValueError("radius must be set to 1.0 if mm_from_edge is provided.")
410+
406411
well_name = well_core.get_name()
407412
labware_id = well_core.labware_id
408413

@@ -424,6 +429,7 @@ def touch_tip(
424429
wellName=well_name,
425430
wellLocation=well_location,
426431
radius=radius,
432+
mmFromEdge=mm_from_edge,
427433
speed=speed,
428434
)
429435
)

api/src/opentrons/protocol_api/core/engine/transfer_components_executor.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -293,13 +293,13 @@ def retract_after_aspiration(self, volume: float) -> None:
293293
and touch_tip_props.z_offset is not None
294294
and touch_tip_props.mm_to_edge is not None
295295
)
296-
# TODO: update this once touch tip has mmToEdge
297296
self._instrument.touch_tip(
298297
location=retract_location,
299298
well_core=self._target_well,
300299
radius=1,
301300
z_offset=touch_tip_props.z_offset,
302301
speed=touch_tip_props.speed,
302+
mm_from_edge=touch_tip_props.mm_to_edge,
303303
)
304304
self._instrument.move_to(
305305
location=retract_location,
@@ -460,8 +460,7 @@ def _do_touch_tip_and_air_gap(
460460
and touch_tip_props.z_offset is not None
461461
and touch_tip_props.mm_to_edge is not None
462462
)
463-
# TODO: update this once touch tip has mmToEdge
464-
# Also, check that when blow out is a non-dest-well,
463+
# TODO:, check that when blow out is a non-dest-well,
465464
# whether the touch tip params from transfer props should be used for
466465
# both dest-well touch tip and non-dest-well touch tip.
467466
if well is not None and location is not None:
@@ -472,6 +471,7 @@ def _do_touch_tip_and_air_gap(
472471
radius=1,
473472
z_offset=touch_tip_props.z_offset,
474473
speed=touch_tip_props.speed,
474+
mm_from_edge=touch_tip_props.mm_to_edge,
475475
)
476476
except TouchTipDisabledError:
477477
# TODO: log a warning

api/src/opentrons/protocol_api/core/instrument.py

+1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ def touch_tip(
103103
radius: float,
104104
z_offset: float,
105105
speed: float,
106+
mm_from_edge: Optional[float] = None,
106107
) -> None:
107108
...
108109

api/src/opentrons/protocol_api/core/legacy/legacy_instrument_core.py

+3
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,14 @@ def touch_tip(
180180
radius: float,
181181
z_offset: float,
182182
speed: float,
183+
mm_from_edge: Optional[float] = None,
183184
) -> None:
184185
"""
185186
Touch the pipette tip to the sides of a well, with the intent of
186187
removing left-over droplets
187188
"""
189+
if mm_from_edge is not None:
190+
raise APIVersionError(api_element="mm_from_edge argument")
188191
# TODO al 20201110 - build_edges relies on where being a Well. This is
189192
# an unpleasant compromise until refactoring build_edges to support
190193
# LegacyWellCore.

api/src/opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py

+3
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,10 @@ def touch_tip(
180180
radius: float,
181181
z_offset: float,
182182
speed: float,
183+
mm_from_edge: Optional[float] = None,
183184
) -> None:
185+
if mm_from_edge is not None:
186+
raise APIVersionError(api_element="mm_from_edge argument")
184187
self.move_to(location)
185188

186189
def pick_up_tip(

api/tests/opentrons/conftest.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ def maximal_liquid_class_def() -> LiquidClassSchemaV1:
947947
touchTip=TouchTipProperties(
948948
enable=True,
949949
params=LiquidClassTouchTipParams(
950-
zOffset=-1, mmToEdge=0.5, speed=30
950+
zOffset=-1, mmToEdge=0.75, speed=30
951951
),
952952
),
953953
delay=DelayProperties(

api/tests/opentrons/protocol_api/core/engine/test_instrument_core.py

+72
Original file line numberDiff line numberDiff line change
@@ -1303,12 +1303,84 @@ def test_touch_tip(
13031303
),
13041304
radius=1.23,
13051305
speed=7.89,
1306+
mmFromEdge=None,
13061307
)
13071308
),
13081309
mock_protocol_core.set_last_location(location=location, mount=Mount.LEFT),
13091310
)
13101311

13111312

1313+
def test_touch_tip_with_mm_from_edge(
1314+
decoy: Decoy,
1315+
subject: InstrumentCore,
1316+
mock_engine_client: EngineClient,
1317+
mock_protocol_core: ProtocolCore,
1318+
) -> None:
1319+
"""It should touch the tip to the edges of the well with mm_from_edge."""
1320+
location = Location(point=Point(1, 2, 3), labware=None)
1321+
1322+
well_core = WellCore(
1323+
name="my cool well", labware_id="123abc", engine_client=mock_engine_client
1324+
)
1325+
subject.touch_tip(
1326+
location=location,
1327+
well_core=well_core,
1328+
radius=1.0,
1329+
z_offset=4.56,
1330+
speed=7.89,
1331+
mm_from_edge=9.87,
1332+
)
1333+
1334+
decoy.verify(
1335+
pipette_movement_conflict.check_safe_for_pipette_movement(
1336+
engine_state=mock_engine_client.state,
1337+
pipette_id="abc123",
1338+
labware_id="123abc",
1339+
well_name="my cool well",
1340+
well_location=WellLocation(
1341+
origin=WellOrigin.TOP, offset=WellOffset(x=0, y=0, z=4.56)
1342+
),
1343+
),
1344+
mock_engine_client.execute_command(
1345+
cmd.TouchTipParams(
1346+
pipetteId="abc123",
1347+
labwareId="123abc",
1348+
wellName="my cool well",
1349+
wellLocation=WellLocation(
1350+
origin=WellOrigin.TOP, offset=WellOffset(x=0, y=0, z=4.56)
1351+
),
1352+
radius=1.0,
1353+
speed=7.89,
1354+
mmFromEdge=9.87,
1355+
)
1356+
),
1357+
mock_protocol_core.set_last_location(location=location, mount=Mount.LEFT),
1358+
)
1359+
1360+
1361+
def test_touch_tip_raises_with_radius_and_mm_from_edge(
1362+
decoy: Decoy,
1363+
subject: InstrumentCore,
1364+
mock_engine_client: EngineClient,
1365+
mock_protocol_core: ProtocolCore,
1366+
) -> None:
1367+
"""It should raise if a value of not 1.0 and a mm_from_edge argument is given."""
1368+
location = Location(point=Point(1, 2, 3), labware=None)
1369+
1370+
well_core = WellCore(
1371+
name="my cool well", labware_id="123abc", engine_client=mock_engine_client
1372+
)
1373+
with pytest.raises(ValueError):
1374+
subject.touch_tip(
1375+
location=location,
1376+
well_core=well_core,
1377+
radius=1.23,
1378+
z_offset=4.56,
1379+
speed=7.89,
1380+
mm_from_edge=9.87,
1381+
)
1382+
1383+
13121384
def test_has_tip(
13131385
decoy: Decoy,
13141386
subject: InstrumentCore,

api/tests/opentrons/protocol_api/core/engine/test_transfer_components_executor.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,8 @@ def test_retract_after_aspiration(
449449
mock_instrument_core.touch_tip(
450450
location=Location(Point(x=4, y=4, z=4), labware=None),
451451
well_core=source_well,
452-
radius=1, # Update this to use mmToEdge once implemented
452+
radius=1,
453+
mm_from_edge=0.5,
453454
z_offset=-1,
454455
speed=30,
455456
),
@@ -599,6 +600,7 @@ def test_retract_after_dispense_with_blowout_in_source(
599600
location=Location(Point(12, 24, 36), labware=None),
600601
well_core=dest_well,
601602
radius=1,
603+
mm_from_edge=0.75,
602604
z_offset=-1,
603605
speed=30,
604606
),
@@ -623,6 +625,7 @@ def test_retract_after_dispense_with_blowout_in_source(
623625
location=Location(Point(10, 20, 30), labware=None),
624626
well_core=source_well,
625627
radius=1,
628+
mm_from_edge=0.75,
626629
z_offset=-1,
627630
speed=30,
628631
),
@@ -711,6 +714,7 @@ def test_retract_after_dispense_with_blowout_in_destination(
711714
location=Location(Point(12, 24, 36), labware=None),
712715
well_core=dest_well,
713716
radius=1,
717+
mm_from_edge=0.75,
714718
z_offset=-1,
715719
speed=30,
716720
),
@@ -788,6 +792,7 @@ def test_retract_after_dispense_with_blowout_in_trash_well(
788792
location=Location(Point(12, 24, 36), labware=None),
789793
well_core=dest_well,
790794
radius=1,
795+
mm_from_edge=0.75,
791796
z_offset=-1,
792797
speed=30,
793798
),
@@ -812,6 +817,7 @@ def test_retract_after_dispense_with_blowout_in_trash_well(
812817
location=trash_location,
813818
well_core=trash_well_core,
814819
radius=1,
820+
mm_from_edge=0.75,
815821
z_offset=-1,
816822
speed=30,
817823
),
@@ -886,6 +892,7 @@ def test_retract_after_dispense_with_blowout_in_disposal_location(
886892
location=Location(Point(12, 24, 36), labware=None),
887893
well_core=dest_well,
888894
radius=1,
895+
mm_from_edge=0.75,
889896
z_offset=-1,
890897
speed=30,
891898
),

0 commit comments

Comments
 (0)