HighRes TundraStore#

HighRes Biosolutions
TundraStore
WIPv1
storage
storageactive cooling
APIpylabrobot.high_res.sample_storage.TundraStore

Property

Value

Model

TundraStore

Transport

TCP, port 1000

Environment

−20 to 4 °C; temperature-dependent humidity

Driver support

Work in progress; not hardware-verified

Warning

TundraStore support has not been verified against TundraStore hardware. Validate temperature, humidity, and motion in a controlled setup.

How it talks#

The store exposes a line-oriented TCP service. Each command receives an acknowledgement, optional data, and one completion status. The driver validates the echoed command and command ID and closes the connection if a timeout or malformed response makes the stream unsafe to reuse.

Physical setup#

Connect the store to a dedicated Ethernet interface. Supply clean dry air above 80 psi before homing or moving pneumatic doors. The factory service is normally 192.168.127.60:1000 and also answers at 10.253.253.253:1000. Give the host interface an address on the corresponding isolated subnet, without a default gateway.

The example inventory below represents one known plate physically present in stacker 1, slot 1. It builds all 24 slots from example getstackerdimensions values. Replace the rack count, zero offsets, slot heights, and slot counts with the layout reported by the actual machine before running motion.

Describe the physical inventory#

high_res_stacker uses the measured HighRes stacker footprint and creates one holder per reported slot. The racks mapping keys are the physical stacker numbers reported by the device, which may be sparse. Carrier spots are zero-based in PLR and map to one-based device slots. The reported slot height is also the physical safety constraint used when selecting a destination.

from pylabrobot.high_res.sample_storage import TundraStore, high_res_stacker
from pylabrobot.resources import Coordinate, Plate, Well

rack = high_res_stacker(
  name="stacker_1",
  zero_offset=0.0,
  slot_height=22.867,
  slot_count=24,
)
site = rack.sites[0]
well = Well(name="A1", size_x=8, size_y=8, size_z=10)
well.location = Coordinate(10, 10, 2)
plate = Plate(
  name="plate_1",
  size_x=127.76,
  size_y=85.48,
  size_z=14,
  ordered_items={"A1": well},
)
site.assign_child_resource(plate)
racks = {1: rack}

Connect#

setup() connects, reads version and environmental information where applicable, and discovers the actual transfer nests. It does not home unless home=True is passed.

store = TundraStore(host="192.168.127.60", name="tundrastore", racks=racks)
await store.setup()

Read version information#

Confirm that the expected device answered.

version = await store.request_version()
print(version)

Inspect transfer nests#

Compare the live sensor report with store.nests. Assign a Plate resource to any physically occupied nest before transfer operations.

nest_status = await store.request_nest_status()
print(nest_status)

Fetch a plate#

This example moves the known plate from stacker 1, slot 1 to the first transfer nest. The driver requires that nest’s live sensor to report clear.

plate = await store.fetch_plate_to_loading_tray("plate_1", tray_index=0)

Transfer between nests#

If the machine reports at least two nests, move the plate from the first to the second. Both live sensors and PLR bookkeeping are validated before motion.

plate = await store.transfer_plate_between_nests(
  source_tray_index=0, destination_tray_index=1
)

Return the plate to storage#

Move the plate from the second nest back to the smallest free site that is tall enough for it.

plate = await store.take_in_plate(tray_index=1, site="smallest")

Scan a barcode#

Barcode scans require every transfer nest to be physically clear. EMPTY means no readable barcode, not necessarily no plate.

barcodes = await store.request_stacker_barcodes(1, slot=1)
print(barcodes)

Open robot doors#

Ensure the carousel and automation interface are clear. If firmware reports an error, the driver waits for every robot door to reach the final open state.

await store.open_all_doors()

Close robot doors#

Close and reseal the robot-access doors.

await store.close_all_doors()

Verify or recover the parked state#

Recovery refuses to move while the spatula sensor reports a plate. Otherwise it retracts and homes only when the store is not safely parked. Recovery proves that the mechanism is parked, but it cannot prove where a plate ended up after a timeout, cancellation, abort, or motion fault. In that case store.unresolved_transfer remains set and further plate moves are blocked. Inspect its source and destination, inspect the machine, then call await store.resolve_unresolved_transfer("source"), await store.resolve_unresolved_transfer("destination"), or await store.resolve_unresolved_transfer("unassigned"). Nest choices are checked against live sensors; selecting a stacker endpoint is operator confirmation because stacker slots have no non-destructive presence sensor.

if not await store.request_is_parked():
  recovered = await store.recover()
  if not recovered:
    raise RuntimeError("Store did not recover to a parked state")

Read environmental state#

Read the installed channels and current temperature and humidity. Humidity is returned as a fraction.

environment = await store.environment.refresh()
temperature = await store.environment.request_current_temperature()
humidity = await store.environment.request_current_humidity()
print(temperature, humidity, environment)

Confirm environmental setpoints#

This writes the existing targets back unchanged, exercising validation without changing the requested conditions.

temperature_target = await store.environment.request_target_temperature()
await store.environment.set_temperature(temperature_target)
humidity_target = await store.environment.request_target_humidity()
await store.environment.set_humidity(humidity_target)

Disconnect#

Close the TCP connection when the workflow is finished.

await store.stop()

Reference#

See the sample-storage overview and event reference for the full API.