tell_client: restore "No Pin in Gripper" detection on empty-gripper mount
Commit 071b4ab made mount() return SUCCESS as soon as it saw the intermediate
TELL "state"/Busy event, before the later "Gripper detection" event is read,
so an empty-gripper mount completed silently with no MountingFailed/pop-up.
check_command_ok blocks (wait_not_busy) until the mount sequence finishes, so
after it returns the robot's own record is authoritative: if get_mounted_sample()
is None the gripper was empty -> return NO_PIN_IN_GRIPPER, which the mounting
service maps to MountingFailed("No Pin in Gripper"). Covers manual and automation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
47e05dc28c
commit
5370c0f168
@@ -30,6 +30,7 @@
|
||||
- `/status` now publishes `pss_prohibited`/`pss_alarm`; the GUI blocks manual mount/unmount and the automation Run button immediately (with a pop-up) when the hutch door is open, instead of letting the robot fail to move server-side.
|
||||
- Centralised the per-action precondition checks (ring current, safety shutter, hutch door) into one combined "continue?" dialog used by all data-collection buttons (Evaluate grid, X-ray centering, Run screening/rotation/fluorescence, simple rotation), with a session-global "Don't ask me again for 1 hour" snooze.
|
||||
- Live automation now pauses and auto-resumes when the beam, experiment shutter, hutch door or robot (TELL) are not ready (with Continue-now / Stop overrides), gated by a "Pause on bad conditions" checkbox (default on) that replaces the dead `CHECK_ENABLED` constant.
|
||||
- Restored "No Pin in Gripper" detection: a mount that returns on the intermediate TELL "Busy" state event now verifies the robot's `get_mounted_sample()` after the command completes, so an empty-gripper mount surfaces `MountingFailed` (and the GUI pop-up) instead of silently reporting success.
|
||||
|
||||
## 0.3.1 (2026-04-29)
|
||||
- **DAQ/Server**:
|
||||
|
||||
@@ -293,6 +293,15 @@ class TellClient:
|
||||
timeout=wait_timeout, msg=f"Mount {segment}{puck}-{sample}: "
|
||||
)
|
||||
logger.info(f"Check command okay response: {msg}")
|
||||
# check_command_ok blocks (wait_not_busy) until the whole
|
||||
# mount sequence has finished, so the gripper-detection event
|
||||
# we observed as an intermediate "state"/Busy event is now
|
||||
# resolved. The robot's own record is authoritative: if it
|
||||
# reports nothing mounted, the gripper was empty (no pin),
|
||||
# which we must surface rather than reporting success.
|
||||
if self.get_mounted_sample() is None:
|
||||
logger.warning("Mount command completed but robot reports no sample mounted")
|
||||
return TellEventValueEnum.NO_PIN_IN_GRIPPER
|
||||
return TellEventValueEnum.SUCCESS
|
||||
elif (
|
||||
event == TellEventTypeEnum.GIPPER_DETECTION.value
|
||||
|
||||
@@ -52,6 +52,8 @@ def test_mount_state_event_succeeds_when_command_completes(
|
||||
"id": 3017907,
|
||||
}
|
||||
client = TellClient(mock_beamline, backend=mock_backend)
|
||||
# Robot reports the requested sample as mounted -> genuine success.
|
||||
client.get_mounted_sample = lambda: _mount_address()
|
||||
|
||||
result = client.mount(_mount_address(), wait=True)
|
||||
|
||||
@@ -59,6 +61,27 @@ def test_mount_state_event_succeeds_when_command_completes(
|
||||
mock_backend.get_result.assert_called() # check_command_ok consulted the result
|
||||
|
||||
|
||||
def test_mount_state_event_reports_no_pin_when_nothing_mounted(
|
||||
mock_beamline, mock_backend
|
||||
):
|
||||
"""If the command completes but the robot reports nothing mounted, the
|
||||
gripper was empty: mount() must return NO_PIN_IN_GRIPPER (so the service
|
||||
raises MountingFailed) rather than reporting success."""
|
||||
mock_backend.wait_events.return_value = ("state", "Busy")
|
||||
mock_backend.get_result.return_value = {
|
||||
"status": "completed",
|
||||
"return": "A39",
|
||||
"exception": None,
|
||||
"id": 3017907,
|
||||
}
|
||||
client = TellClient(mock_beamline, backend=mock_backend)
|
||||
client.get_mounted_sample = lambda: None
|
||||
|
||||
result = client.mount(_mount_address(), wait=True)
|
||||
|
||||
assert result == TellEventValueEnum.NO_PIN_IN_GRIPPER
|
||||
|
||||
|
||||
def test_mount_state_event_raises_when_command_not_completed(
|
||||
mock_beamline, mock_backend
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user