← 返回列表
需源码安装
面向 DeepSeek HarnessDSH的 ROS2 调试工具集与机器人状态视觉分析,以插件形式发布。中文版见…
暂不能直接安装(需源码编译或环境不满足):缺少 main/exports/bin 入口声明;仓库 package.json 标记 private,未发布到 npm,需从源码安装。 · 最近上游提交 2026/9/16 · 已提供中文文档
Deepseek Harness ROS 2 插件可用于高效诊断问题并执行联合调试。
综合分
42.6
GitHub 分
42.6
用户评分
—
★ Stars
21
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add StvLi/dsh-ros2缺少 main/exports/bin 入口声明;仓库 package.json 标记 private,未发布到 npm,需从源码安装,改用 GitHub 源安装
数据截至 2026/9/18(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查需源码安装
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包dsh-ros2-workspace(未发布到 npm,仅可源码安装)
✓Node 引擎要求 ^22.19.0 || >=24.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明
缺少 main/exports/bin 入口声明;仓库 package.json 标记 private,未发布到 npm,需从源码安装
验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/18 07:09:14
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
dsh-ros2
面向 DeepSeek Harness(DSH)的 ROS2 调试工具集与机器人状态视觉分析,以插件形式发布。中文版见 README_CN.md。
CI
Release
License: MIT
[ROS2]()
Node
Tools
版本对应关系:npm 上的 dsh-ros2@0.1.0 就是本仓库当前版本(monorepo 布局)。
GitHub 的 v0.8.0 ~ v0.15.0 标签是已废弃的旧单体布局历史,从未发布到 npm。
版本号在 2026-08 monorepo 拆分时重新基线。详见 docs/versioning.md。
dsh-ros2 让 DSH agent 在任何装有 ROS2 的主机上获得完整的机器人开发 / 调试能力,按四个能力层级组织:
| 层级 | 能力 | 安全边界 |
| --- | --- | --- |
| L1 | 只读诊断:包 / 工作空间 / 依赖检查,节点 / 话题 / 服务 / 动作 / 参数 / 接口枚举,一次性话题采样,TF 树查询,全图拓扑 JSON,ros2doctor,bag 摘要,MoveIt 发现,机器人配置加载,安全状态读取与 VLM 语义仲裁 | 纯只读,无需审批 |
| L2 | 审批门控的管理操作:colcon build(后台任务)、rosdep install、消息骨架生成、param set、有界 bag record、一键安装 ROS2、launch 管理、rosbag 回放、MoveIt 运动、零位姿标定、机器人注册与拓扑学习、safety_monitor 启动 / 人工门控锁定 / 解锁 | 写操作始终先询问(fail-closed) |
| L3 | 可视化:RViz2 / rqt 生命周期管理、截图、多模态视觉描述、xdotool 级窗口交互 | 本地会话操作 |
| L4 | 实时视觉:并行 VLM ROS2 节点 + 图像话题采集(无头;vision_bringup 定期刷新各话题桥接),外加 RViz2 离屏渲染(OGRE 内核 → /rviz/scene 话题) | 纯软件 / GPU 渲染,无需显示器 |
所有工具都在主机上运行普通的 ros2 / colcon / rosdep CLI 命令;L1 从不修改任何内容,L2 始终先询问。
截图
| RViz2 离屏渲染(最新 lite_urdf,真实材质颜色) | 头部相机 | 左腕相机 | 右腕相机 |
| --- | --- | --- | --- |
| mesh render | head cam | wrist left | wrist right |
左侧:rviz_offscreen_node 使用真实的 rviz 栈(OGRE)进行渲染,并发布到 /rviz/scene 图像话题。右侧:由 ros2_image_snapshot 从实时相机话题抓取的三帧图像(1280×720)。完整测试记录:docs/test-robot-state-vision.md。
特性
- 零侵入诊断:83 个工具覆盖大多数 ROS2 调试场景——从“这个包安装了吗?”到“这个话题现在有什么?”,一条命令,一个答案;
- 全图拓扑:ros2_graph 将节点/发布者/订阅者/服务/动作折叠为一个 JSON——几秒内看清系统结构;
- 审批门控写入:构建、依赖安装、消息脚手架等均经过 DSH 审批服务;故障关闭,拒绝即失败;
- 可视化即服务:无头“看见”——截图 / 多模态描述 / 窗口交互完全本地化,无需远程显示;
- 并行实时视觉:VLM 运行在独立的 ROS2 进程(vlm_node,服务 /vlm/describe)中;图像来自话题(sensor_msgs/Image / CompressedImage);vision_bringup 为每个图像话题自动创建一个桥接,支持无头运行;
- RViz2 离屏渲染(llvmpipe 上运动渲染约 22 Hz;GPU 下全速 30 Hz):真实的 rviz 渲染内核(rviz_common + OGRE)在虚拟显示上渲染任意 .rviz 场景,并将其作为图像话题发布——无需截图,不依赖 X11 窗口堆叠。性能优化:open3d 低多边形网格(scripts/simplify_visual_meshes.py)+ 直接 OGRE 像素读取(无 PNG 往返)+ 双重渲染消除 → 运动渲染在 llvmpipe 上从 1.9 → 约 22 Hz(11 倍),并且在 NVIDIA GPU 直通下达到 30 Hz 全速(v0.9.3),内存减少 2.5 倍;
- 实时安全框架(safety_monitor 节点 + robot_safety_ 工具,见安全框架):分层防御——工具层安全门(执行前 /safety/state 检查)→ 反应式监控器(带迟滞的运动跟踪/停滞、关节反馈丢失、看门狗、可选力矩)→ 事件驱动的 VLM 语义仲裁 → 人工仲裁。锁存的 NORMAL/LOCKED 状态机(锁定持续到人工解锁;非致命事件永不锁定);每个阈值/话题/锁定动作都在配置文件的 safety 部分按机器人注册;几何预检查(关节限位 / 速度 / FK 自碰撞)是保留层;
- 内置技能(9 个):每个重复出现的流程对应一个载体——ros2-diagnostics(何时用哪个工具、缩小范围的方法论)、ros2-bringup-recovery(环境 → 启动 → 验证)、ros2-liveness-triage(一两次调用即可获取速率和负载)、ros2-tf-integrity(边、查找、缺失的广播者)、robot-registration / robot-retrieval(本体配置与即时复用)、robot-state-vision-analysis(状态 → 渲染 → VLM → 交叉核对)、robot-motion-control(唯一的 计划 → 验证 → 批准 → 执行 → 验证 路径)以及 robot-safety-procedure(闩锁、LOCKED、边界)。
快速开始
要求
- 一台装有 ROS2 的主机(已验证 Jazzy;Humble 应该也可用),ros2 在 PATH 中;
- Node ^22.19 || >=24(DSH 主机要求);
- L4 视觉额外需要 Python 3 的 rclpy 以及一个 OpenAI 兼容的 VLM 网关(例如 Gemini 或自托管网关)。
安装插件(自 monorepo 拆分后为 9 个 npm 包)
安装你需要的领域包——或者安装 dsh-ros2 聚合包以获得完整的 83 个工具 + 9 个技能(其补丁会插入所有领域 id)。所有包均已发布到 npm,版本为 0.1.0(GitHub ↔ npm 版本对应关系见 docs/versioning.md)。
通过 DSH 插件 CLI(推荐;经由 npm 解析):
full set (aggregate; pulls core/profile/moveit/safety/vision as deps)
dsh plugin --profile add dsh-ros2
or lean installs — e.g. diagnostics only:
dsh plugin --profile add dsh-ros2-core
dsh-ros2-common is a plain library, auto-installed as a dependency.
直接通过 npm(相同的包;适用于检查/安装可选附加组件):
the aggregate (pulls dsh-ros2-common/core/profile/moveit/safety/vision)
npm install dsh-ros2
optional add-ons — the sidecar data plane + its control-plane state client:
npm install dsh-ros2-state dsh-ros2-sidecar
包角色:dsh-ros2(聚合包)· dsh-ros2-common(共享库)·
dsh-ros2-core(核心诊断)· dsh-ros2-profile(配置/拓扑)·
dsh-ros2-moveit(MoveIt 运动)· dsh-ros2-safety(安全框架)·
dsh-ros2-vision(视觉流水线)· dsh-ros2-state(状态客户端)·
dsh-ros2-sidecar(数据平面守护进程)。
提示词指引。 dsh-ros2-core 会贡献一个系统提示词章节,引导模型在 ROS2 工作中使用这套工具链——用 ros2_ 发现图,用 robot_load/robot_topology 加载本体,通过 moveit_/robot_safety_ 进行规划与操作(需经批准,并以 /safety/state 为门控)——而不是临时调用 ros2 CLI 或私有的 rclpy 脚本。因此任何包含 core 的安装都会携带它,dsh-ros2 聚合包也不例外。
该章节在每次组装时都会根据当时已注册的工具重新构建,因此仅安装 core 时绝不会被要求调用它并未附带的 moveit_move 或 robot_safety_。它使用插件自身的
生命周期:禁用或移除插件会将其从提示中移除,因此未加载的 dsh-ros2 不会留下任何残留。
最小配置(按 bundle,整体对象替换)
拆分后,每个 bundle 都携带其自己的运行接缝配置(相同的键按 id 重复),而视觉提供程序仅存在于 dsh-ros2-vision 上:
DSH 配置文件补丁的片段(按 id 定向的配置覆盖)
- id: dsh-ros2-core # 还有:-profile / -moveit / -safety
config:
rosSetup: source /opt/ros/jazzy/setup.bash && # 准备 ROS2 环境
workspaceRoot: /home/you/ros2_ws # colcon/rosdep 的默认 cwd
- id: dsh-ros2-vision
config:
rosSetup: source /opt/ros/jazzy/setup.bash &&
vision:
provider: gemini # mock | gemini | openai
apiKey: ${VLM_API_KEY} # ${ENV} 引用从环境变量解析,勿明文写 key
- id: dsh-ros2-safety
config:
safetyStrict: warn # 'warn' (默认) | 'reject' (fail-closed);LOCKED 始终拒绝
三分钟体验
ros2_topology --tf # 一次调用获取整个系统(节点/话题/服务/动作/TF)
ros2_graph # 一次获取整个系统拓扑
ros2_topic_list # 所有话题和类型
ros2_topic_echo /joint_states # 采样一帧关节状态
ros2_tf_list # TF 树边
ros2_doctor # 系统健康报告
工具参考
工具位于各领域包中:L1/L2/L3 → dsh-ros2-core;motion_validate/moveit_ → dsh-ros2-moveit;robot_/ros2_zero_pose_semantics → dsh-ros2-profile;robot_safety_ → dsh-ros2-safety;视觉工具 → dsh-ros2-vision。
L1 只读诊断
| 工具 | 背后的命令 | 用途 |
| --- | --- | --- |
| ros2_pkg_list | ros2 pkg list | 已安装的包(可选子串过滤) |
| ros2_pkg_prefix / ros2_pkg_executables | ros2 pkg prefix / ros2 pkg executables [pkg] | 包的安装前缀 / 可执行文件(结构化) |
| ros2_colcon_list | colcon list | colcon 工作空间中的包 |
| ros2_rosdep_check | rosdep check --from-paths src --ignore-src | 依赖健康状况(缺失依赖 = 发现项,而非错误) |
| ros2_node_list | ros2 node list | 正在运行的节点 |
| ros2_node_info | ros2 node info [-v] | 单个节点的订阅者 / 发布者 / 服务 / 动作 |
| ros2_topic_list | ros2 topic list -t | 带类型的话题 |
| ros2_topic_find | ros2 topic find | 承载某消息类型的话题 |
| ros2_topic_info | ros2 topic info [-v] | 话题元数据 / QoS |
| ros2_topic_echo | ros2 topic echo --once | 一条消息样本(尽可能为 JSON);--qos-reliability / --qos-durability 覆盖可到达 TRANSIENT_LOCAL 锁存话题 |
| ros2_topic_hz | ros2 topic hz [--window N] | 测量发布频率(窗口内的平均/最小/最大/标准差);自然终止 = 测量超时 |
| ros2_env_check | resolved-setup 探测 | 自检环境:已 source 哪个 setup、路径是否存在、可见的包/节点 |
| ros2_workspace | source /install/setup.bash && | 在会话中切换/显示工作空间(use/show/reset)——不修改配置,不重启 |
| ros2_topic_bw / ros2_topic_delay | ros2 topic bw|delay | 测量话题带宽 / 端到端延迟;超时终止 |
| ros2_service_list | ros2 service list -t | 带类型的服务列表 |
| ros2_service_type / ros2_service_find | ros2 service type|find ... | 服务类型 / 按类型查找服务 |
| ros2_action_list | ros2 action list -t | 带类型的动作列表 |
| ros2_action_info | ros2 action info | 动作类型与状态 |
| ros2_action_type | ros2 action type | 动作类型 |
| ros2_param_list | ros2 param list | 节点的参数列表 |
| ros2_param_get | ros2 param get | 读取单个参数值 |
| ros2_param_dump | ros2 param dump | 转储节点的所有参数 |
| ros2_interface_show | ros2 interface show | 消息/服务/动作的完整字段定义 |
| ros2_interface_list / ros2_interface_prototype / ros2_interface_package | ros2 interface list|prototype|package ... | 所有接口类型 / 默认值原型 / 某个包中的类型 |
| ros2_graph | ros2 node list + 逐节点 node info | 折叠后的 JSON 拓扑图 |
| ros2_topology | 单个 rclpy 进程(不逐动词启动 CLI) | 一次调用获取全系统快照:节点及其 pub/sub/services、带类型和 pub/sub 计数的话题、服务、动作,以及可选的 TF 帧和参数。优先使用它,而不是多次调用更窄的接口 |
| ros2_tf_list | 同一个 rclpy 快照 | 来自 /tf 以及锁存的 /tf_static 的 TF 边(动态帧和静态帧都包括) |
| ros2_tf_echo | 同一个 rclpy 快照 | 两个坐标系之间的变换,包括反向边 |
| ros2_doctor | ros2 doctor | 系统健康报告 |
| ros2_bag_info | ros2 bag info | 包(bag)摘要 |
| moveit_discover | 扫描 MoveIt 包 + 解析 SRDF + 探测 move_group | 发现 MoveIt2 配置包(任何附带 SRDF 的包)、其规划组和命名位姿,以及 /move_action / /execute_trajectory / /compute_cartesian_path 是否在线。传入 srdf 可直接解析指定文件——通用,不绑定特定包 |
| robot_safety_state | ros2 topic echo /safety/state --once | 读取锁存的安全状态(NORMAL / LOCKED + 严重程度 + 触发原因 + 详情);当监控器离线时报告 monitor_running: false |
| robot_safety_arbitrate | ros2 run dsh_ros2_safety safety_vlm_arbitrate ... | 事件驱动的 VLM 语义仲裁(计划变更 / 异常后):固定格式提示词 + 通过 /vlm/describe 获取最新的离屏帧;任何非安全判定都会标记为需人工仲裁 |
| motion_validate | motion_validator.py --trajectory --config | 确定性的执行前验证(只读):关节限位、NaN/Inf、名称与组覆盖、时间戳/时长、时效性、可选工作空间盒、指纹 + TTL —— 碰撞/奇异性仍由 MoveIt 规划负责 |
L2 管理(需审批)
每个 L2 工具都会执行写操作,并先通过 DSH 审批服务询问用户(服务不可用或被拒绝时按失败关闭处理)。只读辅助工具 ros2_jobs_list / ros2_job_status 无需审批。
| 工具 | 背后的命令 | 说明 |
| --- | --- | --- |
| ros2_colcon_build | colcon build [--packages-select ...] [--symlink-install] | 作为后台任务运行(ctx.jobs);返回 jobId,用 ros2_job_status 跟踪 |
| ros2_rosdep_install | rosdep install --from-paths src --ignore-src -y | dryRun 通过 --simulate 预览 |
| ros2_interface_create | 写入 ///. | 骨架生成器;绝不覆盖已有文件 |
| ros2_param_set | ros2 param set | JSON 数字/布尔值会按类型处理,其他值按字符串处理 |
| ros2_bag_record | ros2 bag record --output | 有界录制:在 duration 秒后自动停止 |
| ros2_jobs_list | ctx.jobs.list | 此智能体的后台任务(只读) |
| ros2_job_status | ctx.jobs.get | 按 id 查询某个任务的状态(只读) |
| ros2_install | FishROS 一键安装器(交互式 PTY 会话) | 当 ROS2 缺失时:check 探测(已安装 / 已安装但未 source / 不存在);start(需审批)启动安装器;send / status / stop 驱动并观察交互式菜单 |
| ros2_bag_play | ros2 bag play [--topics ...] [--rate X] [--loop] [--start-offset S] | 将 rosbag 回放到其话题中(需审批;会向图中发布);在前台运行 timeoutMs |
| ros2_topic_pub | ros2 topic pub "" [-r Hz] [-n N\|--once\|-t sec] | 发布消息(需审批;会改变图)。有界发布 + QoS 覆盖(--qos-reliability / --qos-durability) |
| ros2_run | ros2 run [args] | 运行任意已安装的 ROS2 可执行文件(需审批):前台(有界)或后台任务 |
| ros2_process_cleanup | pgrep -f '[p]attern' + kill | 终止匹配模式的残留 ROS2 进程(自身安全);需审批 |
| ros2_service_call | ros2 service call "" | 调用服务(需审批);响应从 repr 解析 |
| ros2_action_send_goal | ros2 action send_goal "" [--feedback] | 发送动作目标(需审批);返回目标 ID + 状态 |
| ros2_daemon | ros2 daemon status|stop|start | 守护进程状态(L1)/ 停止-启动(L2 审批)—— 重新发现过期的图 |
| ros2_param_delete | ros2 param delete | 删除节点参数(需审批) |
| ros2_lifecycle | ros2 lifecycle get|list|set [state] | 生命周期状态获取/列出(L1)或设置(L2 审批) |
| ros2_component | ros2 component list / load | 组件容器列出(L1)/ 加载(L2 审批) |
| ros2_launch | ros2 launch [args] | 将启动文件作为后台作业启动(需审批;返回 jobId,通过 DSH 作业控制停止) |
| ros2_zero_pose_semantics | 发布零位 → 离屏渲染 → VLM → 确认 | 交互式校准零位语义(通用):analyze 渲染全零位姿并询问 VLM 其在三个方面的姿态(手臂:lateral_raise/hanging,肘部:forward/upward,手掌/相机安装:up/forward/down);confirm 将用户批准的组合(或 customText 自由文本描述)记录到 ~/.dsh-ros2/zero-pose.yaml 供技能使用 |
| robot_register | 收集 URDF/TF/相机/MoveIt/零位 → 写入 ~/.dsh-ros2/robots/.yaml | 首次接触时注册机器人本体配置文件(需审批),以便后续即时复用 |
| robot_load | 读取 ~/.dsh-ros2/robots/.yaml | 将已注册的机器人配置文件加载为结构化 JSON(快速路径 —— 无需发现);名称为空则列出所有配置文件 |
| robot_topology | 聚合快照 + 渐进式节点学习(严格模式) | 机器人通信拓扑权衡:snapshot(审批)记录节点/话题/服务列表(轻量,不冗长);learn(审批)记录一个重要节点的角色/描述 + 发布/订阅/服务/动作;show(只读)读取它们 |
| moveit_move | 统一:/move_action + /execute_trajectory | 一个工具,五种基本模式(需审批):joint_abs、joint_rel、pose_abs、pose_rel(坐标系 ee/world)、trajectory。通用:仅标准 moveit_msgs + SRDF。单一运动路径:规划 → 确定性验证(motion_validator,robot 配置文件用于完整限制)→ 人工审批(显示验证摘要)→ 执行 → 验证。以 /safety/state 为门控(LOCKED 始终拒绝;监控关闭按 safetyStrict 处理) |
| robot_safety_start | ros2 run dsh_ros2_safety safety_monitor --profile | 将通用安全监控器作为后台作业启动(需审批);所有机器人特定值来自配置文件 safety 部分 |
| robot_safety_lock / robot_safety_unlock | ros2 service call /safety/set_lock|unlock ... | 人工门控的显式锁定 / 解锁(调用前需 L2 审批);锁定保持锁存状态直到人工解锁(恢复:解锁 → 重新归位 → 继续) |
| moveit_status | 探测 move_group 接口并采样 /joint_states | 运行时状态:在线探测 + 当前关节状态 + SRDF 规划框架(只读) |
L3 可视化
GUI 生命周期 + 截图 + 多模态视觉(“先看,再动”)+ xdotool 级交互(“边看边动”)。截图在 X11 上使用 Pillow ImageGrab(无需额外安装 CLI);视觉提供者可插拔;交互需要 xdotool(sudo apt install xdotool)。
| 工具 | 用途 |
| --- | --- |
| ros2_gui_start | 在主机显示器上启动 RViz2(带 -d config)/ rqt_graph / rqt;会话会被跟踪 |
| ros2_gui_list | 已跟踪的会话 + X11 窗口(wmctrl -lG) |
| ros2_gui_close | 关闭会话(SIGTERM) |
| ros2_screenshot | 将屏幕或某个窗口截图保存为 PNG |
| ros2_vision_describe | 使用配置的多模态模型(Gemini / OpenAI / mock)描述图像 |
| ros2_gui_observe | 确保 GUI 正在运行 → 截图 → 返回多模态描述(“看到它”工作流) |
| ros2_gui_interact | 统一的 xdotool 交互:action=click(点击/滚动,button 4/5 = 滚动),action=drag(按下-拖动-释放:RViz2 旋转/平移/缩放),action=key(组合键如 ctrl+shift+r 或输入文本) |
交互配方(面向模型):使用 ros2_gui_interact {action: "drag", windowTitle: "rviz2", button: 1, toX: , toY: } 旋转 RViz2 视图,使用 action: "drag", button: 3 缩放,使用 ros2_gui_interact {action: "key", keys: "ctrl+shift+r"} 重新加载显示配置。当 wmctrl 无法枚举窗口时(例如显示器上没有窗口管理器),窗口相对交互会报告“window not found”——回退到绝对屏幕坐标。交互仅限于主机会话本地(无需批准,与其他 L3 工具相同)。
L4 实时视觉(ROS2 上的并行 VLM,无头图像话题)
感知与机器人控制栈相匹配:VLM 运行在独立的 ROS2 进程中(vlm_node,服务 /vlm/describe + 缓存话题 /vlm/description),图像来自 sensor_msgs/Image 话题,而非 X11 截图——无头就绪。采集(ros2_image_snapshot)无需自定义包(纯 rclpy);只有 ros2_vlm_analyze/ros2_vision_analyze 需要 dsh_ros2_vlm ROS2 包(vlm/)——构建/运行参见 docs/architecture.md §4。当流水线不可用时,ros2_vlm_analyze/ros2_vision_analyze 返回明确的 VLM_UNAVAILABLE + 降级提示,并且快照 JPEG 可由 Agent 自身的多模态模型直接读取。
| 工具 | 用途 |
| --- | --- |
| ros2_image_snapshot | 从话题(raw/compressed)抓取一帧并保存为 JPEG——纯 rclpy 脚本,无需自定义 ROS2 包;对静默话题使用 --v4l ffmpeg 回退;该 JPEG 可直接供 Agent 自身的多模态模型使用 |
| ros2_vlm_analyze | 通过并行 VLM 分析图像文件或桥接的最新帧(useBridge) |
| ros2_vision_topics | 列出实时图像话题及其自动桥接服务名称 |
| ros2_vision_doctor | 一次性流水线自检:vlm 工作空间已构建 / vlm_node+vision_bringup 正在运行 / 网关可达 / 可见图像话题 / apiKey 解析状态(config/env/secrets/missing)+ 构建启动指引 |
| ros2_vision_set_key | 将用户提供的 VLM API Key 存储到 ~/.dsh-ros2/secrets.json(0600,位于仓库之外——永不提交、永不上传、永不回显);当工具返回 VLM_API_KEY_REQUIRED 时使用 |
| ros2_vision_analyze | 通过其自动桥接分析任意话题的最新帧(ros2_vision_analyze {topic, prompt}) |
build + launch the vision pipeline (auto bridge per image topic)
mkdir -p /tmp/vlm_ws/src && ln -s /vlm /tmp/vlm_ws/src/dsh_ros2_vlm
cd /tmp/vlm_ws && colcon build --symlink-install && source install/setup.bash
VLM_API_KEY=... ros2 run dsh_ros2_vlm vlm_node & # parallel VLM process
ros2 run dsh_ros2_vlm vision_bringup & # discover topics, one bridge each
RViz2 离屏渲染(dsh_ros2_rviz_offscreen)
真正的 rviz 渲染栈(rviz_common + OGRE + rviz_default_plugins)在 Xvfb 下离屏加载 .rviz 场景,并将其发布到 /rviz/scene 图像话题——从渲染内核读取,而非 X 屏幕截图,不依赖窗口堆叠。
build (needs a colcon workspace like vlm_ws)
ln -s /offscreen /tmp/vlm_ws/src/dsh_ros2_rviz_offscreen
cd /tmp/vlm_ws && colcon build --symlink-install && source install/setup.bash
run (config_path points at a .rviz scene file)
xvfb-run -a -s "-screen 0 1280x800x24" ros2 run dsh_ros2_rviz_offscreen rviz_offscreen_node \
--ros-args -p config_path:=/tmp/robot_scene.rviz -p topic:=/rviz/scene \
-p width:=800 -p height:=600 -p rate:=5.0
机器人本体网格渲染要点(已收集的坑;详见 docs/architecture.md §4.4):
1. Jazzy RobotModel 属性:使用 Description Source: Topic + Description Topic: (旧版 Robot Description: 会被忽略 → Links 为空);
2. 网格路径:在 URDF 中使用绝对路径或 file:// 前缀(裸路径在 resource_retriever 中会失败);描述发布者必须保持存活(transient-local,否则后加入的订阅者会错过);
3. URDF 必须按名称绑定到 TF:URDF 链接名称必须与实时 TF 帧名称完全匹配(发布机器人实际的 /robot_description 即可)。不匹配 → 每次链接变换查找都会失败 → 所有网格堆积在固定帧原点;
4. 观察距离:Orbit Distance ≈ 1.5–2.0 m,以获得类似 RViz 的近距离全身视图(> 5 m 会使机器人缩小为中心的一个小点);
5. 健康信号:启动约 3 秒后,节点会记录 FM: ... frames=N 和 transformHasProblems(...)=0——网格已正确绑定到 TF。
MoveIt2 运动——五种基本模式,一个工具
设计意图。 通过 MoveIt 进行机器人运动,其核心只有五种
操作:绝对设置关节、相对微调关节、将末端执行器置于绝对位姿、按相对增量移动它,或执行预先规划好的轨迹。dsh-ros2 没有采用不断膨胀的命名工具集合,而是将它们抽象为一个带有 mode 参数的工具 moveit_move——因此接口保持小巧、可预测且可脚本化,并且适用于任何* MoveIt 包(它读取 SRDF,并且只使用标准 moveit_msgs)。
| 工具 | 作用 |
| --- | --- |
| moveit_discover (L1) | 读取任意 MoveIt 包的 SRDF:规划组、命名位姿、链末端;在线探测标准接口(/move_action、/execute_trajectory、...) |
| moveit_status (L1) | 运行时探测:接口在线 + 当前 /joint_states 采样 + SRDF 规划坐标系 |
| moveit_move (L2,需审批) | 一个工具,五种模式:joint_abs(关节 "j1:=v1 j2:=v2")、joint_rel(deltaJoints = 当前值 + 增量)、pose_abs(位姿 "x y z rx ry rz",位于规划坐标系中)、pose_rel(deltaPose "dx dy dz drx dry drz",坐标系为 ee/world)、trajectory(执行已保存的轨迹 JSON) |
moveit_move {mode: "joint_abs", group: "right_arm", joints: "right_shoulder_roll:=0.5"}
moveit_move {mode: "joint_rel", group: "right_arm", deltaJoints: "right_elbow_pitch:=-0.2"}
moveit_move {mode: "pose_rel", group: "right_arm", deltaPose: "0.05 0 0 0 0 0"}
moveit_move {mode: "pose_abs", group: "right_arm", pose: "0.5 0 0.8 0 0 0"}
moveit_move {mode: "trajectory", group: "right_arm", trajectory: "/tmp/traj.json"}
工作原理。 moveit_discover/moveit_status 告诉你可以移动什么(来自 SRDF 链末端的组、关节、EE 链接,以及在线状态);moveit_move 将任意模式转换为标准 MoveGroup 目标(/move_action),通过 /execute_trajectory 执行,并且——配合 planOnly + trajectoryOut——保存规划出的轨迹,以便 mode: "trajectory" 之后可以运行它(规划/执行分离)。没有任何内容绑定到特定的 MoveIt 包;只有 SRDF 路径重要(通过包扫描自动解析,或显式指定 srdf/package)。
安全框架
设计意图。 一种双层策略,将实时判断与语义判断分开(完整契约:docs/safety-handover.md,这是面向下游机器人适配代理的交接文档——通用框架/接口属于此处,本体特定的数据源/方案/算法属于下游):
工具层安全门(执行前:/safety/state LOCKED;按 safetyStrict 监控下线)
→ 反应式监控器(执行中:运动跟踪/停滞 + 迟滞、
关节反馈丢失、看门狗、可选力矩;以控制频率检测,
响应预算 ≤100 ms)
→ VLM 语义仲裁(计划变更后 / 异常后,数秒——仅在需要时拉起)
→ 人工仲裁(非安全判定始终升级;人工门控解锁)
- safety_monitor 节点(dsh_ros2_safety 包):订阅关节
反馈(+ 可选的指令流 / 力矩流),在
control_frequency 定时器上运行检查器,并在任何 CRITICAL 事件上锁存 LOCKED —
该锁存会持续存在,直到人工解锁(不会自动重置回同一危险状态)。
发布 /safety/state(transient-local)、/safety/event、
/safety/heartbeat、/safety/lock_active;服务 /safety/get_state、
/safety/unlock、/safety/set_lock。
- 锁存式锁定,非致命永不锁定:任何 CRITICAL 事件都会锁存 LOCKED
(该锁存会持续存在,直到人工解锁 — 不会自动重置回同一
危险状态);看门狗将 critical(宕机 → 锁定)与 observed(宕机 →
仅 WARNING)区分开;单帧噪声通过 M-of-K 迟滞进行过滤;WARNING
永不锁存。工具层在监控宕机时的 fail-closed 行为由
safetyStrict: 'reject' 决定(默认 'warn' 会带警告继续执行)。
- 按机器人注册:robot_register 写入一个通用的 safety
段(由 URDF 推导的速度/力矩限制)并自动启动监控器;
robot_profile.py safety set 更新任意阈值/话题/列表
(经 schema 校验)。当不存在力矩反馈时,力矩检查会自动禁用。
保留层(接口已注册,未实现):几何预检查(命令
路径上的关节限位 / 速度 / FK 自碰撞 — motion.max_velocity /
max_acceleration)、计算力矩前馈输入(torque.feedforward_topic)、
YOLO 风格的轻量触发器,以及非 ROS 的急停路径(estop)。
- 工具层门控:moveit_move 在执行前查询 /safety/state
— LOCKED 始终被拒绝(SAFETY_LOCKED);如果监控器不可达,
safetyStrict: 'reject'(fail-closed)或 'warn'(默认)会带
警告继续执行。robot_safety_arbitrate 运行固定格式的 VLM 仲裁,并
将任何非安全裁决标记为需人工仲裁。
- 取证:关节/力矩样本的环形缓冲区会在每次 CRITICAL 锁定时转储到
forensics.dump_dir,用于事后 / VLM 诊断。
构建 safety 包(与 vlm/ 和 offscreen/ 相同的 colcon 工作空间)
ln -s /safety /tmp/vlm_ws/src/dsh_ros2_safety
cd /tmp/vlm_ws && colcon build --symlink-install && source install/setup.bash
safety_core 纯逻辑自带故障注入自测
(python3 packages/safety/safety/scripts/safety_core.py --selftest,12 个场景)— 验证状态机
无需 ROS2。
机器人配置文件与通信拓扑
设计意图。 机器人的本体(URDF 链接/关节、相机、MoveIt 组、
零位姿语义)及其通信图每次重新发现都代价高昂。
该插件将它们持久化为一个结构化配置文件(~/.dsh-ros2/robots/.yaml):
首次接触时注册一次,之后便可即时加载。对于
通信图,完整详细模式无法扩展(复杂机器人有数百个
话题/服务),因此设计是一种权衡:一个聚合快照
(轻量节点/话题/服务列表)加上在你实际使用过程中仅对重要节点进行的渐进式学习。
| 工具 | 作用 |
| --- | --- |
| robot_register (L2) | 收集本体信息(URDF 链接/关节、TF 根、相机、MoveIt SRDF 组、自动关联零位姿标定以及带有 URDF 派生限制的通用 safety 部分)到配置文件中;自动启动安全监控(startSafety: false 可跳过) |
| robot_load (L1) | 将配置文件加载为结构化 JSON —— 快速路径,无需重新发现;空名称列表会列出全部 |
| robot_topology (L1/L2) | 通信图:snapshot(L2,聚合列表)、learn(L2,单个重要节点的角色/描述 + 发布/订阅/服务/动作,严格模式)、show(L1,读回)、diagnose(L1 —— 知识增强诊断:将已学习的知识库 + 快照与实时图进行交叉引用:missing / new / drift / topic_drift)、search(L1 —— 在知识档案中高效检索:按话题反向查找 / 按名称/角色/描述/连接进行关键词匹配) |
| ros2_zero_pose_semantics (L2) | 通过渲染 + VLM + 用户确认来标定零位姿(手臂/肘部/手掌组合或自由文本);配置文件会自动包含它 |
两个捆绑技能完善了整个工作流:robot-registration(首次接触流程:询问名称/URDF → 收集 → 注册 → 验证,外加拓扑基线快照)和 robot-retrieval(即时加载配置文件,并从中启动渲染/诊断/运动,包括已学习的拓扑和零位姿语义)。
工作原理。 所有内容都是 ~/.dsh-ros2/ 下的纯结构化 YAML —— robots/.yaml(本体 + 拓扑)和 zero-pose.yaml(标定)。robot_register 快照本体;robot_topology snapshot 快照聚合层;robot_topology learn 在你发现重要内容时一次追加一个节点(幂等合并)。robot_load 和 robot_topology show 可即时读回它们 —— 一次调用而非 N 次发现调用。
知识库是被消费的,而不仅仅是被存储的。 robot_topology diagnose(L1,只读)是知识增强诊断的入口:它加载已学习的节点 + 快照,并将它们与实时 ros2 图进行交叉引用 ——
- missing:当前离线的已学习节点(控制器/发布者宕机)—— 最高优先级;
- new:知识库中不存在的实时节点(学习候选);
- matched[].drift:对每个已学习节点,预期的发布/订阅/服务/动作与实际对比(缺失的话题 = 连接消失;新增的话题 = 节点已变更);
- topic_drift:聚合快照话题与实时话题对比。
ros2-diagnostics 和 robot-retrieval 技能都以 diagnose 开始诊断,并通过 learn 重要的 new 节点来闭环 —— 因此知识库会随每次会话而改进,每次诊断也会变得更快。
捆绑技能
| 技能 | 内容 |
| --- | --- |
| ros2-diagnostics | 何时使用哪个工具、缩小范围的方法论、调试“topic 没有数据”/消息不匹配/TF 问题 |
| ros2-bringup-recovery | “启动不起来”的旅程:ros2_env_check → ros2_workspace use(会话内,无需重启)→ launch → 作业跟踪 → doctor 验证 |
| ros2-liveness-triage | “它是否存活/为何陈旧”的旅程:ros2_topology {rates} → ros2_topic_sample → 读取发布者数量/频率/QoS,以及会导致误报的超时语义 |
| ros2-tf-integrity | “TF 树是否正确”的旅程:图旁边的 frames、/tf + latched /tf_static 边、反向边查找、将缺失的边定位到其广播者 |
| robot-state-vision-analysis | 完整流水线:状态 → 离屏渲染 → VLM → 交叉检查(包括 Jazzy 的 Description Source/Topic、URDF↔TF 帧名匹配、file:// 网格、视图距离、FM frames 信号、校准的零位姿态语义) |
| robot-registration | 首次接触流程:询问名称/URDF → 收集本体信息 + 零位姿态校准 → robot_register → 拓扑基线快照 |
| robot-retrieval | 即时配置加载(robot_load)以及渲染/诊断/运动的启动;读取并逐步学习通信拓扑(robot_topology) |
| robot-motion-control | “它能否移动/如何移动”的旅程:moveit_status → 组发现 → planOnly → motion_validate → 唯一受审批和 /safety/state 门控的执行路径 → 通过/失败验证 |
| robot-safety-procedure | “它是否安全”的旅程:首先 robot_safety_state,LOCKED 作为停止信号,VLM 仲裁(uncertain ≠ safe),六个层级及其明确边界 |
配置
| 键 | 类型 | 默认值 | 含义 |
| --- | --- | --- | --- |
| rosSetup | string | '' | 用于准备环境的 shell 前缀,例如 source /opt/ros/jazzy/setup.bash && |
| timeoutMs | number | 15000 | 每条命令的超时时间 |
| rosLogDir | string | '' | 覆盖 ROS_LOG_DIR(当 ~/.ros/log 不可写时有用) |
| workspaceRoot | string | '' | 当工具省略 cwd 时,colcon / rosdep 的工作目录 |
| includeStderr | boolean | false | 将末尾的 stderr 附加到成功结果中 |
| display | string | '' | 用于 GUI/截图工具的 DISPLAY 覆盖 |
| screenshotDir | string | '' | 截图输出目录(默认 $TMPDIR/dsh-ros2) |
| screenshotCommand | string | '' | 自定义截图命令;{output} 会替换为 PNG 路径 |
| vision.provider | string | 'mock' | mock \| gemini \| openai |
| vision.apiKey | string | '' | 你的 API 密钥(由用户提供;绝不记录日志) |
| vision.model | string | '' | 模型覆盖(例如 gemini-2.5-flash、gpt-4o-mini) |
| vision.baseUrl | string | '' | API 基础 URL 覆盖(OpenAI 兼容端点) |
rosLogDir 还覆盖由工具(topic echo/pub、ros2 run)启动的 ROS2 Python CLI;此外,当 ~/.ros/log 不可写时,runCommand 会自动回退到可写目录。
项目布局
dsh-ros2/ # pnpm monorepo(工作区根目录,私有)
├── pnpm-workspace.yaml # packages/*
├── tsconfig.base.json
├── packages/
│ ├── common/ # dsh-ros2-common(非 bundle):runner / parse / toolkit + scripts/robot_profile.py(零拷贝)
│ ├── core/ # dsh-ros2-core(61 个工具):L1 诊断 + L2 管理 + L3 GUI + diagnostics/bring-up/liveness/TF 技能 + gui.ts + pty_session.py
│ ├── profile/ # dsh-ros2-profile(4 个工具):robot_register/load/topology + 零位姿标定 + 注册/检索技能
│ ├── moveit/ # dsh-ros2-moveit(4 个工具):discover/status/motion_validate/moveit_move + moveit_.py + motion_validator.py + robot-motion-control 技能
│ ├── safety/ # dsh-ros2-safety(5 个工具):robot_safety_ + safety/ ROS2 包 + safetyStrict 配置 + robot-safety-procedure 技能
│ ├── vision/ # dsh-ros2-vision(7 个工具):vision 工具 + vlm/ + offscreen/ ROS2 包 + vision provider 服务 + state-vision 技能
│ └── dsh-ros2/ # 聚合 bundle(空 apply,向后兼容)
├── docs/ # architecture.md · safety.md / safety-handover.md / safety-todo.md / safety-gpt-review.md · test-*.md · plugin-split-plan.md
├── .github/workflows/ # CI:Node 22/24 → 工作区 typecheck/test/build + 逐包 tarball 校验
└── CHANGELOG.md # 版本历史(Keep a Changelog)
插件拆分(9 个包)
自 v0.15.0 起,该插件是一个由 9 个 npm 包组成的 pnpm monorepo(依据
docs/plugin-split-plan.md,按 ISP 收紧):83 个工具 +
9 个技能(四个原始技能保留,名称与行为不变)。
按需安装各领域
bundle(或安装 dsh-ros2 聚合包以获取完整集合):
- dsh-ros2-common 是一个普通库(不是 cordis bundle)——共享 runner、
parser、toolkit 以及 scripts/robot_profile.py(零拷贝)。
- 跨包运行时契约保持不变:/vlm/describe、
/safety/state、/safety/set_lock ……;safetyStrict 语义不变。
- dsh-ros2-vision 修复了 npm 发布缺陷:其 files 包含
vlm/ + offscreen/。
- vision provider 是一个可选的 cordis 服务(dshRos2.vision);
当它缺失时,ros2_gui_observe(core)和 ros2_zero_pose_semantics(profile)会降级为
VISION_UNAVAILABLE。
故障排查 / 常见问题
- ~/.ros/log 权限被拒绝:ROS2 无法写入其日志目录。设置 rosLogDir(例如 /tmp/ros-log);runCommand 也会自动回退。
- stderr 中大量 RTPS_TRANSPORT_SHM / FastDDS SHM 警告:当 SHM 传输不可用时(在容器/受限环境中很常见)产生的无害噪声;工具默认会将其丢弃。
- ros2 topic echo 返回为空:用 ros2_topic_info -v 检查发布者数量和 QoS;对 transient-local 话题使用 --qos-durability transient_local 进行采样。
- 离屏渲染:“所有部件都堆叠在原点”:URDF 链接名称与 TF 帧名称不匹配(参见 mesh essentials #3);先检查节点日志 FM transformHasProblems()=1。
- RobotModel 不显示任何网格(Links 为空):在 Jazzy 上必须使用 Description Source/Topic;旧版的 Robot Description: 不起任何作用。
- Could not load resource ... Unable to open file:网格路径需要绝对路径或 file:// 前缀。
- 发布者退出后描述丢失:URDF 发布者必须保持存活(transient-local 只会向迟到的订阅者重新发送一次;进程退出后即消失)。
- vision_bringup 遗漏了一些图像话题(测得 2/4):已修复——现在每隔 --refresh 秒(默认 10)刷新一次发现,对稍后出现的话题自动生成桥接,并对消失的话题停止桥接。
开发
使用 pnpm 11.x 安装(仓库固定 packageManager: pnpm@11.22.0;CI 通过 pnpm/action-setup@v6 安装匹配的
pnpm)。需要 Node ^22.19 || >=24。
bash
pnpm install
pnpm run typecheck # tsc --noEmit
pnpm run test # vitest(195 个用例;外加 10 个 sidecar + 6 个 zero-pose + 17 个 profile-name Python 检查)
pnpm run build # tsc -> lib/ + lib/types/
CI(.github/workflows/ci.yml):在推送到 main / PR 时,在 Node 22 和 24 上运行 typecheck/test/build,并验证 pnpm pack 产物包含补丁层(cordis.patch.yml)和构建输出。
发布工作流(npm 和 GitHub Releases):参见 PUBLISH.md。
路线图
- [x] vision_bringup 轮询/刷新发现(自动桥接迟到的话题,对消失的话题停止桥接);
- [x] Zero-pose 语义:通用校准流程(ros2_zero_pose_semantics,渲染 + VLM + 用户确认,3 轴组合)链接到机器人配置文件中;
- [x] npm 发布(9 个包 @ 0.1.0 在 npmjs 上,发布于 2026-08-30;dsh-ros2-state/dsh-ros2-sidecar 于 2026-09 添加;参见 docs/versioning.md);
- [ ] 更多 ROS2 发行版(Humble / Rolling)兼容性验证。
文档
| 文档 | 内容 |
| --- | --- |
| docs/architecture.md | 设计概览、四个层级、L4 视觉与离屏渲染架构、性能演进、安全模型 |
| docs/compatibility.md | 兼容性基线 |
| docs/safety.md | 安全边界:六层(智能体权限 / 人工审批 / 运动验证 / 执行监控 / 执行后验证 / 物理机器人安全)、故障关闭与降级策略、“DSH 不是功能安全系统” |
| docs/safety-handover.md | 面向下游机器人适配智能体的交接文档:通用框架/接口与本体特定数据源/算法、profile safety schema、接口 |
| docs/safety-todo.md | GPT 评审决策 + 批次:0.14.1 已完成(确定性验证)、0.15+(GUI 白名单 / 审计 / C++ 实时节点……) |
| docs/test-robot-state-vision.md | 端到端真机测试:流水线、实时、mesh/TF 绑定修复与验证、四通道关节分析(含图片) |
| docs/test-gpu-passthrough.md | GPU 直通验证:硬件、故障排查、结果、用法 |
| CHANGELOG.md | 版本历史(Keep a Changelog) |
| docs/versioning.md | GitHub tag ↔ npm 包版本对应关系(monorepo 重新基线;旧的单包 tag v0.8–v0.15 从未发布到 npm) |
贡献
欢迎提交 Issue 和 PR(中文或英文均可)。请保持 pnpm run typecheck && pnpm run test && pnpm run build 通过,并更新相关文档。
致谢
- DeepSeek Harness — 插件宿主框架;
- ROS2 / RViz2 社区 — 渲染与工具链基础。
许可证
MIT同作者(StvLi)的其他插件
扫码进群