Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions parol6/client/dry_run_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,14 +238,22 @@ def _snap_to_angles(self, angles_deg: list[float]) -> DryRunResult:
"""Snap to angles instantly (no trajectory) — used by Home and Teleport.

Both establish position references, so subsequent planned moves pass
the homed gate."""
self._planner.flush()
the homed gate. Blended moves still buffered in the planner are
planned first and lead the returned result, so their paths — and any
refusal — reach the caller exactly as the live controller would run
them before the snap."""
pending = [
r
for seg in self._planner.flush()
if (r := self._segment_to_result(seg)) is not None
]
deg = np.asarray(angles_deg, dtype=np.float64)
deg_to_steps(deg, self._state.Position_in)
self._planner.state.Position_in[:] = self._state.Position_in
self._planner.state.Homed_in.fill(1)
rad = np.radians(deg).reshape(1, -1)
return _build_result(rad, duration=0.0)
snap = _build_result(rad, duration=0.0)
return self._merge_results([*pending, snap]) if pending else snap

def _dispatch(self, params: Any) -> DryRunResult | None:
"""Route a command struct through the trajectory planner."""
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/test_dry_run_script_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from the real client.
"""

import numpy as np
import pytest

from parol6.client.dry_run_client import DryRunRobotClient
Expand Down Expand Up @@ -161,3 +162,17 @@ def test_referenced_home_previews_as_return_move(self):
result = client.home()
assert result is not None and result.error is None
assert result.duration == 0.0

def test_snap_carries_the_pending_blend_chain(self):
"""A blended move still buffered when the script homes with calibrate
(or teleports) is planned and leads the returned result — the live
controller runs it before the snap, so the preview must show it."""
client = DryRunRobotClient(initial_joints_deg=HOME, initial_homed=True)
assert client.move_j(ANGLES_A, speed=0.5, r=10) is None # buffered

result = client.home(calibrate=True)
assert result is not None and result.error is None
assert result.duration > 0.0
assert len(result.joint_trajectory_rad) > 1
assert np.allclose(np.degrees(result.end_joints_rad), HOME, atol=0.5)
assert client.flush() == []
Loading