Skip to content

STARBackend: add 96-head capacitive LLD Z-probe#1094

Open
BioCam wants to merge 7 commits into
PyLabRobot:mainfrom
BioCam:create-head96-probe-z-using-clld
Open

STARBackend: add 96-head capacitive LLD Z-probe#1094
BioCam wants to merge 7 commits into
PyLabRobot:mainfrom
BioCam:create-head96-probe-z-using-clld

Conversation

@BioCam

@BioCam BioCam commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Adds head96_probe_z_using_clld - a capacitive LLD (cLLD) liquid-surface probe for the 96-head, the head counterpart of the single-channel clld_probe_z_height_using_channel. It runs a downward cLLD search on the stop-disk Z drive (H0 ZL) and returns the detected surface as a tip-bottom Z height. Builds on #1086 (the stop-disk / tip-bottom Z reference pair) and #1088 (the per-drive speed/acceleration scoping).

Positions are tip-bottom referenced like head96_move_tool_z: the tip overhang (stop disk minus tip bottom, a rigid constant for the mounted tip) maps lowest_immers_pos and start_pos_search to the firmware's zh / zc, and the return value maps the stopped position back to tip-bottom. tip_len and approach_speed default to None, resolving to the measured tip length and head96_z_drive_speed_default. A firmware error during the search retracts the head to Z-safety before re-raising.

The ZL wire format changed between the 2008 and 2013 firmware command sets - the 2013 set adds the lm sensor-selection field and widens the acceleration / current-limit fields - so the parameters are formatted per the head's reported firmware date, in the documented field order; lm selection requires 2013+ firmware.

Validated on hardware: the cLLD search is accepted (er00) across lm modes. An earlier 6-digit zc field width was rejected (er32) and is now 5 digits.

Tests: the assembled wire string (guarding the zc width and the tip-overhang offset), the no-tip guard on both tip-length paths, and the Z-safety retract on firmware error.

BioCam and others added 7 commits June 19, 2026 18:48
Tip-bottom-referenced 96-head cLLD search via the H0 ZL command, mirroring
the single-channel cLLD probe. Resolves search bounds and speed/acceleration
from `Head96Information`, formats the ZL wire fields per the head's firmware
date (the 2008 and 2013 command sets differ), and returns the detected
surface as a tip-bottom position. Guards on firmware tip presence, and when
tip tracking is on also checks the corner channels feeding the selected
sensor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The lm=1 LLD channel's corner label was `A1 or B1`; it is `A1 or B2`. Update
the `lld_sensor` literal, the sensor map, and the tip-tracker corner-check
index (B2 is head96 index 9, not 1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Integrate the ZL `zv` (upper-section / fast-approach speed) and `zw` (current
protection limiter) parameters. `approach_speed` defaults to None, resolving
to `head96_z_drive_speed_default`; `current_protection_limiter` validates
against the firmware-dependent range (0-15 on 2013+, 0-7 on 2008) and is sent
at the matching width.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Emit the ZL parameters in the documented field order (zh, zc, zi, zj, lm, gt,
gl, zv, zl, zr, zw); the firmware tokenizes by field name so order is free, and
the doc order is the clearer convention. Add tests for the assembled wire
string (guarding the zc 5-digit width and the tip-overhang offset), the
no-tip guard on both tip-length paths, and the Z-safety retract on firmware
error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The probe read the head's current Z (`RZ`) after the search, which reflects the
post-detection move (a default 2 mm retract), so the returned surface was off by
that move. Read `H0 RH` ("position of liquid surface found") instead - the head
counterpart of the channel `request_pip_height_last_lld` - via the new
`head96_request_height_last_lld`, which is latched and unaffected by the move.

The RH response parse mirrors RZ but is not yet hardware-confirmed (marked
TODO); the unit test mocks the read-back.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@BioCam BioCam marked this pull request as ready for review June 20, 2026 09:20
@BioCam BioCam requested a review from rickwierenga June 20, 2026 09:20
Comment on lines +8672 to +8686
z_speed_min, z_speed_max = self._head96_information.z_speed_range
z_accel_min, z_accel_max = self._head96_information.z_acceleration_range

if approach_speed is None:
approach_speed = self.head96_z_drive_speed_default
if not z_speed_min <= approach_speed <= z_speed_max:
raise ValueError(
f"approach_speed must be between {z_speed_min} - {z_speed_max} mm/sec, is {approach_speed}"
)
if not z_speed_min <= speed <= z_speed_max:
raise ValueError(f"speed must be between {z_speed_min} - {z_speed_max} mm/sec, is {speed}")
if not z_accel_min <= acceleration <= z_accel_max:
raise ValueError(
f"acceleration must be between {z_accel_min} - {z_accel_max} mm/sec**2, is {acceleration}"
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe at some point we can abstract this now that many features use the same pattern

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I agree, probably 2-3 more commands and we'll be able to see a nice abstraction to apply :)

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