Skip to content

v1 STAR.head96: enable partial tiprack pick_up_/drop_tips via channel<>tip_spot anchoring - #1474

Draft
BioCam wants to merge 1 commit into
PyLabRobot:mainfrom
BioCam:head96-partial-tip-pickup
Draft

BioCam wants to merge 1 commit into
PyLabRobot:mainfrom
BioCam:head96-partial-tip-pickup

Conversation

@BioCam

@BioCam BioCam commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

The Problem

So far PyLabRobot could only use head96s with a perfect placement of the head96's "A1" channel over the tiprack's "A1" TipSpot.

So the head took or left a whole rack or nothing. Taking a block of tips, such as three columns or one quadrant, means shifting the head by whole rows and columns so that only some channels meet tips. An offset could move the head that way, but the model still paired spot A1 with channel A1, so every tip ended up on the wrong channel and return_tips could not return them.

PR Content/Solution

  • head96.pick_up_tips and head96.drop_tips take channel and tip_spot, both A1 to H12: the head channel and the spot it goes over. The defaults are A1 and A1, which is the commands as they were.
  • Picking up, each channel over a spot holding a tip takes that tip. Channels over an empty spot or past the rack's edge take none, so a rack with gaps needs no special handling.
  • Dropping, each channel's tip goes into the spot under it. A channel carrying a tip beside the rack is refused before anything moves.
  • head96.return_tips reads the two from where the tips came from, so tips are returned the way they were picked up. It refused anything but spot A1 on channel A1.
  • Equivalent pairs are the same alignment: channel A1 over spot A1 and channel B1 over spot B1 send the same command.
  • The alignment itself, which item is under which channel and how far channel A1 is shifted, is in lib/liquid_handling/head_alignment.py. It knows nothing of the STAR and works on any grid of the head's size.

The 96-head placing a channel over a tip spot: eight alignments

# columns 10 to 12: head columns 1 to 3 over them, the rest of the head past the rack
await star.head96.pick_up_tips(tip_rack, channel="A1", tip_spot="A10")
await star.head96.discard_tips()

# the top-left quadrant, onto the head's bottom-right channels, then returned to its spots
await star.head96.pick_up_tips(tip_rack, channel="H12", tip_spot="D6")
await star.head96.return_tips()

Channels past the rack's edge come down beside it. What stands there is the caller's to keep clear.

This is the first step. The pair is the low-level form on purpose: whole columns, rows, a quadrant or a set of tip spots each come down to choosing one channel and one tip_spot, so they can follow as thin arguments on top without new device logic, inheriting the model, the refusals and the reach checks from here.

head96.aspirate and head96.dispense still place channel A1 over well A1. head_alignment takes a plate as well as a tip rack, so the same anchoring will follow for them in a future PR.

Tests: a shifted pick-up from a rack with a gap pins the command and the tip on every channel; a return after it pins the command and every spot; one pins the refusal of a tip beside the rack; two pin the alignment on a plain rack.

🤖 Generated with Claude Code

The 96-head's tip commands could only put head channel A1 over tip spot A1, so the head took or
left a whole rack or nothing. An `offset` of whole columns moved the head, but the model
still paired spot A1 with channel A1.

- `pick_up_tips` and `drop_tips` take `channel` and `tip_spot`, both A1 to H12: the head
  channel and the spot it goes over. The defaults are A1 and A1, the commands as they were.
- Picking up, each channel over a spot holding a tip takes that tip; channels over an empty
  spot or past the rack's edge take none.
- Dropping, each channel's tip goes into the spot under it. A channel carrying a tip beside
  the rack is refused before anything moves.
- `return_tips` reads the two from where the tips came from, so tips are returned the way
  they were picked up. It refused anything but spot A1 on channel A1.
- The alignment itself, which item is under which channel and how far channel A1 is shifted,
  is in `lib/liquid_handling/head_alignment.py`. It knows nothing of the STAR and works on
  any grid of the head's size, a plate included.

Tests: a shifted pick-up from a rack with a gap pins the command and the tip on every
channel; a return after it pins the command and every spot; one pins the refusal of a tip
beside the rack; two pin the alignment on a plain rack.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@BioCam
BioCam force-pushed the head96-partial-tip-pickup branch from 4049c2f to 203bea7 Compare October 7, 2026 16:00

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant