skills/pylabrobot/references/resources.md
Verified against PyLabRobot 0.2.1 on 2026-07-23.
PyLabRobot represents a workcell as a resource tree. Typical nodes are:
LiquidHandler / DeckPlate, TipRack, reservoirs, tube racks, and TrashWell, TipSpot, and TipEvery resource has a unique name, dimensions in millimetres, an optional
location relative to its parent, and parent/child relationships. Names are how
Deck.get_resource(name) resolves nested resources, so duplicates are unsafe.
from pylabrobot.resources import Coordinate, Resource
resource = Resource(
name="fixture",
size_x=100.0,
size_y=50.0,
size_z=20.0,
)
parent.assign_child_resource(
resource,
location=Coordinate(x=10.0, y=20.0, z=0.0),
)
The coordinate origin and usable envelope depend on the parent/deck definition. Do not copy coordinates across robots, carriers, adapters, or labware revisions.
Stable 0.2.1 exports vendor/model resource factories. The Hamilton getting started tutorial uses:
from pylabrobot.resources import (
Cor_96_wellplate_360ul_Fb,
PLT_CAR_L5AC_A00,
TIP_CAR_480_A00,
hamilton_96_tiprack_1000uL_filter,
)
from pylabrobot.resources.hamilton import STARLetDeck
Names are case-sensitive. Old examples such as Cos_96_DW_1mL may not identify
the intended current factory. Search the installed 0.2.1 resource namespace or
stable resource docs and verify manufacturer, catalog number, dimensions,
bottom geometry, capacity, lid/adapter, and revision.
Carrier sites are commonly assigned before the carrier is placed on the deck:
tip_carrier = TIP_CAR_480_A00(name="tip_carrier")
tip_carrier[0] = tips = hamilton_96_tiprack_1000uL_filter(name="tips")
plate_carrier = PLT_CAR_L5AC_A00(name="plate_carrier")
plate_carrier[0] = plate = Cor_96_wellplate_360ul_Fb(name="plate")
deck = STARLetDeck()
deck.assign_child_resource(tip_carrier, rails=3)
deck.assign_child_resource(plate_carrier, rails=15)
Rail placement is Hamilton-specific. Other decks use their own sites, coordinates, fixtures, and constraints.
Stable accessors include:
well = plate.get_well("A1")
wells = plate.get_wells(["A1", "B1"])
selected_wells = plate["A1"] # list[Well], even for one identifier
tip_spot = tips.get_item("A1")
selected_tip_spots = tips["A1"] # list[TipSpot]
tip = tip_spot.get_tip()
Relevant stable constructors/attributes include:
Well(..., max_volume=..., height_volume_data=...)Tip(has_filter, total_tip_length, maximal_volume, fitting_depth, ...)TipRack(..., with_tips=True)TipSpot(..., make_tip=...)Tip.maximal_volume is only one compatibility dimension. Also validate fitting,
length, filter, head/tool, pickup/drop geometry, rack model, and vendor support.
Well capacity is geometric bookkeeping. Usable aspiration volume is smaller
when dead volume, well shape, tilt, liquid properties, required immersion, or
assay constraints apply. height_volume_data supports interpolation for
definitions that provide it; it is not a sensor and is only as accurate as the
definition/calibration.
For every resource, verify:
mm).Hamilton deck assignment performs collision checks and exposes an
ignore_collision escape hatch. Do not set ignore_collision=True to make a
layout pass. Resolve the definition or placement and repeat physical review.
Generic resource assignment alone is not a complete collision or motion check.
The bundled checker provides an independent deterministic screen:
python3 skills/pylabrobot/scripts/check_deck_geometry.py \
--input skills/pylabrobot/tests/fixtures/protocol_manifest.json
It checks deck bounds and pairwise axis-aligned box overlap. It intentionally does not claim to model rotation, motion, lids, tubing, cables, tolerances, or vendor firmware paths.
from pylabrobot.resources import set_tip_tracking, set_volume_tracking
set_tip_tracking(True)
set_volume_tracking(True)
tips.fill()
tips.get_item("A1").tracker.has_tip
plate.get_well("A1").tracker.set_volume(200.0)
plate.get_well("A1").tracker.get_used_volume()
plate.get_well("A1").tracker.get_free_volume()
Trackers model expected software state and operation history. They do not physically detect tips, liquid, liquid identity, clogs, seals, lids, or misloaded labware. Reconcile tracker state against a trusted preparation record and the physical deck before any live run.
Keep these separate:
Verified 0.2.1 methods include:
resource.save("deck.json", indent=2)
loaded = Resource.load_from_json_file("deck.json")
state = resource.serialize_all_state()
resource.load_all_state(state)
resource.save_state_to_file("state.json", indent=2)
resource.load_state_from_file("state.json")
Resource.serialize() stores a definition; serialize_state() and
serialize_all_state() store tracker/resource state. Keep definition and state
with protocol version, PyLabRobot version, checksums, device/deck identity, and
preparation metadata.
Treat serialized files as untrusted input:
Resource.deserialize(..., allow_marshal=False) at its safe default;The bundled tools do not deserialize PyLabRobot classes. They use a small, strict manifest schema:
assets/protocol-manifest.schema.jsontests/fixtures/protocol_manifest.jsonThe Python validator adds bounds and cross-field checks beyond the documentation schema:
python3 skills/pylabrobot/scripts/validate_manifest.py \
--input skills/pylabrobot/tests/fixtures/protocol_manifest.json
Inputs must remain under the current working directory, be regular non-symlink files, use the expected extension, and stay under 2 MB.
Do not invent a Plate or Well from nominal SBS footprint alone. Obtain and
review:
Use upstream's current resource-definition contributor tooling and tests. Keep custom definitions versioned and independently reviewed before commissioning.
Checked 2026-07-23:
v0.2.1 resources source
— constructor, serialization, tracker, and collision signatures; tag dated
2026-03-23.height_volume_data; plate stacking_z_height is listed under
Unreleased and is not assumed stable.