"""T-Rex Pinocchio FK helpers (no dexmate_urdf / coal install required).""" from __future__ import annotations import sys import types from functools import lru_cache from pathlib import Path from typing import Callable import numpy as np import pinocchio as pin from pinocchio.robot_wrapper import RobotWrapper _TREX_ROOT = Path("/scratch1/home/zhicao/T-Rex") _QS_SRC = _TREX_ROOT / "dataset_quickstart" / "src" _DEXMATE_PKG = _TREX_ROOT / "hardware_code" / "third_party" / "dexmate-urdf" / "src" _VEGA_DIR = _DEXMATE_PKG / "dexmate_urdf" / "robots" / "humanoid" / "vega_1" VEGA_URDF = str(_VEGA_DIR / "vega_1.urdf") VEGA_PKG = str(_VEGA_DIR) VEGA_SRDF = str(_VEGA_DIR / "vega_1.srdf") DEFAULT_TORSO = np.array([0.9, 1.57, 0.1]) DEFAULT_HEAD = np.array([0.28, 0.0, 0.0]) SHARPA_LEFT_HAND_JOINT_ORDER = [ "left_thumb_CMC_FE", "left_thumb_CMC_AA", "left_thumb_MCP_FE", "left_thumb_MCP_AA", "left_thumb_IP", "left_index_MCP_FE", "left_index_MCP_AA", "left_index_PIP", "left_index_DIP", "left_middle_MCP_FE", "left_middle_MCP_AA", "left_middle_PIP", "left_middle_DIP", "left_ring_MCP_FE", "left_ring_MCP_AA", "left_ring_PIP", "left_ring_DIP", "left_pinky_CMC", "left_pinky_MCP_FE", "left_pinky_MCP_AA", "left_pinky_PIP", "left_pinky_DIP", ] SHARPA_RIGHT_HAND_JOINT_ORDER = [ "right_thumb_CMC_FE", "right_thumb_CMC_AA", "right_thumb_MCP_FE", "right_thumb_MCP_AA", "right_thumb_IP", "right_index_MCP_FE", "right_index_MCP_AA", "right_index_PIP", "right_index_DIP", "right_middle_MCP_FE", "right_middle_MCP_AA", "right_middle_PIP", "right_middle_DIP", "right_ring_MCP_FE", "right_ring_MCP_AA", "right_ring_PIP", "right_ring_DIP", "right_pinky_CMC", "right_pinky_MCP_FE", "right_pinky_MCP_AA", "right_pinky_PIP", "right_pinky_DIP", ] def _bootstrap_trex_imports() -> None: if "coal" not in sys.modules: coal = types.ModuleType("coal") coal.Box = lambda *args, **kwargs: None sys.modules["coal"] = coal vega_1 = types.SimpleNamespace( urdf=VEGA_URDF, _parent_dir=VEGA_PKG, srdf=VEGA_SRDF, ) vega_1_mod = types.ModuleType("dexmate_urdf.robots.humanoid.vega_1") vega_1_mod.vega_1 = vega_1 humanoid = types.ModuleType("dexmate_urdf.robots.humanoid") humanoid.vega_1 = vega_1_mod robots = types.ModuleType("dexmate_urdf.robots") robots.humanoid = humanoid dexmate_urdf = types.ModuleType("dexmate_urdf") dexmate_urdf.robots = robots for name, mod in [ ("dexmate_urdf", dexmate_urdf), ("dexmate_urdf.robots", robots), ("dexmate_urdf.robots.humanoid", humanoid), ("dexmate_urdf.robots.humanoid.vega_1", vega_1_mod), ]: sys.modules.setdefault(name, mod) qs = str(_QS_SRC) if qs not in sys.path: sys.path.insert(0, qs) @lru_cache(maxsize=1) def _load_robot_modules(): _bootstrap_trex_imports() from trex_dataset_quickstart.robot import ( # noqa: WPS433 build_full_robot, build_reduced_bimanual_robot, forward_kinematics, ) return build_full_robot, build_reduced_bimanual_robot, forward_kinematics @lru_cache(maxsize=1) def get_full_robot() -> tuple[RobotWrapper, Callable, Callable]: build_full_robot, _, _ = _load_robot_modules() return build_full_robot({"head": DEFAULT_HEAD, "torso": DEFAULT_TORSO}) @lru_cache(maxsize=1) def get_bimanual_robot() -> tuple[RobotWrapper, Callable, Callable]: _, build_reduced_bimanual_robot, _ = _load_robot_modules() return build_reduced_bimanual_robot({"head": DEFAULT_HEAD, "torso": DEFAULT_TORSO}) def state_to_components(state58: np.ndarray) -> dict[str, np.ndarray]: s = np.asarray(state58, dtype=np.float64).reshape(-1) if s.shape[0] != 58: raise ValueError(f"expected 58-dim state, got {s.shape[0]}") return { "left_arm": s[0:7], "left_hand": s[7:29], "right_arm": s[29:36], "right_hand": s[36:58], } def hand_joint_positions_3d( robot: RobotWrapper, qpos: np.ndarray, joint_names: list[str], ) -> np.ndarray: pin.forwardKinematics(robot.model, robot.data, qpos) pin.updateFramePlacements(robot.model, robot.data) pts = np.zeros((len(joint_names), 3), dtype=np.float64) for i, name in enumerate(joint_names): fid = robot.model.getFrameId(name, pin.FrameType.JOINT) pts[i] = robot.data.oMf[fid].translation return pts def frame_pose_matrix(robot: RobotWrapper, qpos: np.ndarray, frame_name: str) -> np.ndarray: pin.forwardKinematics(robot.model, robot.data, qpos) pin.updateFramePlacements(robot.model, robot.data) fid = robot.model.getFrameId(frame_name) se3 = robot.data.oMf[fid] T = np.eye(4, dtype=np.float64) T[:3, :3] = se3.rotation T[:3, 3] = se3.translation return T def hand_keypoints_world( state58: np.ndarray, ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: """Return left/right hand (22,3) keypoints and L_ee/R_ee cam-to-world 4x4.""" comps = state_to_components(state58) full_robot, assemble_full, _ = get_full_robot() bimanual_robot, assemble_bimanual, _ = get_bimanual_robot() q_full = assemble_full(comps) q_bi = assemble_bimanual( {"left_arm": comps["left_arm"], "right_arm": comps["right_arm"]}, ) left_pts = hand_joint_positions_3d(full_robot, q_full, SHARPA_LEFT_HAND_JOINT_ORDER) right_pts = hand_joint_positions_3d(full_robot, q_full, SHARPA_RIGHT_HAND_JOINT_ORDER) T_left_ee = frame_pose_matrix(full_robot, q_full, "L_ee") T_right_ee = frame_pose_matrix(full_robot, q_full, "R_ee") T_head_cam = frame_pose_matrix(bimanual_robot, q_bi, "zed_left_camera") return left_pts, right_pts, T_head_cam, (T_left_ee, T_right_ee)