Examples

This section demonstrates how to use the DexRobot Kinematics library with complete example scripts.

Hardware control using finger inverse kinematics

In this example, we solve inverse kinematics for a finger, and send the resulting joint angles to DexHand using the pyzlg_dexhand library.

examples/finger_ik_hardware.py
 1"""
 2Solve IK for a single finger and directly control the hardware.
 3
 4The code works for the right hand by default, but you can change the hand as needed.
 5"""
 6
 7import numpy as np
 8import time
 9from dexrobot_kinematics.hand import RightHandKinematics
10from dexrobot_kinematics.utils.types import Position
11from dexrobot_kinematics.utils.hardware import JointMapping
12from pyzlg_dexhand.dexhand_interface import RightDexHand
13
14# Initialize hand
15kin = RightHandKinematics()
16hand = RightDexHand()
17joint_mapping = JointMapping(prefix="r")
18
19# Define a circular trajectory
20center = Position(x=0.01, y=0.04, z=0.22)
21radius = 0.05
22steps = 20
23
24# Simulate motion
25for i in range(2 * steps):
26    # Calculate position along circle
27    if i < steps:
28        angle = np.pi * i / steps
29    else:
30        angle = np.pi * (2 * steps - i) / steps
31    target = Position(
32        x=center.x + radius * np.sin(angle),
33        y=center.y,
34        z=center.z + radius * np.cos(angle),
35    )
36
37    # Solve IK
38    joint_angles, success = kin.inverse_kinematics_finger(
39        finger="index", target_pos=target
40    )
41
42    print(f"Step {i}: Pos ({target.x:.4f}, {target.y:.4f}, {target.z:.4f}), Angles {list(joint_angles.values())}, Success: {success}")
43    # In a real system, you would send these angles to the robot
44    commands = joint_mapping.map_command(joint_angles)
45    hand.move_joints(**commands)
46    hand.clear_errors(clear_all=True)
47    time.sleep(0.1)

Interfacing inverse kinematics with ROS

In this example, we solve inverse kinematics for a finger, and publish the resulting joint angles to a ROS topic. The script can be used in combination with ROS nodes in pyzlg_dexhand or dexrobot_mujoco to control either hardware or simulated hand.

examples/finger_ik_ros.py
 1"""
 2Solve IK for a single finger and send the result to ROS/ROS2.
 3
 4Can be used together with the ROS nodes in dexrobot_mujoco or pyzlg_dexhand to control either the hardware or a simulation.
 5"""
 6
 7import numpy as np
 8import time
 9from ros_compat import ROSNode
10from sensor_msgs.msg import JointState
11from dexrobot_kinematics.hand import RightHandKinematics
12from dexrobot_kinematics.utils.types import Position
13from dexrobot_kinematics.utils.hardware import JointMapping
14
15
16class DexHandIKNode(ROSNode):
17    def __init__(self):
18        super().__init__("dexhand_ik_node")
19        self.kin = RightHandKinematics()
20        self.joint_pub = self.create_publisher(JointState, "joint_commands", 10)
21        self.timer = self.create_timer(0.1, self.timer_callback)
22        self.counter = 0
23
24    def timer_callback(self):
25        # Define a circular trajectory
26        center = Position(x=0.01, y=0.04, z=0.22)
27        radius = 0.05
28        steps = 20
29
30        # Calculate position along circle
31        i = self.counter
32        self.counter += 1
33        if i < steps:
34            angle = np.pi * i / steps
35        else:
36            angle = np.pi * (2 * steps - i) / steps
37        target = Position(
38            x=center.x + radius * np.sin(angle),
39            y=center.y,
40            z=center.z + radius * np.cos(angle),
41        )
42
43        # Solve IK
44        joint_angles, success = self.kin.inverse_kinematics_finger(
45            finger="index", target_pos=target
46        )
47
48        print(f"Step {i}: Pos ({target.x:.4f}, {target.y:.4f}, {target.z:.4f}), Angles {list(joint_angles.values())}, Success: {success}")
49
50        # Publish joint angles
51        msg = JointState()
52        msg.header.stamp = self.get_ros_time().to_msg()
53        msg.name = list(joint_angles.keys())
54        msg.position = list(joint_angles.values())
55        self.joint_pub.publish(msg)
56
57if __name__ == "__main__":
58    node = DexHandIKNode()
59    node.spin()

Forward kinematics based on hardware feedback

In this example, we read joint angles from DexHand using the pyzlg_dexhand library, and compute the forward kinematics to get the fingerpad and fingertip poses.

examples/fk_hardware.py
 1"""
 2Run FK to obtain fingertip and fingerpad positions, from hardware joint angle readings.
 3"""
 4
 5import numpy as np
 6from dexrobot_kinematics.hand import RightHandKinematics
 7from dexrobot_kinematics.utils.types import Position, Pose
 8from dexrobot_kinematics.utils.hardware import JointMapping
 9from pyzlg_dexhand.dexhand_interface import RightDexHand
10
11# Initialize hand
12kin = RightHandKinematics()
13hand = RightDexHand()
14joint_mapping = JointMapping(prefix="r")
15
16# Drive the hand joints to a known position and read feedback
17commands = {
18    "th_rot": 30,
19    "th_mcp": 30,
20    "th_dip": 30,
21    "ff_spr": 20,
22    "ff_mcp": 30,
23    "ff_dip": 30,
24    "mf_mcp": 30,
25    "mf_dip": 30,
26    "rf_mcp": 30,
27    "rf_dip": 30,
28    "lf_mcp": 30,
29    "lf_dip": 30,
30}
31for i in range(10):
32    hand.move_joints(**commands)
33    hand.clear_errors(clear_all=True)
34feedback = hand.get_feedback()
35hardware_feedback_angles = {name: joint.angle for (name, joint) in feedback.joints.items()}
36joint_angles = joint_mapping.map_feedback(hardware_feedback_angles)
37
38# Define base pose of the hand
39R = pin.utils.rpyToMatrix(0, np.pi / 2, 0)
40t = np.array([1.0, 0.0, 0.0])
41base_pose = Pose(position=Position.from_array(t), orientation=R)
42
43# Run forward kinematics
44fingertip_poses_hand = kin.forward_kinematics(joint_angles, frame="hand", end_effector="fingertip")
45fingerpad_poses_hand = kin.forward_kinematics(joint_angles, frame="hand", end_effector="fingerpad")
46fingertip_poses_world = kin.forward_kinematics(joint_angles, base_pose=base_pose, frame="world", end_effector="fingertip")
47fingerpad_poses_world = kin.forward_kinematics(joint_angles, base_pose=base_pose, frame="world", end_effector="fingerpad")
48
49# Print results tables
50print("Fingertip poses (hand frame):")
51print("Finger | Position (m) | Quaternion")
52for finger, pose in fingertip_poses_hand.items():
53    print(f"{finger:6} | {pose.position.to_array()} | {pose.orientation.to_quaternion()}")
54print("\nFingerpad poses (hand frame):")
55print("Finger | Position (m) | Quaternion")
56for finger, pose in fingerpad_poses_hand.items():
57    print(f"{finger:6} | {pose.position.to_array()} | {pose.orientation.to_quaternion()}")
58print("\nFingertip poses (world frame):")
59print("Finger | Position (m) | Quaternion")
60for finger, pose in fingertip_poses_world.items():
61    print(f"{finger:6} | {pose.position.to_array()} | {pose.orientation.to_quaternion()}")
62print("\nFingerpad poses (world frame):")
63print("Finger | Position (m) | Quaternion")
64for finger, pose in fingerpad_poses_world.items():
65    print(f"{finger:6} | {pose.position.to_array()} | {pose.orientation.to_quaternion()}")