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/TriggerCall the service to move fingers to specific angles while trying to achieve target forces.
ros2 service call /adaptive_force_control rh56_controller/srv/AdaptiveForce '{
"target_forces": [100, 100, 100, 500, 100, 100],
"target_angles": [1000, 1000, 1000, 0, 1000, 1000],
"step_size": 50,
"max_iterations": 20
}'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.
Legacy 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.