> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wuji.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# ROS 2 集成

通过 `wuji_hand2_driver` 接入设备后，可读取关节与传感器状态、在 RViz 中查看模型，并通过关节命令和服务控制设备。

## 安装

使用已安装 ROS 2 Lyrical 的 Ubuntu 26.04（resolute），支持 x86\_64 和 aarch64。以下命令获取源码、加载 ROS 环境、安装依赖及 Hand 2 模型，并构建工作区。构建时会自动下载并校验适配当前架构的 Wuji SDK C 包。

```bash theme={null}
# 获取源码并加载 ROS 2 环境
git clone https://github.com/wuji-technology/wuji-ros2.git "$HOME/wuji-ros2"
cd "$HOME/wuji-ros2"
source /opt/ros/lyrical/setup.bash
# 安装构建工具和依赖
sudo apt-get update
sudo apt-get install -y ros-dev-tools
rosdep update
# 安装 Hand 2 模型与工作区依赖
scripts/install_hand2_descriptions.sh
rosdep install --from-paths . --ignore-src -r -y
# 构建工作区。SDK C 包会自动下载并校验
colcon build --cmake-args -DBUILD_TESTING=OFF
# 加载构建结果
source install/setup.bash
```

> [!NOTE]
>
> * 模型安装脚本要求 `/etc/apt/sources.list.d/ros2.sources` 存在。若文件缺失，先按 ROS 2 官方安装流程配置 Lyrical 软件源，再重新运行脚本。
> * 若电脑从未初始化 rosdep，在 `rosdep update` 前执行一次 `sudo rosdep init`。`sudo` 命令需要管理员权限。
> * 若 SDK 下载失败，从 [Wuji SDK v2026.10.12](https://github.com/wuji-technology/wuji-sdk/releases/tag/v2026.10.12) 下载 `wuji-sdk-c-2026.10.12-x86_64-linux-gnu.tar.gz` 或 `wuji-sdk-c-2026.10.12-aarch64-linux-gnu.tar.gz`，按主机架构选择并解压，确认目录包含 `include/wuji_sdk.h`、`lib/libwuji_sdk_c.so` 和 `LICENSE`。将 `/path/to/sdk` 替换为解压目录的绝对路径，在 `wuji-ros2` 目录运行以下命令代替默认构建命令：
>
>   ```bash theme={null}
>   colcon build --cmake-args -DBUILD_TESTING=OFF -DWUJI_SDK_ROOT=/path/to/sdk
>   ```
> * 使用 `WUJI_SDK_ROOT` 时，CMake 不校验 SDK 版本，请使用上述指定发行包。

后续每个新终端均需进入工作区并加载 ROS 环境与构建结果：

```bash theme={null}
cd "$HOME/wuji-ros2"
source /opt/ros/lyrical/setup.bash
source install/setup.bash
```

## 选择设备

完成[机械集成](https://docs.wuji.tech/docs/zh/wuji-hand/latest/hardware-integration.md)中的设备固定和[电气与网络集成](https://docs.wuji.tech/docs/zh/wuji-hand/latest/electrical-network-integration.md)中的供电、网络配置。确认满足[用户须知](https://docs.wuji.tech/docs/zh/wuji-hand/latest/user-notice.md)中的操作要求后，运行以下命令扫描设备：

```bash theme={null}
ros2 run wuji_tools wuji_list
```

记录目标设备必填的 `serial_number` 和 `hand_side`。需要按地址连接时，同时记录可选的 `endpoint`。

| 参数 | 作用 |
| - | - |
| `serial_number` | 选择目标设备。指定 `endpoint` 时用于校验身份 |
| `hand_side` | 选择左手或右手模型，并校验设备手别 |
| `endpoint` | 按 `IP:端口` 网络地址直接连接设备 |

## 查看模型与状态

### 运行验证

**1. 启动驱动并查看模型**

将 `HAND_SERIAL_NUMBER` 和 `HAND_SIDE` 分别替换为[选择设备](#选择设备)中记录的序列号和手别。

运行已构建的 `wuji_bringup` 包中的 `hand2_view.launch.py`，启动驱动、`robot_state_publisher` 和 RViz：

```bash theme={null}
ros2 launch wuji_bringup hand2_view.launch.py \
  serial_number:=HAND_SERIAL_NUMBER hand_side:=HAND_SIDE \
  model_revision:=2 namespace:=hand
```

若需按扫描结果中的 `endpoint` 连接，将 `HAND_ENDPOINT` 替换为该 `IP:端口` 地址，改用以下命令：

```bash theme={null}
ros2 launch wuji_bringup hand2_view.launch.py \
  serial_number:=HAND_SERIAL_NUMBER hand_side:=HAND_SIDE \
  endpoint:=HAND_ENDPOINT model_revision:=2 namespace:=hand
```

> [!NOTE]
>
> 驱动等待设备连接的超时时间默认 10 秒。在启动命令末尾添加 `connect_timeout:=20.0`，可将连接等待时间延长至 20 秒。启动参数仅在启动时读取，布尔参数仅接受小写 `true` / `false`。

该启动文件要求传入 `serial_number`，并将 `auto_enable` 固定为 `false`。启动时不主动使能关节，也不会将此前已使能的手切换为失能。停止 launch 时，驱动调用失能接口关闭全部关节。调用失败时记录警告并继续退出，应确认设备实际停止。

`model_revision:=2` 选择 `wuji_hand2_2_description`。模型根坐标系为左手 `l_mount` 或右手 `r_mount`，RViz 使用对应根坐标系。模型资产与根连杆定义见[模型资产与加载](https://docs.wuji.tech/docs/zh/wuji-hand/latest/model-integration.md)。集成到机器人时，由上层应用补充安装座到机器人或世界坐标系的 TF。

**2. 检查状态数据**

保持 launch 运行。新开终端，进入工作区并加载 ROS 环境与构建结果后运行状态示例：

```bash theme={null}
cd "$HOME/wuji-ros2"
source /opt/ros/lyrical/setup.bash
source install/setup.bash
ros2 run wuji_bringup hand2_status_demo --ros-args -r __ns:=/hand
```

示例默认观察 10 秒，统计 `joint_states`、`joint_diagnostics` 和 `imu` 的接收帧数与平均接收率。成功条件是收到至少 1 帧包含 20 个位置的关节状态、1 帧包含 20 个条目的关节诊断和 1 帧 IMU 数据。检查结果不代表运动控制或全部传感器已通过验收。

示例在完整观察时长结束后输出 PASS/FAIL。需要观察 30 秒时使用：

```bash theme={null}
ros2 run wuji_bringup hand2_status_demo --ros-args -r __ns:=/hand -p duration:=30.0
```

> [!NOTE]
>
> 如果驱动已连接设备，但 RViz 显示 `No tf data` 或状态示例收不到数据，先核对各终端的 namespace、`ROS_DOMAIN_ID` 和 QoS。仍有问题时，再尝试切换 ROS 2 中间件。安装 Cyclone DDS：
>
> ```bash theme={null}
> sudo apt-get install ros-lyrical-rmw-cyclonedds-cpp
> ```
>
> 停止当前 launch。在运行步骤 1 和步骤 2 的两个终端中，分别执行：
>
> ```bash theme={null}
> export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
> ```
>
> 然后重新运行步骤 1 和步骤 2 的命令。后续新开的终端也要设置相同的 ROS 2 中间件。

### 状态与传感器 Topic

驱动通过下表的 Topic 发布关节状态、关节诊断和 IMU 数据。订阅时使用表中消息类型。Topic 名称均为相对名称，例如 `namespace:=hand` 下的 `joint_states` 对应 `/hand/joint_states`。

| Topic | 消息类型 | 内容 |
| - | - | - |
| `joint_states` | `sensor_msgs/msg/JointState` | 有效关节的位置（rad）、速度（rad/s）与电流（A）。`effort` 为电流，不是实测力矩。按 `name` 识别关节 |
| `joint_diagnostics` | `wuji_msgs/msg/JointDiagnosticsArray` | 在线关节的原始 SDK 状态字、故障码、电流、电压、温度和通信统计，不是标准 ROS `/diagnostics` 接口 |
| `imu` | `sensor_msgs/msg/Imu` | 角速度和线加速度。不提供姿态估计，`orientation_covariance[0] = -1` |

> [!NOTE]
>
> 消息字段定义见 `wuji-ros2` 仓库的 `wuji_msgs/msg/JointDiagnosticsArray.msg` 和 `wuji_msgs/msg/JointDiagnostics.msg`，以及 ROS 2 的 [JointState.msg](https://github.com/ros2/common_interfaces/blob/lyrical/sensor_msgs/msg/JointState.msg) 和 [Imu.msg](https://github.com/ros2/common_interfaces/blob/lyrical/sensor_msgs/msg/Imu.msg)。加载工作区后，运行 `ros2 interface show wuji_msgs/msg/JointDiagnosticsArray` 可查看自定义消息及其嵌套字段。

## 控制设备

驱动直接发送位置、速度和电流代理目标，不自动切换控制模式。运动行为取决于设备当前的控制模式与参数。

### 发送关节命令

**1. 启动驱动**

停止 [1. 启动驱动并查看模型](#start-driver-view-model) 时启动的 view launch。固定空载手，确认运动空间内无人。沿用前述序列号和手别启动控制流程：

```bash theme={null}
ros2 launch wuji_bringup hand2.launch.py \
  serial_number:=HAND_SERIAL_NUMBER hand_side:=HAND_SIDE \
  model_revision:=2 namespace:=hand auto_enable:=true
```

`auto_enable:=true` 在启动后使能全部关节，此时尚未发送运动目标。

**2. 检查当前位置**

保持驱动运行。新开终端。

> [!NOTE]
>
> 驱动使用 Cyclone DDS 时，在本终端配置相同的 ROS 2 中间件：
>
> ```bash theme={null}
> export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
> ```

执行以下命令，加载 ROS 环境并读取关节位置：

```bash theme={null}
cd "$HOME/wuji-ros2"
source /opt/ros/lyrical/setup.bash
source install/setup.bash
ros2 topic echo /hand/joint_states sensor_msgs/msg/JointState --once --timeout 20 --field position
```

波形示例启动时直接下发零位目标。运行前确认当前位置到零位的运动路径安全，关节可能快速回位。

**3. 运行波形示例**

在已加载 ROS 环境的终端运行：

```bash theme={null}
ros2 run wuji_bringup hand2_wave_demo --ros-args -r __ns:=/hand
```

波形示例通过 `/hand/joint_commands` 先发布 1 秒零目标，再以 100 Hz 发布波形命令。拇指和外展目标保持 0 rad，其余 4 指按 0.5 Hz 余弦波在 0 到 1.0 rad 之间运动。观察设备动作与关节位置变化。

**4. 停止并失能**

按 `Ctrl+C` 停止波形示例，再失能全部关节：

```bash theme={null}
ros2 service call /hand/set_enabled wuji_msgs/srv/SetEnabled \
  '{enabled: false, mask: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true]}'
```

确认响应中的 `success: true` 后停止驱动 launch，并确认设备实际停止。

> [!WARNING]
>
> 驱动没有命令超时看门狗。停止发布不会自动补零、急停或失能。停止 launch 时，驱动调用失能接口关闭全部关节。调用失败时记录警告并继续退出，应确认设备实际停止。失能调用失败时，不要仅凭 launch 退出或链路中断判断设备已失能。

### 关节命令格式

向 `joint_commands` 发布命令时，使用 `sensor_msgs/msg/JointState` 消息。`name`、`position`、`velocity` 和 `effort` 由发布程序填写，不是启动命令的参数。

**按名称发送：** 自行编写发布程序时，在 `name` 中填写 `joint_states` 发布的关节名称，并按相同顺序填写 `position`。可只指定部分关节，顺序不限。驱动将未指定关节的目标填为 0，因此需要保留目标的关节也应显式指定。

**按固定顺序发送：** 将 `name` 留空，并按下表顺序填写全部 20 项 `position`。上述波形示例使用这种格式。表中的关节名称按手别加上 `l_` 或 `r_` 前缀。固定长度服务也使用该顺序。

| 索引 | 关节名称主体，按顺序排列 |
| - | - |
| 0–3 | `thumb_cmc_flex`、`thumb_cmc_abd`、`thumb_mcp`、`thumb_ip` |
| 4–7 | `index_finger_mcp_flex`、`index_finger_mcp_abd`、`index_finger_pip`、`index_finger_dip` |
| 8–11 | `middle_finger_mcp_flex`、`middle_finger_mcp_abd`、`middle_finger_pip`、`middle_finger_dip` |
| 12–15 | `ring_finger_mcp_flex`、`ring_finger_mcp_abd`、`ring_finger_pip`、`ring_finger_dip` |
| 16–19 | `pinky_mcp_flex`、`pinky_mcp_abd`、`pinky_pip`、`pinky_dip` |

两种格式中，`velocity` 和 `effort` 留空时按 0 填充，非空时长度须与命令关节数量一致。未知、重复或手性不符的名称，无效长度、非有限数值及超出 float32 范围的数值会使整条命令失败。

### 调用控制服务

服务使用可靠传输 QoS。以下服务均位于同一 namespace 下，调用结果需同时检查响应中的成功标志和错误信息。

| 服务 | 类型 | 行为 |
| - | - | - |
| `set_enabled` | `wuji_msgs/srv/SetEnabled` | 通过 20 项掩码使能或失能关节 |
| `clear_faults` | `wuji_msgs/srv/ClearFaults` | 清除 20 项掩码选中的关节故障 |
| `set_effort_limit` | `wuji_msgs/srv/SetEffortLimit` | 为全部关节设置同一电流限值，单位 A |
| `set_effort_limits` | `wuji_msgs/srv/SetEffortLimits` | 按固定顺序设置 20 个电流限值，单位 A |
| `set_mit_params` | `wuji_msgs/srv/SetMitParams` | 按固定顺序设置 20 项 `kp`、`kd` |
| `emergency_stop` | `std_srvs/srv/Trigger` | 调用 SDK 整手急停 |

掩码全部为 `false` 时不操作任何关节。固定长度服务要求完整的 20 项数组，不接受关节名称或部分数组。电流限值、`kp` 和 `kd` 必须为非负有限值。`kp`、`kd` 沿用 SDK 定义，不额外指定物理单位。

关节命令被拒绝时，驱动在终端输出限频 ERROR 日志，不通过 Topic 返回结果。服务调用失败时返回 `success: false` 和错误信息。驱动仍会运行。

需要急停时，调用：

```bash theme={null}
ros2 service call /hand/emergency_stop std_srvs/srv/Trigger '{}'
```

驱动不会锁存急停状态。调用后，上层控制程序须停止发送关节命令，否则后续命令仍可能生效。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.