全部插件

DSH / BUNDLE / CLIENT-UI

dsh-nonead-universal-robots

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

可安装组合包UI 与客户端插件社区 · Topic 自动分析Web UI

概览

dsh-nonead-universal-robots

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

README / ZH

插件文档

目录摘要

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

dsh.pub 核对固定版本的组合包契约、运行时事实与分发语义;完整 README 请查看源仓库。

在 GitHub 阅读完整 README

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