Dexmate Vega-1U · CMU · 内部

Vega-1U 操作手册

Part A 是日常操作;Part B 是新机器人的必读信息与必要设置;Part C 是进阶信息及硬件参考。

机器人名称
dm/vg3eb20f25bb-1u用斜杠,不是短横线
型号
Vega-1U上半身 · 17 自由度 · 不发布躯干/底盘
固件
0.5.0机械臂 1248 · SoC 1263
机载计算机
Jetson Orin NanoL4T 36.5.0 · 内核 5.15.185
WiFi
172.26.161.243CMU-DEVICE · DHCP,地址可能变化
有线网络
192.168.50.20enP8p1s0 · SoC 地址尾号 .21

A 部分

每次使用

机器人已配置并运行。以下是日常使用所需的操作。

A1

当前连接方式

当前配置

这台机器人已经完成配置。不需要重复 B 部分——证书已安装、库已就位,Jetson 开机后会自动连接 CMU-DEVICE 。正常使用流程:SSH 登录,在机载计算机上运行脚本。

项目值说明
连接机器人ssh dexmate@172.26.161.243密码 hello-dex (出厂默认值)。也已配置密钥,因此可能不会提示输入密码。
代码运行位置机载计算机上的 ~/py_scripts/延迟最低,所需软件也已安装
机器人名称dm/vg3eb20f25bb-1u必须显式传入——见下文
有线备用连接192.168.50.20连接 IO hub;电脑使用 192.168.50.x (不要使用 .20/.21)
SoC 管理页面https://192.168.50.21:57832需要 sshuttle 才能从机器人外部访问;仅用于证书和固件

何时必须显式设置 ROBOT_NAME

Dexmate 在 Jetson 上预设了 ROBOT_NAME ,因此进入交互式 shell 后它就已存在——用 echo $ROBOT_NAME 确认,运行脚本无需前缀。只有一种情况必须加前缀:命令没有经过交互式 shell,因为不会加载 ~/.bashrc ,此时 Robot() 会抛出 ValueError.

运行方式ROBOT_NAME是否需要前缀?
ssh 登录后再运行命令已经设置否
ssh dexmate@… 'python3 script.py'未设置是
cron、systemd 服务、单行命令中的 nohup 未设置是
终端 · 从自己的电脑执行单条远程命令
ssh dexmate@172.26.161.243 \
  'ROBOT_NAME="dm/vg3eb20f25bb-1u" python3 ~/py_scripts/inspect_joints.py'

一次完整的使用流程

终端 · 自己的电脑 → Jetson
ssh dexmate@172.26.161.243

# is the robot healthy and talking?
dextop topic list --timeout 10
dextop doctor check

# where are the joints right now? (before commanding any motion)
python3 ~/py_scripts/inspect_joints.py

以上就是全部必需步骤。下面按任务选择——只启用即将使用的子系统。

可选 · 检查相机就绪状态 · Jetson
systemctl status dexsensor wrist-camera-init.service --no-pager
cat /run/wrist-cameras/ready.json

本机的头部相机服务已经运行。通过 A2订阅;腕部 API 按需启动采集。接线和启动配置见 B8.

可选 · 夹爪
sudo modprobe gs_usb                                    # asks for hello-dex
sudo ip link set can1 up type can bitrate 1000000 \
     loopback off listen-only off                       # ip is NOPASSWD
可选 · 机械臂运动
cd ~/py_scripts && python3 goto_ready.py --dry-run

相机(A2)、夹爪(A5)和机械臂运动(A4)相互独立。机械臂始终使用命名位姿,不要使用 pose_pool 条目。

构造 Robot() 会移动头部

每次 Robot() 都会把头部移动到 home,而且没有参数可以阻止——因此 inspect_joints.py 及任何创建会话的脚本都会移动头部。如果只需要图像,请使用 ~/py_scripts/sensor_only.py,它直接构造 Sensors() ,完全不发布控制话题。详见 A2.

sudo 大多需要输入密码

只有三类操作在以下配置中免密: sudoers: /usr/sbin/ip, tee 到指定 USB authorized 路径的操作,以及 systemctl {stop,restart,start} dexsensor.service。其他操作—— modprobe、编辑 dexsensor toml——都需要在交互式提示中输入 hello-dex ,因此无法通过非交互式 SSH 执行。

IP 地址变化时

172.26.161.243 是以下网络上的 DHCP 租约: CMU-DEVICE 和 迟早会变化。SSH 无响应时,按从易到难的顺序尝试:

  1. 扫描子网: nmap -sn 172.26.160.0/22 | grep -B2 -A2 "vega\|dexmate\|ubuntu"
  2. 接网线,使用固定有线地址 192.168.50.20,它不会变化。
  3. 将显示器和键盘接到 IO hub,从桌面查看地址。
哪些内容保持 不 变

IP 变化不代表需要重新配置。证书、机器人名称、固件和库都保存在机器人上,不受地址变化影响——只需更新 ROBOT_IP (如果导出了该变量)以及 SSH 连接目标。

改用工作站运行

目前所有代码都在机载计算机运行。也可以从自己的电脑控制机器人,但需要单独完成一次配置—— dextop、在本地解压同一份证书,并设置环境变量——详见 B5。这样能使用更好的 GPU,代价是增加网络延迟。

A2

读取传感器数据

头部相机由现有的 dexsensor 服务发布。两路原装腕部相机使用本地 WristCameras Python API,可以同时读取。下面的纯传感器示例不构造 Robot(),避免触发头部归位。配置见: B8.

关节、电流、力矩、按钮——不需要 dexsensor

Python
from dexcontrol.robot import Robot

robot = Robot()

robot.left_arm.get_joint_pos()      # joint positions
robot.left_arm.get_joint_vel()      # joint velocities
robot.right_arm.get_joint_current() # current — arms only
robot.left_arm.wrench_sensor.get_wrench_state()   # [fx,fy,fz,tx,ty,tz]
robot.right_arm.wrench_sensor.get_button_state()  # blue / green wrist buttons

robot.shutdown()

头部相机:订阅正在运行的服务

在 Jetson 上以 dexmate 身份使用已安装的系统 Python 运行。在非交互式 shell 中显式设置机器人名称。当 dexsensor 占用相机时,不要启动第二个头部服务或打开另一个 ZED SDK 相机。

Bash · Jetson
export ROBOT_NAME=dm/vg3eb20f25bb-1u
Python · 仅头部相机 · 无运动
from dexcontrol.core.config import get_robot_config
from dexcontrol.sensors.manager import Sensors

configs = get_robot_config()
configs.sensors["head_camera"].enabled = True
sensors = Sensors({"head_camera": configs.sensors["head_camera"]})
try:
    sensors.wait_for_all_active(timeout=10)
    head = sensors.head_camera.get_obs(
        obs_keys=["left_rgb", "right_rgb", "depth"],
        include_timestamp=True,
    )
    if any(head[k] is None for k in ("left_rgb", "right_rgb", "depth")):
        raise RuntimeError("Head streams are not ready")
    rgb = head["left_rgb"]["data"]
    print(rgb.shape, head["left_rgb"]["timestamp_ns"])
    print(sensors.head_camera.get_camera_info())
finally:
    sensors.shutdown()

设置 include_timestamp=True时,每个流返回的记录包含 data, timestamp_ns 和 receive_time_ns;就绪前可能返回 None 。使用默认值 include_timestamp=False时,每项直接返回数组。左右 RGB 为 (1200, 1920, 3);深度为以米为单位的 (1200, 1920) 浮点数组。

本机已验证 · 三种静默失败

字段名是 enabled,不是 enable. 。写错不会报错,只会不起作用。而且 configs.sensors 是普通字典,因此 wiki 中的属性式示例(configs.sensors.head_camera.enable)不适用于当前版本。客户端启用设置仅对当前脚本生效,不会持久保存。

深度需要打开两个开关。 在 /etc/dexmate/dexsensor/default.toml, depth_mode = "NEURAL" 只规定深度 应当 如何计算; [sensors.streams] depth 决定是否发布。关闭流时,dexsensor 向 SDK 传入 DEPTH_MODE::NONE ——因此日志显示 NONE,而配置看起来是 NEURAL。还要设置 enabled = true ,否则服务不会启动任何传感器; dexsensor enable <x> 只在运行时生效,重启后丢失。这些修改已备份到 default.toml.bak ——升级 .deb 可能覆盖它们。

头部相机输出 RGB,不是 BGR,这与 ZED 通常的约定不同。 cv2.imwrite 和 cv2.VideoWriter 都需要 BGR,因此图像需要经过 cv2.COLOR_RGB2BGR ,否则红蓝会互换(棕色桌子变成蓝色)。PIL 默认按 RGB 解释,无需转换。

头部相机分辨率与内参

当前头部配置: HD1200、1920×1200、配置帧率 30 fps、NEURAL 深度。在 /etc/dexmate/dexsensor/default.toml中找到 id = "head_camera"对应的传感器,再查看其参数和流开关。不要按行号修改。通用的 ZED X One 腕部条目必须保持禁用:它们并不描述这些 ISX031 相机。实测吞吐率见 B8.

Bash · 仅在修改头部配置时执行
sudo cp -a /etc/dexmate/dexsensor/default.toml /etc/dexmate/dexsensor/default.toml.camera-$(date +%Y%m%d-%H%M%S).bak
sudoedit /etc/dexmate/dexsensor/default.toml
# After saving the intended head settings (interrupts head streaming):
sudo systemctl restart dexsensor.service

修改配置需要管理员权限。正常读取头部和腕部 API 不需要 sudo.

HD1200 下运行时的校正内参,来自 head_camera.get_camera_info() — distortion 为空,因为流已经过校正:

YAML
image_width: 1920
image_height: 1200
K: [734.7626953125, 0.0, 966.6296997070312,
    0.0, 734.7626953125, 653.073486328125,
    0.0, 0.0, 1.0]
# example from 2026-09-15 · query runtime for current calibration
# distortion [] · baseline ~0.0497 m · serial 53756133 · ZedXMini
API 返回 RGB,不是 BGR

cv2.imwrite 和 cv2.VideoWriter 需要 BGR,因此请使用 cv2.COLOR_RGB2BGR 转换,否则红蓝会互换——木桌变蓝就是明显信号。PIL 按 RGB 解释,无需转换。

双腕:本地 Python API

在 Jetson 上使用 /usr/bin/python3 ,以 dexmate 身份运行(已经属于 video 和 i2c 组)。仅读取腕部不需要 sudo ,也不需要 ROBOT_NAME。代码安装在 /opt/wrist-cameras/ ,通过系统 Python 3.10 dist-packages 目录中的 wrist_cameras_local.pth 暴露。单独的虚拟环境可能找不到这个模块或 GStreamer 绑定。

Python · 双腕
from wrist_cameras import WristCameras

with WristCameras() as cameras:
    for _ in range(30):
        obs = cameras.get_obs(timeout=3)
        rgb_a = obs["wrist_a"]["rgb"]
        rgb_b = obs["wrist_b"]["rgb"]
        print(rgb_a.shape, rgb_b.shape,
              obs["wrist_a"]["frame_id"], obs["wrist_b"]["frame_id"])
# Context exit stops capture/trigger and releases both devices.
字段/方法约定
obs["wrist_a"], obs["wrist_b"]A/B 标识相机链路;尚未确认实际左/右对应关系。
rgb独立的 numpy.uint8 RGB 副本,形状为 (1536, 1920, 3).
frame_id当前打开会话内递增的帧计数。
timestamp_nsGStreamer 管线显示时间戳(PTS), 不是 Unix 时间.
received_monotonic_ns本机 Jetson 单调时钟记录的接收时间。
get_obs(timeout=2.0, fresh=True)等待两路相机均比上次调用更新;否则抛出 TimeoutError 。 fresh=False 允许返回当前最新的一对图像。

API 按传感器名称发现 V4L2 设备,在一个锁下占用双腕,并在独立进程中运行软件触发。第二个读取进程会被拒绝,并抛出 RuntimeError。重启初始化前务必关闭上下文。这是本地 API,不是网络端点;它没有注册为 robot.sensors.left_wrist_camera 或 right_wrist_camera.

在一个进程中读取头部和双腕

按上文设置 ROBOT_NAME ,在 Jetson 上保存为 Python 脚本,然后使用 /usr/bin/python3运行。腕部上下文获取两路相机时,现有的头部发布服务继续运行。

Python · 头部双目+深度+双腕 · 无运动
from dexcontrol.core.config import get_robot_config
from dexcontrol.sensors.manager import Sensors
from wrist_cameras import WristCameras

configs = get_robot_config()
configs.sensors["head_camera"].enabled = True
sensors = Sensors({"head_camera": configs.sensors["head_camera"]})
try:
    sensors.wait_for_all_active(timeout=10)
    with WristCameras() as wrists:
        for _ in range(30):
            wrist = wrists.get_obs(timeout=3, fresh=True)
            head = sensors.head_camera.get_obs(
                obs_keys=["left_rgb", "right_rgb", "depth"],
                include_timestamp=True,
            )
            if any(head[k] is None for k in ("left_rgb", "right_rgb", "depth")):
                raise RuntimeError("Head streams are not ready")
            head_left = head["left_rgb"]["data"]
            head_right = head["right_rgb"]["data"]
            depth = head["depth"]["data"]
            wrist_a = wrist["wrist_a"]["rgb"]
            wrist_b = wrist["wrist_b"]["rgb"]
            print(head_left.shape, wrist_a.shape, wrist_b.shape)
finally:
    sensors.shutdown()
并发不等于同步

头部调用返回最新发布的数据,可能重复同一帧;用其 timestamp_ns 检测重复。腕部新鲜度单独检查。尚未验证硬件曝光同步。头部时间戳和腕部管线 PTS 使用不同时间基准,不能相减来推断对齐关系。

使用 OpenCV 保存 RGB 图像前,先转换:

Python · 在采集循环中
import cv2
if not cv2.imwrite("wrist_a.png", cv2.cvtColor(wrist_a, cv2.COLOR_RGB2BGR)):
    raise RuntimeError("Could not save wrist_a.png")

已测试的四视角录像工具安装在 /home/dexmate/wrist-camera-debug/coexistence/record_api_demo.py。它通过上述 API 订阅,等待操作员 15 秒后开始录像;不发送运动命令。先关闭其他腕部读取进程。

Bash · Jetson · 录制新的 45 秒演示
ROBOT_NAME=dm/vg3eb20f25bb-1u /usr/bin/python3   /home/dexmate/wrist-camera-debug/coexistence/record_api_demo.py   --seconds 45 --output "$HOME/wrist-camera-debug/coexistence/demo-$(date +%Y%m%d-%H%M%S)"

新输出目录包含 preview.avi 和 recording.json。AVI 写入器固定为 6 fps;测量时间应使用 JSON 中的实际采集时长和帧时间戳。预览编码速度不代表相机原生帧率。

其他传感器/自定义 dexsensor 配置

这是 dexsensor 支持传感器的通用参考,不是 ISX031 腕部相机配置步骤。启动自定义发布器前,先停止占用同一相机的已有发布器。本机正常读取头部相机时使用上述运行中的服务。

终端 · Jetson
dexsensor gen-cfg                                       # writes to ~/.dexmate/sensors/
dexsensor launch --config ~/.dexmate/sensors/default_config.yaml

除了各传感器的 enabled 开关,配置文件还可调整分辨率、帧率、深度范围、传输方式(rtc 或 zenoh)以及 JPEG 质量,以便在图像质量和带宽之间取舍。

A3

控制机器人

开始运动前

手放在急停按钮旁。机械臂和躯干采用位置控制,轮子采用速度控制,而 终止程序会停止运动 ——这是最快的软件制动方式。

头部——3 自由度,但顺序为俯仰/偏航/俯仰

轴顺序不是 pan-tilt-roll

已通过 URDF 正运动学验证: head_j1 是 俯仰, head_j2 是 偏航, head_j3 是 第二个俯仰轴。负的 head_j3 表示向下看——厂商自己的 tucked 位姿为 [0, 0, -1.37],遵循相同约定。 fy = 734.72 px/rad 也可用作俯仰角到像素的比例,因此俯仰误差 Δθ 会让图像移动 734.72·Δθ 像素。

Robot() 总会驱动头部归位——无法关闭

Robot.__init__ 只接受 (configs, auto_shutdown). _safe_initialize_components 运行硬编码步骤列表,最后执行 ("default state", self._set_default_state) (robot.py:353),而 _set_default_state (robot.py:424)会无条件调用 head.set_joint_pos(home_pos) ,除非软件急停已激活。 没有参数、配置项或环境变量能跳过它。 构造完成后,在同一会话中重新设置所需头部位姿。

头部位姿也 不会在进程退出后保持:只在会话存续期间保持(实测 25 秒内零漂移),之后从 -0.5056 松弛到约 -0.13 rad。依赖头部角度的程序必须自己保持一个活动的 Robot() 会话。

Python
import numpy as np
from dexcontrol.robot import Robot

robot = Robot()
robot.head.set_joint_pos(np.array([-np.pi/6, 0.0, 0.0]), wait_time=2.0)
robot.shutdown()

机械臂——7 自由度,关节空间控制

Python
current = robot.left_arm.get_joint_pos()
robot.left_arm.set_joint_pos(current, wait_time=1.0)          # absolute

delta = np.zeros(7); delta[-1] += 0.2
robot.left_arm.set_joint_pos(delta, relative=True, wait_time=4.0)  # relative
wait_time=0 的含义

设置 wait_time=0 即进入实时控制:此后必须持续调用 set_joint_pos ,频率为 100–500 Hz。调用频率过低会导致电机响应不足。

手、躯干、底盘

Python
robot.right_hand.close_hand()

# torso — not present on this robot; Vega-1 / Pro only
robot.torso.set_joint_target(target, tracked=True)   # dexcontrol == 0.5.0
robot.torso.set_joint_pos_vel(target, joint_vel=np.ones(3)*0.1, wait_time=3.0)  # < 0.5
robot.torso.stop()

# chassis — not present on this robot
robot.chassis.move_straight(speed=0.4, wait_time=2.0)
robot.chassis.move_sideways(speed=0.4, wait_time=2.0)
robot.chassis.turn(angular_speed=0.4, wait_time=2.0, center='base_center')
robot.chassis.stop()
底层底盘 API 会损坏电机

set_velocity, set_motion_state, set_steering_angle 和 set_wheel_velocity 可能 永久损坏轮毂电机:在转向角让轮子彼此相向时命令前进、轮速与当前转向冲突,或同时快速改变两者。请使用 move_straight / move_sideways / turn.

软件急停

Python
robot.estop.activate()
robot.estop.deactivate()

它补充实体急停按钮的功能,不能替代实体按钮。

A4

安全地切换位姿

本机

两个命名位姿、两个脚本。要记住:碰撞风险在于 运动顺序,而不在目标位姿。

机器人加载的 URDF 不包含夹爪

两个 CAN 夹爪远远伸出 L_ee / R_ee 和 未被建模在 vega_1u.urdf ——dexcontrol 和 pinocchio 实际加载的文件。基于这个模型的任何检查都看不到夹爪,因此厂商的 folded 位姿通过了所有检查,却仍在 2026-09-07 让两夹爪交叉,割断了左夹爪的 CAN 线。

解决办法是: vega_1u_gripper.urdf (位于 ~/Downloads/Dexmate/,也包含在 dexmate_urdf 软件包中) 确实 建模了夹爪,包含 L_gripper_joint / R_gripper_joint 以及伸出腕部约 0.198 m 的真实夹爪网格。碰撞检查应使用这个文件,而不是普通版本,这样才能计算下面的数值。

真实夹爪间隙——实测,不靠假设

带夹爪的 URDF 位于 ~/Downloads/Dexmate/vega_1u_gripper.urdf ,包含夹爪模型,因此可以正确计算间隙:在 25 步关节空间插值沿途,计算左右夹爪碰撞网格之间的最近点距离。

pre_move, manip_init and folded rendered with grippers, in front and top views, each annotated with the closest jaw-to-jaw distance
含夹爪的正视图和俯视图。 pre_move 和 manip_init 以夹爪闭合状态绘制; folded 以夹爪张开状态绘制,计算结果为两个夹爪相接触。
运动过程中的最小夹爪间距同时运动左臂先动右臂先动
pre_move → manip_init0.259 m0.330 m0.367 m
manip_init → pre_move0.259 m0.367 m0.330 m
pre_move → folded0.052 m0.052 m0.052 m

顺序运动在工作位姿切换中多提供 7–11 cm 的间隙,因此 goto_ready.py 和 goto_rest.py 采用相反的先动机械臂。顺序运动的额外收益为 零 在 folded三种顺序都降到约 5 cm,因为碰撞发生在 目标位姿本身,而不是路径上。

位姿终点的间隙夹爪闭合夹爪完全张开
pre_move0.367 m0.298 m
manip_init0.436 m0.333 m
folded0.050 m0.000 m——接触
禁用 folded 现在有了计算依据,而非主观判断

夹爪张开时, folded 会让两个夹爪 接触——0.000 m。而且这还是使用 Dexmate 自己的 夹爪模型计算的;实际安装的第三方 CAN 夹爪更大,因此真实干涉比图中更严重。这直接解释了 2026-09-07 断线的原因。

两个位姿

名称左臂右臂
pre_move
停放/休息
[1.7289, 0.0101, 0.0041, -0.9924, -0.2311, 0.5011, -0.0066][-1.5683, -0.0026, 0.0031, -0.9916, 0.0908, -0.4138, -0.0018]
manip_init
别名 brickbench_home
[0, 1.2, 1.4, -1.57, -1.57, 1, -0.35][0, -1.2, -1.4, -1.57, 1.57, -1, 0.35]

pre_move 记录自机器人自身的休息位置,因此它是经实际验证可安全停放的位姿。 manip_init 是 BrickBench 23 维 Joint_Home_Position中的机械臂部分;腕部最终相距 0.656 m,约与肩部等高。

Bash
cd ~/py_scripts && export ROBOT_NAME="dm/vg3eb20f25bb-1u"

python3 goto_ready.py            # pre_move  -> manip_init, right arm first
python3 goto_rest.py             # manip_init -> pre_move,  left arm first
python3 goto_ready.py --dry-run  # plan + limit check + clearance, no motion

所有参数都可覆盖脚本默认值,例如使用 --step 0.02 --wait 1.0 降低速度,因为 goto_pose 采用第一次出现的参数,而用户参数排在前面。

pre_move and manip_init rendered from vega_1u.urdf in front, side and top orthographic views, with wrist separation annotated
两个位姿通过 vega_1u.urdf 的碰撞网格和正运动学渲染。左臂为青色,右臂为铁锈色;虚线表示腕间距。URDF 未包含夹爪,因此真实夹爪间隙小于图中值——这正是 folded 通过碰撞检查却仍损坏线缆的原因。

为什么机械臂要逐一运动

不同运动顺序下的路径最小腕间距:

方向同时运动左臂先动右臂先动
pre_move → manip_init0.354 m0.431 m0.459 m
manip_init → pre_move0.267 m0.459 m0.434 m
两个方向的起点和终点都安全

同时运动会使腕部在路径中途交错。双臂同时回到 pre_move 时,间距会降到 0.267 m ——比曾导致断线的 0.31 m 更小。逐臂运动仅使总时间翻倍,所以任何大幅双臂转移都应 默认采用 --seq 。

间隙保护

goto_pose.py 模拟实际运动经过的全部路点——采用实际循环相同的逐关节限幅和左右臂顺序——以 URDF 正运动学计算各点腕间距,并抛出 SystemExit ,如果任一路点低于 MIN_WRIST_SEP (0.35 m,可通过 --min-sep覆盖)。以下标定点均来自实际结果:

位姿/路径间距结果
folded0.31 m夹爪交叉, 导致断线
manip_init → pre_move,同时运动0.267 m走过一次,无接触
pre_move ↔ manip_init,同时运动0.364 m走过两次,无接触
pre_move 终点0.44 m正常
manip_init 终点0.66 m正常
这是粗筛,不是间隙证明

注意 0.267 m 那一行: 低于 曾导致损坏的数值,却没有接触。 腕部中心距离忽略了朝向 — folded 将两侧前臂收向内侧,使夹爪彼此相对,比单看距离更加危险。应重新测量,不要降低阈值。

folded 已禁用

folded 和 folded_closed_hand 来自机械臂 pose_pool ,被列入 goto_pose.py的 BANNED 集合,拒绝执行。这些位姿是针对 Dexmate 自有末端执行器设计的。不要把它们当作“安全收纳”—— pre_move 才是本机的收纳位姿。 重力力矩也不能作为判据: zero 静态力矩最低(4.88 N·m),因为双臂垂直向上,但这是不稳定平衡,且可能下落的距离最大。

收尾

Bash
cd ~/py_scripts && export ROBOT_NAME="dm/vg3eb20f25bb-1u"
python3 goto_rest.py
python3 -c "import gripper; g=gripper.Grippers(); g.release(); g.close_bus()"

让机械臂保持通电,停在 pre_move. 。它们会自行保持位置;断电后则会下垂。两次使用之间保持 can1 运行是可以的。

A5

控制夹爪

本机

夹爪 不 属于 dexcontrol——机器人报告的手类型为 UNKNOWN,因此 robot.left_hand 不起作用。它们是共享 CAN 总线的两台 MG4005-i10 V3 伺服电机,由 /home/dexmate/gripper.py封装,与普通机械臂控制并行使用。接线、总线速率和协议考证见 C3;本节介绍库的使用方式。

当前状态——左夹爪不在总线上

自 2026-09-07 起,电机 1(左)不响应 CAN。换线测试已确认:使用右夹爪的正常线缆后, 0x141 立即响应,因此 电机正常,左侧线缆内部有导体断裂 ——外皮看起来完好,原因是 folded 机械臂位姿让两个夹爪交叉。在更换线缆前,下述操作仅适用于 右夹爪。库支持降级运行:探测两台电机,只驱动有响应的电机。

先确保总线已启动

终端 · Jetson
sudo modprobe gs_usb                                          # prompts for hello-dex
sudo ip link set can1 up type can bitrate 1000000 \
     loopback off listen-only off                             # NOPASSWD; spell out both flags
ip -details -statistics link show can1                        # want ERROR-ACTIVE and tx > 3

can0 是 Jetson SoC 自带的控制器, 不 是适配器——始终使用 can1. tx 恰好停在 3 表示没有节点 ACK,并非成功。

对象模型

对象含义
Motor一台伺服电机。CAN ID 为 0x140 + id;回复使用 同一个 ID。 alive() / _require_alive() 会抛出明确指出实际问题的错误,而不是在运动深处失败。
Grippers两台电机及其标定坐标系。电机 1 = 左侧 (0x141),电机 2 = 右侧 (0x142)——通过逐一驱动并观察夹爪验证,不是推断。
方向负值 = 闭合,正值 = 张开,两侧相同,已目视确认。
坐标move_to() 接受标定行程的 0..1 比例 ——0 为闭合,1 为张开。原始角度只在库内部使用。

正常使用流程

Python · Jetson
from gripper import Grippers

g = Grippers()          # opens can1, probes both motors
g.home()                # find the closed stop on each; ~1 min, do not skip

g.both_open()           # both jaws, concurrently — 9 s at 500 dps
g.both_close()
g.both_move_to(0.4, speed=500)   # 40% open

print(g.position())     # fraction per motor
print(g.status())       # angle, current, temp, voltage, error state

g.grip(current=0.6)     # close until the current limit says contact

g.halt()                # stop motion, keep the frame
g.close_bus()           # release the socket, leave motors energised

归零不可省略

保存的标定不会一直有效

编码器坐标系曾在不同会话间漂移 三次 ——有一次达 2545 度——但机械行程保持相同。 始终使用 home();不要默认传入已保存的 calibration= 。

唯一合理的例外:上次运行以 halt() 结束,且电机从那以后 从未 断电,则物理坐标系仍有效,因此 Grippers(calibration=[left_closed, right_closed]) 可省去约一分钟的归零——但 运动前先验证:读取 position() ,确认与上次夹爪位置相符(张开后约 0.98)。不符就重新归零。执行 release() 或任何断电重启后, home() 是必需的。

原因在固件中: 0x80 (关闭电机) 会丢弃多圈计数,此后角度只返回折叠到 (−180, 180] 的单圈值。因此绝对坐标仅在电机持续使能时有效——这正是驱动启动时靠机械限位归零、并在整个会话保持使能的原因。

close() 与 grip()

调用行为用途
close() / both_close()驱动到闭合位置,并 会在任何阻挡物上堵转空夹爪,回到已知状态
grip(current=…)在电流限制下闭合,并报告 gripped有物体时使用。 抓取物体应使用这个方法
move_to(f)单台电机移动到比例位置 f,阻塞执行仅用于单侧操作——见下方警告
both_move_to(f, speed=500)连续发送两条 0xA4 命令,然后轮询两台电机双夹爪运动的默认方式
不要循环对两台电机调用 move_to

这样会串行运行:完整行程需要 18.0 s ,而使用并行方法只需 9.0 s ,调用 both_move_to(),总时间取决于较慢电机,而不是两者之和。 gripper_demo.py 曾有这个问题,现在只要两台电机都有响应,就使用 both_move_to 。

正常数值参考

量正常值含义
全行程电流< 0.3 A右夹爪在 500 dps 下实测 0.17–0.18 A
保持电流0.09–0.13 A电机自行保持,不会被反向驱动
撞到机械限位时的电流~2.5 A这是接触,不是故障—— home() 就是这样找到限位的
完整行程≈ 4680 度左 4679.5,右 4681.1——差异 0.03%,交叉验证标定确实有效
完全张开或闭合500 dps 下 9 秒并行运行。500 dps 的电流不高于慢速运动
总线往返中位数 0.62 msL4T 降级并重编译 gs_usb 后,400/400 次响应,零错误
电压/温度~24.0 V · ~31 °C来自 status()

关闭

调用电机标定坐标系何时使用
close_bus()保持通电并保持位置保留会话间暂停——每台约耗 0.1 A,可省去下次归零
halt() · 0x81停止运动,保持通电保留紧急停止
release() · 0x80断电,夹爪松弛丢失一天结束,或有人要手动接触夹爪时。 home() 下次必须执行
不要在运动中直接退出

Ctrl-C 后电机仍执行上一次的 0xA4 目标——进程退出了,夹爪仍会继续运动。 调用 halt() ,先完成这一步。 保持 can1 运行是可以的。

两个库使用陷阱

每次只运行一个 CAN 客户端

SocketCAN 将每帧发给每个 socket, 包括其他进程发出的查询。查询和回复共用仲裁 ID 和命令字节,简单匹配会把别人的查询解码为 角度 0.00、电流 0.00 ——连续两次就触发堵转检测,产生虚假的 (0.0, 0.0, 'stall')。已在 gripper.py 中修复: _cmd(..., ignore_echo=True) 用于全部遥测读取(但不用在 0x88/0x80/0x81上,因为这些命令的合法回复确实与查询相同)。仍建议总线只用一个客户端——在 REPL 中修改模块后执行 importlib.reload 。

如果绕过库直接操作

电机固件是 混合协议:读取操作码遵循 LK Tech 旧协议,运动操作码遵循 MYACTUATOR,后者偏移一位。 0xA2 是速度闭环,不是位置控制 ——曾把当前角度作为“原地保持”发送,结果电机持续旋转直到撞上限位。使用 0xA4 绝对位置命令,它带速度限制,因而可中止;对不确定的运动使用低速限制(约 20 dps)。 0x81 停止, 0x80 断电。

文件

路径含义
/home/dexmate/gripper.py库: Grippers 和 Motor
~/GRIPPER_README.md文档,包含“安全关闭”
~/py_scripts/gripper_demo.py探测两台电机,对有响应的电机归零并循环开合。 检查左侧断线时应使用这个脚本,因为它能降级为单电机运行
A6

常见问题:症状 → 实际原因

按最先看到的现象排序。多数问题没有文档记录,都是实际排查得到的。

症状一个 CAN 电机响应,另一个无响应,总线计数器正常

这是 断路,不是短路。CAN_H/CAN_L 短路会产生大量错误帧,使正常电机也掉线;总线正常而单节点沉默,表示该节点未电气接入总线。把正常线缆换到无响应夹爪——如果恢复响应,就是线缆故障。不必追查短路损坏。

症状ID 扫描在 0xc 和 0x4 “发现”电机

那些是 错误帧,不是设备。只根据 data != query 过滤会把它们算成回复。应跳过 m.is_error_frame ,先完成这一步。

症状头部不在上次留下的位置

每次 Robot() 都会把头部移动到 home 且没有参数能阻止(robot.py:353 → robot.py:424)。所属进程退出后,头部还会从 -0.5056 松弛到约 -0.13 rad。保持会话存续;若只需图像,直接使用 Sensors() 。

症状TypeError: unsupported operand type(s) for +: 'NoneType' and 'float'

gripper.py 在对离线电机归零—— angle() 返回了 None。已修补: Motor.alive() / _require_alive() 现在会明确报告实际问题,而且 Grippers.home() 会跳过离线电机,而非中止在线电机。

症状保存的图像中木桌变成蓝色

相机输出 RGB; cv2 需要 BGR。请用 cv2.COLOR_RGB2BGR转换。PIL 无需转换。

症状dextop 固件信息查询超时

ROBOT_NAME 被写成了 dm-<serial>。真正的 Zenoh key 使用 dm/vg3eb20f25bb-1u/... — 斜杠. topic list 通过并不代表名称正确。

症状Missing argument 'PACKAGE_FILE'

dextop cert unpack 需要把证书路径作为参数。

症状Failed to connect to SOC: timed out

无法路由到 192.168.50.21。可能是重刷系统清除了 enP8p1s0 上的静态 IP(恢复 192.168.50.20/24),或是在外部电脑上没有运行 sshuttle 。

症状command not found: dextop (under sudo)

安装到 ~/.local/bin,不在 root 的 PATH 中。请使用 sudo -E $(which dextop) ….

症状dextop node start 在端口 7447 上失败

dextop node install-service 已经启动了节点。无害,忽略即可。

症状CAMERA NOT DETECTED,但日志显示 ZED SDK available

是内核版本不匹配,不是缺少驱动。检查 /dev/video*, zed_x_daemon 和解串器模块;本机通过将 L4T 36.5.2 降到 36.5.0(内核 5.15.199 → 5.15.185)解决。

症状undefined symbol: getZEDSDKBuildVersion

dexsensor 0.7.6 基于 ZED SDK 5.2.2 构建,目前运行于 5.2.3。只是警告。

症状ZED SDK not found,但 import pyzed 成功

C++ 标准库不匹配: conda update -c conda-forge libstdcxx-ng -y.

症状代码中已启用相机,但没有数据

字段名是 enabled,不是 enable,写错会静默失败; configs.sensors 是字典,不是对象。另外, dexsensor launch 必须在 Jetson 上运行。

症状日志显示 DEPTH_MODE::NONE,配置却是 NEURAL

depth_mode 和 [sensors.streams] depth 是两个独立开关;两者必须开启,服务层面还要设置 enabled = true 。 dexsensor enable 只在运行时生效,重启后丢失。

症状保存的图像红蓝互换

相机输出 RGB。OpenCV 需要 BGR——添加 cv2.COLOR_RGB2BGR转换。PIL 无需转换。

症状candump 没有输出

夹爪采用查询应答,不主动广播,因此空的 candump 不能说明问题。确认总线为 1 Mbit/s,且 R120 已关闭。

症状can1 完全没有活动

典型原因是 CAN_H/CAN_L 接反——连错误帧也没有。另一种可能是内核更换后 gs_usb.ko 无法加载,需要重新编译。

症状通过 SSH 初始化 ZED 相机失败

使用了 ssh -X。请用普通 SSH 会话。

症状话题速率看起来过低

外部电脑通过 WiFi 连接时常见。使用 dextop topic hz <topic>测量,并设置 ZENOH_CONFIG 和 ROBOT_IP.

症状固件更新后立即出现异常

dextop doctor check,然后执行 dextop doctor restart。确认 dextop/dexcontrol/dexsensor 版本与固件匹配。

Part B

必读与必要设置

每台新机器人都需阅读 B1–B8,并完成适用的设置与检查;B5 中的工作站配置适用于使用外部电脑的情况。

B1

夹爪硬件连接

一次性配置

1. 连接 assembled 线束

组装好的线束一头是 CAN adapter,两侧分支各有一组 4-pin/6-pin 接口。两侧均将 6-pin 接夹爪,4-pin 接机器人。

2. 连接腕部相机线

相机线也要连接,只接偏向内部的一边,位置见 IMG_9360。

IMG_9360:腕部相机偏向内部的连接位置
IMG_9360 · 相机线只接偏向内部的一边。

3. 连接 USB,并设置两个开关

CAN adapter 插入机器人的 USB 口。两个开关都一定要拨向 K 那边,见 IMG_9369。

IMG_9369:CAN adapter 的两个开关均朝向 K
IMG_9369 · 两个开关均朝向 K。

整体连接示例

IMG_9361:夹爪与相机线的整体连接示例
IMG_9361 · 整体连接示例。
IMG_9368 · 整体连接 walkthrough。
B2

PCB 与相机硬件安装

一次性配置

参考:Waveshare MAX9296-GMSL-Deser-Module · Jetson Orin。改线前先断电。

1. 安装采集卡并连接电源

用 kit 自带的铜柱连接采集卡和 PCB,然后接电。红线接 排针 2、4(5 V),地线接 6(GND)。这里是 Jetson 的 5 V 排针,不能接夹爪的 24 V 电源。

Waveshare 采集卡使用 kit 铜柱安装,连接红黑电源线
Kit 铜柱与电源线连接。图片:Waveshare。
Jetson 40-pin 排针定义:2、4 为 5 V,6 为 GND
排针定义 · 2/4 = 5 V;6 = GND。

2. 设置 CFG 开关为 0100

按板上编号 1 → 2 → 3 → 4 读取,依次设置为 0 → 1 → 0 → 0。

Waveshare CFG 开关及板上 1、2、3、4 编号
CFG 开关位置与编号。图片:Waveshare。

3. 更换机器人内的铜柱

拆下机器人的原装铜柱,妥善保存。先用 15 mm 铜柱固定钢架,再接 10 mm 铜柱安装剩余的内存/存储组件及风扇。

IMG_9276:机器人内部安装参考
IMG_9276 · 内部安装参考。

4. 连接内部腕部相机线

  • 拿到母母线:直接拆开内部连接腕部相机的连线,连接到采集卡。
  • 拿到公母线:把机器人后盖上接外部相机的接口拆下,用公母线直连。IMG_9277 walkthrough 演示的就是这种接法。
IMG_9277 · 内部接线 walkthrough,使用公母线直连。

5. 更换 CAM1 排线

拆下原来接在 Jetson CAM1 上的线,使用 kit 自带的排线连接 Jetson CAM1 ↔ 采集卡 CSI0。

Jetson 载板及相机接口区域参考图
Jetson 载板参考图。
Waveshare 采集卡、相机及 CSI 排线连接参考
采集卡与 kit 连接参考。图片:Waveshare。

保存好从机器人拆下来的所有零件,包括原装铜柱、接口和线缆,之后归还机器人时还需要使用。

B3

让机器人连接网络

已完成 · 一次性

没有已知 WiFi 的机器人会在开机时启动自己的热点。规则是: 没有已知网络 → 热点;已知网络在范围内 → 自动加入,热点消失。每台机器人只需配置一次。

三种进入 shell 的方式

方式所需设备地址适用场景
显示器将 DisplayPort 线、USB 键盘和鼠标接入 IO hub—,直接点击 WiFi 托盘图标最简单;不需要了解 SSH
以太网网线,可选交换机192.168.50.20稳定——用于固件和证书操作
机器人热点任何有 WiFi 的笔记本电脑10.42.0.1 或 192.168.4.1手边没有线缆时

以太网连接前,先给自己的电脑设置静态地址: 192.168.50.x 用于 Vega-1 和 Vega-1U(x 可取 1–255, 但不包括 20 和 21)。Vega-1-Pro 的底盘端口使用 192.168.5.x ,躯干端口使用 192.168.50.x 。子网掩码为 255.255.255.0,网关留空。

按生产日期区分热点凭据

批次SSID密码IP
2026 年 1 月之前vega_{mac}_hotspot12345678192.168.4.1
2026 年 1 月之后dexmate-{mac}dexmate12310.42.0.1

开机后等 2–3 分钟再寻找热点。SSH 凭据始终是 dexmate / hello-dex.

终端 · 自己的电脑
ssh dexmate@10.42.0.1

加入自己的 WiFi

终端 · Jetson
# see what's around
timeout 5 sudo iw dev wlP1p1s0 scan > /tmp/scan_results
nmcli device wifi list
终端 · Jetson · 动态 IP(推荐)
sudo nmcli device wifi connect "YourNetworkName" password "YourPassword"
终端 · Jetson · 静态 IP
sudo nmcli device wifi connect "YourNetworkName" password "YourPassword" \
  ip4 JETSON_STATIC_IP/24 gw4 WIFI_GATEWAY
这是预期行为,不是故障

命令一旦成功, 热点就会消失,SSH 会话随之断开。文档明确说明了这一行为。

然后在新网络中寻找机器人。有权限时用路由器管理页面,否则扫描:

终端 · 自己的电脑
nmap -sn 192.168.1.0/24 | grep -B2 -A2 "vega\|dexmate"

无法连接时

  • 没有出现热点 ——完整等待 5 分钟;确认机器人没有保存其他网络(否则会加入那个网络);必要时重启。
  • SSH 连接被拒绝 ——确认确实连上机器人热点、使用了对应批次的 IP,并且启动已完成。
  • 加入 WiFi 失败 ——重新检查 SSID 和密码,确认网络为 2.4 GHz 或双频,把机器人移近路由器。
  • 在新网络中找不到机器人 ——等待 2–3 分钟;若设置了静态 IP,重启路由器并确认地址不与其设置冲突。
B4

证书与固件——每台机器人一次

已完成 · 一次性
先获取本机名称与注册文件

请到 Dexmate 官方平台 获取本机名称,并下载这台机器人对应的 .dzcfg 注册文件。将本机名称用于 ROBOT_NAME 和 installer 的 --robot-name 参数,并使用对应文件完成下方的注册/证书配置。手册中展示的机器人名称是我们这台机器的示例;安装新机器人时,请使用官网为该机提供的名称和文件。

证书是接入总线的凭证:安装一次,直到过期前都有效。固件更新可选,证书不可省略。Dexmate 提供两条路径,而 证书只能通过 Web 管理页面安装.

方式 1 · Web 管理页面(证书必需)

SoC 板位于 192.168.50.x 子网,WiFi 侧无法直接访问,因此先建立路由:

终端 · 自己的电脑
sudo apt install sshuttle
sshuttle -r dexmate@$ROBOT_IP 192.168.50.0/24
  1. 打开 https://192.168.50.21:57832。首次访问会要求设置密码——请记住它。
  2. 先升级管理页面本身 (Check for Updates)。如果失败,从 software.dexmate.ai 下载 socbridge 文件并手动上传。
  3. 在通信部分上传 Dexmate 签发的证书。
  4. 如果需要,也在同一页面更新固件。
管理页面打不开

2026 年 3 月前出厂的机器人可能完全没有 socbridge——在 Jetson 上使用以下命令安装: dextop firmware install-socbridge. 该命令需要能路由到 192.168.50.21;如果重刷系统清除了 enP8p1s0 上的静态 IP,它只会输出 Failed to connect to SOC: timed out.

方式 2 · 命令行(仅适用于已安装有效证书)

终端 · Jetson 或工作站
dextop firmware info      # per-board version table
dextop firmware update    # prompts for the version to install
固件 ≥ 0.5.0 需分两次安装

上传并安装 robot-server 文件 → 重启机器人 → 管理页面重新可访问后,再上传并安装固件文件。低于 0.5.0 的版本只需上传一次。
保持版本一致:固件 0.4.3 需要 dextop==0.4.6;固件 ≥ 0.4.3 时,将 dextop, dexcontrol 和 dexsensor 一起更新到最新版本。

B5

工作站通信

工作站设置

如果只在机载计算机运行代码,可跳过本节。从自己的电脑控制机器人时,工作站必须加入同一 Zenoh 总线。

终端 · 工作站和 Jetson
pip install dextop --upgrade
终端 · 工作站 · 一次性
dextop cert unpack <certificate_file>.dzcfg
不要漏掉参数

dextop cert unpack 需要传入证书路径;不带参数只会返回 Missing argument 'PACKAGE_FILE'。妥善保存证书——它赋予控制机器人的权限。

终端 · Jetson · dextop ≥ 0.5.0
dextop node install-service

低于 0.5.0 时中继需手动启动并持续运行,因此放在 tmux 中:

终端 · Jetson · dextop < 0.5.0
tmux new -s relay
dextop node start          # then Ctrl+B, D to detach
本机已验证

install-service 会自行启动节点,所以随后执行 dextop node start 会在端口 7447 上失败——无害,忽略即可。另外, dextop 安装到 ~/.local/bin,不在 root 的 PATH 中:使用 sudo -E $(which dextop) ….

终端 · 每个运行控制代码的终端
export ROBOT_NAME=dm/vg3eb20f25bb-1u
export ZENOH_CONFIG=~/.dexmate/comm/zenoh/<cert_name>/zenoh_peer_config.json5
export ROBOT_IP=172.26.161.243

多机器人场景下,每台机器人使用单独终端,并设置各自的 ROBOT_NAME ——一台工作站就能控制全部机器人。

B6

安装 dexcontrol 和 dexsensor

已完成 · 一次性

dexcontrol——控制

终端
pip install dexcontrol

开源示例位于 github.com/dexmate-ai。Dexmate 建议先运行 examples/advanced_examples/fold_robot.py 来展开新机器人—— 不要在本机运行它;见常见问题对照表。

dexsensor——感知,仅限 Jetson

从 software.dexmate.ai 下载正确架构(Jetson 使用 arm64),然后执行:

终端 · Jetson
sudo dpkg -i <dexsensor_xxx>.deb
  • 若原先使用基于 Python 的 dexsensor ≤ 0.3.1, 先彻底卸载,再安装 ≥ 0.6.9.
  • ZED SDK 预装在 /usr/local/zed,PyZED 位于基础 conda 环境。若使用自己的环境,在该目录运行 python get_python_api.py 。
  • ZED SDK not found 但 import pyzed 可用时,是 C++ 标准库不匹配: conda update -c conda-forge libstdcxx-ng -y.
  • 每个 dexsensor 版本要求特定 ZED SDK 版本——从 Stereolabs 历史发行版下载。
  • 不要通过 ssh -X启动 dexsensor,否则 ZED 相机初始化会失败。
本机的版本组合

ZED SDK 5.2.3 (ZED_SDK_Tegra_L4T36.5_v5.2.3.zstd.run) + dexsensor 0.7.6 + dextop 0.5.0。dexsensor 0.7.6 基于 ZED SDK 5.2.2 编译,因此使用 5.2.3 时会出现 undefined symbol: getZEDSDKBuildVersion 警告——无害。

B7

验证与诊断

随时可用

编写代码前先运行这些检查。先确认连接正常,能避免反复猜测“是脚本还是机器人出了问题”。

终端
dextop topic list --timeout 10

外部电脑首次调用常常没有返回——dextop 需要一些时间连接机器人。再运行一次或增加超时。

命令何时使用
dextop doctor check机器人行为异常时首先运行;报告硬件层面问题
dextop doctor restartdoctor 标记机器人服务器异常时(固件更新后常见),用于干净地重启
dextop topic hz <topic>速率偏低时量化延迟,尤其在 WiFi 下
dextop firmware info各板卡硬件和软件版本
dexsensor status各传感器状态:Disabled/Running/Error
/usr/local/zed/tools/ZED_Explorer -a安装 ZED SDK 后确认识别到相机(Rahul 的诊断方法)
如何判断某个组件是否存在

根据 dextop topic list中的 Zenoh 话题,或代码中的 has_component() 判断—— 绝不能根据 firmware info 表格。该表列出固件包条目,并非本机实际具有的关节(见下文)。

B8

头部+腕部相机配置

记录于 2026-09-15

头部双目和两路腕部相机已在 dm/vg3eb20f25bb-1u上同时输出图像。硬件:Orin Nano 8 GB p3767-0005 配原装 p3768 载板;L4T 36.5,内核为 Linux 5.15.185-tegra。日常 API 示例见 A2.

当前仓库:开机启动

已经包含腕部初始化自启动。scripts/install.py --apply 会安装并启用 wrist-camera-init.service。开机时等待两个腕部设备、完成初始化并写入就绪标记。这是一次性服务,显示 active (exited) 正常。它不会持续取流:应用打开 WristCameras() 后才启动采集和触发,关闭后停止。

头部取流由厂商的 dexsensor.service 负责。目前 installer 没有显式启用此服务。--configure-head 会写入头部配置和机器人名称,但不会启用或启动服务。请用下方命令检查并启用。这里说明的是仓库行为;命令用于检查实际执行它们的机器人。

新机器人先安装匹配的厂商软件,再按仓库 Quick start 操作。--camera-boot --activate-camera-boot 会生成并选中 DexmateSetupHeadWrists,使用 /boot/initrd-dexmate-setup 和 /boot/tegra234-dexmate-setup.dtbo。不加 --activate-camera-boot 只会准备启动项。installer 不会启动服务或重启机器人。下方原机器人集成记录中的 HeadWrists 路径属于原来的安装。

Bash · Jetson · 检查自启动
systemctl is-enabled dexsensor.service wrist-camera-init.service
systemctl status dexsensor.service wrist-camera-init.service --no-pager
systemctl cat dexsensor.service wrist-camera-init.service
cat /boot/extlinux/extlinux.conf

安装完成后,启用这两个服务用于后续开机。如果提示 unit “not found”,先安装对应软件:头部需要厂商 dexsensor 包,腕部初始化需要本仓库 installer。

Bash · Jetson · 启用自启动,不立即启动
sudo systemctl daemon-reload
sudo systemctl enable dexsensor.service wrist-camera-init.service

检查启动项后手动重启。若只需要在本次开机中启动或重新初始化相机,先关闭腕部读取程序及独立 ZED 查看器,再执行下方命令。它们会中断相机流,不会重启机器人;新选中的内核 overlay 仍需重启后才能生效。

Bash · 先关闭相机读取程序
sudo systemctl restart wrist-camera-init.service
sudo systemctl restart dexsensor.service

相机不工作时怎么排查

先在 Jetson 本机检查,区分硬件/服务问题和工作站通信问题。先看状态与日志:

Bash · Jetson · 只读诊断
uname -r
systemctl status dexsensor.service wrist-camera-init.service --no-pager
journalctl -u dexsensor.service -u wrist-camera-init.service -b -n 160 --no-pager
v4l2-ctl --list-devices
cat /run/wrist-cameras/ready.json
cat /proc/sys/kernel/random/boot_id
sudo journalctl -k -b --no-pager | grep -Ei 'isx031|max929|tegra.*camera|i2c|csi|vi.*error'
现象检查与处理
开机后头部和腕部都不能用检查选中的组合启动项、overlay 和 initrd。本包要求 5.15.185-tegra/L4T 36.5.0 及匹配的 ZED 软件。extlinux 中有启动项不代表本次已使用它;结合开机内核日志和设备枚举检查。
头部服务失败,或相机被占用查看 dexsensor 日志,检查 ZED SDK/ZED Link 安装及头部连线。关闭独立 ZED 查看器或重复发布进程,再重启 dexsensor;同一头部相机只保留一个占用者。
头部服务运行,但没有 RGB/深度检查 /etc/dexmate/dexsensor/default.toml 的 head_camera 块:enabled = true、left_rgb = true、right_rgb = true、depth = true、depth_mode = "NEURAL"。保存后重启服务。通用 ZED X One 腕部项保持禁用。客户端使用 configs.sensors["head_camera"].enabled = True,并核对 ROBOT_NAME 和证书。本机能读但工作站不能读,查看 B5。
腕部服务被跳过/找不到腕部设备ConditionPathExists 要求存在组合设备树路径 /proc/device-tree/bus@0/cam_i2cmux/i2c@0/tca9546@70。检查启动 overlay 和驱动日志。API 需要两个 ISX031 设备,并按名称发现它们;不要固定假设 /dev/videoN 编号。
Wrist probes not ready/串行器读取错误/GMSL 链路未锁定断电后检查 5 V/GND 供电、CFG 0100、CSI0 → CAM1 排线及两条 GMSL 连接,见 B2。2/4 脚为 5 V,6 脚为 GND;夹爪 24 V 电路保持独立。配套驱动要求 MAX9295/3 Gbps。先修复连线或启动配置再重试初始化,不要猜测写入 I²C 寄存器。
未初始化/标记来自另一次开机将 ready.json 中的 boot_id 与上方本次开机 ID 比较。关闭腕部读取程序,重启 wrist-camera-init.service,查看退出状态和日志。不要手动创建或修改就绪标记。
Already owned/设备忙正常关闭另一份腕部程序。可用 sudo fuser -v /dev/video* 找占用者,不要终止无关进程。API 用一个锁同时管理两个腕部,只允许一个读取者。
没有新帧/trigger worker exited使用 A2 的 WristCameras 示例,它会启动软件触发进程;单独用 V4L2 拉流不会。检查异常、GStreamer/内核日志及设备权限。重新初始化前先关闭 API 上下文。
导入/GStreamer/权限错误使用系统 Python 3.10 或安装好的 /opt/dexmate-setup/venv;用 id -nG 检查 video 和 i2c 组。安装后退出登录再进入。缺少 gi/GStreamer 或 wrist_cameras 通常是依赖未安装或 Python 环境不对。

恢复后运行 A2 头部+双腕示例:确认头部 RGB/深度非空,多次读取时头部源时间戳推进,两个腕部的 frame ID 持续增加。服务 active 和存在视频设备节点都不能单独证明已经出图。不要热卸载相机驱动栈;启动/驱动恢复使用保留的启动项并有序重启。

原机器人集成记录 · 2026-09-15

默认配置已设置 · 冷启动仍待测试

DEFAULT HeadWrists 及自动腕部初始化已安装。此检查点上运行的系统是已成功测试的 HeadWristsPatchedTest 启动项。新默认 initrd 通过了解包和静态检查,其初始化服务和 API 也在当前启动中正常工作。 尚未通过重启测试完整的新默认启动+自动初始化流程。

物理连接

组件连接/设置
头部:ZED X Mini,S/N 53756133ZED Link Duo / MAX96712 → Jetson CAM0; serial_b,port-index 1,2 条 CSI lane。一条 GMSL 链路承载双目。
腕部 A+B原装 ISP/ISX-31 MAX9295 AA H195,PN MC30E0Z23-00-08。ISX031 ISP 输出为 1920×1536、UYVY/YUV422。
腕部解串器Waveshare MAX9296A (SKU 33623): CSI0 → Jetson CAM1; serial_c,port-index 2,4 条 CSI lane。
Waveshare 板设置CFG 拨码为 0100 ,按板上开关编号顺序读取。排针 2 或 4 提供 5 V;6 为 GND。1 是 3.3 V,不是 5 V 供电。改线前先断电。
地址/设备发现腕部总线为 I²C 9:解串器 0x48,串行器别名 A 0x44、B 0x42。API 按名称识别传感器后缀 001a/001b 。

测试时腕部枚举为 /dev/video0, /dev/video1 ,头部为 /dev/video2, /dev/video3。这些编号可能随启动变化:使用 API 发现机制,不要硬编码索引。电源灯亮不能证明收到图像;需要下方取流测试。

已安装的启动和初始化链路

  1. /boot/extlinux/extlinux.conf 选择 DEFAULT HeadWrists,加载 /boot/tegra234-head-wrists.dtbo 和 /boot/initrd-head-wrists-default.
  2. initrd 在模块加载前,通过只读 bind mount 提供修补后的 tegra-camera.ko 和 isx031-gmsl-camera-b.ko 。原内核、基础 DTB、磁盘上的模块和 /boot/initrd 均保留。
  3. 已启用的 wrist-camera-init.service 等待两路腕部探测完成,执行相机专用初始化,并写入 /run/wrist-cameras/ready.json。它是 oneshot: active (exited) 且退出状态为 0 属于正常情况。它跳过旧的单相机回退配置。
  4. dexsensor.service 继续通过 ZED 软件栈发布头部相机。 WristCameras() 按需启动腕部采集和软件触发;关闭上下文即停止。开机初始化不会启动持续腕部录像。
Jetson 上的路径用途
/opt/wrist-cameras/wrist_cameras.py, initialize.py, trigger.py, wrist_camera_runtime.py 及 README。
/etc/systemd/system/wrist-camera-init.service开机初始化服务。
/etc/tmpfiles.d/wrist-cameras.conf创建运行时路径和共享的 /run/lock/wrist-cameras.lock,root:i2c,权限 0660。
/usr/local/lib/python3.10/dist-packages/wrist_cameras_local.pth使本地腕部模块可导入。
/etc/dexmate/dexsensor/default.toml启用头部;HD1200,配置 30 fps,NEURAL,启用左/右/深度流。通用 ZED X One 腕部条目保持禁用。

为什么原厂软件包不够用

两个原始 overlay 的 VI/CSI 通道重叠。合并 overlay 保留头部的 26 个通道,把腕部添加到 26/27,总计使用六条物理 CSI lane。它还移除永久选择 CAM0 的 GPIO hog,并将头部板卡的 TCA9546 放到载板 CAM0 GPIO-mux 分支下。

相机框架需要父节点遍历补丁来处理嵌套 I²C mux;否则头部探测会报 i2c bus regbase unavailable /错误 -75。腕部驱动需要识别 MAX9295、配置 3 Gbps 链路,再执行原装相机的复位、时钟、视频和触发初始化。只有设备节点还不足以产生图像。

提供的 Downloads/orin_kernel_img_260506_v3.4/ 软件包包含 5.15.148-rt 内核和 AGX 专用设备树。这些二进制不匹配本 Nano 的 5.15.185-tegra。这里只移植了相机专用初始化;不要对本配置使用该包的全系统安装器。任何内核或 JetPack 升级后,都应重新编译/检查自定义模块。

就绪状态与恢复检查

Bash · Jetson · 只读检查
uname -r
systemctl is-enabled wrist-camera-init.service
systemctl status dexsensor wrist-camera-init.service --no-pager
cat /run/wrist-cameras/ready.json
journalctl -u wrist-camera-init.service -b --no-pager

成功初始化标记必须属于本次启动。如果缺失,检查服务日志和选中的启动文件。设备忙表示另一个读取进程占用腕部,应先关闭该进程。单纯 V4L2 取流不提供必需的软件触发。

若需重新初始化相机,先关闭所有腕部读取进程,然后运行:

Bash · 关闭腕部读取进程后
sudo systemctl restart wrist-camera-init.service

这会重启相机初始化,不会重启机器人。服务成功后重新打开 API。

一次实际崩溃带来的恢复限制

不要热卸载 nvhost_isp5 或批量卸载相机软件栈:调试时原 ISP 驱动的卸载路径曾造成内核崩溃。验证启动时连接显示器和键盘,并保留选择原 ISX031 或 Stereolabs 启动项的途径。

启动配置备份: /boot/extlinux/extlinux.conf.before-default-head-wrists-20260915。选择旧的 ISX031 启动项会恢复仅腕部的启动路径,不能提供头部+腕部联合配置。新默认 initrd 的 SHA256:

SHA256 · /boot/initrd-head-wrists-default
f449a4ea16dc1bda7a0ce3dc6508c82472faf07e6b02e7b31cd102d72eedad69

实测结果与限制

测试路径观测速率含义
头部左右 RGB,HD1200各 15.105 fps20 秒并发原始采集测试中,新订阅帧的速率。
头部 NEURAL 深度,HD120015.054 fps实测发布速率;配置值为 30 fps。
腕部 A/B,原生 UYVY9.327 / 9.293 fps独立软件触发;完整 1920×1536 缓冲区。
全分辨率 RGB 腕部 API+头部订阅5.80 对/秒单进程中 25 次成对 API 读取;包含转换/复制开销。
45.020 秒四视角运动演示236 帧;预览 5.24 fpsAPI 采集加合成/录像;不是传感器原生帧率。

原始测试有 19.662 秒共同重叠时间,源时间戳唯一且递增,应用层采集/触发错误为零。仍有一些启动/停止内核消息;不能据此认定内核日志完全无错。长时间稳定性、腕部 30 fps、断开重连和新默认冷启动仍未验证。

重建文件与证据

Jetson 工作目录: /home/dexmate/wrist-camera-debug/coexistence/。Mac 归档: /Users/huxinyu/Documents/ChatGPT/ICL/camera-coexistence/。复现配置时请保留该归档与本手册;文字说明不能替代修补后的模块和相机寄存器初始化。

  • default-camera/README.md, api-test.json 和 initrd-build-verification.json:已安装 API、服务检查和新默认配置的验证范围。
  • build_candidate.py, sensor-common-nested-gpio-mux.patch 和 default-camera/build_default_initrd.py:合并 overlay、框架补丁和默认 initrd 构建器。
  • RESULTS.md 和 concurrent-independent-trigger-20s.json:并发采集结果。
  • Mac 运动演示: /Users/huxinyu/Documents/ChatGPT/ICL/output/head-wrists-motion-demo-20260915/head-wrists-motion-demo.mp4.

Part C

进阶信息

架构、关节限位、CAN 细节、刷机恢复、硬件与控制信息,以及 TCP/外参参考。

C1

架构:一条 Zenoh 总线上的三个库

参考

每个 Dexmate 组件都通过 Zenoh通信,使用同一份加密证书认证。了解各库应该运行在哪台机器上,是后续步骤的前提——装错位置最容易白费半天。

组件运行位置安装方式作用
dextopJetson 和 工作站pip install dextop --upgrade证书、固件、机器人服务器、话题列表、健康检查
dexcontrol控制代码所在的机器pip install dexcontrol Robot() API:机械臂、头部、手、躯干、底盘、急停
dexsensor仅 Jetsonsudo dpkg -i dexsensor_*.deb相机和 LiDAR 采集与推流;依赖 ZED SDK
dexbot_utils随 dexcontrol 安装—机器人配置、URDF、 dexbot cfg list
socbridge机器人的 SoC 板dextop firmware install-socbridgeWeb 管理页面位于 https://192.168.50.21:57832

两种运行方式

  • 机载计算机 ——代码在 Jetson 上执行。延迟最低, ROBOT_NAME 已设置,是演示和实时控制的默认选择。
  • 从工作站运行 ——使用更好的 GPU 运行 AI 模型,经 WiFi 或以太网发送控制。便利的代价是延迟。两台机器必须在同一局域网,均需安装 dextop,并解压同一份证书。

环境变量

变量是否必需?作用
ROBOT_NAME是选择机器人。 Robot() 缺少它时会抛出 ValueError 。Jetson 上已预设;在工作站的每个终端中导出。
ROBOT_CONFIG建议设置告诉控制脚本安装了哪种末端执行器。使用以下命令列出选项: dexbot cfg list (vega_1u, vega_1u_gripper, vega_1u_f5d6,……)。
ZENOH_CONFIG机器人外部:实际需要指向 ~/.dexmate/comm/zenoh/<cert>/zenoh_peer_config.json5。实际从外部电脑拉取话题时需要。
ROBOT_IP可选新版 dexcomm 用它加快查询响应。
本机已验证

名称必须写成 dm/vg3eb20f25bb-1u ——使用 斜杠。wiki 正文写成了 dm-<serial>,这种写法会使 dextop firmware info 超时,但 wiki 自己的示例输出用的是斜杠。注意 dextop topic list 两种写法都会通过,因为它使用通配匹配 dm/**,因此它 不 能作为名称正确性的有效检查。

C2

这台机器人实际具有的组件

参考 · 本机

Vega-1U 是 Vega-1 的上半身。 可控自由度总数为 17:左臂 7(L_arm_j1..j7),右臂 7(R_arm_j1..j7),头部 3(head_j1..j3). 没有躯干,也没有底盘 — Vega1UConfig.components 只列出双臂、头部、急停和心跳,而 dextop topic list 返回的 16 个 key 不包含 state/torso 或 control/torso.

陷阱

dextop firmware info 表格 确实列出一块 torso 板 (hw 5,sw 123)。这是固件包条目,不是关节。不要解读成“这台机器人有腰”。

机械臂关节限位(rad)——左右不对称

关节左右说明
j1±3.071±3.071
j2[−0.453, 1.553][−1.553, 0.453]肩部俯仰——本机唯一能抬升的关节
j3±3.071±3.071
j4[−3.071, 0.244][−3.071, 0.244]
j5±3.071±3.071
j6±1.396±1.396
j7[−1.378, 1.117][−1.117, 1.378]镜像关系——可用于交叉检查映射

机械臂 pose_pool: folded, folded_closed_hand, L_shape, lift_up, zero。头部: home, tucked.

绝不要在本机执行 folded 位姿

folded 和 folded_closed_hand 曾险些损坏夹爪。 不要执行,也不要把它们当作安全收纳位姿。

原因:这些位姿把前臂紧贴机身,是围绕 Dexmate 自有末端执行器设计的。本机使用的第三方 CAN 夹爪远远伸出 L_ee / R_ee 和 未被建模在 vega_1u.urdf 之中 ——URDF 和 pinocchio 碰撞检测都不知道它们存在。运动学模型认为无碰撞的位姿仍可能挤坏夹爪。

已知安全的停放位姿来自机器人实际停放状态,在首次命令运动前记录并保存为 pre_move:左臂 [1.7289, 0.0101, 0.0041, -0.9924, -0.2311, 0.5011, -0.0066],右臂 [-1.5683, -0.0026, 0.0031, -0.9916, 0.0908, -0.4138, -0.0018],头部 [-0.0883, -0.0338, 0.0486]。应把每个 pose_pool 条目都视为未经本硬件验证;根据腕部周围的真实间隙判断收纳位姿,而不是重力力矩或厂商给位姿起的名字——低力矩位姿仍可能碰撞。

关于 URDF 中的升降机构

运行时事实不变:没有躯干组件,没有 control/torso 话题,也无法控制。但 vega_1u.urdf 确实建模了升降机构 ——pinocchio 读到 19 个关节,机械臂之前的两个是 Lift (Z 向移动关节,0–0.4 m)和 torso_flip (X 向转动关节,0–1.0 rad)。所以“硬件不存在”尚未得到证实;它可能存在,只是在该型号未启用。需查看 SoC 端配置才能确定: https://192.168.50.21:57832.
由此也可识别 BrickBench 23 维向量的开头—— [0.2, 0.5] 处于 Lift (0–0.4)和 torso_flip (0–1.0)的中间范围,两个数对应两个关节。

机器人上已有的脚本

脚本作用
~/py_scripts/inspect_joints.py输出每个组件的自由度、关节名称、限位和当前位置。 遇到任何映射问题时先运行它。
~/py_scripts/goto_home.py通过分步插值(0.12 rad/步)和限位裁剪,将双臂和头部移动到指定位姿; --dry-run 只打印计划
~/py_scripts/goto_ready.pypre_move → manip_init,右臂先动
~/py_scripts/goto_rest.pymanip_init → pre_move,左臂先动
~/py_scripts/goto_pose.py两者共用的执行引擎:命名位姿、限位裁剪、分步运动、 --seq, --min-sep, --dry-run、夹爪间隙保护,以及对 folded 的禁用
~/py_scripts/head_pose.pyread_head_joint_pos() 和 move_head_smooth();直接运行可设置 [0, 0, -0.5056]
~/py_scripts/sensor_only.py读取相机信息和单帧, 没有 Robot(),因此不会运动
~/py_scripts/cam_info_capture.py设置头部俯仰、输出 get_camera_info()、保存全分辨率左侧 RGB 图像
~/py_scripts/path_compare.py离线 FK:按最小腕间距比较同时运动和顺序运动
~/py_scripts/gripper_demo.py探测两台电机,对有响应的电机归零,并行执行开合循环
~/py_scripts/gravity_check.py根据 URDF 计算静态重力力矩和腕部位置。 它不知道夹爪的存在。
始终为命令添加前缀

非交互式 ssh 不会加载交互式 shell 配置,因此 ROBOT_NAME 不会设置——每次都要显式传入:
ROBOT_NAME="dm/vg3eb20f25bb-1u" python3 script.py。已配置到 dexmate@172.26.161.243 的密钥 SSH;无需密码。

C3

夹爪 CAN 总线与接线

参考 · 硬件

两只第三方夹爪挂在同一条 CAN 总线上,由 Jhoinrch RH-02 USB 转 CAN 适配器驱动(Canable/candleLight 克隆,STM32F072C8T6,USB ID 1d50:606f)。机器人报告的手类型为 UNKNOWN,因此 不能通过 robot.left_hand 控制——而是通过 can1 下发命令,与机械臂控制并行使用。

项目值说明
总线速率1 Mbit/s不是 500k。 其他速率都会使总线卡住
供电24 V + GND从机器人取电
接线两只夹爪的 CAN_H/CAN_L 接到适配器接线端子适配器在总线中段以 T 形支路接入
终端电阻R120 必须关闭两只夹爪内部均有 120 Ω——端子处应测到 60 Ω;开启 R120 会变成 40 Ω,导致总线异常
极性保持原接线方向H/L 对调会造成 总线完全没有活动 ——没有完成帧,也没有错误帧
调试时不要被误导

夹爪 是查询应答式的 设备:从不主动广播,因此被动运行 candump 总是空的,不能证明任何问题。它们也不响应地址 0x600+n 上的 CANopen SDO 0x1000 读取(n = 1..127)。

gs_usb 必须手动编译

L4T 内核没有提供 gs_usb (CONFIG_CAN_GS_USB is not set,而且整个 drivers/net/can/usb/ 目录都不存在),也没有 slcan ——所以给适配器刷 slcan 固件无法绕过这个问题。内核头文件存在,可以进行树外编译:

终端 · Jetson
mkdir -p ~/gs_usb_build && cd ~/gs_usb_build
curl -fsSLO https://raw.githubusercontent.com/gregkh/linux/v5.15.199/drivers/net/can/usb/gs_usb.c
echo 'obj-m += gs_usb.o' > Makefile
make -C /lib/modules/$(uname -r)/build M=$PWD modules
sudo cp gs_usb.ko /lib/modules/$(uname -r)/kernel/drivers/net/can/usb/ && sudo depmod -a

任何内核变更都会使其失效 ——针对新版本重新编译(源码 tag 必须匹配运行中的内核)。DKMS 可使其自动持续生效。

C4

Jetson 重刷系统后的恢复

仅在重刷系统后

2026-08-25,本机重刷为 JetPack 6.2.3,清除了全部 Dexmate 出厂配置:ZED SDK、dexsensor、dextop、Zenoh 证书以及 enP8p1s0上的静态 IP。Dexmate 没有 提供重刷后的恢复流程。下面是工单 #126892650 中 Rahul 给出的四个步骤,以及我们为完成恢复自行摸索的内容。

R1

安装 ZED SDK

运行 ZED_SDK_Tegra_L4T36.5_v5.2.3.zstd.run (在 Jetson 上)。使用 /usr/local/zed/tools/ZED_Explorer -a 确认能看到相机。

R2

安装 dexsensor

sudo dpkg -i dexsensor_0.7.6_arm64.deb.

R3

安装 dextop 并设置机器人名称

终端 · Jetson
pip install dextop
sudo -E $(which dextop) robot set_name dm/vg3eb20f25bb-1u

名称来自底盘铭牌贴纸。贴纸不在时,从 socbridge 读取或从旧日志查找。

R4

解压证书

dextop cert unpack <file>.dzcfg ——必须带文件名参数。

R5

安装 socbridge

dextop firmware install-socbridge (本机使用了 socbridgepkg_v0.18.8.dpsw). Failed to connect to SOC: timed out 表示到 192.168.50.21 的路由丢失——恢复静态 IP 192.168.50.20/24 在 enP8p1s0 ,先完成这一步。

R6

使内核与已安装的相机驱动匹配

本机使用 5.15.185-tegra恢复,与已安装的 ZED Link 包匹配。下文记录当时的降级过程;后续头部+ISX031 腕部配置见 B8.

相机问题从来不是缺少驱动

Stereolabs 的 ZED Link 驱动提供 预编译 内核模块,没有 DKMS 源码,且绑定精确内核版本: stereolabs-zedlink-duo_1.4.3-LI-MAX96712-L4T36.5.0 声明 Depends: nvidia-l4t-kernel (>= 5.15.185), (<< 5.15.186)。JetPack 6.2.3/L4T 36.5.2 附带内核 5.15.199,因此每个 .ko 的 vermagic 都不匹配。

两者都标为“36.5”

L4T 小版本 不足以 判断兼容性——请检查内核版本。
而且绝不要对该包使用 --ignore-depends :它的 postinst 还会用另一内核的构建覆盖 host1x.ko 和 tegra-drm.ko (显示和硬件引擎)。

症状很容易误导:SDK 用户态库正常加载(ZED SDK available),但 CAMERA NOT DETECTED 仍然存在——因为没有 /dev/video*、没有 zed_x_daemon,也没有解串器模块。 怀疑线缆或配置前,先检查这三项。

降级——无需重刷

36.5.0 和 36.5.2 位于同一个 r36.5 apt 仓库,因此可以直接降级软件包。关键是: 枚举所有已安装的 nvidia-l4t-* 中具有 36.5.0 版本的包,并在一条命令中列出全部。只列几个会让 apt 删除 其余包,包括 nvidia-l4t-bootloader 和 nvidia-l4t-initrd。正确结果应为“48 downgraded, 0 to remove”。

  • 始终先用以下选项试运行: apt-get install -s ,先完成这一步。
  • apt-mark hold 随后锁定全部包。
  • 它会通过 capsule update 重写引导程序,因此 务必守在控制台前.
需要知道的副作用

降级还恢复了重刷时清除的静态 IP 192.168.50.20/24 在 enP8p1s0 ——这有力表明 Dexmate 出厂镜像基于 L4T 36.5.0,而且应当可以再次访问 192.168.50.21 上的 SoC 管理页面。

本机已确认的硬件

采集卡为 ZED Link Duo ,安装在原装 Orin Nano 开发套件载板上(p3768 / p3767-0005)。头部相机为 ZED X Mini (双目、一条 GMSL 链路、两个 /dev/video* 节点、S/N 53756133),接端口 0。 /etc/dexmate/dexsensor/default.toml 是多个 Vega 型号共用的通用配置,包含 ZED X One 腕部、底部相机和 LiDAR 条目。本机实际腕部为 两只原装 ISX031/MAX9295 相机,连接独立 Waveshare MAX9296A;ZED X One 条目不适用。接线和驱动配置见 B8 。

C5

硬件与控制信息

来自「整理 DexMate 硬件与控制信息」任务的测量记录(2026-09-14 UTC)。该次测量时,左右腕部相机均未启用。

项目记录配置
相机头部为 ZED X Mini 双目相机,接 ZED Link Duo;左右腕为 Sony ISX031。
头部输出提供左右 RGB 和深度,无点云输出;需用 depth + K 反投影。
分辨率/频率配置为 1920×1200、30 fps;实测 RGB 和深度约 24 Hz。
头部内参fx = fy = 734.72; cx = 966.63; cy = 653.07,单位为像素。双目基线:0.0497 m。
外参模型名义机器人几何以 pip 包 dexmate_urdf 内的 URDF 为准。上传的模型及实测 TCP/相机变换见 C6。
通信纯 Zenoh + dexcontrol,无 ROS 2。该次 RGB 实际走 Zenoh/JPEG,不是 RTC。延迟未测。
计算机Jetson Orin Nano;L4T 36.5.0;kernel 5.15.185。
控制dexcontrol 0.5.0,仅支持关节位置控制;wait_time=0 时需以 100–500 Hz 循环调用。无公开笛卡尔、关节 velocity/current 控制接口。第三方 CAN 夹爪单独控制。
六维力get_wrench_state() 返回 [fx, fy, fz, tx, ty, tz],类型为 float32。单位和参考坐标系未注明,需要确认或标定。传感器在该次测量时已激活。

实测发布频率

数据流实测频率
双臂关节状态91–92 Hz
头部关节状态48 Hz
头部 IMU186–190 Hz
RGB/深度≈24 Hz
六维力91–92 Hz

深度反投影

对校正后的像素 (u, v),深度 Z 有效且单位为米时,使用对应图像流的内参:

相机光学坐标 · 米
X = (u - cx) * Z / fx
Y = (v - cy) * Z / fy
p_camera = [X, Y, Z, 1]
p_base = T_base_camera @ p_camera
C6

TCP、相机外参与 URDF 文件

标定记录来自「暂存代码并重新标定区域」任务。该任务在 9 月 24 日最终恢复了 clean 提交 b90bcac 的 TCP/相机组合。原始 pivot 实测拟合值和此前调整 Y 后的组合在下方分别列出。

文件

两份上传的 URDF 与 dexmate_urdf 0.8.4 包内文件逐字节一致,保留了原文件及相对 mesh 路径。Mesh 需在软件包的目录结构中解析;单独下载 URDF 不包含 mesh。用于对照的自定义模型单独存放。

坐标约定

T_parent_child 将列向量坐标从 child 转到 parent:p_parent = T_parent_child @ p_child。平移单位为米,角度单位为弧度。R = Rz(yaw) @ Ry(pitch) @ Rx(roll)。基座轴向:X 向前、Y 向机器人左侧、Z 向上;已标定的左相机光学轴向:X 向图像右侧、Y 向图像下方、Z 向前。

右侧 TCP:模型、实测拟合与选用值

两份上传的软件包 URDF 定义了 L_ee/R_ee,但没有定义 tip_l/tip_r 夹持 TCP。下面的名义 tip 来自单独的自定义模型。

来源R_ee 中的 XYZ(mm)含义
自定义 URDF 名义 tip≈ [0, -15, 198]模型几何值;完整连乘变换见下方。
Pivot 拟合 · 9 月 19 日[-1.025481, -10.438899, 196.928685]实测平移;拟合 RMS 为 1.801540 mm。Pivot 拟合不确定旋转。
调整 Y 的组合 · 9 月 24 日 11:16[-1.025481, -18, 196.928685]采用实测 X/Z,Y 由用户指定;配套相机外参保存在可下载记录中。
恢复的 clean 组合 · 9 月 24 日 11:43[-1, -15, 198]引用任务最终选用的组合。

最终选用值和调整 Y 的组合使用工具坐标约定 rpy = [π, 0, π/2]。这一旋转是名义约定,并非 pivot 实测结果。提供的实测 TCP 数据针对右夹爪。

Clean · T_R_ee_tip_r · 米
[
  [ 0.000000000,  1.000000000,  0.000000000, -0.001000000],
  [ 1.000000000,  0.000000000,  0.000000000, -0.015000000],
  [ 0.000000000,  0.000000000, -1.000000000,  0.198000000],
  [ 0.000000000,  0.000000000,  0.000000000,  1.000000000]
]
自定义 URDF 中的左右 TCP 变换

以下连乘对应 EE 坐标系到 tip 之间的全部固定关节,是模型值,不是左右夹持中心的实测值。

Custom · T_R_ee_tip_r · 米
[
  [ 0.000000127,  1.000000000, -0.000000046,  0.000000193],
  [ 1.000000000, -0.000000127,  0.000006200, -0.015001328],
  [ 0.000006200, -0.000000046, -1.000000000,  0.197999807],
  [ 0.000000000,  0.000000000,  0.000000000,  1.000000000]
]
Custom · T_L_ee_tip_l · 米
[
  [-0.000012680, -1.000000000,  0.000000046, -0.000000005],
  [-1.000000000,  0.000012680, -0.000006200,  0.015001328],
  [ 0.000006200, -0.000000046, -1.000000000,  0.197999807],
  [ 0.000000000,  0.000000000,  0.000000000,  1.000000000]
]

实测头部相机外参

Clean 相机外参使用水平棋盘约束拟合,并与 clean TCP 一起恢复。记录中的留出点 RMS 为 1.176229 mm。该组合对应以下参考头部姿态:

参考关节位置
head_j1 = -0.00017453292093705386 rad
head_j2 = -0.00017453292093705386 rad
head_j3 = -0.5056219100952148 rad
torso_flip = 0.22689280275926285 rad
Lift = 0 m
Clean · T_base_link_zed_left_camera · 米
[
  [-0.001383542, -0.636266466,  0.771468126,  0.089032073],
  [-0.999930278, -0.008166881, -0.008528878,  0.026881780],
  [ 0.011727127, -0.771426138, -0.636210805,  1.169376372],
  [ 0.000000000,  0.000000000,  0.000000000,  1.000000000]
]

矩阵对应上面的头部姿态;头部运动后,基座到相机的变换会变化。标定记录保存的校正左目内参为 fx = fy = 734.7626953125、cx = 966.6296997070312、cy = 653.073486328125,分辨率 1920×1200;这是该次标定保存的值,与 C5 中较早记录的值分别列出。

此前调整 Y 的 TCP/相机组合
Adjusted · T_R_ee_tip_r · 米
[
  [ 0.000000000,  1.000000000,  0.000000000, -0.001025481],
  [ 1.000000000,  0.000000000,  0.000000000, -0.018000000],
  [ 0.000000000,  0.000000000, -1.000000000,  0.196928685],
  [ 0.000000000,  0.000000000,  0.000000000,  1.000000000]
]
Adjusted · T_base_link_zed_left_camera · 米
[
  [-0.001383713, -0.636266468,  0.771468125,  0.089057487],
  [-0.999930277, -0.008166772, -0.008529010,  0.023881859],
  [ 0.011727127, -0.771426138, -0.636210805,  1.170447698],
  [ 0.000000000,  0.000000000,  0.000000000,  1.000000000]
]

上传 URDF 中的名义外参

每行是文件中存储的父子关节原点。两份文件均包含头部和 EE 条目;夹爪和腕部相机安装条目位于 vega_1u_gripper.urdf。

Parent → childXYZ(m)RPY(rad)
head_l3 → zed_depth_frame0.025 0.023 0.0489-1.57079 0 -1.57079
head_l3 → zed_left_camera0.0365 0.023 0.0489-1.57079 0 -1.57079
head_l3 → zed_right_camera0.0365 -0.027 0.0489-1.57079 0 -1.57079
L_arm_l8 → L_ee0 0 00 0 -1.57079
R_arm_l8 → R_ee0 0 00 0 1.57079
L_arm_l8 → L_gripper_base0.0 0 0.08250 0 -1.5708
L_gripper_base → L_camera_link0.0002 -0.07459 0.0017504-0.087266 0 0
R_arm_l8 → R_gripper_base0 0 0.08250 0 -1.5708
R_gripper_base → R_camera_link0.0002 -0.07459 0.0017504-0.087266 0 0

在上述相同参考关节位置下,通过软件包 URDF 正运动学计算出的名义头部变换如下:

URDF FK · T_base_link_zed_left_camera · 米
[
  [-0.000165524, -0.668606938,  0.743615987,  0.084498283],
  [-0.999999986,  0.000085701, -0.000145537,  0.024989645],
  [ 0.000033578, -0.743616000, -0.668606942,  1.144781202],
  [ 0.000000000,  0.000000000,  0.000000000,  1.000000000]
]

URDF 腕部相机安装变换

上传的夹爪 URDF 包含两侧腕部相机 link。连乘固定关节后得到:

URDF · T_L_ee_L_camera_link · 米
[
  [ 1.000000000,  0.000009962,  0.000000872,  0.000199254],
  [-0.000010000,  0.996194738,  0.087155282, -0.074590002],
  [ 0.000000000, -0.087155282,  0.996194738,  0.084250400],
  [ 0.000000000,  0.000000000,  0.000000000,  1.000000000]
]
URDF · T_R_ee_R_camera_link · 米
[
  [-1.000000000,  0.000002643,  0.000000231, -0.000200198],
  [-0.000002654, -0.996194738, -0.087155282,  0.074589999],
  [ 0.000000000, -0.087155282,  0.996194738,  0.084250400],
  [ 0.000000000,  0.000000000,  0.000000000,  1.000000000]
]

这些是名义 camera_link 安装坐标系。文件没有单独定义腕部光学坐标系,也没有给出经实测确认的 ISX031 光学坐标变换。旧任务中“夹爪 URDF 没有腕部相机 link”的结论不适用于这次上传的文件。

单独的自定义对照模型中的关节原点

该模型头部父坐标系是 vega_1u_head_l3,软件包模型则为 head_l3;对比时应使用完整坐标链,不能只比较局部 XYZ/RPY。

Parent → childXYZ(m)RPY(rad)
L_ee_link_gripper_link → tip_l0 -0.015 0.1983.1415927 -0. 1.57079
R_ee → R_ee_link_gripper_link0.0000001 -0.0000001 -0.00000010.0000062 0. 0.0000062
R_ee_link_gripper_link → tip_r0 -0.015 0.1983.1415927 -0. 1.57079
vega_1u_head_l3 → zed_left_camera0.0365 -0.023 -0.04891.5707963 -0.0000062 3.1415863
vega_1u_head_l3 → zed_depth_frame0.025 -0.023 -0.04891.5707963 -0.0000062 3.1415863
vega_1u_head_l3 → zed_right_camera0.0365 0.027 -0.04891.5707963 -0.0000062 3.1415863
—

资料来源

Wiki · 连接 Vega

三种连接方式、热点凭据、nmcli 配置、通信协议

Wiki · 软件配置

证书与固件、socbridge、dextop 诊断、dexcontrol 和 dexsensor 安装与配置

Wiki · 基本概念

ROBOT_NAME 和 ROBOT_CONFIG、三个型号的命名约定

Wiki · 传感器与控制

关节、力矩、相机和 LiDAR 读取;头/臂/手/躯干/底盘控制;底层底盘危险操作列表

支持工单 #126892650

2026-08-21 → 08-26,与 Dexmate 的 Rahul 沟通:重刷后四个步骤、ZED SDK 5.2.3 安装器、 ZED_Explorer -a、通过 socbridge 查找机器人名称

相机集成 · 2026-09-15

本地相机共存归档:成功的并发采集、已安装的 WristCameras API、default-camera README 和 initrd 验证。新默认配置的冷启动仍待测试。

我们自己的调试

2026-08-25 → 09-07:内核降级、CAN 总线初始化、dexsensor 配置、17 自由度验证、夹爪险情