robogym/robot/shadow_hand/hand_forward_kinematics.py (47 lines of code) (raw):
import numpy as np
from robogym.mujoco.forward_kinematics import ForwardKinematics
from robogym.mujoco.mujoco_xml import MujocoXML
from robogym.robot.shadow_hand import hand_interface
FINGERTIP_SITE_NAMES = [
"S_fftip",
"S_mftip",
"S_rftip",
"S_lftip",
"S_thtip",
]
REFERENCE_SITE_NAMES = [
"phasespace_ref0",
"phasespace_ref1",
"phasespace_ref2",
]
HAND_KINEMATICS = ForwardKinematics.prepare(
MujocoXML.parse("robot/shadowhand/main.xml"),
"hand_mount",
[1.0, 1.25, 0.15],
[np.pi / 2, 0, np.pi],
REFERENCE_SITE_NAMES + FINGERTIP_SITE_NAMES,
hand_interface.JOINTS,
)
ZERO_JOINT_POSITIONS = HAND_KINEMATICS.compute(np.zeros(len(hand_interface.JOINTS)))
REFERENCE_POSITIONS = ZERO_JOINT_POSITIONS[:3]
def hand_forward_kinematics(qpos, return_joint_pos=False):
""" Calculate forward kinematics of the hand """
return HAND_KINEMATICS.compute(qpos, return_joint_pos)[3:]
def get_relative_positions(fingertips_xpos, reference_xpos=REFERENCE_POSITIONS):
""" Return positions relative to the reference points """
fingertips_xpos = fingertips_xpos.copy()
reference_xpos = reference_xpos.copy()
fingertips_xpos -= reference_xpos[1]
reference_xpos -= reference_xpos[1] # This point makes other two orthogonal.
for idx in [0, 2]:
reference_xpos[idx] /= np.sqrt(np.sum(np.square(reference_xpos[idx])))
ort = np.cross(reference_xpos[0], reference_xpos[2])
m = np.transpose(np.array([reference_xpos[0], ort, reference_xpos[2]]))
return np.matmul(fingertips_xpos, m)
def compute_forward_kinematics_fingertips(
joint_positions, reference_xpos=REFERENCE_POSITIONS, return_joint_pos=False
) -> np.ndarray:
"""
Compute fingertip positions using forward kinematics from joint angles.
:returns 5x3-element array of current fingertip positions (5 fingertips in 3D)
"""
fingertip_absolute_positions = hand_forward_kinematics(
joint_positions, return_joint_pos=return_joint_pos
)
return get_relative_positions(
fingertip_absolute_positions, reference_xpos=reference_xpos
)