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): introduce correction volume into the liquid classes based transfer flow #17322

Merged
merged 10 commits into from
Jan 28, 2025

Conversation

sanni-t
Copy link
Member

@sanni-t sanni-t commented Jan 22, 2025

Closes AUTH-964

Overview

Adds correctionVolume to protocol engine's aspirate and dispense commands and also adds it as argument to rest of the steps in the pipeline to get the correction volume value from the transfer flow to hardware controller.
The hardware controller then wires it up to move the plunger in proportion to the correction volume.

Test Plan and Hands on Testing

For the PAPI part, unit and integration tests will be sufficient. For hardware control changes, an on-robot test should be performed.

Review requests

  • Mainly check if the hardware controller side changes are correct.

Risk assessment

Low

Copy link

codecov bot commented Jan 22, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 79.04%. Comparing base (0e7b516) to head (6875002).
Report is 9 commits behind head on edge.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             edge   #17322      +/-   ##
==========================================
+ Coverage   73.84%   79.04%   +5.19%     
==========================================
  Files          43      120      +77     
  Lines        3304     4587    +1283     
==========================================
+ Hits         2440     3626    +1186     
- Misses        864      961      +97     
Flag Coverage Δ
g-code-testing 92.43% <ø> (?)

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

see 77 files with indirect coverage changes

Copy link
Contributor

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

@sanni-t sanni-t marked this pull request as ready for review January 24, 2025 16:09
@sanni-t sanni-t requested review from a team as code owners January 24, 2025 16:09
@sanni-t sanni-t removed the gen-analyses-snapshot-pr Generate a healing PR if the analyses snapshot test fails label Jan 24, 2025
@andySigler andySigler assigned andySigler and unassigned andySigler Jan 24, 2025
@andySigler andySigler self-requested a review January 24, 2025 20:30
if ul == 0:
position = instr.plunger_positions.bottom
else:
multiplier = 1.0 + (correction_volume / ul)
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 💣

Copy link
Contributor

@jbleon95 jbleon95 left a comment

Choose a reason for hiding this comment

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

Changes are straightforward and LGTM, ✅

mm = ul / instr.ul_per_mm(ul, action)
position = instr.plunger_positions.bottom - mm
if ul == 0:
position = instr.plunger_positions.bottom
Copy link
Contributor

Choose a reason for hiding this comment

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

Question 1: Do you need this if block here, or does the code below still work correctly even when ul == 0?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nope. It will result in a divide by zero error

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I meant with the alternative expression suggested below :)

In general, I prefer to write equations to avoid singularities when describing physical systems. Conceptually, the position varies smoothly with the ul volume even at 0, so I want the code to reflect a smooth function as well, without the discontinuity at ul==0.

multiplier = 1.0 + (correction_volume / ul)
mm_dist_from_bottom = ul / instr.ul_per_mm(ul, action)
mm_dist_from_bottom_corrected = mm_dist_from_bottom * multiplier
position = instr.plunger_positions.bottom - mm_dist_from_bottom_corrected
Copy link
Contributor

Choose a reason for hiding this comment

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

Question 2: Sorry, I'm bad at math. But is this expression just equivalent to:

position = (
  instr.plunger_positions.bottom -
  (ul + correction_volume) / instr.ul_per_mm(ul, action)
)

If so, I think all the work of introducing another concept like multiplier just makes the math more convoluted and harder to follow.

Copy link
Member Author

Choose a reason for hiding this comment

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

The concept of multiplier actually makes the math, or rather, the reason behind the math, more understandable to me. It shows how we are modifying the distance_from_bottom value according to the correction volume. But if others feel it's confusing as well I can modify it.

"""Aspirate a given volume of air from the current location of the pipette.
Args:
volume: The volume of air to aspirate, in microliters.
flow_rate: The flow rate of air into the pipette, in microliters.
correction_volume: The correction volume in uL.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think a slightly more detailed explanation would be helpful. Like, is the correction added or subtracted from the volume (so that users know what the sign should be).

Copy link
Member Author

Choose a reason for hiding this comment

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

👍 Will address this separately. We need to update descriptions of most of the arguments related to liquid classes.

multiplier = 1.0 + (correction_volume / ul)
mm_dist_from_bottom = ul / instr.ul_per_mm(ul, action)
mm_dist_from_bottom_corrected = mm_dist_from_bottom * multiplier
position = instr.plunger_positions.bottom - mm_dist_from_bottom_corrected
return round(position, 6)
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, this is not part of your diff, but I'm opposed to rounding on inner functions like this. You can round the values for display if you want, but rounding as part of the calculation here runs the risk of destroying precision.

(Also, it's a bit silly to rely on rounding when you're using floats. If rounding was really that important, these functions should be implemented with Decimal instead.)

Copy link
Member Author

Choose a reason for hiding this comment

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

I believe the rounding is needed because of lower level driver restrictions.

Copy link
Member Author

Choose a reason for hiding this comment

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

As for whether we should use Decimal, I think you are right that it's more correct. But since this line has been here since beginning of Flex, I am hesitant to change it now. Maybe @andySigler knows better about the consequences of changing it now.

@sanni-t
Copy link
Member Author

sanni-t commented Jan 28, 2025

Going to merge this in to unblock the next work but will keep it open to reviews. Will also keep the branch available for testing.

@sanni-t sanni-t merged commit 410bfa9 into edge Jan 28, 2025
79 checks passed
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.

4 participants