All plugins

DSH / BUNDLE / CLIENT-UI

dsh-nonead-universal-robots

v0.8.4NoneadChina / dsh-nonead-universal-robots7eb8287e80

InstallableBundlesUI & client pluginsCommunity · Topic auto-analysisWeb UI

Overview

dsh-nonead-universal-robots

一个让 DSH 用自然语言直接控制 Universal Robots(UR)机械臂的插件,由拓德科技(Nonead)基于自研的 nUR MCP Server 同源逻辑开发。

README / EN

Package documentation

Registry summary

一个让 DSH 用自然语言直接控制 Universal Robots(UR)机械臂的插件,由拓德科技(Nonead)基于自研的 nUR MCP Server 同源逻辑开发。

dsh.pub verifies the pinned bundle contract, runtime facts, and distribution semantics. The complete README remains in the source repository.

Read the full README on GitHub

LIMITATIONS

Known limitations

- **Connection persistence** — the worker process lives for the plugin's lifetime and keeps robot connections by IP; after a worker crash or a DSH restart you must `connect` again. - **Remote control mode** — some UR robots must be in "remote control" before they execute motion/program commands, and `ur_connect` reports that state. **CB3 robots running URSoftware 3.1 through 3.20 already allow remote control by default**; a `remote_control: false` reading still means the controller is *currently* not in remote mode — in local/teach-pendant mode URScript and motion commands are silently discarded, so switch the pendant to remote control. Other firmware (e-Series, or CB3 outside that range) needs Remote Control enabled in PolyScope first. An unreadable state is reported as unknown rather than pretended to be `false`. - **Reads you cannot trust are reported as such** — a state-setting command that has no read-back channel answers `verified: false`; a controller that refuses the RTDE session is reported as not running instead of "connected"; a twin frame that could not be refreshed is flagged `stale`. - **Local file access** — `ur_upload_program` **reads** a local file and `ur_download_program` **writes** one, so both are fenced to `programDir` (`<DSH_HOME>/nonead-ur/programs` by default; change it with the `programDir` config). The **host** resolves the path after `realpath` (so a junction/symlink cannot smuggle it out), checks `.urp` + `maxProgramBytes` (1 MiB), and only then injects the absolute `_local_path` / `_remote_path` into the worker payload; the model cannot set those underscore-prefixed keys itself (`sanitizeArgs` drops anything not declared by the schema) and the worker refuses a `_local_path` that is not absolute. An empty `programDir` falls back to the default directory; a missing or unusable directory **fails closed** — nothing local is read or written. This is the same class of exposure as handing the model a shell, which is exactly why it is fenced rather than trusted. - **SSH credentials are redacted in approval and audit** — `password` / `passphrase` / `token` / `secret` / `known_hosts` values are replaced with `***` in the approval prompt and in the NDJSON audit ledger, so an operator confirming an upload/download does not leak the password into the UI or `audit.ndjson`. The worker still receives the real values it needs for SFTP. - **Program transfer is not "fire and forget"** — upload and download compare the byte count on the other side, and delete re-`stat`s the path afterwards. A mismatch is reported as a failure (`VERIFY_FAILED`), never as a success, because the caller's next step would be to run that program. - **Named poses are local data, not robot state** — `ur_save_pose` / `ur_get_pose` / `ur_list_poses` / `ur_delete_pose` read and write one JSON file per pose under `poseDir` and never talk to the controller (unless you ask `ur_save_pose` to capture the current pose, which needs `ip`). An empty `poseDir` uses the default (`<DSH_HOME>/nonead-ur/poses`) and the directory is created on first save; a directory that cannot be created or read **fails closed**. To actually go to a saved pose, do it in two steps (`ur_get_pose` then `ur_movel`) so the gates see the numbers. - **A long motion must never freeze the twin** — the twin's only queue-free data source is the worker's telemetry push thread, and that thread lives in the same Python child as RTDE and the Dashboard. So a single tool call must never kill that child just because a motion legitimately outlasted the call budget: motion ops get a budget **derived from their own parameters** (`t=` / `timeout_s`, with a wide fallback for force-guided moves) **and** `killOnTimeout: false`. A timeout still reports itself honestly — it just no longer destroys the session (and with it, the twin). - **Telemetry has its own channel** — pushed frames travel on **stderr with a magic prefix** and their own lock, not on stdout behind the response lock. Sharing stdout m