Skip to content

Releases: NoneadChina/dsh-nonead-universal-robots

v0.8.1

Choose a tag to compare

@NoneadChina NoneadChina released this 28 Oct 16:50

[0.8.1] - 2026-10-29
Docs — installation rewritten for an npm-published package
Both READMEs gained "Option 0 — from npm" (dsh.cmd plugin add dsh-nonead-universal-robots, or "dsh-nonead-universal-robots": "^0.8.0" in dependencies), and the stale "not published to npm (yet)" note is gone.
In the hand-written bundle route the primary dependency is now the registry range ^0.8.0; file: and github: are documented as offline / air-gapped fallbacks.
New "Languages (UI copy)" section: the eight languages shipped since 0.8.0, the fact that they follow the DSH Desktop app language (locale.preference) and switch without a reload, and the fallback order when no host locale service is present.
Documentation only — lib/, python/ and src/ are untouched; lib/client.js was rebuilt so it still matches src/ byte for byte.

v0.7.5

Choose a tag to compare

@NoneadChina NoneadChina released this 17 Oct 06:54
chore(release): v0.7.5

修复 0.7.4 审核发现的 3 个 P0 与列出的 P1(详见 CHANGELOG)。

安全/正确性:
- ur_run_program 在 play 前要求 load 已确认(sent + loaded 非空 + basename 匹配 + 非失败应答)
- MOTION_OPS 与 APPROVAL_OPS 解耦:wait_steady 按 timeout_s 计预算且不杀 worker;
  运动在飞或状态未知时,任何超时/取消都不再杀 Python 子进程
- 安全闸补齐 draw_*/加速度/力控 limits/speedj-speedl 形状,参数"出现但不合格"一律拒绝
- 门禁 49→53:+set_tcp / 数字模拟输出 / 工具电压/输出模式/通信 / 传送带 tick,
  -stopj / -stopl / -end_force_mode(停止动作不应反过来要审批)
- delete_program 远端路径双重校验;programDir 注入 realpath 绝对路径;download 大小上限
- send_script 审批展示完整脚本 + sha256(64 KiB 上限);审批与审计口令脱敏;
  关闭审批时受门禁 op 仍记审计;axis-move NaN 校验;set_tcp 限幅
- 孪生:按机器人共享帧泵(4 连接放大 1.00×)、最多 4 条流(超出 429)、背压与空闲超时、
  待审批预览按机器人隔离

工程:
- 新增 CI workflow;check-host-compat 支持 --host-asar/--strict 并纳入 run-tests
- peer 范围接受当前宿主;THIRD_PARTY_NOTICES 入包;README 计数/门禁表/取消语义更正

验证:
- 受影响 node 测试 158 项 157 pass(1 skip);py_compile/pyflakes 通过
- check:ops(53 门禁 / 44 MUST / 104 工具)、check:docs、check:manifest PASS
- check-host-compat --host-asar --strict:peer 4/4、104/104 注册、4 路由 PASS
- npm test 45/56(11 项为缺 three/esbuild/GLB 的环境失败);npm pack 37 文件

v0.7.4

Choose a tag to compare

@NoneadChina NoneadChina released this 17 Oct 05:12
chore(release): v0.7.4

以远程 0.7.x 基线为准,统一仓库版本号为 0.7.4。

- package.json: 0.7.3 -> 0.7.4
- CHANGELOG.md / CHANGELOG.zh.md: 将 [Unreleased] / [未发布] 收口为 0.7.4
- 无功能变更;src/、lib/、python/ 未改动

校验:
- check:ops / check:docs / check:manifest / check:host 全部通过
- check:static 的 client bundle 重建因本机未安装 devDependencies(esbuild)未执行;
  本次未改 src/ 与 lib/,提交的 bundle 未变动

v0.7.3

Choose a tag to compare

@NoneadChina NoneadChina released this 15 Oct 04:22
v0.7.3 — 程序文件牢笼修掉 Windows junction 逃逸(realpathSync.native + read/写目标两…

v0.7.2

Choose a tag to compare

@NoneadChina NoneadChina released this 14 Oct 21:56
v0.7.2 — check_pose 假阴性修复、conveyor tick 自证回读、孪生同步两项、命名位姿表(104 工具)

v0.7.1

Choose a tag to compare

@NoneadChina NoneadChina released this 14 Oct 21:25
fix(twin): 遥测走独立通道,不再被响应写锁与 stdout 背压堵住

孪生同步的**第二处**机制修复(第一处是运动预算:不再因 60 秒杀子进程)。

根因:孪生遥测原先走 stdout,并与响应共用同一把 `_PROTOCOL_LOCK`。那把锁在整条响应写期间都被
占着 —— 一条大响应(或宿主一时没抽干导致的 stdout 背压)足以让推送停超过宿主的
`TWIN_PUSH_FRESH_MS`(300 ms);一过这个窗口 `lib/twin-routes.js` 就**回退**去发一次显式读,而那次读
正好排在 worker 的 stdin 队列里、堵在运行中的运动指令后面。于是孪生在这段运动的剩余时间里只剩
「数据已停止更新」—— 用户看到的就是"机器人在动,3D 却不动了"。

改动:
- Python:新增 `_PUSH_LOCK` 与 `PUSH_CHANNEL_PREFIX = "@@DSH-UR-PUSH@@ "`,新增 `_write_push_line()`
  把遥测写进 **stderr + 前缀 + 自己的锁**;写失败**吞掉**(推送是加分项,绝不能打死推送线程,
  更不能影响主协议)。`_twin_push_loop` 改走它。
- 宿主:新增 `lib/push-channel.js`(纯函数 `splitPushChunk` / `looksLikePushStart`)把 stderr 字节流切成
  "遥测"与"普通诊断"两路;`lib/worker.js` 据此分流(遥测 → `_onPush`,其余 → `stderrTail` 原样保留),
  并新增 per-child 缓冲 `_pushBufByProc`。**stdout 上的推送行仍然接受**,旧版 Python 侧可继续工作。

分流模块的三个边界都是"永久丢数据"型,因此逐条单测(test/push-channel.test.mjs,7 条):一行被切成
两段、切点落在**魔数前缀内部**(chunk 恰好停在 `@@DSH-`)、以及**不以换行结尾的 traceback 尾巴必须
立刻交给诊断**(若它也去缓冲,那条诊断就永远进不了 stderrTail —— 这是"只缓冲看起来是推送的尾巴"
这条非对称规则的由来)。

验证:node scripts/run-tests.mjs 56/56(0 跳过、exit 0);check-host-compat 104/104 经宿主真实 DSL。

v0.7.0

Choose a tag to compare

@NoneadChina NoneadChina released this 13 Oct 18:25
0.7.0 — 诚实性与门禁加固

- movej/movel 的 t= 从未下发;12 个状态型 op 谎报生效(改 ok_unverified)
- worker 不再活过宿主(孤儿 Python 曾独占 RTDE 会话);Dashboard 应答不再串到下一条命令
- RTDE:START 被拒绝不再报 isRunning();收包跨 recv 边界不再整帧丢弃
- 门禁:跳过不再算绿;宿主兼容门禁首次真正运行(83/83 经宿主 DSL 注册)
- 孪生陈旧帧不再回放已结束的审批;探针纳入套件(46 → 51 项)

v0.6.9

Choose a tag to compare

@NoneadChina NoneadChina released this 12 Oct 07:01
186d8ea

[0.6.9] - 2026-10-12
Every model drew the same reach envelope, because the reach was never computed. The link-length reader expected the old links shape, while the real data is 6 × {x,y,z,roll,pitch,yaw} — so it returned null for all 14 built-in models.

Fixed — the reach envelope and the fallback arm now follow the model
Root cause (src/client/robot/loader.js): linkLengthsFromKinematics() accepted only [7 × 4×4 row-major number[16]] and required links.length >= 7, whereas assets/kinematics.json (the shape fk.js documents and consumes) holds 6 × {x,y,z,roll,pitch,yaw} fixed displacements. Every real model therefore returned null, and that single null produced both symptoms:
reachRadiusFromKinematics() also returned null, so twin-panel never updated reachSphere.scale — the envelope stayed at its unit radius (1 m) for every robot, which is exactly "the reach looks the same no matter which model is loaded";
loadRobotModel()'s armLinks was always undefined, so the unknown-model fallback arm always collapsed back to UR3-scale ARM_LINKS.
Fix: the function now understands both shapes. In the displacement shape a segment's length is the magnitude hypot(x,y,z) of its entry — the same convention fk.js and model-contract.test.mjs already use — while the legacy 4×4 row-major shape keeps its "distance between adjacent origins" behaviour. Either way it returns exactly 7 segments (base + 6 links, the last one approximated).
Measured after the fix (reach upper bound = sum of the 6 segment magnitudes): ur3 804 mm · ur3e 823 · ur5 1098 · ur5e/ur7e 1201 · ur16e 1295 · ur18 1358 · ur10 1543 · ur10e/ur12e 1627 · ur15 1693 · ur30 1729 · ur8long 2135 · ur20 2168 — a 2.70× span from UR3 to UR20.
Why this stayed green for so long: the unit tests fed hand-made matrix fixtures (straightLinks()) and never read the real assets/kinematics.json. Assertions that read the real data now pin it down: all 14 models resolve, the envelope grows monotonically, and UR20/UR3 > 2.5.
This was never a model-asset problem: the 14 GLBs already differ per model (bounding boxes ur3 0.35 m → ur20 1.06 m). Note the camera still frames each model by its own bounding box (the 0.6.3 design), so with the reach layer switched off the arm still fills the same frame — that is framing normalisation, not a wrong size.

v0.6.8

Choose a tag to compare

@NoneadChina NoneadChina released this 12 Oct 05:11
6298eeb

[0.6.8] - 2026-10-12
The twin now follows the desktop app's colour theme. The DOM half flips with the host's design tokens and the WebGL half is repainted by JS; two token names that do not exist in the DSH design system are gone — on a dark theme they rendered as a white card.

Changed — the digital twin follows the desktop app's colour theme
The DOM half is now coloured with the host's design tokens (var(--dsw-alias-*, )): the tokens flip with the host's body[data-ds-dark-theme] projection, so the panel follows whatever theme is selected under Settings → Appearance — and any third-party theme — with no JS involved. The value after the comma is the previous dark colour, so in an environment without a host token layer the rendering is exactly what it was before.
The WebGL half (which CSS cannot reach) is repainted by JS: new src/client/theme.js (theme detection + 3D palette + MutationObserver); twin-panel builds the scene with the current theme's palette and calls scene.applyTheme() on a theme change to rebuild the base grid (GridHelper bakes its line colours into the geometry's vertex colours, so recolouring means replacing the geometry). The fallback arm's material colour follows too.
Detection only trusts body[data-ds-dark-theme] and never falls back to prefers-color-scheme — otherwise "light theme + dark system" would be read backwards. With no body available it treats the theme as light and does not throw.
Also fixed two references to tokens that do not exist (--dsw-alias-bg-elevated and --dsw-alias-border-secondary are not defined in the DSH design system): they silently fell back, and a light fallback on a dark theme is a white card. The real token names were verified one by one in the local dsh-client-ui-theme / -layout packages before this change.
Four regression cases (the palette really reaches the grid's vertex colours, detection does not fall back to the system preference, the observer fires and unsubscribes, the CSS references only real tokens).

v0.6.7

Choose a tag to compare

@NoneadChina NoneadChina released this 11 Oct 11:28

[0.6.7] - 2026-10-10
The digital twin no longer sits on "data stopped updating Ns". 0.6.6 made a stall visible; this release makes it not happen: telemetry went from "the twin asks" to "the worker pushes".

Fixed — the twin keeps following the robot while it moves (pushed telemetry)
Root cause: the twin's reads and every motion command share one single-threaded stdin queue (for line in sys.stdin in python/ur_worker.py), and the motion confirmation loops (_movej_confirm / _movel_confirm / _wait_robot_idle, 60 s budget) hold it for tens of seconds, so a read simply queues until its 2.5 s budget expires. The data itself never stopped: RTDE is written at 500 Hz by URBasic's own receiver thread into model.dataDir, which has nothing to do with the command queue.
Fix: the worker now runs a 20 Hz background thread (_twin_push_snapshot + _twin_push_loop) that pushes joint angles and TCP as a JSON line without id; the host's _onLine recognises it before matching responses by id and stores it in a latestTelemetry cache; every twin frame reads that cache first (zero worker round trips) and only falls back to an explicit read when it is older than 300 ms or missing.
Wire compatibility: the absent id is the only marker — an older host just records it as an unmatched response, with no side effects.
One write lock for pushes and responses (_PROTOCOL_LOCK): concurrent writes to stdout that are not line-atomic interleave two JSON lines, which shows up as randomly dropped frames and odd timeouts.
Strict validation: a push whose joint angles or TCP are not 6-dimensional is dropped outright, never allowed to overwrite a good reading with half a pose (the arm would visibly jump).
Off switch: DSH_UR_TWIN_PUSH=0 disables the push channel for comparison (the twin then falls back to the 0.6.6 "read + stale" behaviour).
Evidence: new scripts/probe-twin-push-continuity.mjs — with a fake worker whose call() never settles (precisely "the queue is occupied"): with push: 20 frames, max frame gap 112 ms; without push: only 3 stale events. Five regression cases cover push-priority, staleness fallback, error fallback, push lines not counted as unmatched responses, and cache clearing on dispose.