starting another post on capabilities, this one about plate reading. see also: modeling arm capabilities and big architecture discussion on capabilities.
I don’t really have strong thoughts or even detailed proposals on this right now, just raising a couple of points for discussion here, this thread is meant for discussion on how we model plate reading capabilities in PLR v1. @vcjdeboer and @CamilloMoschner talked about this in different posts/chats, some of which I have summarized below.
Splitting classes
it is obvious we need to split the current plate reader into at least 3 classes:
- absorbance (spectrophotometer)
- fluorescence (fluorometer)
- luminescence (luminometer)
since we already have plate readers in PLR that only support one modality and not all 3, the byonoys. this part seems pretty obvious to me, but happy to hear people’s thoughts.
Return types
another point of discussion for this thread is return types. These are difficult to change over time, so we have to design a pattern that will work for any machine and is not likely to change over time, and if it does change it should be easy to have depression warnings. This makes me want to use data classes, because the attributes can have warnings if needed in the future.
As camillo pointed out, it is nice to return the data reading per well-name rather than having this encoded in the position of a 2d array (add byonoy luminescence and absorbance plate readers by rickwierenga · Pull Request #617 · PyLabRobot/pylabrobot · GitHub). I would like to adopt that suggestion.
Kinematics / time series
I think splitting single point reads vs time series into different methods rather than overloading one “read_absorbance” method to do everything, as is currently the case.
Some plate readers support kinematics on the firmware level, but we could consider just doing that on the front end in PLR so that every imager supports it. Is there a benefit to having it exist on the backend level? For example, thermocyclers do benefit from entire protocols being “uploaded” once because they do some planning - theoretically you can imagine just calling “set temp” many times but that does not work as well. I am not sure where plate readers fall on this.
Another point of discussion here is streaming, it would be cool to have callbacks or generators or something to stream data as it comes in.
Plates vs arbitrary positions
I would like to turn @hazlamshamin’s amazing work on turning plate readers into universal imagers (and @CamilloMoschner’s implementation of that on the clariostar) into something that has first class support in PLR.
On the front end, we should obviously still have methods for reading plates since that’s something people often do and we can provide some utilities for it.
On the backend end, we should have the smallest set of atomic commands which are easy to implement to make it easy to add new machines. I am thinking just read_positions will be enough.
[Many plate readers still work on the “plate abstraction”, so on the backend the implementation is necessarily “hacky”, but I think it makes sense to think about a nice abstraction in PLR and then having backends deal with translating that to a specific machine rather than adopting the PLR standard to firmware APIs. Balancing those is kind of an art of course, but this is the general principle]
What I am loosely thinking, without really having looked at implementing:
front end:
read_plate: read wellsread_positions: read coordinates wrt plate lfbread_grid(size, resolution): read a space at a given resolution
backend:
read_positions: read at specific coordinates