Skip to content

fix(star): split pipetting operations by channel spacing - #1164

Open
HaamsRee wants to merge 2 commits into
PyLabRobot:mainfrom
HaamsRee:fix/star-pipetting-batch-spacing
Open

fix(star): split pipetting operations by channel spacing#1164
HaamsRee wants to merge 2 commits into
PyLabRobot:mainfrom
HaamsRee:fix/star-pipetting-batch-spacing

Conversation

@HaamsRee

@HaamsRee HaamsRee commented Jul 13, 2026

Copy link
Copy Markdown

Summary

Fixes STAR backend pipetting behavior when the configured minimum channel spacing is wider than the target spacing. Addresses #822.

Previously, STARBackend.aspirate() and STARBackend.dispense() sent all requested operations in a single C0AS or C0DS command. For adjacent wells in a 96-well plate, this could request 9 mm channel spacing from a STAR configured for a minimum of 18 mm.

This PR changes aspirate and dispense to:

  1. Plan legal groups of simultaneous operations with the existing channel batch planner.
  2. Send one firmware command for each batch instead of one command with impossible channel positions.
  3. Keep volumes, liquid heights, flow rates, and the other per-operation firmware parameters aligned with their original operations in each batch.

It also removes the explicit 100 mm end position and minimum traverse height from the liquid-height probing path, allowing the normal STAR channel traversal height to be used.

The single-batch behavior is unchanged when all requested channel positions are valid simultaneously.

Motivation

On a STAR with four 1 mL channels spaced at 18 mm, adjacent 96-well targets cannot be reached by those channels simultaneously. Sending them in one command requested a mechanically impossible arrangement instead of splitting the work into legal sequential movements.

During testing with probe_liquid_height=True, the hard-coded 100 mm Z end and traverse height also caused the probing workflow to crash on the physical instrument. Removing those overrides restores the backend's normal safe traversal behavior between batches.

Tests

Added STAR backend tests for:

  • splitting an aspirate across adjacent 96-well targets into three commands at 18 mm minimum spacing,
  • splitting a dispense across the same targets,
  • using the normal traversal height after liquid-height probing instead of requesting 100 mm.

Ran:

uv run pytest pylabrobot/liquid_handling/backends/hamilton/STAR_tests.py pylabrobot/liquid_handling/pipette_batch_scheduling_tests.py -q

Result:

146 passed, 13 warnings, 81 subtests passed

ruff check and ruff format --check also pass for both changed files.

@HaamsRee
HaamsRee marked this pull request as ready for review July 13, 2026 16:52
@rickwierenga
rickwierenga requested a review from BioCam August 16, 2026 15:14
@BioCam

BioCam commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

@HaamsRee, Is the standards C0AS command working on your device but just not the auto-surface-following?

The interim-solution for your 4-channel STAR is expected to probe all containers first and then perform the actions:
When you are saying "During testing with probe_liquid_height=True, the hard-coded 100 mm Z end and traverse height also caused the probing workflow to crash on the physical instrument. "
...do you mean a physical crash on the instrument? or do you mean a firmware error?
In either scenario, can you please elaborate more on the error behaviour/message?

Your idea of splitting aspirate is actually why we created the channel batching algorithm and have been trialing it in production via the probe_liquid_height function - because adding it directly to aspirate is a big change of an atomic command, hence our step by step careful approach :)

…to the legacy backend path

On main, STAR_backend.py and STAR_tests.py now live under
pylabrobot/legacy/liquid_handling/backends/hamilton/, and the old module path is a
deprecation shim. This merge relocates the branch's two changes onto the new paths so
the branch stops conflicting.

The aspirate body needed a real resolution: main added a tip-capacity check at the same
anchor where this branch replaced the inline aspirate_pip call with aspirate_kwargs and
aspirate_batch. Both are kept, main's check first. The branch's own lines are unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@HaamsRee

Copy link
Copy Markdown
Author

@HaamsRee, Is the standards C0AS command working on your device but just not the auto-surface-following?

If I remember correctly, sending a single C0AS with the old x_positions, y_positions from:

x_positions, y_positions, channels_involved = self._ops_to_fw_positions(ops, use_channels)

With 18mm channel spacing the single C0AS does not position the channels in the correct places. I think they get offset to make space and the A1 channel gets pushed off the plate as a result.

The interim-solution for your 4-channel STAR is expected to probe all containers first and then perform the actions: When you are saying "During testing with probe_liquid_height=True, the hard-coded 100 mm Z end and traverse height also caused the probing workflow to crash on the physical instrument. " ...do you mean a physical crash on the instrument? or do you mean a firmware error? In either scenario, can you please elaborate more on the error behaviour/message?

Yes a physical crash on the instrument caused by this line, I think:

        z_position_at_end_of_command=100,

The tips just slam into the plate. Why was this there in the first place? Setting z=100 every time will certainly cause crashes.

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.

2 participants