A 部分
每次使用
机器人已配置并运行。以下是日常使用所需的操作。
当前连接方式
当前配置这台机器人已经完成配置。不需要重复 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'
一次完整的使用流程
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
以上就是全部必需步骤。下面按任务选择——只启用即将使用的子系统。
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() 都会把头部移动到 home,而且没有参数可以阻止——因此 inspect_joints.py 及任何创建会话的脚本都会移动头部。如果只需要图像,请使用 ~/py_scripts/sensor_only.py,它直接构造 Sensors() ,完全不发布控制话题。详见 A2.
只有三类操作在以下配置中免密: 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 无响应时,按从易到难的顺序尝试:
- 扫描子网:
nmap -sn 172.26.160.0/22 | grep -B2 -A2 "vega\|dexmate\|ubuntu" - 接网线,使用固定有线地址
192.168.50.20,它不会变化。 - 将显示器和键盘接到 IO hub,从桌面查看地址。
IP 变化不代表需要重新配置。证书、机器人名称、固件和库都保存在机器人上,不受地址变化影响——只需更新 ROBOT_IP (如果导出了该变量)以及 SSH 连接目标。
改用工作站运行
目前所有代码都在机载计算机运行。也可以从自己的电脑控制机器人,但需要单独完成一次配置—— dextop、在本地解压同一份证书,并设置环境变量——详见 B5。这样能使用更好的 GPU,代价是增加网络延迟。
读取传感器数据
头部相机由现有的 dexsensor 服务发布。两路原装腕部相机使用本地 WristCameras Python API,可以同时读取。下面的纯传感器示例不构造 Robot(),避免触发头部归位。配置见: B8.
关节、电流、力矩、按钮——不需要 dexsensor
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 相机。
export ROBOT_NAME=dm/vg3eb20f25bb-1u
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.
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 为空,因为流已经过校正:
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 · ZedXMinicv2.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 绑定。
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_ns | GStreamer 管线显示时间戳(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运行。腕部上下文获取两路相机时,现有的头部发布服务继续运行。
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 图像前,先转换:
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 秒后开始录像;不发送运动命令。先关闭其他腕部读取进程。
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 腕部相机配置步骤。启动自定义发布器前,先停止占用同一相机的已有发布器。本机正常读取头部相机时使用上述运行中的服务。
dexsensor gen-cfg # writes to ~/.dexmate/sensors/
dexsensor launch --config ~/.dexmate/sensors/default_config.yaml除了各传感器的 enabled 开关,配置文件还可调整分辨率、帧率、深度范围、传输方式(rtc 或 zenoh)以及 JPEG 质量,以便在图像质量和带宽之间取舍。
控制机器人
手放在急停按钮旁。机械臂和躯干采用位置控制,轮子采用速度控制,而 终止程序会停止运动 ——这是最快的软件制动方式。
头部——3 自由度,但顺序为俯仰/偏航/俯仰
已通过 URDF 正运动学验证: head_j1 是 俯仰, head_j2 是 偏航, head_j3 是 第二个俯仰轴。负的 head_j3 表示向下看——厂商自己的 tucked 位姿为 [0, 0, -1.37],遵循相同约定。 fy = 734.72 px/rad 也可用作俯仰角到像素的比例,因此俯仰误差 Δθ 会让图像移动 734.72·Δθ 像素。
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() 会话。
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 自由度,关节空间控制
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 即进入实时控制:此后必须持续调用 set_joint_pos ,频率为 100–500 Hz。调用频率过低会导致电机响应不足。
手、躯干、底盘
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()
set_velocity, set_motion_state, set_steering_angle 和 set_wheel_velocity 可能 永久损坏轮毂电机:在转向角让轮子彼此相向时命令前进、轮速与当前转向冲突,或同时快速改变两者。请使用 move_straight / move_sideways / turn.
软件急停
robot.estop.activate() robot.estop.deactivate()
它补充实体急停按钮的功能,不能替代实体按钮。
安全地切换位姿
本机两个命名位姿、两个脚本。要记住:碰撞风险在于 运动顺序,而不在目标位姿。
两个 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 以夹爪闭合状态绘制; folded 以夹爪张开状态绘制,计算结果为两个夹爪相接触。| 运动过程中的最小夹爪间距 | 同时运动 | 左臂先动 | 右臂先动 |
|---|---|---|---|
pre_move → manip_init | 0.259 m | 0.330 m | 0.367 m |
manip_init → pre_move | 0.259 m | 0.367 m | 0.330 m |
pre_move → folded | 0.052 m | 0.052 m | 0.052 m |
顺序运动在工作位姿切换中多提供 7–11 cm 的间隙,因此 goto_ready.py 和 goto_rest.py 采用相反的先动机械臂。顺序运动的额外收益为 零 在 folded三种顺序都降到约 5 cm,因为碰撞发生在 目标位姿本身,而不是路径上。
| 位姿终点的间隙 | 夹爪闭合 | 夹爪完全张开 |
|---|---|---|
pre_move | 0.367 m | 0.298 m |
manip_init | 0.436 m | 0.333 m |
folded | 0.050 m | 0.000 m——接触 |
夹爪张开时, 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,约与肩部等高。
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 采用第一次出现的参数,而用户参数排在前面。
vega_1u.urdf 的碰撞网格和正运动学渲染。左臂为青色,右臂为铁锈色;虚线表示腕间距。URDF 未包含夹爪,因此真实夹爪间隙小于图中值——这正是 folded 通过碰撞检查却仍损坏线缆的原因。为什么机械臂要逐一运动
不同运动顺序下的路径最小腕间距:
| 方向 | 同时运动 | 左臂先动 | 右臂先动 |
|---|---|---|---|
pre_move → manip_init | 0.354 m | 0.431 m | 0.459 m |
manip_init → pre_move | 0.267 m | 0.459 m | 0.434 m |
同时运动会使腕部在路径中途交错。双臂同时回到 pre_move 时,间距会降到 0.267 m ——比曾导致断线的 0.31 m 更小。逐臂运动仅使总时间翻倍,所以任何大幅双臂转移都应 默认采用 --seq 。
间隙保护
goto_pose.py 模拟实际运动经过的全部路点——采用实际循环相同的逐关节限幅和左右臂顺序——以 URDF 正运动学计算各点腕间距,并抛出 SystemExit ,如果任一路点低于 MIN_WRIST_SEP (0.35 m,可通过 --min-sep覆盖)。以下标定点均来自实际结果:
| 位姿/路径 | 间距 | 结果 |
|---|---|---|
folded | 0.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),因为双臂垂直向上,但这是不稳定平衡,且可能下落的距离最大。
收尾
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 运行是可以的。
控制夹爪
本机夹爪 不 属于 dexcontrol——机器人报告的手类型为 UNKNOWN,因此 robot.left_hand 不起作用。它们是共享 CAN 总线的两台 MG4005-i10 V3 伺服电机,由 /home/dexmate/gripper.py封装,与普通机械臂控制并行使用。接线、总线速率和协议考证见 C3;本节介绍库的使用方式。
自 2026-09-07 起,电机 1(左)不响应 CAN。换线测试已确认:使用右夹爪的正常线缆后, 0x141 立即响应,因此 电机正常,左侧线缆内部有导体断裂 ——外皮看起来完好,原因是 folded 机械臂位姿让两个夹爪交叉。在更换线缆前,下述操作仅适用于 右夹爪。库支持降级运行:探测两台电机,只驱动有响应的电机。
先确保总线已启动
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 为张开。原始角度只在库内部使用。 |
正常使用流程
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 命令,然后轮询两台电机 | 双夹爪运动的默认方式 |
这样会串行运行:完整行程需要 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 ms | L4T 降级并重编译 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 运行是可以的。
两个库使用陷阱
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 | 探测两台电机,对有响应的电机归零并循环开合。 检查左侧断线时应使用这个脚本,因为它能降级为单电机运行 |
常见问题:症状 → 实际原因
按最先看到的现象排序。多数问题没有文档记录,都是实际排查得到的。
这是 断路,不是短路。CAN_H/CAN_L 短路会产生大量错误帧,使正常电机也掉线;总线正常而单节点沉默,表示该节点未电气接入总线。把正常线缆换到无响应夹爪——如果恢复响应,就是线缆故障。不必追查短路损坏。
那些是 错误帧,不是设备。只根据 data != query 过滤会把它们算成回复。应跳过 m.is_error_frame ,先完成这一步。
每次 Robot() 都会把头部移动到 home 且没有参数能阻止(robot.py:353 → robot.py:424)。所属进程退出后,头部还会从 -0.5056 松弛到约 -0.13 rad。保持会话存续;若只需图像,直接使用 Sensors() 。
gripper.py 在对离线电机归零—— angle() 返回了 None。已修补: Motor.alive() / _require_alive() 现在会明确报告实际问题,而且 Grippers.home() 会跳过离线电机,而非中止在线电机。
相机输出 RGB; cv2 需要 BGR。请用 cv2.COLOR_RGB2BGR转换。PIL 无需转换。
ROBOT_NAME 被写成了 dm-<serial>。真正的 Zenoh key 使用 dm/vg3eb20f25bb-1u/... — 斜杠. topic list 通过并不代表名称正确。
dextop cert unpack 需要把证书路径作为参数。
无法路由到 192.168.50.21。可能是重刷系统清除了 enP8p1s0 上的静态 IP(恢复 192.168.50.20/24),或是在外部电脑上没有运行 sshuttle 。
安装到 ~/.local/bin,不在 root 的 PATH 中。请使用 sudo -E $(which dextop) ….
dextop node install-service 已经启动了节点。无害,忽略即可。
是内核版本不匹配,不是缺少驱动。检查 /dev/video*, zed_x_daemon 和解串器模块;本机通过将 L4T 36.5.2 降到 36.5.0(内核 5.15.199 → 5.15.185)解决。
dexsensor 0.7.6 基于 ZED SDK 5.2.2 构建,目前运行于 5.2.3。只是警告。
C++ 标准库不匹配: conda update -c conda-forge libstdcxx-ng -y.
字段名是 enabled,不是 enable,写错会静默失败; configs.sensors 是字典,不是对象。另外, dexsensor launch 必须在 Jetson 上运行。
depth_mode 和 [sensors.streams] depth 是两个独立开关;两者必须开启,服务层面还要设置 enabled = true 。 dexsensor enable 只在运行时生效,重启后丢失。
相机输出 RGB。OpenCV 需要 BGR——添加 cv2.COLOR_RGB2BGR转换。PIL 无需转换。
夹爪采用查询应答,不主动广播,因此空的 candump 不能说明问题。确认总线为 1 Mbit/s,且 R120 已关闭。
典型原因是 CAN_H/CAN_L 接反——连错误帧也没有。另一种可能是内核更换后 gs_usb.ko 无法加载,需要重新编译。
使用了 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 中的工作站配置适用于使用外部电脑的情况。
夹爪硬件连接
一次性配置1. 连接 assembled 线束
组装好的线束一头是 CAN adapter,两侧分支各有一组 4-pin/6-pin 接口。两侧均将 6-pin 接夹爪,4-pin 接机器人。
2. 连接腕部相机线
相机线也要连接,只接偏向内部的一边,位置见 IMG_9360。

3. 连接 USB,并设置两个开关
CAN adapter 插入机器人的 USB 口。两个开关都一定要拨向 K 那边,见 IMG_9369。

整体连接示例

PCB 与相机硬件安装
一次性配置参考:Waveshare MAX9296-GMSL-Deser-Module · Jetson Orin。改线前先断电。
1. 安装采集卡并连接电源
用 kit 自带的铜柱连接采集卡和 PCB,然后接电。红线接 排针 2、4(5 V),地线接 6(GND)。这里是 Jetson 的 5 V 排针,不能接夹爪的 24 V 电源。


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

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

4. 连接内部腕部相机线
- 拿到母母线:直接拆开内部连接腕部相机的连线,连接到采集卡。
- 拿到公母线:把机器人后盖上接外部相机的接口拆下,用公母线直连。IMG_9277 walkthrough 演示的就是这种接法。
5. 更换 CAM1 排线
拆下原来接在 Jetson CAM1 上的线,使用 kit 自带的排线连接 Jetson CAM1 ↔ 采集卡 CSI0。


保存好从机器人拆下来的所有零件,包括原装铜柱、接口和线缆,之后归还机器人时还需要使用。
让机器人连接网络
已完成 · 一次性没有已知 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}_hotspot | 12345678 | 192.168.4.1 |
| 2026 年 1 月之后 | dexmate-{mac} | dexmate123 | 10.42.0.1 |
开机后等 2–3 分钟再寻找热点。SSH 凭据始终是 dexmate / hello-dex.
ssh dexmate@10.42.0.1
加入自己的 WiFi
# see what's around
timeout 5 sudo iw dev wlP1p1s0 scan > /tmp/scan_results
nmcli device wifi listsudo nmcli device wifi connect "YourNetworkName" password "YourPassword"
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,重启路由器并确认地址不与其设置冲突。
证书与固件——每台机器人一次
已完成 · 一次性请到 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
- 打开
https://192.168.50.21:57832。首次访问会要求设置密码——请记住它。 - 先升级管理页面本身 (Check for Updates)。如果失败,从 software.dexmate.ai 下载 socbridge 文件并手动上传。
- 在通信部分上传 Dexmate 签发的证书。
- 如果需要,也在同一页面更新固件。
2026 年 3 月前出厂的机器人可能完全没有 socbridge——在 Jetson 上使用以下命令安装: dextop firmware install-socbridge. 该命令需要能路由到 192.168.50.21;如果重刷系统清除了 enP8p1s0 上的静态 IP,它只会输出 Failed to connect to SOC: timed out.
方式 2 · 命令行(仅适用于已安装有效证书)
dextop firmware info # per-board version table dextop firmware update # prompts for the version to install
上传并安装 robot-server 文件 → 重启机器人 → 管理页面重新可访问后,再上传并安装固件文件。低于 0.5.0 的版本只需上传一次。
保持版本一致:固件 0.4.3 需要 dextop==0.4.6;固件 ≥ 0.4.3 时,将 dextop, dexcontrol 和 dexsensor 一起更新到最新版本。
工作站通信
工作站设置如果只在机载计算机运行代码,可跳过本节。从自己的电脑控制机器人时,工作站必须加入同一 Zenoh 总线。
pip install dextop --upgrade
dextop cert unpack <certificate_file>.dzcfg
dextop cert unpack 需要传入证书路径;不带参数只会返回 Missing argument 'PACKAGE_FILE'。妥善保存证书——它赋予控制机器人的权限。
dextop node install-service
低于 0.5.0 时中继需手动启动并持续运行,因此放在 tmux 中:
tmux new -s relay
dextop node start # then Ctrl+B, D to detachinstall-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 ——一台工作站就能控制全部机器人。
安装 dexcontrol 和 dexsensor
已完成 · 一次性dexcontrol——控制
pip install dexcontrol
开源示例位于 github.com/dexmate-ai。Dexmate 建议先运行 examples/advanced_examples/fold_robot.py 来展开新机器人—— 不要在本机运行它;见常见问题对照表。
dexsensor——感知,仅限 Jetson
从 software.dexmate.ai 下载正确架构(Jetson 使用 arm64),然后执行:
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 警告——无害。
验证与诊断
随时可用编写代码前先运行这些检查。先确认连接正常,能避免反复猜测“是脚本还是机器人出了问题”。
dextop topic list --timeout 10
外部电脑首次调用常常没有返回——dextop 需要一些时间连接机器人。再运行一次或增加超时。
| 命令 | 何时使用 |
|---|---|
dextop doctor check | 机器人行为异常时首先运行;报告硬件层面问题 |
dextop doctor restart | doctor 标记机器人服务器异常时(固件更新后常见),用于干净地重启 |
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 表格。该表列出固件包条目,并非本机实际具有的关节(见下文)。
头部+腕部相机配置
记录于 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 路径属于原来的安装。
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。
sudo systemctl daemon-reload sudo systemctl enable dexsensor.service wrist-camera-init.service
检查启动项后手动重启。若只需要在本次开机中启动或重新初始化相机,先关闭腕部读取程序及独立 ZED 查看器,再执行下方命令。它们会中断相机流,不会重启机器人;新选中的内核 overlay 仍需重启后才能生效。
sudo systemctl restart wrist-camera-init.service sudo systemctl restart dexsensor.service
相机不工作时怎么排查
先在 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 53756133 | ZED 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 发现机制,不要硬编码索引。电源灯亮不能证明收到图像;需要下方取流测试。
已安装的启动和初始化链路
/boot/extlinux/extlinux.conf选择DEFAULT HeadWrists,加载/boot/tegra234-head-wrists.dtbo和/boot/initrd-head-wrists-default.- initrd 在模块加载前,通过只读 bind mount 提供修补后的
tegra-camera.ko和isx031-gmsl-camera-b.ko。原内核、基础 DTB、磁盘上的模块和/boot/initrd均保留。 - 已启用的
wrist-camera-init.service等待两路腕部探测完成,执行相机专用初始化,并写入/run/wrist-cameras/ready.json。它是 oneshot:active (exited)且退出状态为 0 属于正常情况。它跳过旧的单相机回退配置。 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 升级后,都应重新编译/检查自定义模块。
就绪状态与恢复检查
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 取流不提供必需的软件触发。
若需重新初始化相机,先关闭所有腕部读取进程,然后运行:
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:
f449a4ea16dc1bda7a0ce3dc6508c82472faf07e6b02e7b31cd102d72eedad69
实测结果与限制
| 测试路径 | 观测速率 | 含义 |
|---|---|---|
| 头部左右 RGB,HD1200 | 各 15.105 fps | 20 秒并发原始采集测试中,新订阅帧的速率。 |
| 头部 NEURAL 深度,HD1200 | 15.054 fps | 实测发布速率;配置值为 30 fps。 |
| 腕部 A/B,原生 UYVY | 9.327 / 9.293 fps | 独立软件触发;完整 1920×1536 缓冲区。 |
| 全分辨率 RGB 腕部 API+头部订阅 | 5.80 对/秒 | 单进程中 25 次成对 API 读取;包含转换/复制开销。 |
| 45.020 秒四视角运动演示 | 236 帧;预览 5.24 fps | API 采集加合成/录像;不是传感器原生帧率。 |
原始测试有 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/外参参考。
架构:一条 Zenoh 总线上的三个库
参考每个 Dexmate 组件都通过 Zenoh通信,使用同一份加密证书认证。了解各库应该运行在哪台机器上,是后续步骤的前提——装错位置最容易白费半天。
| 组件 | 运行位置 | 安装方式 | 作用 |
|---|---|---|---|
dextop | Jetson 和 工作站 | pip install dextop --upgrade | 证书、固件、机器人服务器、话题列表、健康检查 |
dexcontrol | 控制代码所在的机器 | pip install dexcontrol | Robot() API:机械臂、头部、手、躯干、底盘、急停 |
dexsensor | 仅 Jetson | sudo dpkg -i dexsensor_*.deb | 相机和 LiDAR 采集与推流;依赖 ZED SDK |
dexbot_utils | 随 dexcontrol 安装 | — | 机器人配置、URDF、 dexbot cfg list |
| socbridge | 机器人的 SoC 板 | dextop firmware install-socbridge | Web 管理页面位于 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/**,因此它 不 能作为名称正确性的有效检查。
这台机器人实际具有的组件
参考 · 本机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_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 条目都视为未经本硬件验证;根据腕部周围的真实间隙判断收纳位姿,而不是重力力矩或厂商给位姿起的名字——低力矩位姿仍可能碰撞。
运行时事实不变:没有躯干组件,没有 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.py | pre_move → manip_init,右臂先动 |
~/py_scripts/goto_rest.py | manip_init → pre_move,左臂先动 |
~/py_scripts/goto_pose.py | 两者共用的执行引擎:命名位姿、限位裁剪、分步运动、 --seq, --min-sep, --dry-run、夹爪间隙保护,以及对 folded 的禁用 |
~/py_scripts/head_pose.py | read_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;无需密码。
夹爪 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 固件无法绕过这个问题。内核头文件存在,可以进行树外编译:
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 可使其自动持续生效。
Jetson 重刷系统后的恢复
仅在重刷系统后2026-08-25,本机重刷为 JetPack 6.2.3,清除了全部 Dexmate 出厂配置:ZED SDK、dexsensor、dextop、Zenoh 证书以及 enP8p1s0上的静态 IP。Dexmate 没有 提供重刷后的恢复流程。下面是工单 #126892650 中 Rahul 给出的四个步骤,以及我们为完成恢复自行摸索的内容。
安装 ZED SDK
运行 ZED_SDK_Tegra_L4T36.5_v5.2.3.zstd.run (在 Jetson 上)。使用 /usr/local/zed/tools/ZED_Explorer -a 确认能看到相机。
安装 dexsensor
sudo dpkg -i dexsensor_0.7.6_arm64.deb.
安装 dextop 并设置机器人名称
pip install dextop sudo -E $(which dextop) robot set_name dm/vg3eb20f25bb-1u
名称来自底盘铭牌贴纸。贴纸不在时,从 socbridge 读取或从旧日志查找。
解压证书
dextop cert unpack <file>.dzcfg ——必须带文件名参数。
安装 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 ,先完成这一步。
使内核与已安装的相机驱动匹配
本机使用 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 都不匹配。
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 。
硬件与控制信息
来自「整理 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 |
| 头部 IMU | 186–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
TCP、相机外参与 URDF 文件
标定记录来自「暂存代码并重新标定区域」任务。该任务在 9 月 24 日最终恢复了 clean 提交 b90bcac 的 TCP/相机组合。原始 pivot 实测拟合值和此前调整 Y 后的组合在下方分别列出。
文件
- vega_1u.urdf · 上传的机器人模型。
- vega_1u_gripper.urdf · 上传的夹爪模型,包含
L_camera_link和R_camera_link。 - 标定项目中的自定义夹爪 URDF · 另一份包含
tip_l/tip_r的模型,用于名义 TCP 对照。 - Clean TCP+相机标定 · 此前调整 Y 的组合 · Pivot 实测拟合结果。
- 全部矩阵、源文件校验值及坐标系定义(JSON)。
两份上传的 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 数据针对右夹爪。
[ [ 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 之间的全部固定关节,是模型值,不是左右夹持中心的实测值。
[ [ 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] ]
[ [-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
[ [-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/相机组合
[ [ 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] ]
[ [-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 → child | XYZ(m) | RPY(rad) |
|---|---|---|
head_l3 → zed_depth_frame | 0.025 0.023 0.0489 | -1.57079 0 -1.57079 |
head_l3 → zed_left_camera | 0.0365 0.023 0.0489 | -1.57079 0 -1.57079 |
head_l3 → zed_right_camera | 0.0365 -0.027 0.0489 | -1.57079 0 -1.57079 |
L_arm_l8 → L_ee | 0 0 0 | 0 0 -1.57079 |
R_arm_l8 → R_ee | 0 0 0 | 0 0 1.57079 |
L_arm_l8 → L_gripper_base | 0.0 0 0.0825 | 0 0 -1.5708 |
L_gripper_base → L_camera_link | 0.0002 -0.07459 0.0017504 | -0.087266 0 0 |
R_arm_l8 → R_gripper_base | 0 0 0.0825 | 0 0 -1.5708 |
R_gripper_base → R_camera_link | 0.0002 -0.07459 0.0017504 | -0.087266 0 0 |
在上述相同参考关节位置下,通过软件包 URDF 正运动学计算出的名义头部变换如下:
[ [-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。连乘固定关节后得到:
[ [ 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] ]
[ [-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 → child | XYZ(m) | RPY(rad) |
|---|---|---|
L_ee_link_gripper_link → tip_l | 0 -0.015 0.198 | 3.1415927 -0. 1.57079 |
R_ee → R_ee_link_gripper_link | 0.0000001 -0.0000001 -0.0000001 | 0.0000062 0. 0.0000062 |
R_ee_link_gripper_link → tip_r | 0 -0.015 0.198 | 3.1415927 -0. 1.57079 |
vega_1u_head_l3 → zed_left_camera | 0.0365 -0.023 -0.0489 | 1.5707963 -0.0000062 3.1415863 |
vega_1u_head_l3 → zed_depth_frame | 0.025 -0.023 -0.0489 | 1.5707963 -0.0000062 3.1415863 |
vega_1u_head_l3 → zed_right_camera | 0.0365 0.027 -0.0489 | 1.5707963 -0.0000062 3.1415863 |
资料来源
三种连接方式、热点凭据、nmcli 配置、通信协议
证书与固件、socbridge、dextop 诊断、dexcontrol 和 dexsensor 安装与配置
ROBOT_NAME 和 ROBOT_CONFIG、三个型号的命名约定
关节、力矩、相机和 LiDAR 读取;头/臂/手/躯干/底盘控制;底层底盘危险操作列表
2026-08-21 → 08-26,与 Dexmate 的 Rahul 沟通:重刷后四个步骤、ZED SDK 5.2.3 安装器、 ZED_Explorer -a、通过 socbridge 查找机器人名称
本地相机共存归档:成功的并发采集、已安装的 WristCameras API、default-camera README 和 initrd 验证。新默认配置的冷启动仍待测试。
2026-08-25 → 09-07:内核降级、CAN 总线初始化、dexsensor 配置、17 自由度验证、夹爪险情