feat: run gripper teleop over the validated zenoh link - #15
Merged
Merged
Conversation
The teleop shipped in #11 invented its own network layer -- a plain-UDP transport on `litegrip/teleop/{master_id}` -- and was merged on hardware-free tests alone. The system actually validated on hardware is a zenoh point-to-point link, so the SDK now uses that structure: the topic and port come from the shared litearm namespace, both ends run in peer mode with multicast and gossip off, the leader listens on a TCP port and the follower connects to it, and the frame stays byte-identical to the litearm stack's. zenoh is an optional extra (`pip install litegrip[zenoh]`), resolved lazily, so `import litegrip` still works on a machine that will never teleoperate. The UDP transport stays available through `link="udp"` and is no longer the default. Alongside the transport, port the safety rules the validated design spec has and #11 was missing: non-finite frames are dropped at the wire boundary rather than clamped onto a hard stop; the follower's target is clamped into its own calibrated travel every cycle; a `send_mit_frame` that returns False and a gripper `error_code` other than "enabled" are counted instead of swallowed; follow gains fall back to the calibration's own kp/kd; a non-positive watchdog is rejected at construction; staleness is read from the slot's "never received" state rather than a 0.0 timestamp sentinel; teleop refuses to start on an uncalibrated or zero-travel gripper; and the leader's zenoh listener is resident for the life of the gripper, because rebuilding it per session leaves the port bound and makes matching fail intermittently.
`litegrip.teleop` has no zenoh dependency, so the import belongs at module level. Behind the `HAVE_ZENOH` guard it left `teleop_topic` undefined when zenoh is absent, and the module failed to import instead of skipping — which is exactly the machine CI runs on.
|
🎉 This PR is included in version 0.6.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The teleop shipped in #11 invented its own network layer — a plain-UDP transport on
litegrip/teleop/{master_id}— and was merged on hardware-free tests alone. The system actually validated on hardware is a zenoh point-to-point link, so the SDK now uses that structure, and picks up the safety rules from the validated design spec that #11 was missing.zenoh becomes an optional extra.
litegrip-pythonis deliberately zero-dependency, soimport litegripmust keep working on a bare controller that will never teleoperate: the new module is resolved lazily, never at package import time.Changes
src/litegrip/zenoh_link.py(new) —Listener(leader: listens, publishes,matching),Connector(follower: connects, subscribes),LatestSlot(latest-wins slot whosetake()does not clear the receive timestamp, and whosepeek_age()returnsNonefor "never received"), andZenohTeleopTransport, which adapts both onto the existingTeleopTransportseam. Discovery is off (mode="peer", no multicast, no gossip), so only the explicit endpoint connects the two ends.src/litegrip/teleop.py— topic is nowlitearm/v4/{grip_id}/gripper_teleopand the default port is17448(the arm uses17447), matchinggrip_wire; non-finite frames are rejected at the wire boundary on both ends, including the first frame used for the align; the follower clamps its target into its own calibrated travel every cycle;send_mit_framereturningFalsecounts assend_failedand a non-enablederror_codesetsfault; follow gains fall back to the calibration'skp/kd; staleness reads the slot's "never received" state instead of a0.0timestamp sentinel; the align wait keeps sending hold frames; a non-positive watchdog is rejected at construction;TeleopNotReady/check_readygate the session.src/litegrip/gripper.py—teleop_start(..., link="zenoh", grip_id=..., port=17448); the leader'sListeneris resident for the life of the gripper and closed bydisconnect(), while the follower'sConnectorstays per-session.src/litegrip/__init__.py— lazy__getattr__re-exports for the zenoh classes, with an "installlitegrip[zenoh]" message when the dependency is absent.pyproject.toml—[project.optional-dependencies] zenoh = ["eclipse-zenoh>=1.0"].tests/test_zenoh_link.py(new) andtests/test_teleop.py— config keys, slot semantics, a real loopbackListener→Connectorroundtrip, and the safety rules above.README.md/readme_zn.md/examples/teleop.py— zenoh install, topic/port, leader/follower roles, and the non-finite-frame note.Note for consumers:
teleop_start'smaster_id=keyword is replaced bygrip_id=, and the default transport changes from UDP to zenoh. Under this repository's policy that publishes as a minor, though it does rename a public keyword — say so if you want it treated as a major before merging.Testing
The zenoh loopback cases run for real against the installed
eclipse-zenoh1.7.2 (13 zenoh tests, none skipped).import litegripwith thezenohmodule blocked still succeeds, andlitegrip.ZenohTeleopTransportthen raises the "installlitegrip[zenoh]" message.Teleoperation itself was exercised on real hardware on 2026-09-29 (leader on can0, follower on can1, hand-driven jaws), with tracking confirmed in both directions and no
rejected/fault. That run covered the follower algorithm and the safety rules; I did not separately record which transport that session used, so treat the zenoh wire itself as covered by the loopback tests here rather than by that run.Issues
None — the repository has no issue tracker entries, matching the previous PRs.