面向 DeepSeek Harness 的 ROS2 调试工具集与机器人状态视觉分析:节点/话题/服务/动作/接口/TF 枚举、全图拓扑 JSON、依赖检查,审批门控的构建与自定义消息骨架生成,GUI 截图与多模态视觉观察,以及无头 RViz2 离屏渲染(低模 + 直读像素 + GPU 直通,动作渲染 30Hz)与并行 VLM 实时分析。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:StvLi/dsh-ros2
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
ROS2 调试工具集与机器人状态视觉分析能力,作为 DeepSeek Harness (DSH) 插件分发。
版本对应关系:npm 上的
dsh-ros2@0.1.0就是本仓库当前版本(monorepo 布局)。 GitHub 的v0.8.0 ~ v0.15.0标签是已废弃的旧单体布局历史,从未发布到 npm。 版本号在 2026-08 的 monorepo 拆分时重新基线。详见 docs/versioning.md。
dsh-ros2 让 DSH 智能体在一台装有 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 话题) |
纯软件渲染,无需显示器 |
所有工具直接调用宿主上的 ros2 / colcon / rosdep CLI;L1 永远不修改任何东西,L2 永远先询问。
截图
RViz2 离屏渲染(最新 lite_urdf,真实材质配色) |
头部相机 | 左手眼相机 | 右手眼相机 |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
左图由
rviz_offscreen_node在 Xvfb 下用真实 rviz 渲染栈(OGRE)渲染并发布到/rviz/scene图像话题;右侧三图由ros2_image_snapshot从相机话题取帧(1280×720)。完整实测记录见docs/test-robot-state-vision.md。
特性一览
- 零侵入诊断:83 个工具覆盖 ROS2 调试的绝大多数场景,从"包装了没有"到"这一帧话题里是什么",一条命令一个结果;
- 全图拓扑:
ros2_graph将节点/发布/订阅/服务/动作折叠为一份 JSON,几秒看清系统结构; - 审批门控的写操作:构建、装依赖、生成消息骨架等写操作通过 DSH 审批服务,fail-closed,拒绝即失败;
- 可视化即服务:无头也能"看"——截图/多模态描述/窗口交互全部本地化,不依赖远程显示;
- 并行实时视觉: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 低模 mesh(scripts/simplify_visual_meshes.py)+ OGRE 直接读像素(跳过 PNG 中转)+ 消除双重渲染 → 动作渲染 1.9 → llvmpipe ~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 / 自建网关)。
安装插件
全部 9 个 npm 包以 0.1.0 发布(GitHub ↔ npm 版本对应关系见 docs/versioning.md)。
方式一:DSH 插件 CLI(推荐;经 npm 解析)
# 全集(聚合包;自动拉取 core/profile/moveit/safety/vision 依赖)
dsh plugin --profile <profile> add dsh-ros2
# 按需瘦身安装——例如只装诊断:
dsh plugin --profile <profile> add dsh-ros2-core
# dsh-ros2-common 为纯库,随依赖自动安装。
方式二:直接 npm 安装(同一批包;也用于安装可选附加包)
# 聚合包(自动拉取 dsh-ros2-common/core/profile/moveit/safety/vision)
npm install dsh-ros2
# 可选附加:sidecar 数据面守护进程 + 控制面状态客户端
npm install dsh-ros2-state dsh-ros2-sidecar
方式三:墙内版(走 npmmirror 镜像,推荐大陆网络环境)
# ① 全局切换镜像源(推荐——DSH 插件 CLI 同样生效,一次配置处处可用):
npm config set registry https://registry.npmmirror.com
# 之后正常执行方式一/方式二的命令即可。
# ② 或单次安装走镜像(不改全局配置):
npm install dsh-ros2 --registry=https://registry.npmmirror.com
npm install dsh-ros2-state dsh-ros2-sidecar --registry=https://registry.npmmirror.com
镜像说明:本项目发布走 npm 官方源;npmmirror 会定期同步,新发布的小版本 可能有几分钟到几十分钟的传播延迟——若镜像上暂缺,可用
--registry=https://registry.npmjs.org直连官方源验证或应急安装。包角色:
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会向 system prompt 注入一段分节,引导模型用本 工具链做 ROS2 相关工作——用ros2_*发现图、用robot_load/robot_topology载入机体、用moveit_*/robot_safety_*规划与执行(均需审批,并以/safety/state为闸门)——而不是临时拼ros2CLI 或私自写rclpy脚本。 因此凡是装了 core 的安装形态都带它(含dsh-ros2聚合包)。该分节在每次组装的当下依据已注册的工具重建,所以只装 core 时不会被引导去调用 它并未随附的
moveit_move/robot_safety_*。它与插件同生命周期注册: 禁用/卸载插件即从提示词中移除,不会留下残留。
最小配置(per-bundle,整体对象替换)
拆分后每个 bundle 携带各自的运行 seam 配置(同样的键按 id 重复),vision
provider 只存在于 dsh-ros2-vision:
# DSH profile 补丁片段(按 id 定向配置覆盖)
- id: dsh-ros2-core # 亦可用:-profile / -moveit / -safety
config:
rosSetup: source /opt/ros/jazzy/setup.bash && # 准备 ROS2 环境
workspaceRoot: /home/you/ros2_ws # colcon/rosdep 的默认工作目录
- 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 只读诊断
| Tool | 底层命令 | 用途 |
|---|---|---|
ros2_pkg_list |
ros2 pkg list |
已安装包(可选子串过滤) |
ros2_pkg_prefix / ros2_pkg_executables |
ros2 pkg prefix <pkg> / ros2 pkg executables [pkg] |
包的安装前缀 / 可执行文件(结构化) |
ros2_colcon_list |
colcon list |
工作区内的包 |
ros2_rosdep_check |
rosdep check --from-paths src --ignore-src |
依赖健康(缺依赖 = finding 而非 error) |
ros2_node_list |
ros2 node list |
运行中的节点 |
ros2_node_info |
ros2 node info <node> [-v] |
单节点订阅/发布/服务/动作 |
ros2_topic_list |
ros2 topic list -t |
话题及类型 |
ros2_topic_find |
ros2 topic find <type> |
携带某消息类型的话题 |
ros2_topic_info |
ros2 topic info <topic> [-v] |
话题元数据 / QoS |
ros2_topic_echo |
ros2 topic echo <topic> --once |
单帧消息(尽量 JSON);--qos-reliability / --qos-durability 透传,可读 TRANSIENT_LOCAL 锁存话题 |
ros2_topic_hz |
ros2 topic hz <topic> [--window N] |
测量话题发布频率(窗口内均值/最小/最大/标准差);自然终止 = 测量超时 |
ros2_env_check |
环境解析探测 | 自检:当前 source 哪个 setup、路径是否存在、可见包/节点数 |
ros2_workspace |
source <ws>/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 <action> |
动作类型与状态 |
ros2_action_type |
ros2 action type <action> |
动作类型 |
ros2_param_list |
ros2 param list <node> |
节点参数 |
ros2_param_get |
ros2 param get <node> <param> |
读取单个参数值 |
ros2_param_dump |
ros2 param dump <node> |
转储节点全部参数 |
ros2_interface_show |
ros2 interface show <type> |
消息/服务/动作完整字段定义 |
ros2_interface_list / ros2_interface_prototype / ros2_interface_package |
`ros2 interface list | prototype |
ros2_graph |
ros2 node list + 逐节点 node info |
折叠式 JSON 拓扑图 |
ros2_topology |
单个 rclpy 进程(不再逐个 CLI 调用) |
一次调用拿到全系统快照:节点及其 pub/sub/服务、带类型的话题与 pub/sub 计数、服务、动作,可选 TF 帧与参数。优先用它替代多次窄查询 |
ros2_tf_list |
同上(同一 rclpy 快照) |
同时采样 /tf 与锁存的 /tf_static,动态与静态帧一并给出 |
ros2_tf_echo |
同上(同一 rclpy 快照) |
两帧间变换,含反向边 |
ros2_doctor |
ros2 doctor |
系统健康报告 |
ros2_bag_info |
ros2 bag info <path> |
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 语义仲裁(方案变更/异常后):固定格式化 prompt + 新鲜离屏帧经 /vlm/describe;非 safe 一律提示人工裁决 |
motion_validate |
motion_validator.py --trajectory <file> --config <json> |
确定性预执行校验(只读):关节限位、NaN/Inf、名字与规划组覆盖、时间戳/时长、新鲜度、可选 workspace box、指纹 + TTL——碰撞/奇异留给 MoveIt 规划 |
L2 管理(审批门控)
每个 L2 工具执行写操作,先经 DSH 审批服务询问用户(无审批服务/被拒 = fail-closed)。只读辅助 ros2_jobs_list / ros2_job_status 无需审批。
| Tool | 底层命令 | 说明 |
|---|---|---|
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 |
写入 <root>/<pkg>/<msg|srv|action>/<Name>.* |
骨架生成器;绝不覆盖已有文件 |
ros2_param_set |
ros2 param set <node> <param> <value> |
JSON 数字/布尔按类型处理,其余按字符串 |
ros2_bag_record |
ros2 bag record <topics...> --output <dir> |
限时录制:duration 秒后自动停止 |
ros2_jobs_list |
ctx.jobs.list |
本智能体的后台任务(只读) |
ros2_job_status |
ctx.jobs.get |
按 id 查任务状态(只读) |
ros2_install |
鱼香ROS一键安装(交互式 PTY 会话) | ROS2 未安装时:check 探测(已装/已装未 source/未装);start(审批)拉起安装器;send/status/stop 驱动与观察交互菜单 |
ros2_bag_play |
ros2 bag play <path> [--topics ...] [--rate X] [--loop] [--start-offset S] |
回放 rosbag 到其话题(审批门控;会发布到图);前台运行 timeoutMs |
ros2_topic_pub |
`ros2 topic pub "" [-r Hz] [-n N | --once |
ros2_run |
ros2 run <pkg> <executable> [args] |
运行任意已安装 ROS2 可执行文件(审批门控):前台(限时)或后台任务 |
ros2_process_cleanup |
pgrep -f '[p]attern' + kill |
清理匹配模式的残留 ROS2 进程(自安全);审批门控 |
ros2_service_call |
ros2 service call <svc> <type> "<yaml>" |
调用服务(审批门控);响应从 repr 解析 |
ros2_action_send_goal |
ros2 action send_goal <action> <type> "<yaml>" [--feedback] |
发送动作目标(审批门控);返回 goal id + 状态 |
ros2_daemon |
`ros2 daemon status | stop |
ros2_param_delete |
ros2 param delete <node> <param> |
删除节点参数(审批门控) |
ros2_lifecycle |
`ros2 lifecycle get | list |
ros2_component |
ros2 component list / load <container> <pkg> <type> |
组件容器 list(L1)/ load(L2 审批) |
ros2_launch |
ros2 launch <pkg> <launch_file> [args] |
以后台任务启动 launch 文件(审批门控;返回 jobId,用 DSH job 控制停止) |
ros2_zero_pose_semantics |
发零位→离屏渲染→VLM→确认 | 交互式校准零位语义(通用):analyze 渲染全零姿态并让 VLM 从三维度描述(臂:侧平举/下垂;肘:向前/向上;手掌/相机支架:上/前/下);confirm 记录使用者确认的组合(或 customText 自定义文字)到 ~/.dsh-ros2/zero-pose.yaml 供 skill 使用 |
robot_register |
采集 URDF/TF/相机/MoveIt/零位语义 → 写入 ~/.dsh-ros2/robots/<name>.yaml |
首次接触时注册机器人本体档案(审批门控),便于后续即时复用 |
robot_load |
读取 ~/.dsh-ros2/robots/<name>.yaml |
加载已注册的机器人档案为结构化 JSON(快速路径——无需重新发现);name 为空列出全部 |
robot_topology |
聚合快照 + 渐进式重要节点学习(严格 schema) | 机器人通信拓扑的取舍:snapshot(审批)记录节点/话题/服务清单(轻量不冗杂);learn(审批)记录单个重要节点的角色/功能 + pub/sub/srv/act;show(只读)读回 |
moveit_move |
统一:/move_action + /execute_trajectory |
一个工具五种本质模式(审批门控):joint_abs、joint_rel、pose_abs、pose_rel(frame ee/world)、trajectory。通用:仅标准 moveit_msgs + SRDF。单一路径:规划 → 确定性校验(motion_validator,robot 档案提供完整限位)→ 人工审批(展示校验摘要)→ 执行 → 验证;执行前查 /safety/state(LOCKED 恒拒;监视器失联按 safetyStrict)。planOnly + trajectoryOut 分离规划/执行 |
robot_safety_start |
ros2 run dsh_ros2_safety safety_monitor --profile <yaml> |
以后台任务启动通用安全监视器(审批门控);本体相关值全部来自档案 safety 段 |
robot_safety_lock / robot_safety_unlock |
`ros2 service call /safety/set_lock | unlock ...` |
moveit_status |
探测 move_group 接口 + 采样 /joint_states |
运行时状态:在线探测 + 当前关节状态 + SRDF 规划帧(只读) |
L3 可视化
GUI 生命周期 + 截图 + 多模态视觉("先能看,再谈动")+ xdotool 级交互("能看也能动")。截图用 Pillow ImageGrab(X11,无需额外 CLI);视觉 provider 可插拔;交互需 xdotool(sudo apt install xdotool)。
| Tool | 用途 |
|---|---|
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 orbit/pan/zoom)、action=key(组合键如 ctrl+shift+r 或输入文本) |
交互配方(模型视角):ros2_gui_interact {action: "drag", windowTitle: "rviz2", button: 1, toX: <dx>, toY: <dy>} 环绕视角、action: "drag", button: 3 缩放、ros2_gui_interact {action: "key", keys: "ctrl+shift+r"} 重载配置。wmctrl 枚举不到窗口(如显示上没有窗口管理器)时窗口相对交互会报"未找到窗口"——退回绝对屏幕坐标。交互属于本地会话操作(无需审批,与其它 L3 工具一致)。
L4 实时视觉(并行 VLM over ROS2,无头图像话题)
感知与机器人控制栈同构:VLM 跑在独立 ROS2 进程(vlm_node,服务 /vlm/describe + 缓存话题 /vlm/description),图像来自 sensor_msgs/Image 话题而非 X11 截图——无头就绪。需要 dsh_ros2_vlm ROS2 包(vlm/);构建/运行见 docs/architecture.md §4。
| Tool | 用途 |
|---|---|
ros2_image_snapshot |
从话题抓一帧存 JPEG——纯 rclpy 脚本,无需自建 ROS2 包;--v4l 经 ffmpeg 兜底抓取静默话题;JPEG 可直接交给 Agent 自身多模态模型 |
ros2_vlm_analyze |
分析图像文件或桥的缓存帧(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}) |
# 构建并启动视觉流水线(每图像话题自动建桥)
# 工作区请建在 /tmp 之外:重启会清空 /tmp,而 `rosSetup` source 一个已删除的
# 工作区正是 docs/feedback-env-recovery.md 记录的那类错误配置。这里用 `~/vlm_ws`。
mkdir -p ~/vlm_ws/src && ln -s <repo>/vlm ~/vlm_ws/src/dsh_ros2_vlm
cd ~/vlm_ws && colcon build --symlink-install && source install/setup.bash
VLM_API_KEY=... ros2 run dsh_ros2_vlm vlm_node & # 并行 VLM 进程
ros2 run dsh_ros2_vlm vision_bringup & # 发现话题,每路一桥
RViz2 离屏渲染(dsh_ros2_rviz_offscreen)
真实 rviz 渲染栈(rviz_common + OGRE + rviz_default_plugins)在 Xvfb(虚拟显示器)下加载 .rviz 场景离屏渲染,把画面发布为 /rviz/scene 图像话题——读取渲染内核而非 X 截图,无窗口层级依赖。
# 构建(需要 vlm_ws 同款工作区——同样别建在 /tmp 里)
ln -s <repo>/offscreen ~/vlm_ws/src/dsh_ros2_rviz_offscreen
cd ~/vlm_ws && colcon build --symlink-install && source install/setup.bash
# 运行(config_path 指向 .rviz 场景文件)
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
机器人本体 mesh 渲染要点(踩坑总结,详见 docs/architecture.md §4.4):
- Jazzy RobotModel 属性:用
Description Source: Topic+Description Topic: <话题>(旧版Robot Description:被忽略 →Links为空); - mesh 路径:URDF 内 mesh 用绝对路径或
file://前缀(裸路径resource_retrieverfopen 失败);发布者须常驻(transient-local,退出后新订阅者收不到); - URDF 与 TF 必须同名绑定:URDF link 名必须与实时 TF 帧名完全一致(发布真机
/robot_description即可)。不匹配时所有 link 变换查找失败,mesh 全部堆到固定坐标系原点; - 视距:Orbit
Distance≈ 1.5–2.0 m 得到 RViz 式近景全身视角(>5 m 时缩成画面中心小点); - 判定信号:节点启动 ~3 s 后日志打印
FM: ... frames=N与transformHasProblems(...)=0,即 mesh 已正确绑定 TF。
MoveIt2 运动——五种本质模式,一个工具
设计意图。机器人经 MoveIt 的运动,本质只有五种操作:关节角绝对设置、关节角相对微调、
末端位姿绝对到达、末端位姿相对增量、执行预规划轨迹。与其让工具随需求不断膨胀,
dsh-ros2 将它们抽象为 一个工具 moveit_move + mode 参数——接口小而可预期、可脚本化,
并且对任意 MoveIt 包通用(读取 SRDF、只讲标准 moveit_msgs)。
| 工具 | 职责 |
|---|---|
moveit_discover(L1) |
读取任意 MoveIt 包的 SRDF:规划组、命名姿态、chain 末端;探测标准接口(/move_action、/execute_trajectory…)在线状态 |
moveit_status(L1) |
运行时探测:接口在线 + 当前 /joint_states 采样 + SRDF 规划帧 |
moveit_move(L2 审批) |
一个工具五种模式:joint_abs(joints "j1:=v1 j2:=v2")、joint_rel(deltaJoints = 当前 + 增量)、pose_abs(pose "x y z rx ry rz" 规划帧)、pose_rel(deltaPose "dx dy dz drx dry drz",frame 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 chain
末端的 EE link、在线状态);moveit_move 把任意模式转成标准 MoveGroup goal
(/move_action),经 /execute_trajectory 执行;配合 planOnly + trajectoryOut
保存规划轨迹,之后用 mode: "trajectory" 单独执行(规划/执行分离)。不绑定任何具体
MoveIt 包——只需 SRDF 路径(包扫描自动解析,或显式 srdf/package)。
安全框架
设计意图。兼顾实时与语义判断的两层策略(完整契约见 docs/safety-handover.md
——本体适配交接文档:通用框架/接口归本仓库,本体数据源/方案/算法归下游):
工具层安全门(执行前:/safety/state 是否 LOCKED;监视器失联按 safetyStrict)
→ 反应式监视(执行中:轨迹跟踪/堵转 + 迟滞、关节反馈丢失、看门狗、可选力矩;控制频率检测,响应 ≤100ms 预算)
→ VLM 语义仲裁(方案变更/异常后,秒级——不必要时不拉起)
→ 人工仲裁(非 safe 一律升级人工;人工门解锁)
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 <key> <json>可改任意阈值/话题/名单 (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 仲裁, 非 safe 一律提示人工裁决。 - 取证:关节/力矩环形缓冲在每次 CRITICAL 锁死时落盘到
forensics.dump_dir, 供事后 / VLM 诊断。
# 构建 safety 包(与 vlm/、offscreen/ 同一 colcon 工作区)
ln -s <repo>/safety ~/vlm_ws/src/dsh_ros2_safety
cd ~/vlm_ws && colcon build --symlink-install && source install/setup.bash
safety_core 纯逻辑自带故障注入自测(python3 packages/safety/safety/scripts/safety_core.py --selftest,12 个场景)——无需 ROS2 即可验证状态机。
机器人注册与通信拓扑维护
设计意图。机器人的本体(URDF link/joint、相机、MoveIt 组、零位语义)与通信拓扑,
每次重新发现成本很高。插件将它们固化为结构化档案
(~/.dsh-ros2/robots/<name>.yaml):首次接触注册一次,之后即时读取。对通信图,
全量逐节点深挖在复杂机器人(成百上千话题/服务)下不可扩展,因此设计取折中:
聚合层快照(轻量的节点/话题/服务清单)+ 使用中渐进学习(只记录真正重要的节点)。
| 工具 | 职责 |
|---|---|
robot_register(L2) |
采集本体信息(URDF link/joint、TF 根、相机、MoveIt SRDF 组、自动联动零位语义校准与通用 safety 段——URDF 派生限位)写入档案;随后自动拉起 safety_monitor(startSafety: false 可关) |
robot_load(L1) |
按名加载档案为结构化 JSON——快速路径,无需重新发现;name 为空列出全部 |
robot_topology(L1/L2) |
通信拓扑:snapshot(L2,聚合清单)、learn(L2,单个重要节点的角色/描述 + pub/sub/srv/act,严格 schema)、show(L1,读回)、diagnose(L1——知识增强诊断:知识库 + 快照 × 实时图交叉比对:missing / new / drift / topic_drift)、search(L1——知识库高效检索:按 topic 反查 / 按 name/role/description/连接关键字匹配) |
ros2_zero_pose_semantics(L2) |
经"渲染 + VLM + 使用者确认"校准零位(臂/肘/手掌组合或自定义文字);档案自动纳入 |
配套两个内置 skill 完成闭环:robot-registration(首接触流程:问名称/URDF →
采集 → 注册 → 校验,并建立拓扑基线快照)与 robot-retrieval(即时加载档案,
据此拉起渲染/诊断/运动——含已学习的拓扑与零位语义)。
实现方式。全部为 ~/.dsh-ros2/ 下的结构化 YAML:robots/<name>.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:在线但未入知识库的节点(learn 候选);matched[].drift:每个已学节点的期望 pub/sub/srv/act vs 实时(缺话题 = 连接 消失;多话题 = 节点已变化);topic_drift:聚合快照话题 vs 实时话题。
ros2-diagnostics 与 robot-retrieval 两个 skill 都以 diagnose 开始诊断,
并用 learn 记录重要的 new 节点收尾——知识库每次会话都在变好,诊断一次比一次快。
内置技能
| Skill | 内容 |
|---|---|
ros2-diagnostics |
何时用哪个工具、如何由宽到窄定位、排查"话题无数据"/消息格式不匹配/TF 问题的方法论 |
ros2-bringup-recovery |
旅程"起不来":ros2_env_check → ros2_workspace use(会话内切换,不重启)→ 启动 → 作业跟踪 → doctor 验证 |
ros2-liveness-triage |
旅程"还活着吗 / 为什么没数据":ros2_topology {rates} → ros2_topic_sample → 读发布者数量/速率/QoS,并说明造成误报的超时语义 |
ros2-tf-integrity |
旅程"TF 树对不对":帧与图并列、/tf 与 latch 的 /tf_static 边、反向边查表、把缺失的边定位到广播者 |
robot-state-vision-analysis |
完整流水线:状态读取 → 离屏渲染 → 传 VLM → 交叉验证(含 Jazzy Description Source/Topic、URDF↔TF 帧名一致、file:// mesh、视距、FM frames 信号、校准后的零位语义) |
robot-registration |
首接触流程:问名称/URDF → 采集本体 + 零位语义校准 → robot_register → 拓扑基线快照 |
robot-retrieval |
即时加载档案(robot_load)并拉起渲染/诊断/运动;读取并渐进学习通信拓扑(robot_topology) |
robot-motion-control |
旅程"能不能动 / 怎么动":moveit_status → 发现规划组 → planOnly → motion_validate → 唯一的审批与 /safety/state 门控执行路径 → pass/fail 验证 |
robot-safety-procedure |
旅程"安全吗":先读 robot_safety_state,LOCKED 即停止信号,VLM 仲裁(uncertain ≠ safe),六层防御与明确的边界声明 |
配置
| Key | 类型 | 默认 | 含义 |
|---|---|---|---|
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 key(用户提供;永不记录日志) |
vision.model |
string | '' |
模型覆盖(如 gemini-2.5-flash、gpt-4o-mini) |
vision.baseUrl |
string | '' |
API base URL 覆盖(OpenAI 兼容端点) |
rosLogDir同样覆盖工具拉起的 ROS2 Python CLI(topic echo/pub、ros2 run);此外runCommand在~/.ros/log不可写时自动回退到可写目录。
项目结构
dsh-ros2/ # pnpm monorepo(工作区根,private)
├── pnpm-workspace.yaml # packages/*
├── tsconfig.base.json
├── packages/
│ ├── common/ # dsh-ros2-common(非 bundle):runner / parse / toolkit + scripts/robot_profile.py(零复制)
│ ├── core/ # dsh-ros2-core(59 工具):L1 诊断 + L2 管理 + L3 GUI + ros2-diagnostics skill + gui.ts + pty_session.py
│ ├── profile/ # dsh-ros2-profile(4 工具):robot_register/load/topology + 零位校准 + registration/retrieval skills
│ ├── moveit/ # dsh-ros2-moveit(4 工具):discover/status/motion_validate/moveit_move + moveit_*.py + motion_validator.py
│ ├── safety/ # dsh-ros2-safety(5 工具):robot_safety_* + safety/ ROS2 包 + safetyStrict 配置
│ ├── vision/ # dsh-ros2-vision(7 工具):视觉工具 + vlm/ + offscreen/ ROS2 包 + vision provider 服务 + state-vision skill
│ └── 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 · versioning.md
├── .github/workflows/ # CI:Node 22/24 → 工作区 typecheck/test/build + 每包 tarball 校验
└── CHANGELOG.md # 版本变更记录(Keep a Changelog)
插件拆分(9 个包)
自 v0.15.0 起插件为 pnpm monorepo,含 9 个 npm 包(见
docs/plugin-split-plan.md,ISP 收紧版):83 工具 +
9 skills(原有 4 个 skill 的名称与行为不变)。按需安装域包(或安装 dsh-ros2 聚合包获得全集):
dsh-ros2-common为纯库(非 cordis bundle)——共享 runner/解析/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。
故障排查 / FAQ
~/.ros/logPermission denied:ROS2 写日志目录失败。设rosLogDir(如/tmp/ros-log)即可;runCommand也会自动回退。- stderr 里一堆
RTPS_TRANSPORT_SHM/ FastDDS SHM 警告:SHM 传输不可用(常见于容器/受限环境)的无害噪音,工具默认丢弃。 ros2 topic echo返回空:先ros2_topic_info -v看 publisher 数与 QoS;transient-local 话题用--qos-durability transient_local采样。- RViz2 离屏渲染"零件全部堆在原点":URDF link 名与 TF 帧名不一致(详见上文 mesh 渲染要点 3);先看节点日志
FM transformHasProblems(<link>)=1定位。 - RobotModel 没有 mesh(
Links空):Jazzy 必须用Description Source/Topic,旧Robot Description:无效。 Could not load resource ... Unable to open file:mesh 路径需绝对路径或file://前缀。- 发布者退出后收不到描述:URDF 发布者须常驻(transient-local 只对后订阅者补发一次,进程退出即失效)。
vision_bringup曾漏发现部分图像话题(实测 2/4 路):已修复——现在每--refresh秒(默认 10)刷新发现,后续出现的话题自动补桥、消失的话题自动停桥。
开发
安装需 pnpm 11.x(仓库固定 packageManager: pnpm@11.22.0;CI 通过 pnpm/action-setup@v6 安装匹配版本)。
Node 需 ^22.19 || >=24。
pnpm install
pnpm run typecheck # tsc --noEmit
pnpm run test # vitest(304 例;另有 10 个 sidecar Python 场景 + 6 个 zero-pose 自检 + 29 项档案名/路径/TF 解析自检)
pnpm run build # tsc -> lib/ + lib/types/
CI(.github/workflows/ci.yml):push 到 main / PR 时在 Node 22 与 24 上跑 typecheck/test/build,并校验 pnpm pack 产物包含补丁层(cordis.patch.yml)与构建产物。
发布流程(npm 与 GitHub Release)见 PUBLISH.md。
路线图
-
vision_bringup轮询/刷新发现(晚出现话题自动补桥、消失自动停桥); - 零位语义:通用校准流程(
ros2_zero_pose_semantics,渲染 + VLM + 使用者确认,三维组合)并联动进机器人档案; - 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 |
安全边界:六层(agent 权限 / 人工审批 / 运动校验 / 执行监视 / 事后验证 / 物理机器人安全)、fail-closed 与降级策略、"DSH 非功能安全系统"声明 |
docs/safety-handover.md |
本体适配交接:通用框架/接口 vs 本体数据源/算法、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 社区 — 渲染与工具链基础。
License
链接
同类插件
Tencent/WeKnora#dsh-weknora★ 32045
把 WeKnora 知识库接入 dsh 的四个只读工具:列出知识库、混合检索原文片段、按顺序还原单篇文档,以及直接取用 WeKnora 自己带引用的 RAG 或 ReAct agent 回答(含可续聊的 session id)。
superdesigndev/treg★ 4145
给 Agent 的工具目录:按「要做的事」检索约 2,600 个外部接口(SEO 与 SERP、外链、社交、人物与公司信息补全、广告库、抓取),查看参数与单次调用价格后直接调用,凭据由服务端注入。附带技能,MCP 行在未设置 TREG_TOKEN 前保持禁用。
TencentCloudBase/CloudBase-AI-Toolkit#dsh-plugin★ 1131
把腾讯云 CloudBase 后端接入 DeepSeek Harness——在对话里搭好并部署全栈应用,查询结果渲染为表格卡片(分页、排序、导出 CSV),部署后可预览真实域名,并提供 CloudBase MCP 工具集(`mcp__cloudbase__*`),登录走 device-code 流程。
gitroomhq/postiz-agent#dsh-postiz★ 501
通过 MCP 将 DeepSeek Harness 连接到 Postiz:列出已连接的社交媒体渠道、获取各平台发帖规则,并向 X、LinkedIn、Instagram、Facebook、Threads、TikTok、YouTube、Reddit、Bluesky、Mastodon、Discord、Slack、Telegram 等平台排期、存草稿或发布帖子;附带 postiz 工作流技能。
EthanYoQ/Invoice-Downloader#dsh-invoice-downloader★ 489
面向 DeepSeek Harness 的本地 IMAP 发票下载、OCR 识别、归档与 Excel 报销汇总。
anysearch-team/anysearch-dsh★ 446
基于 AnySearch 的实时网页与垂直搜索插件,为 DeepSeek Harness 提供搜索工具。




社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。