This repository provides both the control stack and the quantitative experimental benchmarks for the Inspire RH56DFX dexterous hand. It includes calibrated force mapping, dynamic step-response characterization, high-speed force-limiting analysis, and command-to-motion latency, establishing a reproducible baseline for contact-rich manipulation research while supporting ROS 2 integration for deployment.
Click a preview to open the full MP4.
| Preview | Video |
|---|---|
![]() |
▶︎ MP4 |
| Preview | Video |
|---|---|
![]() |
▶︎ MP4 |
![]() |
▶︎ MP4 |
![]() |
▶︎ MP4 |
| Preview | Video |
|---|---|
![]() |
▶︎ MP4 |
![]() |
▶︎ MP4 |
This repository currently exposes finger forces in raw 0–1000 units.
External experiments show a linear relationship between the raw readingrand force in NewtonsFfor each finger:
$$ F_i,[\mathrm{N}] = a_i \cdot r_i + b_i $$ Where (i \in {\text{pinky, ring, middle, index, thumb_bend, thumb_rotate}}).
Status. We will publish the initial coefficients for thumb_bend, index, and middle here, together with the validation range and R² (others TBD).
We fitted a linear model for index, middle, and thumb_bend using ground‑truth measurements from a force meter:
| Finger | a (N/unit) | b (N) | R² | Valid raw range | N |
|---|---|---|---|---|---|
| index | 0.007478 | -0.414 | 0.987 | 102–980 | 10 |
| middle | 0.006452 | 0.018 | 0.986 | 112–990 | 10 |
| thumb bend | 0.012547 | 0.384 | 0.993 | 91–1000 | 9 |
Usage (example):
# raw -> Newtons
COEFFS = {
"index": ( 0.007478, -0.414 ),
"middle": ( 0.006452, 0.018 ),
"thumb_bend": ( 0.012547, 0.384 ),
}
def raw_to_newtons(raw, finger="index"):
a, b = COEFFS[finger]
return a * float(raw) + bNotes.
- Our hand is damaged so the results might not be accurate.
- The fits are valid within the listed raw ranges; outside this interval you will be extrapolating.
- Measured maximal forces at
r=1000are approximately: index ≈ 7.06 N, middle ≈ 6.47 N, thumb_bend ≈ 12.93 N.
Note on Poll Rate
Currently only the q, tau are read from the hands and published to /hands/state. This is because the hands are on the same serial device with different slave IDs. While I am able to send separate, async commands to the hands for some reason, async read operations overlap and cause serial bus errors. So, we read and build the /hands/state with these four sequential calls:
right_angles = self.righthand.angle_read()
right_forces = self.righthand.force_act()
left_angles = self.lefthand.angle_read()
left_forces = self.lefthand.force_act()
Each read operation takes 0.006s, totalling 0.024s for four reads. After ROS overhead, the 41.67 Hz poll rate is closer to 40.2 Hz. This should be fast enough but I welcome any efforts to potentially double this by asynchronously reading.
What it does.
X‑mode is a lightweight, event‑driven controller for the RH56 hand that
- auto‑closes on contact to pick the part, and
- auto‑opens after a short horizontal verification confirms that the peg is constrained by the hole (index finger spike), enabling fully automated pick–insert–release cycles.
Signals & units.
All force/pressure readings are raw, unitless counts (e.g., 0–1000). Thresholds below are specified in these raw units.
- Pre‑grasp & limits. Move to a precision‑pinch pre‑grasp and set per‑finger force limits (index, thumb).
- Auto‑close on contact (thumb). Monitor the thumb channel; when a positive jump ΔF_th ≥
CONTACT_SPIKEoccurs, close to grasp.
Timeout: if no contact is detected forTIMEOUT(≈20 s), open and reset toWAIT. - Stabilize grasp (index). After closing, monitor the index moving‑average; once it exceeds
LOAD_ARM, the grasp is considered established. - Horizontal verification. If the index force reading shows a spike ΔF_idx ≥
LATERAL_SPIKE, interpret this as peg constrained by the hole (i.e., insertion achieved). - Auto‑open to release. On successful horizontal verification, open (with an error‑clear + second open for robustness) and return to
WAIT.
Timeout: if no lateral spike is observed forTIMEOUT, open and reset.
FORCE_LIMIT(per finger): ~800CONTACT_SPIKE(thumb Δ): +75LOAD_ARM(index moving‑avg): ≥ 500LATERAL_SPIKE(index Δ during sweep): +75- Moving‑average window: ~0.5 s
TIMEOUT: ~20 s
This section aggregates the results from today's experiments and can be moved into a new experiments/2025-11-04/ folder in the repo if desired. The raw data files are listed at the end of this section.
Setup. Each finger was commanded a unit step from its baseline to target_angle = 500 (raw units) at several speeds. We report rise/settling times, overshoot and steady‑state error as computed by the post‑processing scripts.
Takeaways.
- At
speed=1000, rise times are ~0.18–0.30 s and settling times ~0.27–0.43 s for index/middle/thumb joints with minimal overshoot (where observed). - Thumb‑rotate often undershoots the target (negative steady‑state error); consider offset compensation in the driver.
The test applied a fixed force limit (raw units) and measured the peak force at different speeds on middle (finger=2):
| speed | force_limit | force_peak | overshoot | peak_limit_pct |
|---|---|---|---|---|
| 1000.000 | 500.000 | 1556.000 | 1056.000 | 211.200 |
| 500.000 | 500.000 | 1246.000 | 746.000 | 149.200 |
| 250.000 | 500.000 | 1073.000 | 573.000 | 114.600 |
| 100.000 | 500.000 | 996.000 | 496.000 | 99.200 |
| 50.000 | 500.000 | 825.000 | 325.000 | 65.000 |
| 25.000 | 500.000 | 524.000 | 24.000 | 4.800 |
| 10.000 | 500.000 | 478.000 | -22.000 | -4.400 |
Observation. Overshoot is strongly speed‑dependent. For precision grasps, consider lowering speed during the final approach and using a two‑stage closing policy.
Several approaches were tested to mitigate the overshoot observed when using the vendor-provided force_limit register at high motor speeds.
Because the internal register does not reliably stop motion in time when speed ≥ 25, we attempted to implement custom software-level safeguards:
- Real-time force monitoring: continuously reading the finger’s force sensor and sending an immediate new target angle to halt motion when the threshold was reached.
- Dynamic angle stepping: issuing small incremental angle commands (small step size) to effectively lower motion speed while retaining manual force supervision.
- Hybrid scheme: combining 1 and 2 to emulate a closed-loop stop.
However, comparative tests against the native register control showed no measurable improvement in either peak force or overshoot timing.
This suggests that the observed overshoot originates in the firmware-side latency of command execution rather than host-side timing, and cannot be fully compensated without direct low-level access to the actuator’s embedded controller.
Conclusion: for speeds above 25, the hardware register remains the limiting factor; software-side interception offers no significant benefit under the current communication interface.
Empirically, the hardware-level force_limit register becomes ineffective at speeds above ≈25, where the actuator continues to move significantly past the intended stop threshold.
The lack of responsiveness suggests that the limit enforcement occurs only after a buffered command cycle, rather than in real-time on the motor controller.
A possible next step is to explore a predictive host-side cutoff, in which the system:
- Continuously samples the real-time force readings;
- Estimates the short-term rate of force increase (force growth trend); and
- Issues an early stop command based on the measured command–actuation latency (≈60–70 ms).
This would allow the software to preemptively compensate for communication and processing delays.
However, this concept has not yet been experimentally validated, and remains a candidate for future investigation once low-latency force streaming and synchronization are implemented.
| trial | t_cmd | t_move | latency_s | init_at_cmd | cmd_angle |
|---|---|---|---|---|---|
| 1 | 220123.942812 | 220123.993149 | 0.050337 | 1000 | 700 |
| 2 | 220124.126521 | 220124.170575 | 0.044054 | 995 | 700 |
| 3 | 220124.301840 | 220124.370165 | 0.068324 | 991 | 700 |
| 4 | 220124.527222 | 220124.597639 | 0.070417 | 990 | 700 |
| 5 | 220124.743827 | 220124.812808 | 0.068980 | 993 | 700 |
| 6 | 220124.962745 | 220125.031467 | 0.068721 | 994 | 700 |
| 7 | 220125.182071 | 220125.251125 | 0.069053 | 993 | 700 |
| 8 | 220125.405745 | 220125.469990 | 0.062445 | 992 | 700 |
| 9 | 220125.626845 | 220125.689260 | 0.062416 | 994 | 700 |
| 10 | 220125.846464 | 220125.910199 | 0.063735 | 991 | 700 |
We measured latency from the command publish timestamp to the first detected motion:
- p50: 0.066 s
- p90: 0.069 s
- p95: 0.070 s
- p99: 0.070 s
Harness parameters (representative): baseline≈1000, cmd_angle≈700, |Δ|≈300, speed≈1000, movement_eps≈10.
Commit these into e.g. resource/experiments/2025-11-04/:
force mapping.xlsx(Index/Mid/Thumb_bend sheets; columns: “Hand reading”, “force meter reading / N”).summary_index.csv,summary_mid.csv,summary_thumb_bend.csv,summary_thumb_rotate.csv(step‑response summaries).force_stop_summary.csv(force‑limit overshoot).latency_log.csv,latency_summary.json(latency micro‑benchmark).
Protocol (two-finger baseline).
To evaluate grasp behavior without perception or planning, we fix the thumb rotation and set the thumb bend to a contact-seeking angle, lightly “preloading” the object. We then close the index (two-finger pinch). For larger or elongated objects we optionally add more fingers (thumb–index–middle / thumb–index–middle–ring).
What this measures (and what it doesn’t).
- The experiment probes local contact mechanics (pinch vs. power grasp) under a fixed-pose assumption.
- The absolute success rate is not a reliable metric for the grasp policy itself, because performance depends mainly on pre-contact alignment—that is, the relative pose between the hand, object, and table.
- When pre-alignment is accurate, small items (e.g., nuts) can be grasped almost perfectly; when alignment drifts, failures increase sharply for small parts but are less critical for larger objects.
Interpretation.
- The current rule-based closing logic performs consistently once contact is properly established.
- Experiment outcomes therefore reflect the precision of object presentation and hand pre-pose, not the control policy.
- In future closed-loop systems (with visual or force feedback), these trials will serve as baseline open-loop performance data.
Recommendations.
- Report success rate alongside placement error (e.g., translational / angular deviation) rather than as an isolated figure.
- Use a two-stage close (high-speed → low-speed near contact) to mitigate over-sensitivity in small objects.
- For long or heavy objects, extend to tripod or power grasps once stable pinch contact is detected.
Summary: In these open-loop tests, grasp outcome is governed primarily by pose accuracy rather than control strategy. Improving perception and pre-grasp alignment will yield the largest real-world gains.
The Grasp module provides a structured framework for evaluating and demonstrating various grasping strategies with the Inspire RH56 dexterous hand.
Its current implementation focuses on simple, rule-based heuristics that allow the hand to adapt its grasp configuration based on object geometry without external perception or planning.
Rather than using vision or high-level planning, this module relies on measurable object dimensions—primarily width and length—to parameterize the grasp.
By keeping the thumb rotation fixed and varying only the thumb bend angle and number of active fingers, the controller achieves a range of grasp types from precision to power grasps with minimal complexity.
-
Thumb Configuration (Width-Based):
- The object width determines the thumb bend angle (
thumb_bend). - Two different configurations are used now for different width object.
- This allows the thumb to form a stable initial pinch against the index or middle finger.
- The object width determines the thumb bend angle (
-
Finger Selection (Length-Based):
- The object length determines how many fingers are involved in the grasp.
- Short objects trigger a two-finger (thumb–index) pinch.
- Medium objects use a three-finger (thumb–index–middle) tripod grasp.
- Long or wide objects engage four fingers (thumb-index–middle–ring) for a full power grasp.
- Pinky isn't really useful due to its length
-
Force Regulation:
- Each finger closes until its force reading reaches a target threshold, converted to Newtons using the linear force mapping calibration.
- This enables consistent contact pressure across objects of different stiffness and size.
- Successfully grasps small metallic nuts, medium-sized items (e.g., Rubik’s cubes), and large objects up to 10 cm wide.
- Demonstrates both precision and power grasp behaviors using the same heuristic policy.
- Compatible with both stand-alone scripts and the ROS 2 driver through topic-level command injection.
- Integrate visual sensing for dynamic object dimension estimation.
- Extend the heuristics into a learning-based grasp selection policy.
- Quantify grasp stability through external load and slippage tests.
This module aims to balance simplicity, reproducibility, and real-world performance, serving as a baseline for more advanced manipulation strategies.
This package provides a ROS 2 driver for the Inspire RH56DFX robotic hand, which wraps the serial interface with a Python API. Force-control (in Newtons) is WIP. States publish at ~40 Hz.
- Clone this repository into your ROS 2 workspace's
srcdirectory. - Navigate to the root of your workspace.
- Build the package using
colcon:colcon build --packages-select rh56_controller
- Source the workspace's
setup.bashfile:source install/setup.bash
Temporary Usage: By default, the inspire_hand.service connects to the hands' serial bus and publishes/subscribes to the inspire/state and inspire/cmd topics. Stop this service with:
sudo systemctl stop inspire_hand.service To run the driver node, use the provided launch file. You can specify the serial port, which is /dev/ttyUSB0 by default if not specified.
ros2 launch rh56_controller rh56_controller.launch.py serial_port:=/dev/ttyUSB0If for whatever reason pyserial is denied access to the hands USB device, run:
sudo chmod 666 /dev/ttyUSB0This is a transient issue and has not cropped up for me after initial testing.
There are a few differences between these topics and the old /inspire/state message.
The new message, in custom_ros_messages/msg/MotorState, looks like
int32 mode
float64 q
float64 dq
float64 ddq
float64 tau
float64 tau_lim
float64 current
float64 temperature
float64 q_raw
float64 dq_raw
float64 tau_raw
float64 tau_lim_rawWhere q represents the motor position, from 0 (closed) to pi (extended). q_raw keeps it in the arbitrary 0-1000 units. Currently, tau, tau_lim, tau_raw, tau_lim_raw are all in the same 0-1000 units because we do not have reliable force calibration. This is because the Inspire conversion simply takes the raw unit, normalizes by 1000, and divides by gravitational acceleration (9.8 m/s^2). This would mean that the each actuator produces a maximum of 1 N of force, which is meaningless since 1) we expect a Nm measurement for motor torque, 2) the fingers have variable lengths and thus different ranges of contact forces, and 3) such a limit does not align with the provided specs, which lists grip forces exceeding >6 N.
/hands/state(custom_ros_messages/msg/MotorStates)- A not-quite-mirror of the original
inspire/statetopic. Publishes the current angle of each finger joint in radians, not the 0-1000 range, in a 12-element array ([right[6] + left[6]]). Subject to change if this is annoying.
- A not-quite-mirror of the original
/hands/cmd(custom_ros_messages/msg/MotorCmds)- A not-quite-mirror of the original
inspire/cmdtopic. Subscribes to the 12-element array of commanded angles ([right[6] + left[6]]) for each finger joint in radians, not the 0-1000 range. Subject to change if this is annoying.
- A not-quite-mirror of the original
/hands/set_angles(custom_ros_messages/srv/SetHandAngles)- Input: 6-element float array, hand specification ('left', 'right', 'both')
- This command opens both hands.
-
ros2 service call /hands/set_angles custom_ros_messages/srv/SetHandAngles "{{angles: [1000, 1000, 1000, 1000, 1000, 1000], hand: 'both'}}"
/hands/calibrate_force_sensors(std_srvs/srv/Trigger)- Initiates the hardware's force sensor calibration routine. This process takes approximately 15 seconds.
/hands/save_parameters(std_srvs/srv/Trigger)- Saves the current configuration to the hand's non-volatile memory.
- TODO:
/hands/adaptive_force_control(rh56_controller/srv/AdaptiveForce)- Executes the advanced adaptive force control routine. DOES NOT WORK YET
- Preliminary feature: named gestures
{name: String: angles: List[Int]}in therh56_driver.py:self._gesture_libraryclass dictionary will autopopulate/hands/<gesture>,/hands/left/<gesture>, and/hands/right/<gesture>services. Runros2 service list | grep '^/hands/'to see the full list of generated services. These are genericTriggerservices and can be run with:-
ros2 service call /hands/<gesture> std_srvs/srv/Trigger ros2 service call /hands/left/<gesture> std_srvs/srv/Trigger ros2 service call /hands/right/<gesture> std_srvs/srv/Trigger
-
ros2 service list | grep '^/hands/' /hands/close /hands/left/close /hands/left/open /hands/left/pinch /hands/left/point /hands/open /hands/pinch /hands/point /hands/right/close /hands/right/open /hands/right/pinch /hands/right/point
-
The joints on the hand are ordered as such: [pinky, ring, middle, index, thumb_bend (pitch), thumb_rotate (yaw)]. This command closes the index finger while opening the other joints.
ros2 service call /hands/set_angles custom_ros_messages/srv/SetHandAngles "{{angles: [1000, 1000, 1000, 0, 1000, 1000], hand: 'both'}}"ros2 service call /calibrate_force_sensors std_srvs/srv/TriggerLegacy Python Script Documentation (Pre-ROS)
This project contains a Python script (controller.py) for controlling the RH56 dexterous hand via a serial port. The script encapsulates the low-level communication protocol and provides a high-level RH56Hand Python class, making it easier for developers to implement complex control logic.
Currently, the project features a Adaptive Force Control function that can adjust force thresholds while dynamically changing finger positions to achieve a preset contact force.
- Basic Control:
- Set/read the angle for all six degrees of freedom (five fingers + thumb rotation).
- Set/read the movement speed for each finger.
- Set/read the force control threshold for each finger (unit: grams).
- Sensor Reading:
- Real-time reading of the pressure sensor for each finger (unit: grams).
- Force Sensor Calibration:
- Provides an interactive calibration routine to calibrate the force sensors before precise control operations.
- Advanced Control Logic:
- Adaptive Force Control (
adaptive_force_control): This is an advanced control mode with the following characteristics:- Position-Force Coordinated Control: Can simultaneously move fingers to a target angle and have them reach a target contact force.
- Step-wise Adjustment: Gradually moves fingers to the target position instead of all at once, making the control process smoother and more stable.
- Intelligent Force Adjustment: During movement, it dynamically adjusts the force control threshold based on the difference between the current force reading and the original target.
- Adaptive Force Control (
- RH56 Dexterous Hand
- USB-to-Serial adapter to connect the hand to the computer
- Python 3
pyseriallibrarynumpylibrary
Before running the script, you need to modify two key parameters at the bottom of the controller.py file, inside the if __name__ == "__main__": block, according to your setup:
-
Serial Port (
port):- Find the line
hand = RH56Hand(...). - Change the
portparameter to the actual serial port recognized by your computer.- Windows: e.g.,
COM3,COM4 - macOS/Linux: e.g.,
/dev/tty.usbserial-xxxxor/dev/ttyUSB0
- Windows: e.g.,
- Find the line
-
Hand ID (
hand_id):- In the same line, modify the
hand_idparameter.- 1: Right Hand
- 2: Left Hand
- In the same line, modify the
Example:
if __name__ == "__main__":
# Modify the parameters here based on your hardware connection
hand = RH56Hand(port="/dev/tty.usbserial-1130", hand_id=1)
...The script can be run directly to start the pre-configured Adaptive Force Control demonstration.
- Connect Hardware: Ensure the dexterous hand is correctly connected to the computer and powered on.
- Modify Configuration: Correctly configure the serial port and hand ID as described in the previous section.
- Execute Script: Run the following command in your terminal:
python controller.py
- Start Calibration (Optional):
- By default, the script first runs
demonstrate_force_calibration. - You will see the prompt
Press Enter to start calibration.... Press Enter to begin. The calibration process takes about 15 seconds. - If you do not need to calibrate, you can comment out the
demonstrate_force_calibration(...)line in the__main__block.
- By default, the script first runs
- Observe Adaptive Force Control:
- After calibration, the script will automatically start the
adaptive_force_controlroutine. - You will see real-time output in the terminal showing each finger's current angle, current force reading, original target force, and the action taken for each iteration.
- The program will finish after reaching the targets or the maximum number of iterations and will print a final summary report.
- After calibration, the script will automatically start the
force_set(thresholds: List[int])
- Function: Directly sets the force control thresholds for the 6 fingers.
- Parameters:
thresholds- A list of 6 integers, with each value ranging from 0-1000g.
angle_set(angles: List[int])
- Function: Sets the target angles for the 6 fingers.
- Parameters:
angles- A list of 6 integers, with each value ranging from 0-1000.
force_act() -> Optional[List[int]]
- Function: Reads and returns the current force sensor readings for the 6 fingers (unit: grams).
- Returns: A list of 6 integers, or
Noneif the read fails.
angle_read() -> Optional[List[int]]
- Function: Reads and returns the current angle positions for the 6 fingers.
- Returns: A list of 6 integers, or
Noneif the read fails.
adaptive_force_control(target_forces: List[int], target_angles: List[int], step_size: int = 50, max_iterations: int = 20)
- Function: Executes the advanced adaptive force control routine.
- Parameters:
target_forces: List of target contact forces (unit: grams).target_angles: List of target angles.step_size: The angle step for each iteration.max_iterations: The maximum number of iterations.
- Returns: A dictionary containing detailed results and history.
demonstrate_force_calibration(port: str, hand_id: int)
- Function: Starts an interactive force sensor calibration routine. It is recommended to run this before performing precision tasks.
- Controller Precision and Response: The precision and response speed of the finger controllers are currently limited.
- Force Control Overshoot: Even at the slowest movement speeds, the force control can overshoot the preset target values by 50-100 grams.
- High-Speed Behavior: When moving at high speeds, the fingers tend to "ignore" the preset maximum force thresholds and move directly to their peak force.
- Testing Status: All features have currently only undergone light and informal testing.






