question by @naikymen
let’s discuss here
Thanks Rick!
The argument is that tips are similar to containers:
Making them proper Resources would also allow them to have a location, which I think could be used to redefine how the tip’s Z coordinate is derived. They could also gain additional properties to represent more complex interactions with other resources.
Another matter I’d like to introduce is the notion of compatibility. I have well defined data for the mechanical interfaces between a handful of brands and variants of tubes and tips, and their respective racks.
A tip can only be placed in a spot if it has been calibrated. I now understand that PLR’s idea is to not enforce any checking, but my end does, and it requires this dimensional information.
I’ll add more ideas as I remember them.
My question is a bit simpler:
Does a tip follow PLR’s Container
definition?
Container
is a direct subclass of Resource
:
Resource
├── Container
│ ├── Well
│ ├── PetriDish
│ ├── Tube
│ └── Trough
…and Container
is defined as
class Container(Resource):
""" A container is an abstract base class for a resource that can hold liquid. """
def __init__(
self,
name: str,
size_x: float,
size_y: float,
size_z: float,
material_z_thickness: Optional[float] = None,
max_volume: Optional[float] = None,
category: Optional[str] = None,
model: Optional[str] = None,
compute_volume_from_height: Optional[Callable[[float], float]] = None,
compute_height_from_volume: Optional[Callable[[float], float]] = None,
):
Based on the definition of Container
…
→ 1.a) tips do not have a material_z_thickness
because they don’t have a bottom nor a top.
→ 1.b) compute_volume/height functions don’t make much sense for a tip because the volumetracker tracks the volume of the liquid inside the tip already and the actual tip_volume is variable depending on piston movement.
→ I would therefore argue that a tip does not meet the definition of the PLR class Container
because it does not meet the geometric characteristics that define this class.
A tip is basically a tube, a Container
is an item that has 5 sides around its cavity, i.e. has a bottom but has no top.
Also, mechanistically Container
’s depend on gravity to hold a liquid inside them, i.e. they are passive objects in terms of holding a liquid.
Tip’s are essentially the opposite: they fight gravity using energy.
In summary, the PLR class Container
is clearly defined in PLR.
The word “container”, on the other hand, is very ambiguous (hence the need for a clear PLR definition), and could be interpreted as anything that holds a liquid.
But that is different to the PLR class Container
.
I completely agree with this!
I also think that we should make tips a resource.
My take is that Container
is already too precisely defined and different to the geometric and functional characteristics of a tip.
Instead we should face the complexity by modelling reality:
I propose creating a new Resource
subclass called Tip
directly.
We can discuss whether there are any other subclasses whose behaviour directly applies to Tip
and Tip
could therefore become a direct subclass of that class.
But to my understanding Tip
is sufficiently distinct to be a direct subclass of Resource
itself.
I really like your idea @naikymen of giving tips specialised attributes this way!
This can solve an array of problems:
The first one that comes to my mind is that Hamilton uses HamiltonTip
s which cannot be used on ‘friction-fit-dependent’ liquid handlers.
Similarly, FrictionTip
s cannot be used on Hamilton liquid handlers.
Instantly, PLR can be refactored to take specialised Tip
subclasses into account to only ensure correct tip compatibility
Makes sense then to not make them containers.
Can you elaborate on this one a bit more?
I think that leaving room for height functions is interesting. I want to eventually write a “paranoid mode” for running protocols, that checks every step with cameras and opencv or ai. Knowing the expected height would be handy to check if a tip has volume in it.
A question: do you always use exactly one kind of tip on each tip rack and vice versa?
In my case there is a few-to-a-few relationship between the tip racks that we have and the tips we buy, which change brand every year or so.
I’d like to model this into a PLR Tip, as I already do it in my schemas. At least I would like a place to store the information, otherwise going through PLR is “lossy”.
That happens with other items too, but we can talk about that later.
Thanks for input.
Let’s agree that Containers are
Resource
Let’s agree to make Tip
s inherit from Resource
soon.
Resource
location = None
) when mounted on a liquid handlerWe can formalize this and put it on the docs website.
realistically, it’s likely, but the actual racks can hold any arbitrary tip in Hamilton’s case.
I suppose we could have a supported_tips
list.
But why is this necessary on a level beyond the GUI? On the GUI I understand it makes things nice for the user. I’m just trying to understand the use case so we can design an api, or potentially drop the requirement (simpler is better, Occam’s razor applies to api design as well).
I love “paranoid mode”! LOL
PLR has both tip and volume tracking: Using trackers — PyLabRobot documentation
Though, I am actually not sure whether this tracking keeps a record of the assumed/target volume inside the tips or just in Container
s?
Besides this most of the machines I interact with have tip volume tracking via piston state built-in already at the firmware level. The reason appears to be that firmware must protect hardware, i.e. the channels/pipettes: if the piston inside the pipette would be sent beyond the shaft it is in, it would break the pipette.
Keeping a record of the position of the piston is therefore very important.
But since piston_volume and target_liquid_volume are not always correlated in the same way (because of “liquid_classes”) it makes more sense for the hardware to track for the piston_volume, rather than the target_liquid_volume.
I think that leaving room for height functions is interesting. I want to eventually write a “paranoid mode” for running protocols, that checks every step with cameras and opencv or ai. Knowing the expected height would be handy to check if a tip has volume in it.
hahaha yes, I like this idea too
Though I would be cautious of the cost-benefit of such a computer vision task:
Getting the quality of the cameras, camera-movement to each channel (if you’re building a multi-channel system?), image segmentation of all objects in question (tip, various liquid types) … all right in varying light conditions using the processing power of the control machine (i.e. on “edge”) in real-time with the aim of performing distance measurements (i.e. height of the liquid) is quite a project.
(I’d recommend looking into the challenges behind photogrammetry when considering this approach)
There are definitely some easier open-source CV tasks that liquid handlers would massively benefit of imo (e.g. deck verification, TipRack verification and autocorrection,…) but this is moving outside the remit of this thread though
I think that leaving room for height functions is interesting. I want to eventually write a “paranoid mode” for running protocols, that checks every step with cameras and opencv or ai. Knowing the expected height would be handy to check if a tip has volume in it.
Keeping / Providing the height functions also leaves room for other interesting stuff you can do with this information. I vote to keep / provide those functions.
Absolutely, PLR should never withhold functionality.
The height/volume functions are technically independent of the Container
class (PR#59, PR#136, PR#139, PR#200) and could easily be integrated into a Tip
class.
I am curious, what kind of stuff can we do with this information?
Assuming utility, how would users go about measuring liquid height and volume inside a Tip
directly?
Assuming a photogrammetic method is robust, one still requires validating it for a given liquid-tip first.
(I think a spectrophometric method would actually be easier? but would still depend on adding currently non-existing hardware…)
This means generating a volume-to-height dataset for the tip in question.
Volume: The volume taken up is dependent on the accuracy of the aspiration process (trusted, manual liquid transfer into a tip on a channel is impossible); so I guess it could be assumed to be the aspiration_target_volume after extensive liquid aspiration verification → that could give the volume (?).
Height: Measuring height of the liquid inside the tip is not possible though through the machine itself, to my knowledge.
This means (in the absence of access to a photogrammetric or spectrophotometric height measurement method) one would have to manually take a list of caliper measurements of the liquid height inside the tip, each time aspirating a little bit more volume into the tip, assuming that the summed volume is still correct?
This is another difference between Tip
and Container
:
Liquid volume-height relationships are super simple to precisely measure for a Container
because Container
s have a bottom and passively hold liquid:
ztouch_probe
function (Build ztouch Probing Function by BioCam · Pull Request #260 · PyLabRobot/pylabrobot · GitHub) to precisely measure the non-conductive container_cavity_bottom_z_coordinate,clld_probe
function to measure the height of the liquid, recording both volume and clld_z_height,Container
geometry difference, i.e. "small increments around sharp curvatures in the Container
),Meant to add this to the docs for ages
(Re-reading this I understand that this is very Hamilton-centric, apologies to those not using a Hamilton machine.)
I’m not sure how we’d go about creating a similar approach for the different Tip
instances.
But I agree that this can be very useful. In case of Container
you can do so much with this information:
The ability to calculate height from volume and vice versa has numerous direct applications:
e.g. liquid level following is super easy → you know the volume in a container you have and will have → liquid_following_distance can be calculated and (to my understanding in a PLR-first) dynamically adjusts for Container
geometry inconsistencies (no more 2nd section commands needed )
e.g. you can probe the liquid volume in any well-defined Container
→ no more guesswork of “how much liquid do you think might still be in these wells?”
e.g. a PID-controlled liquid transfer that probes the volume it has just transferred until it gets it right
So I wonder what could be done with this information in Tip
Assuming a photogrammetic method is robust, one still requires validating it for a given liquid-tip first.
Using photometric methods will only work with transparent tips, which would be a general limitation. However, vendors would be able to provide precise geometry definitions of the tips.
Liquid volume-height relationships are super simple to precisely measure for a
Container
becauseContainer
s have a bottom and passively hold liquid
Is measuring required because no geometry definition is available from the vendors or because the provided data is not as accurate as required?
Using photometric methods will only work with transparent tips, which would be a general limitation.
Of course, I didn’t consider that. Thank you for pointing that out.
Another aspect to why measuring liquids inside Tip
s is difficult to the point of questioning its utility without a clear use case for it.
Is measuring required because no geometry definition is available from the vendors or because the provided data is not as accurate as required?
Both plus more:
Measuring is required because…
Resource
s/dataResource
data - if even available - is not accurate enough/tolerances needed for automation are not presentedResource
- even if known - is so complex across their x-z and y-z planes that a rational height/volume function becomes too complex to be readable/maintanable/usable. Simply measuring and performing a polynomial fit is a “black box” approach but actually just easier.Container
definition. Measuring the heights of volumes empirically rather than from definitions reduces risk of incorrect definitions propagating to incorrect height/volume functions.PlateCarrierSites
: PR#205; but is still a problem in some instances)Assuming utility, how would users go about measuring liquid height and volume inside a
Tip
directly?
I imagine that taking pictures is as direct as it gets, but I was not aware that opaque tips existed. Internal pressure sensors could work, but would depend on vapour pressures of the solution, temperature, etc. I have not seen lasers or ultrasound in use yet, they could be used in a custom pipette to measure the level or the free dead volume, through TOF or resonance.
Re-reading this I understand that this is very Hamilton-centric
Part of the question is hardware and application specific. My idea for this is just to offer an “expected” height, such that backends may take advantage of it.
My intended application does not require PLR to calculate the current/expected height, as one could always estimate it outside. It wouldn’t be terrible to leave out, but it would be convenient to keep al kinds of liquid tracking and height calculations for all labware in one place.
This means generating a volume-to-height dataset for the tip in question.
I am under the idea that one has to validate each new brand and type of tips. They are not all made equal, unfortunately. Some are bent, some have burr on the tip, some fit differently on the same pipette, etc.
This leads me back to the idea of having tips be of a certain brand and model, with certain dimensional parameters, and certain compatible tip racks (its “spots” actually) and micropipettes. I have this information in my data schemas, and would also like the new “TipContainer” class to have it.
These new properties should be optional, for backwards compatibility, but having them would give backends more information to work with.
Meant to add this to the docs for ages
(Re-reading this I understand that this is very Hamilton-centric, apologies to those not using a Hamilton machine.)
We have some hamilton specific documentation: Hamilton STAR — PyLabRobot documentation
Please add! You can simply put a jupyter notebook / markdown file here: pylabrobot/docs/user_guide/hamilton-star at main · PyLabRobot/pylabrobot · GitHub
My intended application does not require PLR to calculate the current/expected height, as one could always estimate it outside. It wouldn’t be terrible to leave out, but it would be convenient to keep al kinds of liquid tracking and height calculations for all labware in one place.
I think since this would be a very rough estimation, it might not be good to add to PLR. It sounds like getting good data is unreasonably hard, and to be honest, I don’t really see a general use-case (perhaps I lack imagination, please tell me about applications!)
These new properties should be optional, for backwards compatibility, but having them would give backends more information to work with.
Can we store these in a static __metadata__
property?