Context
The storage user guide already defines two retrieval patterns — Stacking Access (Sequential) vs Random Access — and explicitly puts the Agilent BenchCel 4R, Labware MiniHub, and Lab Services PlateCarousel in the sequential column (docs/user_guide/01_material-handling/storage/storage.rst).
In code, though, that distinction doesn't exist yet: Incubator is the only storage frontend, and it is fundamentally random-access — it takes racks: List[PlateCarrier] of addressable PlateHolder sites and exposes find_random_site / find_smallest_site_for_plate / take_in_plate(site). Every backend (CytomatBackend, LiCONiC, Heraeus, and now BenchCel4RBackend) subclasses IncubatorBackend.
The mismatch (surfaced while adding the BenchCel, #1109)
A BenchCel stacker is a single-ended LIFO stack of nesting plates — the firmware only addresses whole stackers (downstack/upstack at one end); there is no slot addressing. To fit the Incubator model, #1109 currently fakes each stacker as a 20-site PlateCarrier where only the stacker identity is ever used and the sites are cosmetic. The frontend therefore advertises random-access operations (find_random_site, placing into an arbitrary site) that the hardware cannot honor.
Opportunity
ResourceStack(direction="z") already models exactly this: single-ended LIFO access (it only lets you unassign the top item), and — since #1110 (Plate.stacking_z_height) and #1112 — it nests plates by their stacking pitch, which is precisely a stacker's geometry. #1109 also now maps Plate.stacking_z_height → BenchCel StackingThickness.
Proposal / question for discussion
Would you be open to a sequential/stacking storage abstraction (e.g. a Stacker frontend, or a shared storage base) backed by ResourceStack, exposing downstack/upstack (LIFO) semantics instead of random-access site selection? It would model the documented "Stacking Access" category directly and would also fit the MiniHub / PlateCarousel.
Open design questions I'd love your steer on, @rickwierenga:
- A new parallel frontend (
Stacker) vs. generalizing the existing storage frontend to support both access patterns.
- Whether to introduce a
StorageBackend base above IncubatorBackend, or keep backends as-is.
- How loading/transfer should be modelled for sequential devices (the BenchCel has no fixed loading position — it uses teachpoints).
Happy to prototype whichever direction you prefer. Not blocking #1109 — that ships with the current Incubator-based model and a doc note describing this limitation.
Refs: #1109 (BenchCel), #1110 (Plate.stacking_z_height), #1112 (ResourceStack nesting).
Context
The storage user guide already defines two retrieval patterns — Stacking Access (Sequential) vs Random Access — and explicitly puts the Agilent BenchCel 4R, Labware MiniHub, and Lab Services PlateCarousel in the sequential column (
docs/user_guide/01_material-handling/storage/storage.rst).In code, though, that distinction doesn't exist yet:
Incubatoris the only storage frontend, and it is fundamentally random-access — it takesracks: List[PlateCarrier]of addressablePlateHoldersites and exposesfind_random_site/find_smallest_site_for_plate/take_in_plate(site). Every backend (CytomatBackend, LiCONiC, Heraeus, and nowBenchCel4RBackend) subclassesIncubatorBackend.The mismatch (surfaced while adding the BenchCel, #1109)
A BenchCel stacker is a single-ended LIFO stack of nesting plates — the firmware only addresses whole stackers (downstack/upstack at one end); there is no slot addressing. To fit the
Incubatormodel, #1109 currently fakes each stacker as a 20-sitePlateCarrierwhere only the stacker identity is ever used and the sites are cosmetic. The frontend therefore advertises random-access operations (find_random_site, placing into an arbitrary site) that the hardware cannot honor.Opportunity
ResourceStack(direction="z")already models exactly this: single-ended LIFO access (it only lets you unassign the top item), and — since #1110 (Plate.stacking_z_height) and #1112 — it nests plates by their stacking pitch, which is precisely a stacker's geometry. #1109 also now mapsPlate.stacking_z_height→ BenchCelStackingThickness.Proposal / question for discussion
Would you be open to a sequential/stacking storage abstraction (e.g. a
Stackerfrontend, or a shared storage base) backed byResourceStack, exposing downstack/upstack (LIFO) semantics instead of random-access site selection? It would model the documented "Stacking Access" category directly and would also fit the MiniHub / PlateCarousel.Open design questions I'd love your steer on, @rickwierenga:
Stacker) vs. generalizing the existing storage frontend to support both access patterns.StorageBackendbase aboveIncubatorBackend, or keep backends as-is.Happy to prototype whichever direction you prefer. Not blocking #1109 — that ships with the current
Incubator-based model and a doc note describing this limitation.Refs: #1109 (BenchCel), #1110 (
Plate.stacking_z_height), #1112 (ResourceStack nesting).