Thank you @fderop for your message and report of the issue’s you’re encountering.
That is exactly the same issue I encountered, starting this thread
I have been working on identifying the problem and fixing it since February; it would be awesome to have another person working on this!
A couple of things to note and a summary of the work I’ve done so far with @rickwierenga:
- We renamed what has been named “CarrierSite skirt” to “pedestal” because
Plate
s have skirts,CarrierSite
s don’t. Small item but the nomenclature can become very confusing.
- I completely agree; this issue is so deeply engrained in PLR and affects so much functionality, making it very complex. A good guide is needed. I’ve created a series of visualisations in the PRs I created for this purpose. But ultimately I aimed to write up a “Plate Definition Post-Mortem” similar to the 50ul Tip Troubleshooting Report / Post-Mortem I wrote after we fixed the 50ul tip definition
- This is already the definition of
Plate.size_z
(to my knowledge).
- This is already the definition of
Well.size_z
-Well.material_z_thickness
.
- This has been one of the cruxes of the definition problem:
This attribute has so far been completely missing in PLR, and what makes the matter more confusing, this attribute is supposed to be calledWell.dz
as it is the offset of the well in relationship to its plate.
However, the termdz
has already been incorrectly occupied in PLR, as theWell.material_z_thickness
(due to an import error from VENUS definitions).
Fixing the definition ofPlate
is a precedence constraint to fixing the placement issue.
We therefore agreed upon a new definition scheme that I made this visualisation for:
- I completely agree; though most people I’ve met use a metal plate adapter instead of this plastic one because the plastic one tends to create a friction fit between the plastic_adapter and the plastic semi-/non-skirted plate. As a result the robot is at risk of picking up both plastic_adapter+non-skirted plate when trying to move the plate.
Since we didn’t have a plate adapter definition that correctly, automatically adjusts the placement of a plate onto an adapter I developed one viaPlateAdapter
in PR#152.
- Unfortunately, that is not completely accurate for all plates:
Many plates’ wells actually stick out of the plate top plateau (hence why I added a plate like this in the figure I made above).
This means it is very hard to calculate theWell.material_z_thickness
, the attribute you calledwell_bottom_dz
, from other information and that is currently being added to allContainer
in PR#183.
Instead it is a lot easier to measure it directly on a Hamilton machine:
i. Use the CMM cLLD function that I developed in PR#69,STAR.probe_z_height_using_channel()
to measure the pedestal z-coordinate of aPlateCarrierSite
with a pedestal.
ii. Place plate on thatPlateCarrierSite
iii. move channel with tip to the inside bottom of a well of that plate, incrementally decreasing the z-coordinate of the tip, checking whether the tip can scratch the bottom already (not pressing against it), note the z-coordinate
iv. the difference between these two measures is theWell.material_z_thickness
(funnily that is exactly the same way that I’ve seen Hamilton engineers identify this attribute, which they call “thickness_of_container_base”)
- Unfortunately, no, this is not quite what I was trying to say (and I apologise for the confusion, there are multiple parallel problems that all need to be solved at the same time, and I might have not conveyed them all in an easy to understand matter):
What you are suggesting, i.e. adding theWell.material_z_thickness
(yourmaterial_bottom_dz
) as the offset when a plate sits on aPlateCarrierSite
with a pedestal, is exactly what PLR is doing right now.
→ The problem is that PLR doesn’t change this when the plate sits on aPlateCarrierSite
without a pedestal AND that PLR currently cannot do so because it misses the definition ofWell.dz
andWell.material_z_thickness
.
.
I investigated a couple of different methods to fix this:
A.) change the z-origin of the well based on the type ofPlateCarrierSite
→ this doesn’t work because the well origin never changes its location in relationship to the origin of the plate.
From a coding side, this is because the well origin coordinates are created bycreate_equally_spaced_2d
inpylabrobot/resources/utils.py
but, importantly, thedx
,dy
, anddz
variables are not attributes ofPlate
, making their modifications based on whatPlateCarrierSite
the plate sits on (i.e. with vs without a pedestal) very hard. It would get us back into “offset land” where we have to correct for definition errors with offsets which have to be maintained and updated every time we change the definition, creating infinite technical dept.
From a physical reality side, this doesn’t make sense because it is not the well that changes its location, it is the entire plate.
B.) Correct the definition ofPlate
→ minimal required information is- getting the site ready:
PlateCarrierSite.pedestal_z_height
(added in PR#143) - getting the plate ready:
Well.material_z_thickness
(currently being added in PR#183)
Well.dz
(currently being discussed to be added in PR#183 under the synonymskirt_base_to_well_base
→ reason:dz
is wrongly pre-occupied with the value of the realWell.material_z_thickness
at the moment, and we have to transition to the corrected nomenclature without breaking anything)
- getting the site ready:
-
With this information we can simply say:
- If
PlateCarrierSite.pedestal_z_height
>Plate
’sWell.dz
“sink” plate into thePlateCarrierSite
(to get the plate origin into its real location) - Else place
Plate
origin ontoPlateCarrierSite
origin
- If
-
I hope this explains it a little bit better, and showcases how deeply the problem is engrained, and what we have to do to fix it.
-
There are two issues with this:
i. The bottom of the pedestal is not at the purple arrow but is higher up (in z-dimension) at the cyan arrow. This little protrusion at the sides is what a plate skirt would sit on top of if theWell.dz
>PlateCarrierSite.pedestal_z_height
.
@rickwierenga add a new photo to demonstrate what has to be measured to Docs: Plate Carriers
ii. the origin of the
PlateCarrierSite
is at the topmost surface of the site, i.e. the top of the pedestal (this is how VENUS appears to handle this problem, and we chose to adapt a similar solution).
ThereforePlateCarrierSite.pedestal_z_height
is actually a negative float that showcases how far a plate can sink into its site.
- Yes, that is a big problem for using robots for actual experiments, and I believe this is one of the main reasons why most robotics in biology has been confined to what I call “process churning”, i.e. perform the same repetitive tasks over and over again, not changing anything about the setup… because as you said: even changing a plate to a different
PlateCarrierSite
on the same carrier can have different offsets.
What we all seem to want though is using robotics for experiments, i.e. tasks that are fundamentally changing from one automation run to the next. (thanks to procedural robotic control like PLR this is now possible from a software side but the hardware is now the next challenge).
I found working with careful considerations of tolerances gets me 90% where I need to go.
Plus, for those really tough applications there is lld_mode=4, z-touchoff, i.e. crash tip into the bottom and aspirate from there… but that might not work for all applications and it is slower.
Besides that I am myself trying to work out a couple of new solutions for applications where this has become a limiting problem