Overview
Configure MIT impedance control parameters, enable the motors, then interpolate smoothly from each joint’s measured position to zero and hold there. This is the basic pattern for controlling a Wuji Hand 2. The example homes the hand, but the samepublisher.send() path carries teleoperation, trajectory playback, and output from a higher-level controller.
Matching examples: examples/python/wuji_hand_2/2.publish.py and examples/c/wuji_hand_2/1_control_motion.c.
For joint command fields and value ranges, see Joint State and Control, and for control modes and safety bounds, see Control Guide. This page covers only how to run it and what the measurements show.
This example enables the motors and drives every online joint. Clear people, cables, and desk objects from around the hand before starting, keep someone watching throughout, and stay ready to cut power.
Interpolation
Sendingpos=0 directly and interpolating to pos=0 are entirely different motions under MIT impedance.
MIT control produces torque proportional to position error. With the hand starting curled, the first frame at pos=0 carries an error of “current angle − 0”, and with kp=3 that becomes a large torque that snaps the hand back to zero.
Interpolating means reading the current position first, then pulling the target linearly from there to 0. Each frame’s error stays small, torque stays small with it, and the whole motion is gentle. Gentleness comes from the target trajectory, not from lowering the gains, so kp and kd keep their normal values.
Prerequisites
Hardware
This example connects to the first Wuji Hand 2 it finds (
hand_devices[0]). On a shared network, change it to name a serial number.
Software
Control Parameters
These three control values match the factory defaults, and reading them back returns
kp=3, kd=0.05, effort_limit=1.5.
Data Flow
Parameter Setters Broadcast
set() on effort_limit and mit_params is polymorphic:
Runtime Handling
ext_state values: 0 is Init, 1 is Ready, 2 is Enabled, 3 is Stopped. Before enable every joint reads 1, and within 52 ms after enable every joint reads 2.
Integration Steps
- Python
- C
Running It
- Python
- C
Measurements
On a right-hand Wuji Hand 2 with all 20 joints online:
There’s a 26x gap between
enable() returning and the motors being ready. Commands sent inside that window are discarded or behave unexpectedly, which is why the wait is required.
After homing, joints don’t land exactly on 0 but within 0.02 rad. MIT impedance is compliant control, and static friction plus gravity leave a steady-state offset between actual position and target. That’s normal.
Adapting It
Tune How Gentle Homing Is
ChangeHOME_SECONDS. A longer duration makes each frame’s position step smaller and the motion gentler. Don’t chase gentleness by lowering kp, which sacrifices tracking accuracy overall.
Feed Your Own Trajectory
Replace the interpolation in step 5 with your own trajectory source, leaving thepublisher.send() call unchanged. Each send() carries a complete 20-element frame, which the SDK serializes and transmits without waiting for a response, so it sustains a high-rate loop.
Choosing a Publish Rate
The example uses 200 Hz. Higher rates make trajectories smoother, provided generating one frame stays reliably faster than the period. The measurement above shows an actual rate of exactly 200.0 Hz, so there’s headroom at this scale.Controlling Only Some Joints
Every frame still carries the full 20-element array. For joints you don’t want to move, fill in their current measured positions rather than 0. Filling 0 commands them home, which is the trap the MIT joint sweep ran into.Related
- Running an MIT Joint Sweep: the minimal command-path check, and a warning that it pulls other joints toward zero
- Replaying a Thumb Opposition: high-rate playback of a complete recorded trajectory
- Subscribing With Callbacks: how to read joint state
- Common Data Types:
JointCommandand diagnostic structures