HumansXドキュメントセンター English公式サイトへ ↗
ナレッジベース › Wuji Hand 2 › マニュアル

Replaying a Thumb Opposition

SDK Practice

このページは現在英語版のみです。日本語でのご説明が必要な場合は HumansX までお問い合わせください。

Overview

Read the recording shipped with the example, pick the left- or right-hand file by device handedness, and replay 30000 joint-angle frames straight through at 1 kHz.

This is the larger of the two motion examples, meant for observing the hand’s full range. The example does no interpolation, no resampling, no smoothing, and adds no recovery motion. What the recording holds is what goes out.

Matching examples: examples/python/wuji_hand_2/6_opposition/opposition.py and examples/c/wuji_hand_2/6_opposition/opposition.c.

For API and field definitions, see JointCommand.

This example drives all 20 joints through large motions, with a measured command peak of 1.43 rad (about 82 degrees) sustained over 30 seconds. Before starting, confirm the hand is firmly mounted, clear people, cables, and desk objects from around it, keep someone watching throughout, and stay ready to cut power.

Prerequisites

Hardware

ItemRequirement
Wuji Hand 21, with all 20 joints online
MountingThe device must be firmly mounted. 30 seconds of continuous large motion produces noticeable reaction forces
ConnectionEthernet
NetworkOnly this device may be on the network, since the example uses auto_connect()

Software

ItemRequirement
Operating systemLinux or a Mac with Apple silicon, meeting the system requirements
Wuji SDKv2026.8.31 or later
Python3.10 or later
C toolchainCMake 3.16 or later. This example is a standalone CMake project

Replay Files

The example directory ships data/right.replay and data/left.replay. Copy the entire 6_opposition/ directory, since taking only the source file fails when it can’t find the data.

Data Flow

File Format

A fixed-length container with a 16-byte header followed by 84 bytes per frame.

SectionLayoutNote
Header<8sHBBImagic WJH2RPL\0, version, handedness ID, joint count, frame count
Per frame<I20f4-byte frame index plus 20 float32 joint angles in radians

Handedness ID is 1 for right and 2 for left. The shipped files measure 30000 frames and 2520016 bytes, matching 16 + 30000 x 84 exactly.

Validation completes before enabling. If any of magic, version, handedness, joint count, or file length fails, the example reports an error and exits without enabling the motors.

Integration Steps

1. Connect and Validate the Replay File

Read handedness after connecting, and select left.replay or right.replay. After opening the file, validate the magic, version, handedness marker, joint count, and file length. Don’t enable the device if validation fails.

hand = manager.auto_connect("hand_2_opposition")
if hand.online_joints_count().get() != 20:
    raise RuntimeError("expected 20 online joints")
stream, frame_count = _open_replay(_side_for_hand(hand), data_dir=data_dir)

2. Check Online Joints and Prepare the Publisher

Confirm all 20 joints are online, then call enable() and create a joint_command publisher. Read one current joint_states frame and use a cosine transition to reach the first replay frame smoothly.

hand.enable()
publisher = hand.joint_command().publish()
start = _capture_start_positions(hand)

C uses wuji_hand_2_online_joints_count(), wuji_hand_2_enable(), and wuji_hand_2_joint_command_publish(). It selects the replay file with wuji_hand_2_get_handedness().

3. Publish Replay Frames at 1 kHz

Read 20 position values per frame, create JointCommand(position, 0, 0) entries, and send them at 1 ms intervals. The replay loop must handle stop requests and file-read errors.

def send(qpos):
    publisher.send([wuji_sdk.JointCommand(float(v), 0.0, 0.0) for v in qpos])
_play_replay(stream, frame_count, send, ramp_start=start,
             stop_requested=lambda: _STOP_REQUESTED)

The functions with leading underscores are helpers in Python example. _open_replay() validates the complete container, _capture_start_positions() orders joints by nid, and _play_replay() handles the starting transition and frame-by-frame playback.

C uses open_replay_path(), capture_start_positions(), send_ramp(), and play_replay(). They send a fixed 20-joint array through wuji_joint_command_publisher_send().

4. Disable and Release Resources

On normal completion or an error, disable first, close the publisher and replay file, then disconnect. C uses wuji_hand_2_disable(device, NULL) and wuji_joint_command_publisher_close(publisher), closes the replay file, disconnects and releases the device, and calls wuji_shutdown().

hand.disable()
publisher.close()
stream.close()
manager.disconnect_all()

Place cleanup in finally. Collect errors individually, as shown in Python example and C example, so a failure in one cleanup operation doesn’t prevent releasing the remaining resources.

Running It

  • Python

  • C

python examples/python/wuji_hand_2/6_opposition/opposition.py
./build/hand2-opposition/6_opposition

Measurements

A complete run on a right-hand Wuji Hand 2 with all 20 joints online:

MetricMeasured
Frames replayed30000, none dropped
Total duration30.00 seconds
Actual publish rate1000.0 Hz
Command peak1.4315 rad (82.0 degrees)
Largest absolute starting angle0.0668 rad
Largest absolute ending angle0.0563 rad

Python held the 1 ms target interval reliably, and accumulated error across 30000 frames is negligible.

The hand settles on its own at the end. The recording’s last frame already returns to an open position, so a normal run needs no extra homing. That comes from the recording’s content rather than anything the example does, and an interrupted run gets no such guarantee.

Range of Motion per Finger

Per-joint travel computed offline from the right-hand replay file:

FingerTravel across four joints (rad)Peak
Thumb1.125 / 0.734 / 1.296 / 0.801+1.319
Index0.799 / 0.477 / 1.428 / 1.257+1.431
Middle0.787 / 0.620 / 1.205 / 0.298+1.197
Ring0.930 / 0.434 / 0.795 / 0.104+0.925
Pinky0.630 / 0.524 / 1.188 / 0.322+1.184

The index finger’s third joint travels furthest at 1.428 rad, about 81.8 degrees.

Notes

Branch pointBehaviorWhat to do
Handedness mismatchside_id validation fails when a right hand reads left.replayReports an error and exits without enabling. The example picks by device handedness, so this rarely triggers
File missing or corruptReports replay file not found or a container validation failureConfirm you copied the whole 6_opposition/ directory
Fewer than 20 joints onlineReports an error and exitsInvestigate the offline joints first
Several devices on the networkauto_connect() reports Found N devices, please specify SN and exitsOn a shared network, change it to name a serial number
Ctrl+CExit code 130, stopping further frames and performing no return motionThe hand holds the posture it stopped in, then is disabled
Normal completionExit code 0The recording’s final frame already returns to an open hand

On interrupt the hand holds its current posture rather than opening automatically. Stopping mid-motion can leave it clenched, which needs handling by hand.

Adapting It

Name an SN on a Shared Network

As with the MIT joint sweep, auto_connect() refuses to connect when it finds several devices and lists every serial number rather than guessing. Change it to manager.connect(sn="WH2KA00XXXXXXXXX", device_name="hand_2_opposition").

Replay Your Own Recording

Generate a file in the same container format and the whole replay path works unchanged: a 16-byte header plus 84 bytes per frame. The frame index is skipped during replay, and only the 20 joint angles drive control. Make sure side_id matches the target device’s handedness, or container validation fails.

Changing Playback Speed

The interval is hard-coded at 1 ms. Increasing it slows the whole motion, but since nothing is resampled the joint-angle sequence stays the same and each posture simply holds longer. Real speed changes need you to resample the trajectory yourself.

Recovering After an Interrupt

Ctrl+C triggers no return motion. After stopping mid-run, the hand holds its posture, and the smooth homing routine in Publishing Control Commands brings it gently back to zero. Don’t send pos=0 directly, since a large error under MIT impedance snaps the hand back hard.