Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): Addition of Evotip specific commands #17351

Merged
merged 27 commits into from
Jan 30, 2025

Conversation

CaseyBatten
Copy link
Contributor

@CaseyBatten CaseyBatten commented Jan 27, 2025

Overview

Covers EXEC-907

Introduces Evotip (or resin-tip) specific commands to the instrument context. These commands achieve the desired sealing, pressurization and unsealing steps for a resin tip protocol.

To Do:

  • Update the Run Log commands
  • Validate the amount of real liquid dispensed from the resin tips

Test Plan and Hands on Testing

  • The following protocol must pass analysis and execute as expected (Note: must have labware definitions merged in):
from opentrons.protocol_api import ProtocolContext

metadata = {
    'protocolName': 'Evo Tips Test',
    'description': ''
}

requirements = {
    "robotType": "Flex",
    "apiLevel": "2.22",
}

def run(ctx: ProtocolContext):
    
    tiprack = ctx.load_labware("opentrons_flex_96_tiprack_200uL", "A2", adapter="opentrons_flex_96_tiprack_adapter")
    pipette = ctx.load_instrument("flex_96channel_1000", 'left', tip_racks=[tiprack])

    well_plate = ctx.load_labware("nest_96_wellplate_2ml_deep", "C3")
    trash = ctx.load_trash_bin("B3")

    # Load the Evo Tips Labware
    evotips_adapter = ctx.load_adapter("evotips_flex_96_tiprack_adapter", "D2")
    evosep_tips_labware = evotips_adapter.load_labware("evotips_opentrons_96_labware")

    # Fill the Evo Tips with liquid
    pipette.pick_up_tip()
    pipette.aspirate(150, well_plate.wells()[0])
    pipette.dispense(150, evosep_tips_labware.wells()[0].top())
    pipette.drop_tip(trash)

    # Soak the Evo Tips for 20 seconds
    ctx.move_labware(evosep_tips_labware, well_plate, True)
    ctx.delay(20)
    ctx.move_labware(evosep_tips_labware, evotips_adapter, True)


    # Seal the pipette to the evotips
    pipette.resin_tip_seal(location=evosep_tips_labware)
    # Dispense all liquid at 2uL/S
    pipette.resin_tip_dispense(location=evosep_tips_labware.wells()[0].top())
    # Unseal/eject the Evo Tips
    pipette.resin_tip_unseal(evosep_tips_labware)

Changelog

Addition of new instrument context and engine commands. Addition of necessary optional flags to hardware API fields to allow for specialty Axis movement and skipping of certain home steps in situations involving the evo tips.

Review requests

Do the approaches used for movement coordination seem appropriate under the engine commands being used?

Risk assessment

Low - New behavior that does not have cross-interaction with other commands. These are also beta commands which will not be publicly documented.

Copy link

codecov bot commented Jan 27, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Please upload report for BASE (chore_release-8.3.0@c048e5b). Learn more about missing BASE report.

Additional details and impacted files

Impacted file tree graph

@@                  Coverage Diff                   @@
##             chore_release-8.3.0   #17351   +/-   ##
======================================================
  Coverage                       ?   72.91%           
======================================================
  Files                          ?      152           
  Lines                          ?     6265           
  Branches                       ?        0           
======================================================
  Hits                           ?     4568           
  Misses                         ?     1697           
  Partials                       ?        0           
Flag Coverage Δ
g-code-testing 92.43% <ø> (?)
shared-data 73.82% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

@CaseyBatten CaseyBatten marked this pull request as ready for review January 27, 2025 18:56
@CaseyBatten CaseyBatten requested a review from a team as a code owner January 27, 2025 18:56
@CaseyBatten CaseyBatten added the gen-analyses-snapshot-pr Generate a healing PR if the analyses snapshot test fails label Jan 27, 2025
Copy link
Contributor

A PR has been opened to address analyses snapshot changes. Please review the changes here: #17356

@@ -778,6 +778,7 @@ async def move_axes(
position: Mapping[Axis, float],
speed: Optional[float] = None,
max_speeds: Optional[Dict[Axis, float]] = None,
_expect_stalls: bool = False,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this supposed to be an internal arg? maybe we don't need the _

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I don't think we need the _

Copy link
Member

@sfoster1 sfoster1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's tighten up some of the dispense implementation and get rid of what parameters we can, please. It does look fine in structure. I eagerly anticipate following this up after release by moving some of these exact movement commands out of the engine and into hardware.

@@ -778,6 +778,7 @@ async def move_axes(
position: Mapping[Axis, float],
speed: Optional[float] = None,
max_speeds: Optional[Dict[Axis, float]] = None,
_expect_stalls: bool = False,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I don't think we need the _

self,
mount: Union[top_types.Mount, OT3Mount],
home_after: bool = False,
ignore_plunger: Optional[bool] = False,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't be Optional unless it can be none, and if it can be none we should handle the None case. looks like just ignore_plunger: bool = False is fine.

)

if (
isinstance(current_location, CurrentWell)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is right. CurrentWell will presumably be the "well" of the tips, right? And evotip_dispense is actually removing liquid from those. The place that it's adding liquid is the intermediate plate, which I think in general the engine won't know about, right? I think we should just not do volume handling here until we know we can do it correctly, which means removing lines 125 to 139.

)
return SuccessData(
public=EvotipDispenseResult(volume=result.public.volume),
state_update=result.state_update.set_liquid_operated(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and removing the set liquid operated



class TipPickUpParams(BaseModel):
prepDistance: float = Field(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have these default to none and look up defaults from something else, so if we have to change these defaults it doesn't have to alter the command schema.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also these are only relevant to low-throughput pipettes, right? The 96 uses completely different options. I dunno about these, but I'm open to keeping them

pressDistance: float = Field(
default=3.5, description="The distance to press on tips."
)
ejectorPushmm: float = Field(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ejectorPushmm: float = Field(
ejectorPushMm: float = Field(

"""Result data from the execution of a EvotipSealPipette."""

tipVolume: float = Field(
0,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do these need defaults?

tip_geometry: TipGeometry,
tip_pick_up_params: TipPickUpParams,
mount: MountType,
press_fit: bool,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's just have these be two functions instead of one function that completely changes behavior based on a bool argument. Also IMO we can factor this function out of the object and pass in the gantry mover, and do the state bookkeeping after the call.

)

# Drive mount down for press-fit
await self._gantry_mover.move_axes(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's drop a TODO for this stuff to (a) have its constants factored out and (b) move into the hardware controller.

default_factory=DropTipWellLocation,
description="Relative well location at which to drop the tip.",
)
homeAfter: Optional[bool] = Field(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this?

@skowalski08
Copy link
Contributor

tested with @CaseyBatten, gripper pickup offsets need to be corrected for move evotips, but otherwise runs as expected

@CaseyBatten CaseyBatten requested a review from sfoster1 January 29, 2025 21:08
@CaseyBatten CaseyBatten requested a review from a team as a code owner January 29, 2025 22:32
Copy link
Member

@sfoster1 sfoster1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with this in broad strokes but imo we should look at the defaults for tip pickup and have them capture None instead of data, and we should fix the drop_tips ignore_plunger thing.

Also I suspect that we'll want to provide a default behavior of "current labware" for unseal, but I could be convinced otherwise pretty easily

@CaseyBatten CaseyBatten merged commit 3d78c1f into chore_release-8.3.0 Jan 30, 2025
56 checks passed
@CaseyBatten CaseyBatten deleted the EXEC-907-evotip-specific-commands branch January 30, 2025 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
gen-analyses-snapshot-pr Generate a healing PR if the analyses snapshot test fails
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants