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): Tip tracking for all 96ch configurations #14488

Merged
merged 32 commits into from
Mar 12, 2024

Conversation

CaseyBatten
Copy link
Contributor

@CaseyBatten CaseyBatten commented Feb 13, 2024

Overview

Addresses PLAT-53.

Previously tip tracking was gated to several pre-determined configuration types. Inside the TipView, we had each of these special cased and were handling them independently (such as a special case for single column pickup, for full 96 ch pickup, and for single tip pickup). This logic has been preserved, but can only be reached using starting tips.

In its place, the new logic instead utilizes information garnered from the nozzle configuration map to identify a critical tip within the tiprack based on the current configuration's ideal direction of entry. It then identifies a "cluster" of tips that would be picked up, and validates that none of them are Used. Positively confirmed clusters return their critical tip as the well to target for pickup, ensuring the entire desired cluster is picked up. Tips from that cluster are then set as Used, so on follow-up passes the next valid section of remaining tips may be used.

Test Plan

The following protocol should pass analysis and should have the following events occur:
NOTE: In order to execute this protocol on the Flex, you would first have to disable the raise case under _get_tip_presence() in tip_presence_manager.py. This is because currently the hardware controller does not support quadrants.

from opentrons.protocol_api import COLUMN
from opentrons.protocol_api._nozzle_layout import NozzleLayout

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

def run(protocol_context):
    tip_rack = protocol_context.load_labware("opentrons_flex_96_tiprack_50ul", "C2")

    instrument = protocol_context.load_instrument('flex_96channel_1000', mount="left", tip_racks=[tip_rack])

    trash = protocol_context.load_trash_bin("A3")

    instrument.configure_nozzle_layout(style=COLUMN, start="A1")
    instrument.pick_up_tip(tip_rack)
    instrument.drop_tip()

    instrument.configure_nozzle_layout(style=COLUMN, start="A12")
    instrument.pick_up_tip(tip_rack)
    instrument.drop_tip()

    instrument.configure_nozzle_layout(style=COLUMN, start="A1")
    instrument.pick_up_tip(tip_rack)
    instrument.drop_tip()

    instrument.configure_nozzle_layout(style=COLUMN, start="A12")
    instrument.pick_up_tip(tip_rack)
    instrument.drop_tip()

    #bite chunks out
    instrument.configure_nozzle_layout(style=NozzleLayout.QUADRANT, start="A1", front_right = "H3")
    instrument.pick_up_tip(tip_rack)
    instrument.drop_tip()

    instrument.pick_up_tip(tip_rack)
    instrument.drop_tip()

    instrument.configure_nozzle_layout(style=NozzleLayout.QUADRANT, start="A1", front_right="F2")
    instrument.pick_up_tip(tip_rack)
    instrument.drop_tip()

    #cleanup remaining 4 with single tip
    instrument.configure_nozzle_layout(style=NozzleLayout.SINGLE, start="H12")
    instrument.pick_up_tip(tip_rack)
    instrument.drop_tip()

    instrument.configure_nozzle_layout(style=NozzleLayout.SINGLE, start="H1")
    instrument.pick_up_tip(tip_rack)
    instrument.drop_tip()

    instrument.configure_nozzle_layout(style=NozzleLayout.SINGLE, start="A12")
    instrument.pick_up_tip(tip_rack)
    instrument.drop_tip()

    instrument.configure_nozzle_layout(style=NozzleLayout.SINGLE, start="A1")
    instrument.pick_up_tip(tip_rack)
    instrument.drop_tip()

Changelog

  • The tip tracking hierarchy now accepts an optional nozzle map
  • get_next_tip(...) now has split functionality:
    • If a starting tip has been specified, the original ruleset for finding a matching tip will be utilized as starting tips have been deemed incompatible with partial tip actions.
    • Otherwise, we will dynamically identify a cluster of tips that best matches the current nozzle map configuration per instrument type, including partial configurations.

Review requests

Does the logic at play in get_next_tip(...) make sense?

Does anything standout as possibly causing problems for us down the line?

Risk assessment

Medium/Low - After much testing and refactoring, I think we've arrived at a stable form of implementing this that frees up the ability to utilize partial tip configurations of all varieties alongside automatic tip tracking. The splits track for get_next_tip() is an appropriate solution due to the support needed for things like starting tip, which unfortunately would introduce unneeded complexity to partial tip pickup (primarily for multi/96 ch pipettes).

Copy link

codecov bot commented Feb 13, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 67.43%. Comparing base (d6d9416) to head (6940253).
Report is 29 commits behind head on edge.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             edge   #14488      +/-   ##
==========================================
- Coverage   67.50%   67.43%   -0.08%     
==========================================
  Files        2514     2485      -29     
  Lines       72376    71474     -902     
  Branches     9317     9121     -196     
==========================================
- Hits        48857    48195     -662     
+ Misses      21314    21114     -200     
+ Partials     2205     2165      -40     
Flag Coverage Δ
g-code-testing 92.43% <ø> (ø)
hardware-testing ∅ <ø> (∅)
shared-data 75.94% <ø> (+0.64%) ⬆️

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

Files Coverage Δ
...i/src/opentrons/protocol_api/instrument_context.py 89.09% <ø> (ø)
api/src/opentrons/protocol_api/labware.py 91.30% <ø> (-0.05%) ⬇️
api/src/opentrons/protocol_engine/types.py 97.50% <ø> (ø)

... and 29 files with indirect coverage changes

@@ -56,6 +59,7 @@ def __init__(self) -> None:
channels_by_pipette_id={},
length_by_pipette_id={},
active_channels_by_pipette_id={},
nozzle_map=None,
Copy link
Member

Choose a reason for hiding this comment

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

This will need to be mapped by pipette id

@CaseyBatten CaseyBatten marked this pull request as ready for review March 1, 2024 18:40
@CaseyBatten CaseyBatten requested review from a team as code owners March 1, 2024 18:40
@SyntaxColoring SyntaxColoring self-requested a review March 4, 2024 15:47
Copy link
Contributor

@SyntaxColoring SyntaxColoring left a comment

Choose a reason for hiding this comment

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

Sweet, thank you! Some preliminary comments. I haven't gotten to the new algorithmic stuff in tips.py yet.

api/src/opentrons/protocol_api/core/engine/labware.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_api/instrument_context.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_api/labware.py Outdated Show resolved Hide resolved
Copy link
Contributor

@SyntaxColoring SyntaxColoring left a comment

Choose a reason for hiding this comment

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

Sweet, thank you. Here are a few small suggestions, plus one more meaningful one about exposing the NozzleMap type.

api/src/opentrons/protocol_api/instrument_context.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_api/labware.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_api/labware.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_api/labware.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_api/instrument_context.py Outdated Show resolved Hide resolved
Copy link
Contributor

@SyntaxColoring SyntaxColoring left a comment

Choose a reason for hiding this comment

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

Changes since my last review look good, thanks. This looks good to me if it looks good to you and @sanni-t.

As mentioned in calls, we think there's a lot of room for simplifying the logic in state/tips.py. I'm happy for that to happen in other PRs if you think the tests you're introducing here will cover us enough in the meantime.

@CaseyBatten CaseyBatten merged commit f9ddf17 into edge Mar 12, 2024
44 checks passed
Carlos-fernandez pushed a commit that referenced this pull request May 20, 2024
Adds tip tracking for all 96ch and 8ch configurations as long as no starting tip is specified
Carlos-fernandez pushed a commit that referenced this pull request Jun 3, 2024
Adds tip tracking for all 96ch and 8ch configurations as long as no starting tip is specified
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants