Skip to content

PreciseFlexArm.probe_z_using_ztouch: force-sensed Z probing - #1577

Open
BioCam wants to merge 5 commits into
mainfrom
precise-flex-probe-z-using-ztouch
Open

BioCam wants to merge 5 commits into
mainfrom
precise-flex-probe-z-using-ztouch

Conversation

@BioCam

@BioCam BioCam commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Hi everyone,

It started in February 2024 with one function that made a STAR channel find the height of whatever was below it. Since then the tradition has only grown:

Z-Probing

Y-Probing and X-Probing

Liquid probing

Tips and tools

v1 and the Prep

All of those were liquid handlers. Here the tradition of Z probing continues... even on arms. 🦾

The Problem

In PLR, a PreciseFlex can only find out how high something is if a person teaches it by hand. Whenever a nest, a plate stack or a deck feature has moved or is new, somebody has to stand next to the arm and jog it down by eye.

Brooks has already built this into the arm: the PreciseFlex's licensed Z height detection lowers the arm until the gripper presses on something, and reports the height. It's a great feature, but until now PLR has had no way of calling it. This PR exposes it to the PLR community and everyone else using these arms.

Sending the HeightDetect command raw has three traps:

  • send only some of its arguments and the others become 0
  • it holds the connection until it ends, so a halt cannot go on the same connection
  • a halted search answers with a height, as if it had touched something

PR Content

Here I am adding PreciseFlexArm.probe_z_using_ztouch(), with the argument names of the v1 STAR's probe_z_using_ztouch wherever a counterpart exists:

class PreciseFlexArm:
  ...
  default_ztouch_search_speed_percent: int = 20  # checked on assignment: 5 to 100

  async def probe_z_using_ztouch(
    self,
    *,
    search_start_position: Optional[float] = None,  # mm, where the arm stands if None
    search_end_position: Optional[float] = None,  # mm, the Z soft limit if None
    approach_speed_percent: Optional[float] = None,
    search_speed_percent: Optional[int] = None,  # the default above if None
    detection_force: float = 15.0,  # N
    perform_second_measurement_on_lift_off: bool = False,
    post_detection_distance: float = 2.0,  # mm, not moved after if 0
    move_to_parking_position_after: bool = False,
  ) -> Optional[float]:  # tool point z in mm, None if it met nothing

It sends this firmware command, always with all three arguments:

HeightDetect  <QuickMode>  <rXSearchLimit>  <XMaxForce>
HeightDetect       1            -28.0          -15.0     ->  0 4.15
Argument Meaning Comes from
QuickMode 1 measures on the way down, 2 measures again on the way up perform_second_measurement_on_lift_off
rXSearchLimit how far it may travel from where it stands, in mm, negative search_end_position minus the start
XMaxForce the force at which it stops, in N, negative detection_force

The command has no speed argument: only the system speed (mspeed) changes it. So the method sets it for the search and puts it back afterwards.

Before anything moves, it checks the licence bit for Z height detection, the arguments, the column and the base plate. Reaching the end of the search with nothing met returns None. An interrupt sends halt on the controller's second port (10000) and discards the false height, so the next command gets its own reply.

Warnings

  • Stand the wrist joint over the target, not the fingers. What presses is the underside of the gripper, and the tool point stands gripper_length further along the heading.
  • The returned height is the tool point's. The controller does not know which part of the gripper touched.
  • A halt from anywhere else (e.g. another client) also returns a height with nothing met: the reply looks the same.
  • This is a controlled press onto whatever is below, so please check what is below!
  • It needs a controller licensed for Z height detection.

At the default 20 percent system speed it descends at about 5 mm / second.

Precision

These numbers come from sending HeightDetect directly, not yet through this method. On a PF400, 36 searches on the same block, at 8 to 15 N and at mspeed 20, 50 and 100, read within 0.16 mm of each other. Neither force nor speed moved the reading by more than that. A second measurement on lift-off read about 0.15 mm higher than the first.

Power

An arm can now measure its own environment too: the height of a nest or a stack, with no hand on the arm. Together with the probing on the liquid handlers, PLR programmers can now check heights across a workcell against the model 👀

Please let us know your thoughts, and whether you encounter any issues.

Happy automation 🦾

🤖 Generated with Claude Code

@BioCam
BioCam marked this pull request as ready for review October 30, 2026 23:37
@BioCam
BioCam requested a review from a team as a code owner October 30, 2026 23:37
BioCam and others added 3 commits October 31, 2026 14:34

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