← Về thư mục
📄 / / profiles / r-and-d / raw_evidence / scientific-agent-skills / skills / pylabrobot / references / liquid-handling.md

Liquid handling

Verified against PyLabRobot 0.2.1 on 2026-07-23. Examples in this reference are planning or chatterbox-only. They are not authorization to connect to a robot.

Stable frontend and backend

from pylabrobot.liquid_handling import LiquidHandler
from pylabrobot.liquid_handling.backends import LiquidHandlerChatterboxBackend
from pylabrobot.resources.hamilton import STARLetDeck

lh = LiquidHandler(
    backend=LiquidHandlerChatterboxBackend(num_channels=8),
    deck=STARLetDeck(),
)
await lh.setup()  # prints operations; no hardware transport

For 0.2.1, the important frontend signatures are:

pick_up_tips(tip_spots, use_channels=None, offsets=None, **backend_kwargs)
drop_tips(tip_spots, use_channels=None, offsets=None,
          allow_nonzero_volume=False, **backend_kwargs)
return_tips(use_channels=None, allow_nonzero_volume=False, offsets=None,
            **backend_kwargs)
aspirate(resources, vols, use_channels=None, flow_rates=None, offsets=None,
         liquid_height=None, blow_out_air_volume=None, spread="wide",
         mix=None, **backend_kwargs)
dispense(resources, vols, use_channels=None, flow_rates=None, offsets=None,
         liquid_height=None, blow_out_air_volume=None, spread="wide",
         mix=None, **backend_kwargs)

Volumes are microlitres (uL), coordinates/heights are millimetres (mm), and flow rates are uL/s unless the exact backend page says otherwise. Use lists whose lengths agree with selected resources/channels; do not rely on scalar broadcasting copied from an older example.

Safe operation shape

With the software-only backend and already assigned resources:

source.get_well("A1").tracker.set_volume(100.0)  # bookkeeping only

await lh.pick_up_tips(tips["A1"])
await lh.aspirate(
    source["A1"],
    vols=[25.0],
    use_channels=[0],
    flow_rates=[50.0],
    liquid_height=[1.0],
)
await lh.dispense(
    destination["A1"],
    vols=[25.0],
    use_channels=[0],
    flow_rates=[75.0],
    liquid_height=[2.0],
)
await lh.return_tips()

Before translating this to any physical system, verify:

The bundled transfer planner makes the conservative choice of one new tip per CSV row.

transfer() is not the old plate-copy API

In 0.2.1 the verified signature is:

transfer(source: Well, targets: List[Well], source_vol=None, ratios=None,
         target_vols=None, aspiration_flow_rate=None,
         dispense_flow_rates=None, **backend_kwargs)

It represents distribution from one source to multiple targets. Old examples that pass parallel source=source_plate["A1:H12"], dest=..., and vols=... do not match this stable signature. For one-to-one transfers, plan explicit aspirate/dispense pairs and validate channel/tip state.

Tip tracking

Enable tracking before operations:

from pylabrobot.resources import set_tip_tracking

set_tip_tracking(True)

Tip racks normally start populated; supported factories accept with_tips=False, and TipRack.fill(), empty(), and set_tip_state(...) modify planned state. return_tips() depends on operation history. Tip tracking can catch inconsistent planned operations, but it cannot detect whether a tip is physically present, seated, blocked, damaged, or the expected type.

Never disable tracking merely to bypass NoTipError or HasTipError. Reconcile the physical deck and planned state instead.

Volume tracking is bookkeeping

from pylabrobot.resources import set_volume_tracking

set_volume_tracking(True)
well.tracker.set_volume(200.0)
used_uL = well.tracker.get_used_volume()
free_uL = well.tracker.get_free_volume()

The VolumeTracker updates planned volumes and can reject under-aspiration, tip overfill, or well overfill. It does not measure a meniscus or confirm liquid identity. Initial state must come from a trusted preparation record and human reconciliation.

Keep dead volume separate from geometric capacity. The tracker may allow a withdrawal that is physically unreliable because of vessel shape, tilt, surface tension, foam, viscosity, or required submersion.

Physical liquid detection is backend-specific

Hamilton STAR liquid-level detection is a separate physical feature. Stable STAR docs expose backend kwargs such as lld_mode, immersion_depth, and surface_following_distance. It is not portable to all backends and is not enabled by volume tracking. Validate the model, sensors, consumables, conductive properties, firmware behavior, failure handling, and channel-specific values before considering it.

Liquid classes

There is no stable generic import:

# Invalid in 0.2.1:
# from pylabrobot.liquid_handling import LiquidClass

Hamilton liquid classes are vendor-specific:

from pylabrobot.liquid_handling.liquid_classes.hamilton import HamiltonLiquidClass
from pylabrobot.liquid_handling.liquid_classes.hamilton.star import (
    HighVolumeFilter_Water_DispenseSurface_Part,
)

await lh.aspirate(
    source["A1"],
    vols=[100.0],
    hamilton_liquid_classes=[
        HighVolumeFilter_Water_DispenseSurface_Part
    ],
)

The keyword above is a STAR backend kwarg, not a universal frontend contract. TecanLiquidClass and get_liquid_class exist under pylabrobot.liquid_handling.liquid_classes.tecan, but are a different vendor-specific system.

Do not select a class from its name alone. Review liquid, tip, head, volume range, jet/surface mode, vessel geometry, calibration curve, flow, settling, transport air, blowout, and firmware/model applicability. Custom classes need documented gravimetric or assay validation and operator approval.

Mixing, serial dilution, and multichannel work

Deterministic preflight

python3 skills/pylabrobot/scripts/plan_transfers.py \
  --manifest tests/pylabrobot/fixtures/protocol_manifest.json \
  --transfers tests/pylabrobot/fixtures/transfers.csv

The CSV header is exact and fixed. Unknown columns, duplicate IDs, unsupported tip policies, missing source volumes, non-finite numbers, out-of-grid wells, unallowlisted liquid classes/tips, excess rates/heights/volumes, channel mismatches, dead-volume violations, destination overflow, and insufficient tips fail closed.

Sources

Checked 2026-07-23: