> ## 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 Integration

`wuji_glove_driver` publishes Wuji Glove joint angles, tracked poses, palm IMU data, and tactile data as ROS 2 topics. The driver doesn't load a model, publish TF, or provide control or calibration services. Complete [wearing and connection](https://docs.wuji.tech/docs/en/wuji-glove/latest/getting-started.md) and any required [calibration](https://docs.wuji.tech/docs/en/wuji-glove/latest/calibration.md) before starting.

## Installation

Use Ubuntu 26.04 (resolute) with ROS 2 Lyrical installed, on x86\_64 or aarch64. The commands below fetch the source, load ROS, install dependencies and Hand 2 descriptions, and build the workspace. The build downloads and verifies the Wuji SDK C package for the host architecture.

```bash theme={null}
# Fetch the source and load 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
# Install build tools and dependencies
sudo apt-get update
sudo apt-get install -y ros-dev-tools
rosdep update
# Install the Hand 2 descriptions and workspace dependencies
scripts/install_hand2_descriptions.sh
rosdep install --from-paths . --ignore-src -r -y
# Build the workspace. The SDK C package is downloaded and verified automatically
colcon build --cmake-args -DBUILD_TESTING=OFF
# Load the built workspace
source install/setup.bash
```

> [!NOTE]
>
> * The description installer requires `/etc/apt/sources.list.d/ros2.sources`. If it is missing, configure the Lyrical package source using the official ROS 2 installation steps, then rerun the script.
> * If rosdep has never been initialized on the computer, run `sudo rosdep init` once before `rosdep update`. The `sudo` commands require administrator access.
> * If the SDK download fails, download and extract `wuji-sdk-c-2026.10.12-x86_64-linux-gnu.tar.gz` or `wuji-sdk-c-2026.10.12-aarch64-linux-gnu.tar.gz` from [Wuji SDK v2026.10.12](https://github.com/wuji-technology/wuji-sdk/releases/tag/v2026.10.12), matching your host architecture. Confirm that the extracted directory contains `include/wuji_sdk.h`, `lib/libwuji_sdk_c.so`, and `LICENSE`. Replace `/path/to/sdk` with the absolute path to that directory, then run this command from `wuji-ros2` instead of the default build command:
>
>   ```bash theme={null}
>   colcon build --cmake-args -DBUILD_TESTING=OFF -DWUJI_SDK_ROOT=/path/to/sdk
>   ```
> * CMake does not validate the SDK version when `WUJI_SDK_ROOT` is set. Use the release package specified above.

In each new terminal, enter the workspace and load ROS and the built packages:

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

## Select a Device

After putting on and connecting the glove, scan for devices:

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

Record the target glove's serial number. The driver accepts these selectors at startup:

| Parameter | Purpose |
| - | - |
| `serial_number` | Selects the glove by its scanned serial number. Validates device identity when `endpoint` is set |
| `hand_side` | Selects the unique left or right glove when used alone. Validates handedness when combined with `serial_number` or `endpoint`. Use `left` or `right` |
| `endpoint` | Connects directly to the scanned `IP:port` address when needed |

Without a selector, the driver connects only if discovery finds one Wuji Glove. Multiple gloves cause an immediate error and exit. If none are found, the driver waits until `connect_timeout` and exits. The driver holds an exclusive connection, so other SDK programs and `wuji viz` cannot connect to the same glove at the same time. To connect multiple gloves, use a different serial number and namespace for each driver process.

## Read Glove Data

### Run the Validation

**1. Start the driver**

Replace `GLOVE_SERIAL_NUMBER` with the serial number recorded in [Select a Device](#select-a-device), then start the driver:

```bash theme={null}
ros2 launch wuji_bringup glove.launch.py \
  serial_number:=GLOVE_SERIAL_NUMBER namespace:=glove
```

To connect by network address, replace `GLOVE_ENDPOINT` with the `IP:port` address from the scan and use this command:

```bash theme={null}
ros2 launch wuji_bringup glove.launch.py \
  serial_number:=GLOVE_SERIAL_NUMBER endpoint:=GLOVE_ENDPOINT namespace:=glove
```

To validate the hand side, append `hand_side:=left` or `hand_side:=right` to the launch command.

> [!NOTE]
>
> The driver waits up to 10 seconds for the glove to connect by default. Append `connect_timeout:=20.0` to the launch command to extend the wait to 20 seconds. Set it to `0.0` to wait until the device connects. Launch arguments are read only at startup.

**2. Check data**

Keep the driver running. Open a new terminal, load ROS and the built packages, then run the status demo:

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

The demo prints five-finger joint angles and confidence for each frame. By default, it runs for 10 seconds and then summarizes frame counts and average receive rates for each topic. The check passes if it receives at least one `joint_angles` frame. Missing optional streams produce warnings.

To measure receive rates for 30 seconds without printing each frame, run:

```bash theme={null}
ros2 run wuji_bringup glove_status_demo \
  --duration 30 --rate-only --ros-args -r __ns:=/glove
```

Place `--duration` and `--rate-only` before `--ros-args`. Receive rates use the interval from the first callback to the last. They measure ROS messages processed by the demo, not the device's source output rate.

> [!NOTE]
>
> If the driver connects but the status demo receives no data, first check that the terminals use matching namespaces, `ROS_DOMAIN_ID`, and compatible QoS. If the problem persists, try another ROS 2 middleware. Install Cyclone DDS:
>
> ```bash theme={null}
> sudo apt-get install ros-lyrical-rmw-cyclonedds-cpp
> ```
>
> Stop the current launch. Run this command in both the driver and status demo terminals:
>
> ```bash theme={null}
> export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
> ```
>
> Then repeat steps 1 and 2. Set the same ROS 2 middleware in any new terminals you open later.

**3. Stop the driver**

Press `Ctrl+C` in the driver terminal. The driver closes subscriptions and disconnects the device.

### Data Topics

All 10 topics use SensorDataQoS: best-effort, volatile, and keep-last 5. Use best-effort subscribers. Reliable subscribers cannot receive data from these publishers.

The driver publishes glove data on the topics below. Subscribe using the listed message types. Topic names are relative: with `namespace:=glove`, `joint_angles` resolves to `/glove/joint_angles`.

| Topic | Message Type | Content | Startup Switch |
| - | - | - | - |
| `joint_angles` | `wuji_msgs/msg/HandJointAngles` | Joint-angle arrays and confidence for five fingers | Always enabled |
| `emf_poses` | `wuji_msgs/msg/TrackedPoseArray` | Named EMF tracking poses with confidence | `publish_emf_poses` |
| `tip_poses` | `wuji_msgs/msg/TrackedPoseArray` | Named fingertip poses with confidence | `publish_tip_poses` |
| `hand_skeleton` | `wuji_msgs/msg/TrackedPoseArray` | Named hand-skeleton poses with confidence | `publish_skeleton` |
| `imu/palm` | `sensor_msgs/msg/Imu` | Raw palm IMU from SDK `imu_raw/palm` | `publish_imu` |
| `tactile` | `wuji_msgs/msg/TactileGrid` | Grid dimensions and tactile data array | `publish_tactile` |
| `tactile/residual` | `wuji_msgs/msg/TactileGrid` | Grid dimensions and tactile residual array | `publish_tactile_residual` |
| `tactile/binary` | `wuji_msgs/msg/TactileGrid` | Grid dimensions and tactile binary array | `publish_tactile_binary` |
| `tactile/zones` | `wuji_msgs/msg/TactileZoneArray` | Tactile zone names and values | `publish_tactile_zones` |
| `tactile/points` | `sensor_msgs/msg/PointCloud2` | Tactile point cloud | `publish_tactile_points` |

> [!NOTE]
>
> For Wuji message fields, see the `.msg` files matching the listed types in the `wuji_msgs/msg/` directory of the `wuji-ros2` repository. Nested message types are in the same directory. For standard messages, see the ROS 2 [Imu.msg](https://github.com/ros2/common_interfaces/blob/lyrical/sensor_msgs/msg/Imu.msg) and [PointCloud2.msg](https://github.com/ros2/common_interfaces/blob/lyrical/sensor_msgs/msg/PointCloud2.msg) definitions.

After sourcing the workspace, run these commands to inspect the message fields in the installed version:

```bash theme={null}
ros2 interface show wuji_msgs/msg/HandJointAngles
ros2 interface show wuji_msgs/msg/TrackedPoseArray
ros2 interface show wuji_msgs/msg/TactileGrid
ros2 interface show wuji_msgs/msg/TactileZoneArray
```

### Interpret the Data

* Joint angles use rad, and pose positions use m. Read each finger’s `angles` array by its actual length: five entries for the thumb and four for each other finger. Don't interpret confidence as a normalized probability.
* Messages preserve SDK timestamps, frame identifiers, and payload values. ROS namespaces don't rewrite message `frame_id` values. See [Coordinate Frames](https://docs.wuji.tech/docs/en/wuji-glove/latest/coordinate-frames.md) for frame definitions.
* The driver copies raw SDK IMU fields and covariance into `imu/palm` without computing a new orientation estimate. It doesn't publish the SDK-derived `imu_data/palm` stream.
* Tactile grids use `rows × columns` row-major arrays. Value semantics depend on the topic. Residual and binary grids aren't force measurements.
* Parse tactile point clouds using their own `fields`, `point_step`, and `row_step`. Don't assume an xyz-only layout.

## Configure Topic Publishing

Except for required `joint_angles`, the nine data streams in the table can be controlled by launch arguments. All are enabled by default. For example, to disable the tactile point cloud, run:

```bash theme={null}
ros2 launch wuji_bringup glove.launch.py \
  serial_number:=GLOVE_SERIAL_NUMBER namespace:=glove \
  publish_tactile_points:=false
```

Boolean launch arguments accept only lowercase `true` / `false`. Use the corresponding `publish_*` argument in the table for other optional streams. `joint_angles` has no disable switch.

### Handle Stream End and Errors

If required `joint_angles` can't start, ends, or reports an error, the driver exits with a nonzero status and the launch shuts down. An optional-stream failure stops only that stream and records a log message. Other streams continue.

The driver doesn't reconnect automatically. Restore the device and network, then restart the launch. Stream end or error events trigger this handling. Applications that need to check whether data continues to arrive should monitor message timestamps.


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