Skip to content

Conversation

@BioCam
Copy link
Collaborator

@BioCam BioCam commented Dec 12, 2025

Hi everyone,

Our automated Protocols (aPs) keep using liquids from Containers and we must know what the volume in all containers (Wells inside wellplates, Tubes, Troughs, ...) is.

This is crucial for "compound management" and verification correct workcell/deck setups.

Here, I am proposing a beta version of STAR.probe_liquid_volumes() which can measure the volume of any Container for which height/volume functions have been previously defined in PyLabRobot.

This first version uses the STAR.aspirate() function with volume=0 to enable liquid level detection in either a...

  1. capacitative- or
  2. pressure- based mode.

This means that both conductive and non-conductive/clear tips can be used to probe the volume in containers.

Accuracy: cLLD/pLLD is not always the most precise measurement technique and for low-volume or narrow Containers might not work at all, based on the STAR cLLD/pLLD limitations.
You have to verify that the LLD works for your Containers and give your processes enough dead-volume if you use it at the low-volume end.

However, by enabling both LLD modes you have quite some flexibility to find a way that suits your application.

Furthermore, by default, 3 technical replicates of the probing will be executed, and this can be adjusted based on the method arguments:

  async def probe_liquid_volumes(
    self,
    containers: List[Container],
    use_channels: List[int],
    resource_offsets: Optional[List[Coordinate]] = None,
    lld_mode: Optional[List[int]] = None,
    minimum_traverse_height_at_beginning_of_a_command: Optional[float] = None,
    min_z_endpos: Optional[float] = None, # defaults to self._channel_traversal_height
    techn_replicate_num: int = 3,
    return_mean: bool = True,
    traversal_height: Optional[float] = None, # defaults to self._channel_traversal_height
    move_to_z_safety_after: bool = True,
) -> Union[List[float], List[Tuple[float, ...]]]:

This has been tested on single Container (troughs) and different multi-wellplates on a Hamilton STAR.

Note: This is a beta method - use with caution and we will continuously iterate and improve over the coming months.
E.g.: a discussion should be had about whether to swap the .aspirate() implementation with clld_probe_/plld_probe_ implementation.
Please report any issues you might encounter on the PyLabRobot forum.

Happy compound management 🧪

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new method probe_liquid_volumes() for the Hamilton STAR backend that enables automated measurement of liquid volumes in containers using Liquid Level Detection (LLD). The method supports both capacitive and pressure-based detection modes, performs multiple technical replicates for accuracy, and converts detected heights to volumes using container-specific volume functions.

Key Changes:

  • Added probe_liquid_volumes() method that performs zero-volume aspirate operations to detect liquid levels
  • Implements support for both capacitive (mode 1) and pressure-based (mode 2) LLD
  • Returns either geometric mean or individual replicate measurements based on configuration

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rickwierenga
Copy link
Member

I think this would be easier by calling probe_liquid_heights and then simply the height to volume functions for the corresponding containers.

@BioCam
Copy link
Collaborator Author

BioCam commented Dec 16, 2025

I think this would be easier by calling probe_liquid_heights and then simply the height to volume functions for the corresponding containers.

Yes, that is what I initially wanted to do but

  1. probe_liquid_heights is dependent on being given a list of HamiltonTip instances directly - that is unnecessarily extra work and should be handled by the backend directly; and though hacky, this PR shows that there is a way to overcome the firmware limitation (and removing the Tip instance dependency)... which we could integrate into probe_liquid_heights, but the reason I didn't do this here yet is also...
  2. probe_liquid_heights is actually clld_probe_liquid_heights which mean plld_probe_liquid_heights is not supported, but that's what I have been using with this new function for all my transparent tips :)

We'd first have to implement the pressure sensing though to facilitate this (it is command PXZE)

@BioCam
Copy link
Collaborator Author

BioCam commented Dec 16, 2025

So the long-term solution I see:

  1. Move the lld_mode argument into probe_liquid_heights directly.
  2. Remove the HamiltonTip dependency from probe_liquid_heights.
  3. Then make probe_liquid_volumes simply call and forward the arguments to the updated probe_liquid_heights.

But that takes time and I think, first needed an example of how it could be done (this PR).

So I wanted (and needed) a probe_liquid_volumes now which can be refactored in the future to achieve the exact same with the exact same parameters

@rickwierenga
Copy link
Member

regarding everything you said: this can be fixed by improving probe_liquid_heights

if we have a robust probe_liquid_heights function, the step to volume should be super trivial. in any case, probe_liquid_volumes will be probing the liquid height first, so it only makes sense to me to have that logic be in probe_liquid_heights

@rickwierenga
Copy link
Member

in your code, you just bypass the tip requirement by always saying tip=standard_volume_tip_with_filter(). it is not a real fix

@rickwierenga
Copy link
Member

I agree it's a real problem, and we should have a good fix, but right now we just have to whack solutions:

  • user passes tip
  • always tip=standard_volume_tip_with_filter()

I think 1 is the lesser evil because at least it's correct

@BioCam
Copy link
Collaborator Author

BioCam commented Dec 16, 2025

in your code, you just bypass the tip requirement by always saying tip=standard_volume_tip_with_filter(). it is not a real fix

I agree... but there are two problems here:

  1. the firmware does not allow us to access its memory of what tip it knows is currently on a head
  2. PyLabRobot forces an aspiration to be given a tip instance

In terms of results, this implementation gives the correct result.
In terms of truthfulness to the PLR-created code requirements, it uses a never used fake tip instance to get to the correct conclusion.

@rickwierenga
Copy link
Member

which is fine, given that that hack works better actually.

but I still think that prove_liquid_volume can be written simply in one go: probe liquid height and then convert it to volume. everything else should be done in probe_liquid_height. including this hack, why don't you put the logic in probe_liquid_height?

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.

2 participants