Open EvanKirshenbaum opened 5 months ago
This issue was referenced by the following commit before migration:
What I think we're going to want to do is to reify the notion of a WellPlate
as something associated with a Pipettor
, where each WellPlate
has a number of WellPlateWell
s, nameable by name (e.g., A2
) or XYLoc
.
Board
s, WellPlate
s will presumably want an Orientation
, but the default will probably be NORTH_NEG_EAST_POS
.The Pipettor
model will want to keep track of what (it believes) is where, update as a MonitoredProperty
, and the user or protocol should be able to change the reagent or volume of a WellPlateWell
to reflect additions or removals that the system is unaware of (including telling the system about initial conditions).
For the OT2
, this means that
OT2
needs to parse the reagents spec and config spec to figure out the initial conditions or, possibly better, the robot needs to tell the system on its first ready
call where everything is. ready
call) what deltas actually happened on the last request.
I'm thinking of simplifying this a bit.
Instead of WellPlate
s and WellPlateWells
, we'll just have a PipettingSource
, analagous to PipettingTarget
, but concrete. It will have
name
, which is a string interpretable by the Pipettor
capacity
, which can be None
to indicated unknown or unlimitedcontents
, from which you can get reagent
and volume
pipettor
The Pipettor
will have the ability to look up PipettingSource
s by reagent (getting a possibly empty sequence) and name (getting an Optional[PipettingSource]
).
In the macro language, you can talk about, e.g.,
source "A2"
source "A2/2" // e.g., A2 at slot 2, but interpreted by the Pipettor
r's source
r's source = "A2"
r's source = 2uL
source "A3"'s contents = 200uL of r1
r's source's volume
Going into the contractor freeze, what's implemented seems stable, and I've merged it into master
, even though the Opentrons protocol doesn't transfer source information back and forth.
What I've currently got is a PipettingSource
class that has
name
, canonically something like "A1"
or "B2/3"
(for "B2"
on slot 3
).capacity
, which can be infinite.bounds
as a tuple of minimum and maximum volume in the source.
capacity
.min_volume
and max_volume
pulled from bounds
exact_volume
returns None
if the min and max aren't the samereagent
that's settable once.
assigned_reagent
that gets reagent
when it's set.is_assigned
which is true if reagent
has been set
Aside from the attributes, the only thing you can do with a PipettingSource
is add or subtract volume.A Pipettor
has
@abstractmethod
def perform(self, transfer: Transfer) -> None:
...
@abstractmethod
def sources_for(self, reagent: Reagent) -> Sequence[PipettingSource]:
...
def source_for(self, reagent: Reagent) -> Optional[PipettingSource]:
...
where source_for()
calls sources_for()
and returns
None
if sources_for()
returns an empty sequence,max_volume
> 0, if that exists, orThis is all implemented for DummyPipettor
, ManualPipettor
, and OT2
, but the OT2
implementation doesn't yet exchange information with the robot to keep it up to date.
What it does do is add a source to a set of dirty sources if the bounds
or reagent
change unless it thinks it's receiving changes from the robot, in a synchronized region. The OT2
creates WPWell
s (a subclass of PipettingSource
) for each well in each well plate listed in the config
and assigns them according to the reagents
specified to __init__()
.
What I intend to do next is that either on each call or on ready
calls (I think each call makes more sense) either side can send a list of sources that need to be updated. This would include the plate, well name, reagent, and quantity.
When replying to a message, the list would be created based on the dirty set, which would then be cleared. When receiving a message, the sources would be updated.
As presently implemented, the
Pipettor
is responsible for knowing where to obtain reagents from and where to put products and waste (and any reagents transferred back to source locations).For the
DummyPipettor
, this doesn't matter, and for a manual pipettor (#163), we can assume that the user knows what's where (although this facility could be useful to add information to the prompts to make errors less likely).For the Opentrons
OT2
, it is assumed that by theconfig
andreagents
parameters to its__init__()
, it knowThis information is passed to the OT2 itself, and its software takes care of keeping track of what's where to satisfy requests, which just talk in terms of reagents and quantities.
This works fine for protocols like combinatorial synthesis, which can run unattended, but it won't work when people want to use an OT2 interactively via the macro language (#147).
Migrated from internal repository. Originally created by @EvanKirshenbaum on Jun 09, 2022 at 11:44 AM PDT.