Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/__init__.py +0 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/g1_body.py +67 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/g1_env.py +324 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/g1_hand.py +89 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/__init__.py +0 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/base_sim.py +772 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/image_publish_utils.py +256 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/metric_utils.py +71 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/robocasa_sim.py +63 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/sim_utilts.py +96 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/simulator_factory.py +144 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/unitree_sdk2py_bridge.py +459 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/__init__.py +0 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/command_sender.py +146 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/joint_safety.py +534 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/state_processor.py +143 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/__init__.py +0 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/async_env_server.py +305 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/sync_env.py +586 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/__init__.py +0 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/cam_key_converter.py +73 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/controller_utils.py +54 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/robocasa_env.py +443 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/robot_key_converter.py +301 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/sim_utils.py +8 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/__init__.py +0 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/configs.py +483 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/g1_29dof_gear_wbc.yaml +421 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/g1_gear_wbc.yaml +45 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/identifiers.py +14 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/playback_sync_sim_data.py +627 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_camera_viewer.py +249 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_g1_control_loop.py +236 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_g1_data_exporter.py +364 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_navigation_policy_loop.py +68 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_sim_loop.py +61 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_sync_sim_data_collection.py +213 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_teleop_policy_loop.py +110 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/instantiation/__init__.py +15 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/instantiation/g1.py +62 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof.urdf +1091 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_old.xml +568 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_with_hand.urdf +1497 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_with_hand.xml +748 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_with_hand_rev_1_0_activatedfinger.xml +669 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/lift_box_43dof.xml +49 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/meshes/left_ankle_pitch_link.STL +0 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/meshes/left_elbow_link.STL +0 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/meshes/left_hand_thumb_0_link.STL +0 -0
- GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/meshes/left_wrist_pitch_link.STL +0 -0
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/__init__.py
ADDED
|
File without changes
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/g1_body.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any, Dict
|
| 2 |
+
|
| 3 |
+
import gymnasium as gym
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
from decoupled_wbc.control.base.env import Env
|
| 7 |
+
from decoupled_wbc.control.envs.g1.utils.command_sender import BodyCommandSender
|
| 8 |
+
from decoupled_wbc.control.envs.g1.utils.state_processor import BodyStateProcessor
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class G1Body(Env):
|
| 12 |
+
def __init__(self, config: Dict[str, Any]):
|
| 13 |
+
super().__init__()
|
| 14 |
+
self.body_state_processor = BodyStateProcessor(config=config)
|
| 15 |
+
self.body_command_sender = BodyCommandSender(config=config)
|
| 16 |
+
|
| 17 |
+
def observe(self) -> dict[str, any]:
|
| 18 |
+
body_state = self.body_state_processor._prepare_low_state() # (1, 148)
|
| 19 |
+
assert body_state.shape == (1, 148)
|
| 20 |
+
body_q = body_state[
|
| 21 |
+
0, 7 : 7 + 12 + 3 + 7 + 7
|
| 22 |
+
] # leg (12) + waist (3) + left arm (7) + right arm (7)
|
| 23 |
+
body_dq = body_state[0, 42 : 42 + 12 + 3 + 7 + 7]
|
| 24 |
+
body_ddq = body_state[0, 112 : 112 + 12 + 3 + 7 + 7]
|
| 25 |
+
body_tau_est = body_state[0, 77 : 77 + 12 + 3 + 7 + 7]
|
| 26 |
+
floating_base_pose = body_state[0, 0:7]
|
| 27 |
+
floating_base_vel = body_state[0, 36:42]
|
| 28 |
+
floating_base_acc = body_state[0, 106:112]
|
| 29 |
+
torso_quat = body_state[0, 141:145]
|
| 30 |
+
torso_ang_vel = body_state[0, 145:148]
|
| 31 |
+
|
| 32 |
+
return {
|
| 33 |
+
"body_q": body_q,
|
| 34 |
+
"body_dq": body_dq,
|
| 35 |
+
"body_ddq": body_ddq,
|
| 36 |
+
"body_tau_est": body_tau_est,
|
| 37 |
+
"floating_base_pose": floating_base_pose,
|
| 38 |
+
"floating_base_vel": floating_base_vel,
|
| 39 |
+
"floating_base_acc": floating_base_acc,
|
| 40 |
+
"torso_quat": torso_quat,
|
| 41 |
+
"torso_ang_vel": torso_ang_vel,
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
def queue_action(self, action: dict[str, any]):
|
| 45 |
+
# action should contain body_q, body_dq, body_tau
|
| 46 |
+
self.body_command_sender.send_command(
|
| 47 |
+
action["body_q"], action["body_dq"], action["body_tau"]
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
+
def observation_space(self) -> gym.Space:
|
| 51 |
+
return gym.spaces.Dict(
|
| 52 |
+
{
|
| 53 |
+
"body_q": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(29,)),
|
| 54 |
+
"body_dq": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(29,)),
|
| 55 |
+
"floating_base_pose": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(7,)),
|
| 56 |
+
"floating_base_vel": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(6,)),
|
| 57 |
+
}
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
def action_space(self) -> gym.Space:
|
| 61 |
+
return gym.spaces.Dict(
|
| 62 |
+
{
|
| 63 |
+
"body_q": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(29,)),
|
| 64 |
+
"body_dq": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(29,)),
|
| 65 |
+
"body_tau": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(29,)),
|
| 66 |
+
}
|
| 67 |
+
)
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/g1_env.py
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from copy import deepcopy
|
| 2 |
+
from typing import Dict
|
| 3 |
+
|
| 4 |
+
import gymnasium as gym
|
| 5 |
+
import numpy as np
|
| 6 |
+
from scipy.spatial.transform import Rotation as R
|
| 7 |
+
|
| 8 |
+
from decoupled_wbc.control.base.humanoid_env import Hands, HumanoidEnv
|
| 9 |
+
from decoupled_wbc.control.envs.g1.g1_body import G1Body
|
| 10 |
+
from decoupled_wbc.control.envs.g1.g1_hand import G1ThreeFingerHand
|
| 11 |
+
from decoupled_wbc.control.envs.g1.sim.simulator_factory import SimulatorFactory, init_channel
|
| 12 |
+
from decoupled_wbc.control.envs.g1.utils.joint_safety import JointSafetyMonitor
|
| 13 |
+
from decoupled_wbc.control.robot_model.instantiation.g1 import instantiate_g1_robot_model
|
| 14 |
+
from decoupled_wbc.control.robot_model.robot_model import RobotModel
|
| 15 |
+
from decoupled_wbc.control.utils.ros_utils import ROSManager
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class G1Env(HumanoidEnv):
|
| 19 |
+
def __init__(
|
| 20 |
+
self,
|
| 21 |
+
env_name: str = "default",
|
| 22 |
+
robot_model: RobotModel = None,
|
| 23 |
+
wbc_version: str = "v2",
|
| 24 |
+
config: Dict[str, any] = None,
|
| 25 |
+
**kwargs,
|
| 26 |
+
):
|
| 27 |
+
super().__init__()
|
| 28 |
+
self.robot_model = deepcopy(robot_model) # need to cache FK results
|
| 29 |
+
self.config = config
|
| 30 |
+
|
| 31 |
+
# Initialize safety monitor (visualization disabled)
|
| 32 |
+
self.safety_monitor = JointSafetyMonitor(
|
| 33 |
+
robot_model, enable_viz=False, env_type=self.config.get("ENV_TYPE", "real")
|
| 34 |
+
)
|
| 35 |
+
self.last_obs = None
|
| 36 |
+
self.last_safety_ok = True # Track last safety status from queue_action
|
| 37 |
+
|
| 38 |
+
init_channel(config=self.config)
|
| 39 |
+
|
| 40 |
+
# Initialize body and hands
|
| 41 |
+
self._body = G1Body(config=self.config)
|
| 42 |
+
|
| 43 |
+
self.with_hands = config.get("with_hands", False)
|
| 44 |
+
|
| 45 |
+
# Gravity compensation settings
|
| 46 |
+
self.enable_gravity_compensation = config.get("enable_gravity_compensation", False)
|
| 47 |
+
self.gravity_compensation_joints = config.get("gravity_compensation_joints", ["arms"])
|
| 48 |
+
|
| 49 |
+
if self.enable_gravity_compensation:
|
| 50 |
+
print(
|
| 51 |
+
f"Gravity compensation enabled for joint groups: {self.gravity_compensation_joints}"
|
| 52 |
+
)
|
| 53 |
+
if self.with_hands:
|
| 54 |
+
self._hands = Hands()
|
| 55 |
+
self._hands.left = G1ThreeFingerHand(is_left=True)
|
| 56 |
+
self._hands.right = G1ThreeFingerHand(is_left=False)
|
| 57 |
+
|
| 58 |
+
# Initialize simulator if in simulation mode
|
| 59 |
+
self.use_sim = self.config.get("ENV_TYPE") == "sim"
|
| 60 |
+
|
| 61 |
+
if self.use_sim:
|
| 62 |
+
# Create simulator using factory
|
| 63 |
+
|
| 64 |
+
kwargs.update(
|
| 65 |
+
{
|
| 66 |
+
"onscreen": self.config.get("ENABLE_ONSCREEN", True),
|
| 67 |
+
"offscreen": self.config.get("ENABLE_OFFSCREEN", False),
|
| 68 |
+
}
|
| 69 |
+
)
|
| 70 |
+
self.sim = SimulatorFactory.create_simulator(
|
| 71 |
+
config=self.config,
|
| 72 |
+
env_name=env_name,
|
| 73 |
+
wbc_version=wbc_version,
|
| 74 |
+
body_ik_solver_settings_type=kwargs.get("body_ik_solver_settings_type", "default"),
|
| 75 |
+
**kwargs,
|
| 76 |
+
)
|
| 77 |
+
else:
|
| 78 |
+
self.sim = None
|
| 79 |
+
|
| 80 |
+
# using the real robot
|
| 81 |
+
self.calibrate_hands()
|
| 82 |
+
|
| 83 |
+
# Initialize ROS 2 node
|
| 84 |
+
self.ros_manager = ROSManager(node_name="g1_env")
|
| 85 |
+
self.ros_node = self.ros_manager.node
|
| 86 |
+
|
| 87 |
+
self.delay_list = []
|
| 88 |
+
self.visualize_delay = False
|
| 89 |
+
self.print_delay_interval = 100
|
| 90 |
+
self.cnt = 0
|
| 91 |
+
|
| 92 |
+
def start_simulator(self):
|
| 93 |
+
# imag epublish disabled since the sim is running in a sub-thread
|
| 94 |
+
SimulatorFactory.start_simulator(self.sim, as_thread=True, enable_image_publish=False)
|
| 95 |
+
|
| 96 |
+
def step_simulator(self):
|
| 97 |
+
sim_num_steps = int(self.config["REWARD_DT"] / self.config["SIMULATE_DT"])
|
| 98 |
+
for _ in range(sim_num_steps):
|
| 99 |
+
self.sim.sim_env.sim_step()
|
| 100 |
+
self.sim.sim_env.update_viewer()
|
| 101 |
+
|
| 102 |
+
def body(self) -> G1Body:
|
| 103 |
+
return self._body
|
| 104 |
+
|
| 105 |
+
def hands(self) -> Hands:
|
| 106 |
+
if not self.with_hands:
|
| 107 |
+
raise RuntimeError(
|
| 108 |
+
"Hands not initialized. Use --with_hands True to enable hand functionality."
|
| 109 |
+
)
|
| 110 |
+
return self._hands
|
| 111 |
+
|
| 112 |
+
def observe(self) -> Dict[str, any]:
|
| 113 |
+
# Get observations from body and hands
|
| 114 |
+
body_obs = self.body().observe()
|
| 115 |
+
|
| 116 |
+
body_q = body_obs["body_q"]
|
| 117 |
+
body_dq = body_obs["body_dq"]
|
| 118 |
+
body_ddq = body_obs["body_ddq"]
|
| 119 |
+
body_tau_est = body_obs["body_tau_est"]
|
| 120 |
+
|
| 121 |
+
if self.with_hands:
|
| 122 |
+
left_hand_obs = self.hands().left.observe()
|
| 123 |
+
right_hand_obs = self.hands().right.observe()
|
| 124 |
+
left_hand_q = left_hand_obs["hand_q"]
|
| 125 |
+
right_hand_q = right_hand_obs["hand_q"]
|
| 126 |
+
left_hand_dq = left_hand_obs["hand_dq"]
|
| 127 |
+
right_hand_dq = right_hand_obs["hand_dq"]
|
| 128 |
+
left_hand_ddq = left_hand_obs["hand_ddq"]
|
| 129 |
+
right_hand_ddq = right_hand_obs["hand_ddq"]
|
| 130 |
+
left_hand_tau_est = left_hand_obs["hand_tau_est"]
|
| 131 |
+
right_hand_tau_est = right_hand_obs["hand_tau_est"]
|
| 132 |
+
|
| 133 |
+
# Body and hand joint measurements come in actuator order, so we need to convert them to joint order
|
| 134 |
+
whole_q = self.robot_model.get_configuration_from_actuated_joints(
|
| 135 |
+
body_actuated_joint_values=body_q,
|
| 136 |
+
left_hand_actuated_joint_values=left_hand_q,
|
| 137 |
+
right_hand_actuated_joint_values=right_hand_q,
|
| 138 |
+
)
|
| 139 |
+
whole_dq = self.robot_model.get_configuration_from_actuated_joints(
|
| 140 |
+
body_actuated_joint_values=body_dq,
|
| 141 |
+
left_hand_actuated_joint_values=left_hand_dq,
|
| 142 |
+
right_hand_actuated_joint_values=right_hand_dq,
|
| 143 |
+
)
|
| 144 |
+
whole_ddq = self.robot_model.get_configuration_from_actuated_joints(
|
| 145 |
+
body_actuated_joint_values=body_ddq,
|
| 146 |
+
left_hand_actuated_joint_values=left_hand_ddq,
|
| 147 |
+
right_hand_actuated_joint_values=right_hand_ddq,
|
| 148 |
+
)
|
| 149 |
+
whole_tau_est = self.robot_model.get_configuration_from_actuated_joints(
|
| 150 |
+
body_actuated_joint_values=body_tau_est,
|
| 151 |
+
left_hand_actuated_joint_values=left_hand_tau_est,
|
| 152 |
+
right_hand_actuated_joint_values=right_hand_tau_est,
|
| 153 |
+
)
|
| 154 |
+
else:
|
| 155 |
+
# Body and hand joint measurements come in actuator order, so we need to convert them to joint order
|
| 156 |
+
whole_q = self.robot_model.get_configuration_from_actuated_joints(
|
| 157 |
+
body_actuated_joint_values=body_q,
|
| 158 |
+
)
|
| 159 |
+
whole_dq = self.robot_model.get_configuration_from_actuated_joints(
|
| 160 |
+
body_actuated_joint_values=body_dq,
|
| 161 |
+
)
|
| 162 |
+
whole_ddq = self.robot_model.get_configuration_from_actuated_joints(
|
| 163 |
+
body_actuated_joint_values=body_ddq,
|
| 164 |
+
)
|
| 165 |
+
whole_tau_est = self.robot_model.get_configuration_from_actuated_joints(
|
| 166 |
+
body_actuated_joint_values=body_tau_est,
|
| 167 |
+
)
|
| 168 |
+
|
| 169 |
+
eef_obs = self.get_eef_obs(whole_q)
|
| 170 |
+
|
| 171 |
+
obs = {
|
| 172 |
+
"q": whole_q,
|
| 173 |
+
"dq": whole_dq,
|
| 174 |
+
"ddq": whole_ddq,
|
| 175 |
+
"tau_est": whole_tau_est,
|
| 176 |
+
"floating_base_pose": body_obs["floating_base_pose"],
|
| 177 |
+
"floating_base_vel": body_obs["floating_base_vel"],
|
| 178 |
+
"floating_base_acc": body_obs["floating_base_acc"],
|
| 179 |
+
"wrist_pose": np.concatenate([eef_obs["left_wrist_pose"], eef_obs["right_wrist_pose"]]),
|
| 180 |
+
"torso_quat": body_obs["torso_quat"],
|
| 181 |
+
"torso_ang_vel": body_obs["torso_ang_vel"],
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
if self.use_sim and self.sim:
|
| 185 |
+
obs.update(self.sim.get_privileged_obs())
|
| 186 |
+
|
| 187 |
+
# Store last observation for safety checking
|
| 188 |
+
self.last_obs = obs
|
| 189 |
+
|
| 190 |
+
return obs
|
| 191 |
+
|
| 192 |
+
@property
|
| 193 |
+
def observation_space(self) -> gym.Space:
|
| 194 |
+
# @todo: check if the low and high bounds are correct for body_obs.
|
| 195 |
+
q_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(self.robot_model.num_dofs,))
|
| 196 |
+
dq_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(self.robot_model.num_dofs,))
|
| 197 |
+
ddq_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(self.robot_model.num_dofs,))
|
| 198 |
+
tau_est_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(self.robot_model.num_dofs,))
|
| 199 |
+
floating_base_pose_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(7,))
|
| 200 |
+
floating_base_vel_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(6,))
|
| 201 |
+
floating_base_acc_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(6,))
|
| 202 |
+
wrist_pose_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(7 + 7,))
|
| 203 |
+
return gym.spaces.Dict(
|
| 204 |
+
{
|
| 205 |
+
"floating_base_pose": floating_base_pose_space,
|
| 206 |
+
"floating_base_vel": floating_base_vel_space,
|
| 207 |
+
"floating_base_acc": floating_base_acc_space,
|
| 208 |
+
"q": q_space,
|
| 209 |
+
"dq": dq_space,
|
| 210 |
+
"ddq": ddq_space,
|
| 211 |
+
"tau_est": tau_est_space,
|
| 212 |
+
"wrist_pose": wrist_pose_space,
|
| 213 |
+
}
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
def queue_action(self, action: Dict[str, any]):
|
| 217 |
+
# Safety check
|
| 218 |
+
if self.last_obs is not None:
|
| 219 |
+
safety_result = self.safety_monitor.handle_violations(self.last_obs, action)
|
| 220 |
+
action = safety_result["action"]
|
| 221 |
+
|
| 222 |
+
# Map action from joint order to actuator order
|
| 223 |
+
body_actuator_q = self.robot_model.get_body_actuated_joints(action["q"])
|
| 224 |
+
|
| 225 |
+
self.body().queue_action(
|
| 226 |
+
{
|
| 227 |
+
"body_q": body_actuator_q,
|
| 228 |
+
"body_dq": np.zeros_like(body_actuator_q),
|
| 229 |
+
"body_tau": np.zeros_like(body_actuator_q),
|
| 230 |
+
}
|
| 231 |
+
)
|
| 232 |
+
|
| 233 |
+
if self.with_hands:
|
| 234 |
+
left_hand_actuator_q = self.robot_model.get_hand_actuated_joints(
|
| 235 |
+
action["q"], side="left"
|
| 236 |
+
)
|
| 237 |
+
right_hand_actuator_q = self.robot_model.get_hand_actuated_joints(
|
| 238 |
+
action["q"], side="right"
|
| 239 |
+
)
|
| 240 |
+
self.hands().left.queue_action({"hand_q": left_hand_actuator_q})
|
| 241 |
+
self.hands().right.queue_action({"hand_q": right_hand_actuator_q})
|
| 242 |
+
|
| 243 |
+
def action_space(self) -> gym.Space:
|
| 244 |
+
return gym.spaces.Box(low=-np.inf, high=np.inf, shape=(self.robot_model.num_dofs,))
|
| 245 |
+
|
| 246 |
+
def calibrate_hands(self):
|
| 247 |
+
"""Calibrate the hand joint qpos if real robot"""
|
| 248 |
+
if self.with_hands:
|
| 249 |
+
print("calibrating left hand")
|
| 250 |
+
self.hands().left.calibrate_hand()
|
| 251 |
+
print("calibrating right hand")
|
| 252 |
+
self.hands().right.calibrate_hand()
|
| 253 |
+
else:
|
| 254 |
+
print("Skipping hand calibration - hands disabled")
|
| 255 |
+
|
| 256 |
+
def set_ik_indicator(self, teleop_cmd):
|
| 257 |
+
"""Set the IK indicators for the simulator"""
|
| 258 |
+
if self.config["SIMULATOR"] == "robocasa":
|
| 259 |
+
if "left_wrist" in teleop_cmd and "right_wrist" in teleop_cmd:
|
| 260 |
+
left_wrist_input_pose = teleop_cmd["left_wrist"]
|
| 261 |
+
right_wrist_input_pose = teleop_cmd["right_wrist"]
|
| 262 |
+
ik_wrapper = self.sim.env.env.unwrapped.env
|
| 263 |
+
ik_wrapper.set_target_poses_outside_env(
|
| 264 |
+
[left_wrist_input_pose, right_wrist_input_pose]
|
| 265 |
+
)
|
| 266 |
+
else:
|
| 267 |
+
raise NotImplementedError("IK indicators are only implemented for robocasa simulator")
|
| 268 |
+
|
| 269 |
+
def set_sync_mode(self, sync_mode: bool, steps_per_action: int = 4):
|
| 270 |
+
"""When set to True, the simulator will wait for the action to be sent to it"""
|
| 271 |
+
if self.config["SIMULATOR"] == "robocasa":
|
| 272 |
+
self.sim.set_sync_mode(sync_mode, steps_per_action)
|
| 273 |
+
|
| 274 |
+
def reset(self):
|
| 275 |
+
if self.sim:
|
| 276 |
+
self.sim.reset()
|
| 277 |
+
|
| 278 |
+
def close(self):
|
| 279 |
+
if self.sim:
|
| 280 |
+
self.sim.close()
|
| 281 |
+
|
| 282 |
+
def robot_model(self) -> RobotModel:
|
| 283 |
+
return self.robot_model
|
| 284 |
+
|
| 285 |
+
def get_reward(self):
|
| 286 |
+
if self.sim:
|
| 287 |
+
return self.sim.get_reward()
|
| 288 |
+
|
| 289 |
+
def reset_obj_pos(self):
|
| 290 |
+
if hasattr(self.sim, "base_env") and hasattr(self.sim.base_env, "reset_obj_pos"):
|
| 291 |
+
self.sim.base_env.reset_obj_pos()
|
| 292 |
+
|
| 293 |
+
def get_eef_obs(self, q: np.ndarray) -> Dict[str, np.ndarray]:
|
| 294 |
+
self.robot_model.cache_forward_kinematics(q)
|
| 295 |
+
eef_obs = {}
|
| 296 |
+
for side in ["left", "right"]:
|
| 297 |
+
wrist_placement = self.robot_model.frame_placement(
|
| 298 |
+
self.robot_model.supplemental_info.hand_frame_names[side]
|
| 299 |
+
)
|
| 300 |
+
wrist_pos, wrist_quat = wrist_placement.translation[:3], R.from_matrix(
|
| 301 |
+
wrist_placement.rotation
|
| 302 |
+
).as_quat(scalar_first=True)
|
| 303 |
+
eef_obs[f"{side}_wrist_pose"] = np.concatenate([wrist_pos, wrist_quat])
|
| 304 |
+
|
| 305 |
+
return eef_obs
|
| 306 |
+
|
| 307 |
+
def get_joint_safety_status(self) -> bool:
|
| 308 |
+
"""Get current joint safety status from the last queue_action safety check.
|
| 309 |
+
|
| 310 |
+
Returns:
|
| 311 |
+
bool: True if joints are safe (no shutdown required), False if unsafe
|
| 312 |
+
"""
|
| 313 |
+
return self.last_safety_ok
|
| 314 |
+
|
| 315 |
+
def handle_keyboard_button(self, key):
|
| 316 |
+
# Only handles keyboard buttons for the mujoco simulator for now.
|
| 317 |
+
if self.use_sim and self.config.get("SIMULATOR", "mujoco") == "mujoco":
|
| 318 |
+
self.sim.handle_keyboard_button(key)
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
if __name__ == "__main__":
|
| 322 |
+
env = G1Env(robot_model=instantiate_g1_robot_model(), wbc_version="gear_wbc")
|
| 323 |
+
while True:
|
| 324 |
+
print(env.observe())
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/g1_hand.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import time
|
| 2 |
+
|
| 3 |
+
import gymnasium as gym
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
from decoupled_wbc.control.base.env import Env
|
| 7 |
+
from decoupled_wbc.control.envs.g1.utils.command_sender import HandCommandSender
|
| 8 |
+
from decoupled_wbc.control.envs.g1.utils.state_processor import HandStateProcessor
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class G1ThreeFingerHand(Env):
|
| 12 |
+
def __init__(self, is_left: bool = True):
|
| 13 |
+
super().__init__()
|
| 14 |
+
self.is_left = is_left
|
| 15 |
+
self.hand_state_processor = HandStateProcessor(is_left=self.is_left)
|
| 16 |
+
self.hand_command_sender = HandCommandSender(is_left=self.is_left)
|
| 17 |
+
self.hand_q_offset = np.zeros(7)
|
| 18 |
+
|
| 19 |
+
def observe(self) -> dict[str, any]:
|
| 20 |
+
hand_state = self.hand_state_processor._prepare_low_state() # (1, 28)
|
| 21 |
+
assert hand_state.shape == (1, 28)
|
| 22 |
+
|
| 23 |
+
# Apply offset to the hand state
|
| 24 |
+
hand_state[0, :7] = hand_state[0, :7] + self.hand_q_offset
|
| 25 |
+
|
| 26 |
+
hand_q = hand_state[0, :7]
|
| 27 |
+
hand_dq = hand_state[0, 7:14]
|
| 28 |
+
hand_ddq = hand_state[0, 21:28]
|
| 29 |
+
hand_tau_est = hand_state[0, 14:21]
|
| 30 |
+
|
| 31 |
+
# Return the state for this specific hand (left or right)
|
| 32 |
+
return {
|
| 33 |
+
"hand_q": hand_q,
|
| 34 |
+
"hand_dq": hand_dq,
|
| 35 |
+
"hand_ddq": hand_ddq,
|
| 36 |
+
"hand_tau_est": hand_tau_est,
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
def queue_action(self, action: dict[str, any]):
|
| 40 |
+
# Apply offset to the hand target
|
| 41 |
+
action["hand_q"] = action["hand_q"] - self.hand_q_offset
|
| 42 |
+
|
| 43 |
+
# action should contain hand_q
|
| 44 |
+
self.hand_command_sender.send_command(action["hand_q"])
|
| 45 |
+
|
| 46 |
+
def observation_space(self) -> gym.Space:
|
| 47 |
+
return gym.spaces.Dict(
|
| 48 |
+
{
|
| 49 |
+
"hand_q": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(7,)),
|
| 50 |
+
"hand_dq": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(7,)),
|
| 51 |
+
"hand_ddq": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(7,)),
|
| 52 |
+
"hand_tau_est": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(7,)),
|
| 53 |
+
}
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
def action_space(self) -> gym.Space:
|
| 57 |
+
return gym.spaces.Dict({"hand_q": gym.spaces.Box(low=-np.inf, high=np.inf, shape=(7,))})
|
| 58 |
+
|
| 59 |
+
def calibrate_hand(self):
|
| 60 |
+
hand_obs = self.observe()
|
| 61 |
+
hand_q = hand_obs["hand_q"]
|
| 62 |
+
|
| 63 |
+
hand_q_target = np.zeros_like(hand_q)
|
| 64 |
+
hand_q_target[0] = hand_q[0]
|
| 65 |
+
|
| 66 |
+
# joint limit
|
| 67 |
+
hand_q0_upper_limit = np.deg2rad(60) # lower limit is -60
|
| 68 |
+
|
| 69 |
+
# move the figure counterclockwise until the limit
|
| 70 |
+
while True:
|
| 71 |
+
|
| 72 |
+
if hand_q_target[0] - hand_q[0] < np.deg2rad(60):
|
| 73 |
+
hand_q_target[0] += np.deg2rad(10)
|
| 74 |
+
else:
|
| 75 |
+
self.hand_q_offset[0] = hand_q0_upper_limit - hand_q[0]
|
| 76 |
+
break
|
| 77 |
+
|
| 78 |
+
self.queue_action({"hand_q": hand_q_target})
|
| 79 |
+
|
| 80 |
+
hand_obs = self.observe()
|
| 81 |
+
hand_q = hand_obs["hand_q"]
|
| 82 |
+
|
| 83 |
+
time.sleep(0.1)
|
| 84 |
+
|
| 85 |
+
print("done calibration, q0 offset (deg):", np.rad2deg(self.hand_q_offset[0]))
|
| 86 |
+
|
| 87 |
+
# done calibrating, set target to zero
|
| 88 |
+
self.hand_q_target = np.zeros_like(hand_q)
|
| 89 |
+
self.queue_action({"hand_q": self.hand_q_target})
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/__init__.py
ADDED
|
File without changes
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/base_sim.py
ADDED
|
@@ -0,0 +1,772 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import pathlib
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
import threading
|
| 5 |
+
from threading import Lock, Thread
|
| 6 |
+
from typing import Dict
|
| 7 |
+
|
| 8 |
+
import mujoco
|
| 9 |
+
import mujoco.viewer
|
| 10 |
+
import numpy as np
|
| 11 |
+
import rclpy
|
| 12 |
+
from unitree_sdk2py.core.channel import ChannelFactoryInitialize
|
| 13 |
+
import yaml
|
| 14 |
+
|
| 15 |
+
from decoupled_wbc.control.envs.g1.sim.image_publish_utils import ImagePublishProcess
|
| 16 |
+
from decoupled_wbc.control.envs.g1.sim.metric_utils import check_contact, check_height
|
| 17 |
+
from decoupled_wbc.control.envs.g1.sim.sim_utilts import get_subtree_body_names
|
| 18 |
+
from decoupled_wbc.control.envs.g1.sim.unitree_sdk2py_bridge import ElasticBand, UnitreeSdk2Bridge
|
| 19 |
+
|
| 20 |
+
DECOUPLED_WBC_ROOT = Path(__file__).resolve().parent.parent.parent.parent.parent.parent
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
class DefaultEnv:
|
| 24 |
+
"""Base environment class that handles simulation environment setup and step"""
|
| 25 |
+
|
| 26 |
+
def __init__(
|
| 27 |
+
self,
|
| 28 |
+
config: Dict[str, any],
|
| 29 |
+
env_name: str = "default",
|
| 30 |
+
camera_configs: Dict[str, any] = {},
|
| 31 |
+
onscreen: bool = False,
|
| 32 |
+
offscreen: bool = False,
|
| 33 |
+
enable_image_publish: bool = False,
|
| 34 |
+
):
|
| 35 |
+
# global_view is only set up for this specifc scene for now.
|
| 36 |
+
if config["ROBOT_SCENE"] == "decoupled_wbc/control/robot_model/model_data/g1/scene_29dof.xml":
|
| 37 |
+
camera_configs["global_view"] = {
|
| 38 |
+
"height": 400,
|
| 39 |
+
"width": 400,
|
| 40 |
+
}
|
| 41 |
+
self.config = config
|
| 42 |
+
self.env_name = env_name
|
| 43 |
+
self.num_body_dof = self.config["NUM_JOINTS"]
|
| 44 |
+
self.num_hand_dof = self.config["NUM_HAND_JOINTS"]
|
| 45 |
+
self.sim_dt = self.config["SIMULATE_DT"]
|
| 46 |
+
self.obs = None
|
| 47 |
+
self.torques = np.zeros(self.num_body_dof + self.num_hand_dof * 2)
|
| 48 |
+
self.torque_limit = np.array(self.config["motor_effort_limit_list"])
|
| 49 |
+
self.camera_configs = camera_configs
|
| 50 |
+
|
| 51 |
+
# Thread safety lock
|
| 52 |
+
self.reward_lock = Lock()
|
| 53 |
+
|
| 54 |
+
# Unitree bridge will be initialized by the simulator
|
| 55 |
+
self.unitree_bridge = None
|
| 56 |
+
|
| 57 |
+
# Store display mode
|
| 58 |
+
self.onscreen = onscreen
|
| 59 |
+
|
| 60 |
+
# Initialize scene (defined in subclasses)
|
| 61 |
+
self.init_scene()
|
| 62 |
+
self.last_reward = 0
|
| 63 |
+
|
| 64 |
+
# Setup offscreen rendering if needed
|
| 65 |
+
self.offscreen = offscreen
|
| 66 |
+
if self.offscreen:
|
| 67 |
+
self.init_renderers()
|
| 68 |
+
self.image_dt = self.config.get("IMAGE_DT", 0.033333)
|
| 69 |
+
self.image_publish_process = None
|
| 70 |
+
|
| 71 |
+
def start_image_publish_subprocess(self, start_method: str = "spawn", camera_port: int = 5555):
|
| 72 |
+
# Use spawn method for better GIL isolation, or configured method
|
| 73 |
+
if len(self.camera_configs) == 0:
|
| 74 |
+
print(
|
| 75 |
+
"Warning: No camera configs provided, image publishing subprocess will not be started"
|
| 76 |
+
)
|
| 77 |
+
return
|
| 78 |
+
start_method = self.config.get("MP_START_METHOD", "spawn")
|
| 79 |
+
self.image_publish_process = ImagePublishProcess(
|
| 80 |
+
camera_configs=self.camera_configs,
|
| 81 |
+
image_dt=self.image_dt,
|
| 82 |
+
zmq_port=camera_port,
|
| 83 |
+
start_method=start_method,
|
| 84 |
+
verbose=self.config.get("verbose", False),
|
| 85 |
+
)
|
| 86 |
+
self.image_publish_process.start_process()
|
| 87 |
+
|
| 88 |
+
def init_scene(self):
|
| 89 |
+
"""Initialize the default robot scene"""
|
| 90 |
+
self.mj_model = mujoco.MjModel.from_xml_path(
|
| 91 |
+
str(pathlib.Path(DECOUPLED_WBC_ROOT) / self.config["ROBOT_SCENE"])
|
| 92 |
+
)
|
| 93 |
+
self.mj_data = mujoco.MjData(self.mj_model)
|
| 94 |
+
self.mj_model.opt.timestep = self.sim_dt
|
| 95 |
+
self.torso_index = mujoco.mj_name2id(self.mj_model, mujoco.mjtObj.mjOBJ_BODY, "torso_link")
|
| 96 |
+
self.root_body = "pelvis"
|
| 97 |
+
# Enable the elastic band
|
| 98 |
+
if self.config["ENABLE_ELASTIC_BAND"]:
|
| 99 |
+
self.elastic_band = ElasticBand()
|
| 100 |
+
if "g1" in self.config["ROBOT_TYPE"]:
|
| 101 |
+
if self.config["enable_waist"]:
|
| 102 |
+
self.band_attached_link = self.mj_model.body("pelvis").id
|
| 103 |
+
else:
|
| 104 |
+
self.band_attached_link = self.mj_model.body("torso_link").id
|
| 105 |
+
elif "h1" in self.config["ROBOT_TYPE"]:
|
| 106 |
+
self.band_attached_link = self.mj_model.body("torso_link").id
|
| 107 |
+
else:
|
| 108 |
+
self.band_attached_link = self.mj_model.body("base_link").id
|
| 109 |
+
|
| 110 |
+
if self.onscreen:
|
| 111 |
+
self.viewer = mujoco.viewer.launch_passive(
|
| 112 |
+
self.mj_model,
|
| 113 |
+
self.mj_data,
|
| 114 |
+
key_callback=self.elastic_band.MujuocoKeyCallback,
|
| 115 |
+
show_left_ui=False,
|
| 116 |
+
show_right_ui=False,
|
| 117 |
+
)
|
| 118 |
+
else:
|
| 119 |
+
mujoco.mj_forward(self.mj_model, self.mj_data)
|
| 120 |
+
self.viewer = None
|
| 121 |
+
else:
|
| 122 |
+
if self.onscreen:
|
| 123 |
+
self.viewer = mujoco.viewer.launch_passive(
|
| 124 |
+
self.mj_model, self.mj_data, show_left_ui=False, show_right_ui=False
|
| 125 |
+
)
|
| 126 |
+
else:
|
| 127 |
+
mujoco.mj_forward(self.mj_model, self.mj_data)
|
| 128 |
+
self.viewer = None
|
| 129 |
+
|
| 130 |
+
if self.viewer:
|
| 131 |
+
# viewer camera
|
| 132 |
+
self.viewer.cam.azimuth = 120 # Horizontal rotation in degrees
|
| 133 |
+
self.viewer.cam.elevation = -30 # Vertical tilt in degrees
|
| 134 |
+
self.viewer.cam.distance = 2.0 # Distance from camera to target
|
| 135 |
+
self.viewer.cam.lookat = np.array([0, 0, 0.5]) # Point the camera is looking at
|
| 136 |
+
|
| 137 |
+
# Note that the actuator order is the same as the joint order in the mujoco model.
|
| 138 |
+
self.body_joint_index = []
|
| 139 |
+
self.left_hand_index = []
|
| 140 |
+
self.right_hand_index = []
|
| 141 |
+
for i in range(self.mj_model.njnt):
|
| 142 |
+
name = self.mj_model.joint(i).name
|
| 143 |
+
if any(
|
| 144 |
+
[
|
| 145 |
+
part_name in name
|
| 146 |
+
for part_name in ["hip", "knee", "ankle", "waist", "shoulder", "elbow", "wrist"]
|
| 147 |
+
]
|
| 148 |
+
):
|
| 149 |
+
self.body_joint_index.append(i)
|
| 150 |
+
elif "left_hand" in name:
|
| 151 |
+
self.left_hand_index.append(i)
|
| 152 |
+
elif "right_hand" in name:
|
| 153 |
+
self.right_hand_index.append(i)
|
| 154 |
+
|
| 155 |
+
assert len(self.body_joint_index) == self.config["NUM_JOINTS"]
|
| 156 |
+
assert len(self.left_hand_index) == self.config["NUM_HAND_JOINTS"]
|
| 157 |
+
assert len(self.right_hand_index) == self.config["NUM_HAND_JOINTS"]
|
| 158 |
+
|
| 159 |
+
self.body_joint_index = np.array(self.body_joint_index)
|
| 160 |
+
self.left_hand_index = np.array(self.left_hand_index)
|
| 161 |
+
self.right_hand_index = np.array(self.right_hand_index)
|
| 162 |
+
|
| 163 |
+
def init_renderers(self):
|
| 164 |
+
# Initialize camera renderers
|
| 165 |
+
self.renderers = {}
|
| 166 |
+
for camera_name, camera_config in self.camera_configs.items():
|
| 167 |
+
renderer = mujoco.Renderer(
|
| 168 |
+
self.mj_model, height=camera_config["height"], width=camera_config["width"]
|
| 169 |
+
)
|
| 170 |
+
self.renderers[camera_name] = renderer
|
| 171 |
+
|
| 172 |
+
def compute_body_torques(self) -> np.ndarray:
|
| 173 |
+
"""Compute body torques based on the current robot state"""
|
| 174 |
+
body_torques = np.zeros(self.num_body_dof)
|
| 175 |
+
if self.unitree_bridge is not None and self.unitree_bridge.low_cmd:
|
| 176 |
+
for i in range(self.unitree_bridge.num_body_motor):
|
| 177 |
+
if self.unitree_bridge.use_sensor:
|
| 178 |
+
body_torques[i] = (
|
| 179 |
+
self.unitree_bridge.low_cmd.motor_cmd[i].tau
|
| 180 |
+
+ self.unitree_bridge.low_cmd.motor_cmd[i].kp
|
| 181 |
+
* (self.unitree_bridge.low_cmd.motor_cmd[i].q - self.mj_data.sensordata[i])
|
| 182 |
+
+ self.unitree_bridge.low_cmd.motor_cmd[i].kd
|
| 183 |
+
* (
|
| 184 |
+
self.unitree_bridge.low_cmd.motor_cmd[i].dq
|
| 185 |
+
- self.mj_data.sensordata[i + self.unitree_bridge.num_body_motor]
|
| 186 |
+
)
|
| 187 |
+
)
|
| 188 |
+
else:
|
| 189 |
+
body_torques[i] = (
|
| 190 |
+
self.unitree_bridge.low_cmd.motor_cmd[i].tau
|
| 191 |
+
+ self.unitree_bridge.low_cmd.motor_cmd[i].kp
|
| 192 |
+
* (
|
| 193 |
+
self.unitree_bridge.low_cmd.motor_cmd[i].q
|
| 194 |
+
- self.mj_data.qpos[self.body_joint_index[i] + 7 - 1]
|
| 195 |
+
)
|
| 196 |
+
+ self.unitree_bridge.low_cmd.motor_cmd[i].kd
|
| 197 |
+
* (
|
| 198 |
+
self.unitree_bridge.low_cmd.motor_cmd[i].dq
|
| 199 |
+
- self.mj_data.qvel[self.body_joint_index[i] + 6 - 1]
|
| 200 |
+
)
|
| 201 |
+
)
|
| 202 |
+
return body_torques
|
| 203 |
+
|
| 204 |
+
def compute_hand_torques(self) -> np.ndarray:
|
| 205 |
+
"""Compute hand torques based on the current robot state"""
|
| 206 |
+
left_hand_torques = np.zeros(self.num_hand_dof)
|
| 207 |
+
right_hand_torques = np.zeros(self.num_hand_dof)
|
| 208 |
+
if self.unitree_bridge is not None and self.unitree_bridge.low_cmd:
|
| 209 |
+
for i in range(self.unitree_bridge.num_hand_motor):
|
| 210 |
+
left_hand_torques[i] = (
|
| 211 |
+
self.unitree_bridge.left_hand_cmd.motor_cmd[i].tau
|
| 212 |
+
+ self.unitree_bridge.left_hand_cmd.motor_cmd[i].kp
|
| 213 |
+
* (
|
| 214 |
+
self.unitree_bridge.left_hand_cmd.motor_cmd[i].q
|
| 215 |
+
- self.mj_data.qpos[self.left_hand_index[i] + 7 - 1]
|
| 216 |
+
)
|
| 217 |
+
+ self.unitree_bridge.left_hand_cmd.motor_cmd[i].kd
|
| 218 |
+
* (
|
| 219 |
+
self.unitree_bridge.left_hand_cmd.motor_cmd[i].dq
|
| 220 |
+
- self.mj_data.qvel[self.left_hand_index[i] + 6 - 1]
|
| 221 |
+
)
|
| 222 |
+
)
|
| 223 |
+
right_hand_torques[i] = (
|
| 224 |
+
self.unitree_bridge.right_hand_cmd.motor_cmd[i].tau
|
| 225 |
+
+ self.unitree_bridge.right_hand_cmd.motor_cmd[i].kp
|
| 226 |
+
* (
|
| 227 |
+
self.unitree_bridge.right_hand_cmd.motor_cmd[i].q
|
| 228 |
+
- self.mj_data.qpos[self.right_hand_index[i] + 7 - 1]
|
| 229 |
+
)
|
| 230 |
+
+ self.unitree_bridge.right_hand_cmd.motor_cmd[i].kd
|
| 231 |
+
* (
|
| 232 |
+
self.unitree_bridge.right_hand_cmd.motor_cmd[i].dq
|
| 233 |
+
- self.mj_data.qvel[self.right_hand_index[i] + 6 - 1]
|
| 234 |
+
)
|
| 235 |
+
)
|
| 236 |
+
return np.concatenate((left_hand_torques, right_hand_torques))
|
| 237 |
+
|
| 238 |
+
def compute_body_qpos(self) -> np.ndarray:
|
| 239 |
+
"""Compute body joint positions based on the current command"""
|
| 240 |
+
body_qpos = np.zeros(self.num_body_dof)
|
| 241 |
+
if self.unitree_bridge is not None and self.unitree_bridge.low_cmd:
|
| 242 |
+
for i in range(self.unitree_bridge.num_body_motor):
|
| 243 |
+
body_qpos[i] = self.unitree_bridge.low_cmd.motor_cmd[i].q
|
| 244 |
+
return body_qpos
|
| 245 |
+
|
| 246 |
+
def compute_hand_qpos(self) -> np.ndarray:
|
| 247 |
+
"""Compute hand joint positions based on the current command"""
|
| 248 |
+
hand_qpos = np.zeros(self.num_hand_dof * 2)
|
| 249 |
+
if self.unitree_bridge is not None and self.unitree_bridge.low_cmd:
|
| 250 |
+
for i in range(self.unitree_bridge.num_hand_motor):
|
| 251 |
+
hand_qpos[i] = self.unitree_bridge.left_hand_cmd.motor_cmd[i].q
|
| 252 |
+
hand_qpos[i + self.num_hand_dof] = self.unitree_bridge.right_hand_cmd.motor_cmd[i].q
|
| 253 |
+
return hand_qpos
|
| 254 |
+
|
| 255 |
+
def prepare_obs(self) -> Dict[str, any]:
|
| 256 |
+
"""Prepare observation dictionary from the current robot state"""
|
| 257 |
+
obs = {}
|
| 258 |
+
obs["floating_base_pose"] = self.mj_data.qpos[:7]
|
| 259 |
+
obs["floating_base_vel"] = self.mj_data.qvel[:6]
|
| 260 |
+
obs["floating_base_acc"] = self.mj_data.qacc[:6]
|
| 261 |
+
obs["secondary_imu_quat"] = self.mj_data.xquat[self.torso_index]
|
| 262 |
+
obs["secondary_imu_vel"] = self.mj_data.cvel[self.torso_index]
|
| 263 |
+
obs["body_q"] = self.mj_data.qpos[self.body_joint_index + 7 - 1]
|
| 264 |
+
obs["body_dq"] = self.mj_data.qvel[self.body_joint_index + 6 - 1]
|
| 265 |
+
obs["body_ddq"] = self.mj_data.qacc[self.body_joint_index + 6 - 1]
|
| 266 |
+
obs["body_tau_est"] = self.mj_data.actuator_force[self.body_joint_index - 1]
|
| 267 |
+
if self.num_hand_dof > 0:
|
| 268 |
+
obs["left_hand_q"] = self.mj_data.qpos[self.left_hand_index + 7 - 1]
|
| 269 |
+
obs["left_hand_dq"] = self.mj_data.qvel[self.left_hand_index + 6 - 1]
|
| 270 |
+
obs["left_hand_ddq"] = self.mj_data.qacc[self.left_hand_index + 6 - 1]
|
| 271 |
+
obs["left_hand_tau_est"] = self.mj_data.actuator_force[self.left_hand_index - 1]
|
| 272 |
+
obs["right_hand_q"] = self.mj_data.qpos[self.right_hand_index + 7 - 1]
|
| 273 |
+
obs["right_hand_dq"] = self.mj_data.qvel[self.right_hand_index + 6 - 1]
|
| 274 |
+
obs["right_hand_ddq"] = self.mj_data.qacc[self.right_hand_index + 6 - 1]
|
| 275 |
+
obs["right_hand_tau_est"] = self.mj_data.actuator_force[self.right_hand_index - 1]
|
| 276 |
+
obs["time"] = self.mj_data.time
|
| 277 |
+
return obs
|
| 278 |
+
|
| 279 |
+
def sim_step(self):
|
| 280 |
+
self.obs = self.prepare_obs()
|
| 281 |
+
self.unitree_bridge.PublishLowState(self.obs)
|
| 282 |
+
if self.unitree_bridge.joystick:
|
| 283 |
+
self.unitree_bridge.PublishWirelessController()
|
| 284 |
+
if self.config["ENABLE_ELASTIC_BAND"]:
|
| 285 |
+
if self.elastic_band.enable:
|
| 286 |
+
# Get Cartesian pose and velocity of the band_attached_link
|
| 287 |
+
pose = np.concatenate(
|
| 288 |
+
[
|
| 289 |
+
self.mj_data.xpos[self.band_attached_link], # link position in world
|
| 290 |
+
self.mj_data.xquat[
|
| 291 |
+
self.band_attached_link
|
| 292 |
+
], # link quaternion in world [w,x,y,z]
|
| 293 |
+
np.zeros(6), # placeholder for velocity
|
| 294 |
+
]
|
| 295 |
+
)
|
| 296 |
+
|
| 297 |
+
# Get velocity in world frame
|
| 298 |
+
mujoco.mj_objectVelocity(
|
| 299 |
+
self.mj_model,
|
| 300 |
+
self.mj_data,
|
| 301 |
+
mujoco.mjtObj.mjOBJ_BODY,
|
| 302 |
+
self.band_attached_link,
|
| 303 |
+
pose[7:13],
|
| 304 |
+
0, # 0 for world frame
|
| 305 |
+
)
|
| 306 |
+
|
| 307 |
+
# Reorder velocity from [ang, lin] to [lin, ang]
|
| 308 |
+
pose[7:10], pose[10:13] = pose[10:13], pose[7:10].copy()
|
| 309 |
+
self.mj_data.xfrc_applied[self.band_attached_link] = self.elastic_band.Advance(pose)
|
| 310 |
+
else:
|
| 311 |
+
# explicitly resetting the force when the band is not enabled
|
| 312 |
+
self.mj_data.xfrc_applied[self.band_attached_link] = np.zeros(6)
|
| 313 |
+
body_torques = self.compute_body_torques()
|
| 314 |
+
hand_torques = self.compute_hand_torques()
|
| 315 |
+
self.torques[self.body_joint_index - 1] = body_torques
|
| 316 |
+
if self.num_hand_dof > 0:
|
| 317 |
+
self.torques[self.left_hand_index - 1] = hand_torques[: self.num_hand_dof]
|
| 318 |
+
self.torques[self.right_hand_index - 1] = hand_torques[self.num_hand_dof :]
|
| 319 |
+
|
| 320 |
+
self.torques = np.clip(self.torques, -self.torque_limit, self.torque_limit)
|
| 321 |
+
|
| 322 |
+
if self.config["FREE_BASE"]:
|
| 323 |
+
self.mj_data.ctrl = np.concatenate((np.zeros(6), self.torques))
|
| 324 |
+
else:
|
| 325 |
+
self.mj_data.ctrl = self.torques
|
| 326 |
+
mujoco.mj_step(self.mj_model, self.mj_data)
|
| 327 |
+
# self.check_self_collision()
|
| 328 |
+
|
| 329 |
+
def kinematics_step(self):
|
| 330 |
+
"""
|
| 331 |
+
Run kinematics only: compute the qpos of the robot and directly set the qpos.
|
| 332 |
+
For debugging purposes.
|
| 333 |
+
"""
|
| 334 |
+
if self.unitree_bridge is not None:
|
| 335 |
+
self.unitree_bridge.PublishLowState(self.prepare_obs())
|
| 336 |
+
if self.unitree_bridge.joystick:
|
| 337 |
+
self.unitree_bridge.PublishWirelessController()
|
| 338 |
+
|
| 339 |
+
if self.config["ENABLE_ELASTIC_BAND"]:
|
| 340 |
+
if self.elastic_band.enable:
|
| 341 |
+
# Get Cartesian pose and velocity of the band_attached_link
|
| 342 |
+
pose = np.concatenate(
|
| 343 |
+
[
|
| 344 |
+
self.mj_data.xpos[self.band_attached_link], # link position in world
|
| 345 |
+
self.mj_data.xquat[
|
| 346 |
+
self.band_attached_link
|
| 347 |
+
], # link quaternion in world [w,x,y,z]
|
| 348 |
+
np.zeros(6), # placeholder for velocity
|
| 349 |
+
]
|
| 350 |
+
)
|
| 351 |
+
|
| 352 |
+
# Get velocity in world frame
|
| 353 |
+
mujoco.mj_objectVelocity(
|
| 354 |
+
self.mj_model,
|
| 355 |
+
self.mj_data,
|
| 356 |
+
mujoco.mjtObj.mjOBJ_BODY,
|
| 357 |
+
self.band_attached_link,
|
| 358 |
+
pose[7:13],
|
| 359 |
+
0, # 0 for world frame
|
| 360 |
+
)
|
| 361 |
+
|
| 362 |
+
# Reorder velocity from [ang, lin] to [lin, ang]
|
| 363 |
+
pose[7:10], pose[10:13] = pose[10:13], pose[7:10].copy()
|
| 364 |
+
|
| 365 |
+
self.mj_data.xfrc_applied[self.band_attached_link] = self.elastic_band.Advance(pose)
|
| 366 |
+
else:
|
| 367 |
+
# explicitly resetting the force when the band is not enabled
|
| 368 |
+
self.mj_data.xfrc_applied[self.band_attached_link] = np.zeros(6)
|
| 369 |
+
|
| 370 |
+
body_qpos = self.compute_body_qpos() # (num_body_dof,)
|
| 371 |
+
hand_qpos = self.compute_hand_qpos() # (num_hand_dof * 2,)
|
| 372 |
+
|
| 373 |
+
self.mj_data.qpos[self.body_joint_index + 7 - 1] = body_qpos
|
| 374 |
+
self.mj_data.qpos[self.left_hand_index + 7 - 1] = hand_qpos[: self.num_hand_dof]
|
| 375 |
+
self.mj_data.qpos[self.right_hand_index + 7 - 1] = hand_qpos[self.num_hand_dof :]
|
| 376 |
+
|
| 377 |
+
mujoco.mj_kinematics(self.mj_model, self.mj_data)
|
| 378 |
+
mujoco.mj_comPos(self.mj_model, self.mj_data)
|
| 379 |
+
|
| 380 |
+
def apply_perturbation(self, key):
|
| 381 |
+
"""Apply perturbation to the robot"""
|
| 382 |
+
# Add velocity perturbations in body frame
|
| 383 |
+
perturbation_x_body = 0.0 # forward/backward in body frame
|
| 384 |
+
perturbation_y_body = 0.0 # left/right in body frame
|
| 385 |
+
if key == "up":
|
| 386 |
+
perturbation_x_body = 1.0 # forward
|
| 387 |
+
elif key == "down":
|
| 388 |
+
perturbation_x_body = -1.0 # backward
|
| 389 |
+
elif key == "left":
|
| 390 |
+
perturbation_y_body = 1.0 # left
|
| 391 |
+
elif key == "right":
|
| 392 |
+
perturbation_y_body = -1.0 # right
|
| 393 |
+
|
| 394 |
+
# Transform body frame velocity to world frame using MuJoCo's rotation
|
| 395 |
+
vel_body = np.array([perturbation_x_body, perturbation_y_body, 0.0])
|
| 396 |
+
vel_world = np.zeros(3)
|
| 397 |
+
base_quat = self.mj_data.qpos[3:7] # [w, x, y, z] quaternion
|
| 398 |
+
|
| 399 |
+
# Use MuJoCo's robust quaternion rotation (handles invalid quaternions automatically)
|
| 400 |
+
mujoco.mju_rotVecQuat(vel_world, vel_body, base_quat)
|
| 401 |
+
|
| 402 |
+
# Apply to base linear velocity in world frame
|
| 403 |
+
self.mj_data.qvel[0] += vel_world[0] # world X velocity
|
| 404 |
+
self.mj_data.qvel[1] += vel_world[1] # world Y velocity
|
| 405 |
+
|
| 406 |
+
# Update dynamics after velocity change
|
| 407 |
+
mujoco.mj_forward(self.mj_model, self.mj_data)
|
| 408 |
+
|
| 409 |
+
def update_viewer(self):
|
| 410 |
+
if self.viewer is not None:
|
| 411 |
+
self.viewer.sync()
|
| 412 |
+
|
| 413 |
+
def update_viewer_camera(self):
|
| 414 |
+
if self.viewer is not None:
|
| 415 |
+
if self.viewer.cam.type == mujoco.mjtCamera.mjCAMERA_TRACKING:
|
| 416 |
+
self.viewer.cam.type = mujoco.mjtCamera.mjCAMERA_FREE
|
| 417 |
+
else:
|
| 418 |
+
self.viewer.cam.type = mujoco.mjtCamera.mjCAMERA_TRACKING
|
| 419 |
+
|
| 420 |
+
def update_reward(self):
|
| 421 |
+
"""Calculate reward. Should be implemented by subclasses."""
|
| 422 |
+
with self.reward_lock:
|
| 423 |
+
self.last_reward = 0
|
| 424 |
+
|
| 425 |
+
def get_reward(self):
|
| 426 |
+
"""Thread-safe way to get the last calculated reward."""
|
| 427 |
+
with self.reward_lock:
|
| 428 |
+
return self.last_reward
|
| 429 |
+
|
| 430 |
+
def set_unitree_bridge(self, unitree_bridge):
|
| 431 |
+
"""Set the unitree bridge from the simulator"""
|
| 432 |
+
self.unitree_bridge = unitree_bridge
|
| 433 |
+
|
| 434 |
+
def get_privileged_obs(self):
|
| 435 |
+
"""Get privileged observation. Should be implemented by subclasses."""
|
| 436 |
+
return {}
|
| 437 |
+
|
| 438 |
+
def update_render_caches(self):
|
| 439 |
+
"""Update render cache and shared memory for subprocess."""
|
| 440 |
+
render_caches = {}
|
| 441 |
+
for camera_name, camera_config in self.camera_configs.items():
|
| 442 |
+
renderer = self.renderers[camera_name]
|
| 443 |
+
if "params" in camera_config:
|
| 444 |
+
renderer.update_scene(self.mj_data, camera=camera_config["params"])
|
| 445 |
+
else:
|
| 446 |
+
renderer.update_scene(self.mj_data, camera=camera_name)
|
| 447 |
+
render_caches[camera_name + "_image"] = renderer.render()
|
| 448 |
+
|
| 449 |
+
# Update shared memory if image publishing process is available
|
| 450 |
+
if self.image_publish_process is not None:
|
| 451 |
+
self.image_publish_process.update_shared_memory(render_caches)
|
| 452 |
+
|
| 453 |
+
return render_caches
|
| 454 |
+
|
| 455 |
+
def handle_keyboard_button(self, key):
|
| 456 |
+
if self.elastic_band is not None:
|
| 457 |
+
self.elastic_band.handle_keyboard_button(key)
|
| 458 |
+
|
| 459 |
+
if key == "backspace":
|
| 460 |
+
self.reset()
|
| 461 |
+
if key == "v":
|
| 462 |
+
self.update_viewer_camera()
|
| 463 |
+
if key in ["up", "down", "left", "right"]:
|
| 464 |
+
self.apply_perturbation(key)
|
| 465 |
+
|
| 466 |
+
def check_fall(self):
|
| 467 |
+
"""Check if the robot has fallen"""
|
| 468 |
+
self.fall = False
|
| 469 |
+
if self.mj_data.qpos[2] < 0.2:
|
| 470 |
+
self.fall = True
|
| 471 |
+
print(f"Warning: Robot has fallen, height: {self.mj_data.qpos[2]:.3f} m")
|
| 472 |
+
|
| 473 |
+
if self.fall:
|
| 474 |
+
self.reset()
|
| 475 |
+
|
| 476 |
+
def check_self_collision(self):
|
| 477 |
+
"""Check for self-collision of the robot"""
|
| 478 |
+
robot_bodies = get_subtree_body_names(self.mj_model, self.mj_model.body(self.root_body).id)
|
| 479 |
+
self_collision, contact_bodies = check_contact(
|
| 480 |
+
self.mj_model, self.mj_data, robot_bodies, robot_bodies, return_all_contact_bodies=True
|
| 481 |
+
)
|
| 482 |
+
if self_collision:
|
| 483 |
+
print(f"Warning: Self-collision detected: {contact_bodies}")
|
| 484 |
+
return self_collision
|
| 485 |
+
|
| 486 |
+
def reset(self):
|
| 487 |
+
mujoco.mj_resetData(self.mj_model, self.mj_data)
|
| 488 |
+
|
| 489 |
+
|
| 490 |
+
class CubeEnv(DefaultEnv):
|
| 491 |
+
"""Environment with a cube object for pick and place tasks"""
|
| 492 |
+
|
| 493 |
+
def __init__(
|
| 494 |
+
self,
|
| 495 |
+
config: Dict[str, any],
|
| 496 |
+
onscreen: bool = False,
|
| 497 |
+
offscreen: bool = False,
|
| 498 |
+
enable_image_publish: bool = False,
|
| 499 |
+
):
|
| 500 |
+
# Override the robot scene
|
| 501 |
+
config = config.copy() # Create a copy to avoid modifying the original
|
| 502 |
+
config["ROBOT_SCENE"] = "decoupled_wbc/control/robot_model/model_data/g1/pnp_cube_43dof.xml"
|
| 503 |
+
super().__init__(config, "cube", {}, onscreen, offscreen, enable_image_publish)
|
| 504 |
+
|
| 505 |
+
def update_reward(self):
|
| 506 |
+
"""Calculate reward based on gripper contact with cube and cube height"""
|
| 507 |
+
right_hand_body = [
|
| 508 |
+
"right_hand_thumb_2_link",
|
| 509 |
+
"right_hand_middle_1_link",
|
| 510 |
+
"right_hand_index_1_link",
|
| 511 |
+
]
|
| 512 |
+
gripper_cube_contact = check_contact(
|
| 513 |
+
self.mj_model, self.mj_data, right_hand_body, "cube_body"
|
| 514 |
+
)
|
| 515 |
+
cube_lifted = check_height(self.mj_model, self.mj_data, "cube", 0.85, 2.0)
|
| 516 |
+
|
| 517 |
+
with self.reward_lock:
|
| 518 |
+
self.last_reward = gripper_cube_contact & cube_lifted
|
| 519 |
+
|
| 520 |
+
|
| 521 |
+
class BoxEnv(DefaultEnv):
|
| 522 |
+
"""Environment with a box object for manipulation tasks"""
|
| 523 |
+
|
| 524 |
+
def __init__(
|
| 525 |
+
self,
|
| 526 |
+
config: Dict[str, any],
|
| 527 |
+
onscreen: bool = False,
|
| 528 |
+
offscreen: bool = False,
|
| 529 |
+
enable_image_publish: bool = False,
|
| 530 |
+
):
|
| 531 |
+
# Override the robot scene
|
| 532 |
+
config = config.copy() # Create a copy to avoid modifying the original
|
| 533 |
+
config["ROBOT_SCENE"] = "decoupled_wbc/control/robot_model/model_data/g1/lift_box_43dof.xml"
|
| 534 |
+
super().__init__(config, "box", {}, onscreen, offscreen, enable_image_publish)
|
| 535 |
+
|
| 536 |
+
def reward(self):
|
| 537 |
+
"""Calculate reward based on gripper contact with cube and cube height"""
|
| 538 |
+
left_hand_body = [
|
| 539 |
+
"left_hand_thumb_2_link",
|
| 540 |
+
"left_hand_middle_1_link",
|
| 541 |
+
"left_hand_index_1_link",
|
| 542 |
+
]
|
| 543 |
+
right_hand_body = [
|
| 544 |
+
"right_hand_thumb_2_link",
|
| 545 |
+
"right_hand_middle_1_link",
|
| 546 |
+
"right_hand_index_1_link",
|
| 547 |
+
]
|
| 548 |
+
gripper_box_contact = check_contact(self.mj_model, self.mj_data, left_hand_body, "box_body")
|
| 549 |
+
gripper_box_contact &= check_contact(
|
| 550 |
+
self.mj_model, self.mj_data, right_hand_body, "box_body"
|
| 551 |
+
)
|
| 552 |
+
box_lifted = check_height(self.mj_model, self.mj_data, "box", 0.92, 2.0)
|
| 553 |
+
|
| 554 |
+
print("gripper_box_contact: ", gripper_box_contact, "box_lifted: ", box_lifted)
|
| 555 |
+
|
| 556 |
+
with self.reward_lock:
|
| 557 |
+
self.last_reward = gripper_box_contact & box_lifted
|
| 558 |
+
return self.last_reward
|
| 559 |
+
|
| 560 |
+
|
| 561 |
+
class BottleEnv(DefaultEnv):
|
| 562 |
+
"""Environment with a cylinder object for manipulation tasks"""
|
| 563 |
+
|
| 564 |
+
def __init__(
|
| 565 |
+
self,
|
| 566 |
+
config: Dict[str, any],
|
| 567 |
+
onscreen: bool = False,
|
| 568 |
+
offscreen: bool = False,
|
| 569 |
+
enable_image_publish: bool = False,
|
| 570 |
+
):
|
| 571 |
+
# Override the robot scene
|
| 572 |
+
config = config.copy() # Create a copy to avoid modifying the original
|
| 573 |
+
config["ROBOT_SCENE"] = "decoupled_wbc/control/robot_model/model_data/g1/pnp_bottle_43dof.xml"
|
| 574 |
+
camera_configs = {
|
| 575 |
+
"egoview": {
|
| 576 |
+
"height": 400,
|
| 577 |
+
"width": 400,
|
| 578 |
+
},
|
| 579 |
+
}
|
| 580 |
+
super().__init__(
|
| 581 |
+
config, "cylinder", camera_configs, onscreen, offscreen, enable_image_publish
|
| 582 |
+
)
|
| 583 |
+
|
| 584 |
+
self.bottle_body = self.mj_model.body("bottle_body")
|
| 585 |
+
self.bottle_geom = self.mj_model.geom("bottle")
|
| 586 |
+
|
| 587 |
+
if self.viewer is not None:
|
| 588 |
+
self.viewer.cam.type = mujoco.mjtCamera.mjCAMERA_FIXED
|
| 589 |
+
self.viewer.cam.fixedcamid = self.mj_model.camera("egoview").id
|
| 590 |
+
|
| 591 |
+
def update_reward(self):
|
| 592 |
+
"""Calculate reward based on gripper contact with cylinder and cylinder height"""
|
| 593 |
+
pass
|
| 594 |
+
|
| 595 |
+
def get_privileged_obs(self):
|
| 596 |
+
obs_pos = self.mj_data.xpos[self.bottle_body.id]
|
| 597 |
+
obs_quat = self.mj_data.xquat[self.bottle_body.id]
|
| 598 |
+
return {"bottle_pos": obs_pos, "bottle_quat": obs_quat}
|
| 599 |
+
|
| 600 |
+
|
| 601 |
+
class BaseSimulator:
|
| 602 |
+
"""Base simulator class that handles initialization and running of simulations"""
|
| 603 |
+
|
| 604 |
+
def __init__(self, config: Dict[str, any], env_name: str = "default", **kwargs):
|
| 605 |
+
self.config = config
|
| 606 |
+
self.env_name = env_name
|
| 607 |
+
|
| 608 |
+
# Initialize ROS 2 node
|
| 609 |
+
if not rclpy.ok():
|
| 610 |
+
rclpy.init()
|
| 611 |
+
self.node = rclpy.create_node("sim_mujoco")
|
| 612 |
+
self.thread = threading.Thread(target=rclpy.spin, args=(self.node,), daemon=True)
|
| 613 |
+
self.thread.start()
|
| 614 |
+
else:
|
| 615 |
+
self.thread = None
|
| 616 |
+
executor = rclpy.get_global_executor()
|
| 617 |
+
self.node = executor.get_nodes()[0] # will only take the first node
|
| 618 |
+
|
| 619 |
+
# Create rate objects for different update frequencies
|
| 620 |
+
self.sim_dt = self.config["SIMULATE_DT"]
|
| 621 |
+
self.reward_dt = self.config.get("REWARD_DT", 0.02)
|
| 622 |
+
self.image_dt = self.config.get("IMAGE_DT", 0.033333)
|
| 623 |
+
self.viewer_dt = self.config.get("VIEWER_DT", 0.02)
|
| 624 |
+
self.rate = self.node.create_rate(1 / self.sim_dt)
|
| 625 |
+
|
| 626 |
+
# Create the appropriate environment based on name
|
| 627 |
+
if env_name == "default":
|
| 628 |
+
self.sim_env = DefaultEnv(config, env_name, **kwargs)
|
| 629 |
+
elif env_name == "pnp_cube":
|
| 630 |
+
self.sim_env = CubeEnv(config, **kwargs)
|
| 631 |
+
elif env_name == "lift_box":
|
| 632 |
+
self.sim_env = BoxEnv(config, **kwargs)
|
| 633 |
+
elif env_name == "pnp_bottle":
|
| 634 |
+
self.sim_env = BottleEnv(config, **kwargs)
|
| 635 |
+
else:
|
| 636 |
+
raise ValueError(f"Invalid environment name: {env_name}")
|
| 637 |
+
|
| 638 |
+
# Initialize the DDS communication layer - should be safe to call multiple times
|
| 639 |
+
|
| 640 |
+
try:
|
| 641 |
+
if self.config.get("INTERFACE", None):
|
| 642 |
+
ChannelFactoryInitialize(self.config["DOMAIN_ID"], self.config["INTERFACE"])
|
| 643 |
+
else:
|
| 644 |
+
ChannelFactoryInitialize(self.config["DOMAIN_ID"])
|
| 645 |
+
except Exception as e:
|
| 646 |
+
# If it fails because it's already initialized, that's okay
|
| 647 |
+
print(f"Note: Channel factory initialization attempt: {e}")
|
| 648 |
+
|
| 649 |
+
# Initialize the unitree bridge and pass it to the environment
|
| 650 |
+
self.init_unitree_bridge()
|
| 651 |
+
self.sim_env.set_unitree_bridge(self.unitree_bridge)
|
| 652 |
+
|
| 653 |
+
# Initialize additional components
|
| 654 |
+
self.init_subscriber()
|
| 655 |
+
self.init_publisher()
|
| 656 |
+
|
| 657 |
+
self.sim_thread = None
|
| 658 |
+
|
| 659 |
+
def start_as_thread(self):
|
| 660 |
+
# Create simulation thread
|
| 661 |
+
self.sim_thread = Thread(target=self.start)
|
| 662 |
+
self.sim_thread.start()
|
| 663 |
+
|
| 664 |
+
def start_image_publish_subprocess(self, start_method: str = "spawn", camera_port: int = 5555):
|
| 665 |
+
"""Start the image publish subprocess"""
|
| 666 |
+
self.sim_env.start_image_publish_subprocess(start_method, camera_port)
|
| 667 |
+
|
| 668 |
+
def init_subscriber(self):
|
| 669 |
+
"""Initialize subscribers. Can be overridden by subclasses."""
|
| 670 |
+
pass
|
| 671 |
+
|
| 672 |
+
def init_publisher(self):
|
| 673 |
+
"""Initialize publishers. Can be overridden by subclasses."""
|
| 674 |
+
pass
|
| 675 |
+
|
| 676 |
+
def init_unitree_bridge(self):
|
| 677 |
+
"""Initialize the unitree SDK bridge"""
|
| 678 |
+
self.unitree_bridge = UnitreeSdk2Bridge(self.config)
|
| 679 |
+
if self.config["USE_JOYSTICK"]:
|
| 680 |
+
self.unitree_bridge.SetupJoystick(
|
| 681 |
+
device_id=self.config["JOYSTICK_DEVICE"], js_type=self.config["JOYSTICK_TYPE"]
|
| 682 |
+
)
|
| 683 |
+
|
| 684 |
+
def start(self):
|
| 685 |
+
"""Main simulation loop"""
|
| 686 |
+
sim_cnt = 0
|
| 687 |
+
|
| 688 |
+
try:
|
| 689 |
+
while (
|
| 690 |
+
self.sim_env.viewer and self.sim_env.viewer.is_running()
|
| 691 |
+
) or self.sim_env.viewer is None:
|
| 692 |
+
# Run simulation step
|
| 693 |
+
self.sim_env.sim_step()
|
| 694 |
+
|
| 695 |
+
# Update viewer at viewer rate
|
| 696 |
+
if sim_cnt % int(self.viewer_dt / self.sim_dt) == 0:
|
| 697 |
+
self.sim_env.update_viewer()
|
| 698 |
+
|
| 699 |
+
# Calculate reward at reward rate
|
| 700 |
+
if sim_cnt % int(self.reward_dt / self.sim_dt) == 0:
|
| 701 |
+
self.sim_env.update_reward()
|
| 702 |
+
|
| 703 |
+
# Update render caches at image rate
|
| 704 |
+
if sim_cnt % int(self.image_dt / self.sim_dt) == 0:
|
| 705 |
+
self.sim_env.update_render_caches()
|
| 706 |
+
|
| 707 |
+
# Sleep to maintain correct rate
|
| 708 |
+
self.rate.sleep()
|
| 709 |
+
|
| 710 |
+
sim_cnt += 1
|
| 711 |
+
except rclpy.exceptions.ROSInterruptException:
|
| 712 |
+
# This is expected when ROS shuts down - exit cleanly
|
| 713 |
+
pass
|
| 714 |
+
except Exception:
|
| 715 |
+
self.close()
|
| 716 |
+
|
| 717 |
+
def __del__(self):
|
| 718 |
+
"""Clean up resources when simulator is deleted"""
|
| 719 |
+
self.close()
|
| 720 |
+
|
| 721 |
+
def reset(self):
|
| 722 |
+
"""Reset the simulation. Can be overridden by subclasses."""
|
| 723 |
+
self.sim_env.reset()
|
| 724 |
+
|
| 725 |
+
def close(self):
|
| 726 |
+
"""Close the simulation. Can be overridden by subclasses."""
|
| 727 |
+
try:
|
| 728 |
+
# Stop image publishing subprocess
|
| 729 |
+
if self.sim_env.image_publish_process is not None:
|
| 730 |
+
self.sim_env.image_publish_process.stop()
|
| 731 |
+
|
| 732 |
+
# Close viewer
|
| 733 |
+
if hasattr(self.sim_env, "viewer") and self.sim_env.viewer is not None:
|
| 734 |
+
self.sim_env.viewer.close()
|
| 735 |
+
|
| 736 |
+
# Shutdown ROS
|
| 737 |
+
if rclpy.ok():
|
| 738 |
+
rclpy.shutdown()
|
| 739 |
+
except Exception as e:
|
| 740 |
+
print(f"Warning during close: {e}")
|
| 741 |
+
|
| 742 |
+
def get_privileged_obs(self):
|
| 743 |
+
obs = self.sim_env.get_privileged_obs()
|
| 744 |
+
# TODO: add ros2 topic to get privileged obs
|
| 745 |
+
return obs
|
| 746 |
+
|
| 747 |
+
def handle_keyboard_button(self, key):
|
| 748 |
+
# Only handles keyboard buttons for default env.
|
| 749 |
+
if self.env_name == "default":
|
| 750 |
+
self.sim_env.handle_keyboard_button(key)
|
| 751 |
+
|
| 752 |
+
|
| 753 |
+
if __name__ == "__main__":
|
| 754 |
+
parser = argparse.ArgumentParser(description="Robot")
|
| 755 |
+
parser.add_argument(
|
| 756 |
+
"--config",
|
| 757 |
+
type=str,
|
| 758 |
+
default="./decoupled_wbc/control/main/teleop/configs/g1_29dof_gear_wbc.yaml",
|
| 759 |
+
help="config file",
|
| 760 |
+
)
|
| 761 |
+
args = parser.parse_args()
|
| 762 |
+
|
| 763 |
+
with open(args.config, "r") as file:
|
| 764 |
+
config = yaml.load(file, Loader=yaml.FullLoader)
|
| 765 |
+
|
| 766 |
+
if config.get("INTERFACE", None):
|
| 767 |
+
ChannelFactoryInitialize(config["DOMAIN_ID"], config["INTERFACE"])
|
| 768 |
+
else:
|
| 769 |
+
ChannelFactoryInitialize(config["DOMAIN_ID"])
|
| 770 |
+
|
| 771 |
+
simulation = BaseSimulator(config)
|
| 772 |
+
simulation.start_as_thread()
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/image_publish_utils.py
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import multiprocessing as mp
|
| 2 |
+
from multiprocessing import shared_memory
|
| 3 |
+
import time
|
| 4 |
+
from typing import Any, Dict
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
|
| 8 |
+
from decoupled_wbc.control.sensor.sensor_server import ImageMessageSchema, SensorServer
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def get_multiprocessing_info(verbose: bool = True):
|
| 12 |
+
"""Get information about multiprocessing start methods"""
|
| 13 |
+
|
| 14 |
+
if verbose:
|
| 15 |
+
print(f"Available start methods: {mp.get_all_start_methods()}")
|
| 16 |
+
return mp.get_start_method()
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class ImagePublishProcess:
|
| 20 |
+
"""Subprocess for publishing images using shared memory and ZMQ"""
|
| 21 |
+
|
| 22 |
+
def __init__(
|
| 23 |
+
self,
|
| 24 |
+
camera_configs: Dict[str, Any],
|
| 25 |
+
image_dt: float,
|
| 26 |
+
zmq_port: int = 5555,
|
| 27 |
+
start_method: str = "spawn",
|
| 28 |
+
verbose: bool = False,
|
| 29 |
+
):
|
| 30 |
+
self.camera_configs = camera_configs
|
| 31 |
+
self.image_dt = image_dt
|
| 32 |
+
self.zmq_port = zmq_port
|
| 33 |
+
self.verbose = verbose
|
| 34 |
+
self.shared_memory_blocks = {}
|
| 35 |
+
self.shared_memory_info = {}
|
| 36 |
+
self.process = None
|
| 37 |
+
|
| 38 |
+
# Use specific context to avoid global state pollution
|
| 39 |
+
self.mp_context = mp.get_context(start_method)
|
| 40 |
+
if self.verbose:
|
| 41 |
+
print(f"Using multiprocessing context: {start_method}")
|
| 42 |
+
|
| 43 |
+
self.stop_event = self.mp_context.Event()
|
| 44 |
+
self.data_ready_event = self.mp_context.Event()
|
| 45 |
+
|
| 46 |
+
# Ensure events start in correct state
|
| 47 |
+
self.stop_event.clear()
|
| 48 |
+
self.data_ready_event.clear()
|
| 49 |
+
|
| 50 |
+
if self.verbose:
|
| 51 |
+
print(f"Initial stop_event state: {self.stop_event.is_set()}")
|
| 52 |
+
print(f"Initial data_ready_event state: {self.data_ready_event.is_set()}")
|
| 53 |
+
|
| 54 |
+
# Calculate shared memory requirements for each camera
|
| 55 |
+
for camera_name, camera_config in camera_configs.items():
|
| 56 |
+
height = camera_config["height"]
|
| 57 |
+
width = camera_config["width"]
|
| 58 |
+
# RGB image: height * width * 3 (uint8)
|
| 59 |
+
size = height * width * 3
|
| 60 |
+
|
| 61 |
+
# Create shared memory block
|
| 62 |
+
shm = shared_memory.SharedMemory(create=True, size=size)
|
| 63 |
+
self.shared_memory_blocks[camera_name] = shm
|
| 64 |
+
self.shared_memory_info[camera_name] = {
|
| 65 |
+
"name": shm.name,
|
| 66 |
+
"size": size,
|
| 67 |
+
"shape": (height, width, 3),
|
| 68 |
+
"dtype": np.uint8,
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
def start_process(self):
|
| 72 |
+
"""Start the image publishing subprocess"""
|
| 73 |
+
if self.verbose:
|
| 74 |
+
print(f"Starting subprocess with stop_event state: {self.stop_event.is_set()}")
|
| 75 |
+
self.process = self.mp_context.Process(
|
| 76 |
+
target=self._image_publish_worker,
|
| 77 |
+
args=(
|
| 78 |
+
self.shared_memory_info,
|
| 79 |
+
self.image_dt,
|
| 80 |
+
self.zmq_port,
|
| 81 |
+
self.stop_event,
|
| 82 |
+
self.data_ready_event,
|
| 83 |
+
self.verbose,
|
| 84 |
+
),
|
| 85 |
+
)
|
| 86 |
+
self.process.start()
|
| 87 |
+
if self.verbose:
|
| 88 |
+
print(f"Subprocess started, PID: {self.process.pid}")
|
| 89 |
+
|
| 90 |
+
def update_shared_memory(self, render_caches: Dict[str, np.ndarray]):
|
| 91 |
+
"""Update shared memory with new rendered images"""
|
| 92 |
+
images_updated = 0
|
| 93 |
+
for camera_name in self.camera_configs.keys():
|
| 94 |
+
image_key = f"{camera_name}_image"
|
| 95 |
+
if image_key in render_caches:
|
| 96 |
+
image = render_caches[image_key]
|
| 97 |
+
|
| 98 |
+
# Ensure image is uint8 and has correct shape
|
| 99 |
+
if image.dtype != np.uint8:
|
| 100 |
+
image = (image * 255).astype(np.uint8)
|
| 101 |
+
|
| 102 |
+
# Get shared memory array
|
| 103 |
+
shm = self.shared_memory_blocks[camera_name]
|
| 104 |
+
shared_array = np.ndarray(
|
| 105 |
+
self.shared_memory_info[camera_name]["shape"],
|
| 106 |
+
dtype=self.shared_memory_info[camera_name]["dtype"],
|
| 107 |
+
buffer=shm.buf,
|
| 108 |
+
)
|
| 109 |
+
|
| 110 |
+
# Copy image data to shared memory atomically
|
| 111 |
+
np.copyto(shared_array, image)
|
| 112 |
+
images_updated += 1
|
| 113 |
+
|
| 114 |
+
# Signal that new data is ready only after all images are written
|
| 115 |
+
if images_updated > 0:
|
| 116 |
+
if self.verbose:
|
| 117 |
+
print(f"Main process: Updated {images_updated} images, setting data_ready_event")
|
| 118 |
+
self.data_ready_event.set()
|
| 119 |
+
elif self.verbose:
|
| 120 |
+
print(
|
| 121 |
+
"Main process: No images to update. "
|
| 122 |
+
"please check if camera configs are provided and the renderer is properly initialized"
|
| 123 |
+
)
|
| 124 |
+
|
| 125 |
+
def stop(self):
|
| 126 |
+
"""Stop the image publishing subprocess"""
|
| 127 |
+
if self.verbose:
|
| 128 |
+
print("Stopping image publishing subprocess...")
|
| 129 |
+
self.stop_event.set()
|
| 130 |
+
|
| 131 |
+
if self.process and self.process.is_alive():
|
| 132 |
+
# Give the process time to clean up gracefully
|
| 133 |
+
self.process.join(timeout=5)
|
| 134 |
+
if self.process.is_alive():
|
| 135 |
+
if self.verbose:
|
| 136 |
+
print("Subprocess didn't stop gracefully, terminating...")
|
| 137 |
+
self.process.terminate()
|
| 138 |
+
self.process.join(timeout=2)
|
| 139 |
+
if self.process.is_alive():
|
| 140 |
+
if self.verbose:
|
| 141 |
+
print("Force killing subprocess...")
|
| 142 |
+
self.process.kill()
|
| 143 |
+
self.process.join()
|
| 144 |
+
|
| 145 |
+
# Clean up shared memory
|
| 146 |
+
for camera_name, shm in self.shared_memory_blocks.items():
|
| 147 |
+
try:
|
| 148 |
+
shm.close()
|
| 149 |
+
shm.unlink()
|
| 150 |
+
if self.verbose:
|
| 151 |
+
print(f"Cleaned up shared memory for {camera_name}")
|
| 152 |
+
except Exception as e:
|
| 153 |
+
if self.verbose:
|
| 154 |
+
print(f"Warning: Failed to cleanup shared memory for {camera_name}: {e}")
|
| 155 |
+
|
| 156 |
+
self.shared_memory_blocks.clear()
|
| 157 |
+
if self.verbose:
|
| 158 |
+
print("Image publishing subprocess stopped and cleaned up")
|
| 159 |
+
|
| 160 |
+
@staticmethod
|
| 161 |
+
def _image_publish_worker(
|
| 162 |
+
shared_memory_info, image_dt, zmq_port, stop_event, data_ready_event, verbose
|
| 163 |
+
):
|
| 164 |
+
"""Worker function that runs in the subprocess"""
|
| 165 |
+
if verbose:
|
| 166 |
+
print(f"Worker started! PID: {__import__('os').getpid()}")
|
| 167 |
+
print(f"Worker stop_event state at start: {stop_event.is_set()}")
|
| 168 |
+
print(f"Worker data_ready_event state at start: {data_ready_event.is_set()}")
|
| 169 |
+
|
| 170 |
+
try:
|
| 171 |
+
# Initialize ZMQ sensor server
|
| 172 |
+
sensor_server = SensorServer()
|
| 173 |
+
sensor_server.start_server(port=zmq_port)
|
| 174 |
+
|
| 175 |
+
# Connect to shared memory blocks
|
| 176 |
+
shared_arrays = {}
|
| 177 |
+
shm_blocks = {}
|
| 178 |
+
for camera_name, info in shared_memory_info.items():
|
| 179 |
+
shm = shared_memory.SharedMemory(name=info["name"])
|
| 180 |
+
shm_blocks[camera_name] = shm
|
| 181 |
+
shared_arrays[camera_name] = np.ndarray(
|
| 182 |
+
info["shape"], dtype=info["dtype"], buffer=shm.buf
|
| 183 |
+
)
|
| 184 |
+
|
| 185 |
+
print(
|
| 186 |
+
f"Image publishing subprocess started with {len(shared_arrays)} cameras on ZMQ port {zmq_port}"
|
| 187 |
+
)
|
| 188 |
+
|
| 189 |
+
loop_count = 0
|
| 190 |
+
last_data_time = time.time()
|
| 191 |
+
|
| 192 |
+
while not stop_event.is_set():
|
| 193 |
+
loop_count += 1
|
| 194 |
+
|
| 195 |
+
# Wait for new data with shorter timeout for better responsiveness
|
| 196 |
+
timeout = min(image_dt, 0.1) # Max 100ms timeout
|
| 197 |
+
data_available = data_ready_event.wait(timeout=timeout)
|
| 198 |
+
|
| 199 |
+
current_time = time.time()
|
| 200 |
+
|
| 201 |
+
if data_available:
|
| 202 |
+
data_ready_event.clear()
|
| 203 |
+
if loop_count % 50 == 0:
|
| 204 |
+
print("Image publish frequency: ", 1 / (current_time - last_data_time))
|
| 205 |
+
last_data_time = current_time
|
| 206 |
+
|
| 207 |
+
# Collect all camera images and serialize them
|
| 208 |
+
try:
|
| 209 |
+
from decoupled_wbc.control.sensor.sensor_server import ImageUtils
|
| 210 |
+
|
| 211 |
+
# Copy all images atomically at once
|
| 212 |
+
image_copies = {name: arr.copy() for name, arr in shared_arrays.items()}
|
| 213 |
+
|
| 214 |
+
# Create message with all camera images
|
| 215 |
+
message_dict = {
|
| 216 |
+
"images": image_copies,
|
| 217 |
+
"timestamps": {name: current_time for name in image_copies.keys()},
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
# Create ImageMessageSchema and serialize
|
| 221 |
+
image_msg = ImageMessageSchema(
|
| 222 |
+
timestamps=message_dict.get("timestamps"),
|
| 223 |
+
images=message_dict.get("images", None),
|
| 224 |
+
)
|
| 225 |
+
|
| 226 |
+
# Serialize and send via ZMQ
|
| 227 |
+
serialized_data = image_msg.serialize()
|
| 228 |
+
|
| 229 |
+
# Add individual camera images to the message
|
| 230 |
+
for camera_name, image_copy in image_copies.items():
|
| 231 |
+
serialized_data[f"{camera_name}"] = ImageUtils.encode_image(image_copy)
|
| 232 |
+
|
| 233 |
+
sensor_server.send_message(serialized_data)
|
| 234 |
+
|
| 235 |
+
except Exception as e:
|
| 236 |
+
print(f"Error publishing images: {e}")
|
| 237 |
+
|
| 238 |
+
elif verbose and loop_count % 10 == 0:
|
| 239 |
+
print(f"Subprocess: Still waiting for data... (iteration {loop_count})")
|
| 240 |
+
|
| 241 |
+
# Small sleep to prevent busy waiting when no data
|
| 242 |
+
if not data_available:
|
| 243 |
+
time.sleep(0.001)
|
| 244 |
+
|
| 245 |
+
except KeyboardInterrupt:
|
| 246 |
+
print("Image publisher interrupted by user")
|
| 247 |
+
finally:
|
| 248 |
+
# Clean up
|
| 249 |
+
try:
|
| 250 |
+
for shm in shm_blocks.values():
|
| 251 |
+
shm.close()
|
| 252 |
+
sensor_server.stop_server()
|
| 253 |
+
except Exception as e:
|
| 254 |
+
print(f"Error during subprocess cleanup: {e}")
|
| 255 |
+
if verbose:
|
| 256 |
+
print("Image publish subprocess stopped")
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/metric_utils.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import List, Tuple
|
| 2 |
+
|
| 3 |
+
import mujoco
|
| 4 |
+
|
| 5 |
+
from decoupled_wbc.control.envs.g1.sim.sim_utilts import get_body_geom_ids
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def check_contact(
|
| 9 |
+
mj_model: mujoco.MjModel,
|
| 10 |
+
mj_data: mujoco.MjData,
|
| 11 |
+
bodies_1: List[str] | str,
|
| 12 |
+
bodies_2: List[str] | str,
|
| 13 |
+
return_all_contact_bodies: bool = False,
|
| 14 |
+
) -> Tuple[bool, List[Tuple[str, str]]] | bool:
|
| 15 |
+
"""
|
| 16 |
+
Finds contact between two body groups. Any geom in the body is considered to be in contact.
|
| 17 |
+
Args:
|
| 18 |
+
mj_model (MujocoModel): Current simulation object
|
| 19 |
+
mj_data (MjData): Current simulation data
|
| 20 |
+
bodies_1 (str or list of int): an individual body name or list of body names.
|
| 21 |
+
bodies_2 (str or list of int): another individual body name or list of body names.
|
| 22 |
+
Returns:
|
| 23 |
+
bool: True if any body in @bodies_1 is in contact with any body in @bodies_2.
|
| 24 |
+
"""
|
| 25 |
+
if isinstance(bodies_1, str):
|
| 26 |
+
bodies_1 = [bodies_1]
|
| 27 |
+
if isinstance(bodies_2, str):
|
| 28 |
+
bodies_2 = [bodies_2]
|
| 29 |
+
|
| 30 |
+
geoms_1 = [get_body_geom_ids(mj_model, mj_model.body(g).id) for g in bodies_1]
|
| 31 |
+
geoms_1 = [g for geom_list in geoms_1 for g in geom_list]
|
| 32 |
+
geoms_2 = [get_body_geom_ids(mj_model, mj_model.body(g).id) for g in bodies_2]
|
| 33 |
+
geoms_2 = [g for geom_list in geoms_2 for g in geom_list]
|
| 34 |
+
contact_bodies = []
|
| 35 |
+
for i in range(mj_data.ncon):
|
| 36 |
+
contact = mj_data.contact[i]
|
| 37 |
+
# check contact geom in geoms
|
| 38 |
+
c1_in_g1 = contact.geom1 in geoms_1
|
| 39 |
+
c2_in_g2 = contact.geom2 in geoms_2 if geoms_2 is not None else True
|
| 40 |
+
# check contact geom in geoms (flipped)
|
| 41 |
+
c2_in_g1 = contact.geom2 in geoms_1
|
| 42 |
+
c1_in_g2 = contact.geom1 in geoms_2 if geoms_2 is not None else True
|
| 43 |
+
if (c1_in_g1 and c2_in_g2) or (c1_in_g2 and c2_in_g1):
|
| 44 |
+
contact_bodies.append(
|
| 45 |
+
(
|
| 46 |
+
mj_model.body(mj_model.geom(contact.geom1).bodyid).name,
|
| 47 |
+
mj_model.body(mj_model.geom(contact.geom2).bodyid).name,
|
| 48 |
+
)
|
| 49 |
+
)
|
| 50 |
+
if not return_all_contact_bodies:
|
| 51 |
+
break
|
| 52 |
+
if return_all_contact_bodies:
|
| 53 |
+
return len(contact_bodies) > 0, set(contact_bodies)
|
| 54 |
+
else:
|
| 55 |
+
return len(contact_bodies) > 0
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def check_height(
|
| 59 |
+
mj_model: mujoco.MjModel,
|
| 60 |
+
mj_data: mujoco.MjData,
|
| 61 |
+
geom_name: str,
|
| 62 |
+
lower_bound: float = -float("inf"),
|
| 63 |
+
upper_bound: float = float("inf"),
|
| 64 |
+
):
|
| 65 |
+
"""
|
| 66 |
+
Checks if the height of a geom is greater than a given height.
|
| 67 |
+
"""
|
| 68 |
+
geom_id = mj_model.geom(geom_name).id
|
| 69 |
+
return (
|
| 70 |
+
mj_data.geom_xpos[geom_id][2] < upper_bound and mj_data.geom_xpos[geom_id][2] > lower_bound
|
| 71 |
+
)
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/robocasa_sim.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any, Dict, Tuple
|
| 2 |
+
|
| 3 |
+
from unitree_sdk2py.core.channel import ChannelFactoryInitialize
|
| 4 |
+
|
| 5 |
+
from decoupled_wbc.control.envs.g1.sim.unitree_sdk2py_bridge import UnitreeSdk2Bridge
|
| 6 |
+
from decoupled_wbc.control.envs.robocasa.async_env_server import RoboCasaEnvServer
|
| 7 |
+
from decoupled_wbc.control.robot_model.instantiation import get_robot_type_and_model
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class RoboCasaG1EnvServer(RoboCasaEnvServer):
|
| 11 |
+
def __init__(
|
| 12 |
+
self, env_name: str, wbc_config: Dict[str, Any], env_kwargs: Dict[str, Any], **kwargs
|
| 13 |
+
):
|
| 14 |
+
if UnitreeSdk2Bridge is None:
|
| 15 |
+
raise ImportError("UnitreeSdk2Bridge is required for RoboCasaG1EnvServer")
|
| 16 |
+
self.wbc_config = wbc_config
|
| 17 |
+
_, robot_model = get_robot_type_and_model(
|
| 18 |
+
"G1",
|
| 19 |
+
enable_waist_ik=wbc_config["enable_waist"],
|
| 20 |
+
)
|
| 21 |
+
if env_kwargs.get("camera_names", None) is None:
|
| 22 |
+
env_kwargs["camera_names"] = [
|
| 23 |
+
"robot0_oak_egoview",
|
| 24 |
+
"robot0_oak_left_monoview",
|
| 25 |
+
"robot0_oak_right_monoview",
|
| 26 |
+
"robot0_rs_tppview",
|
| 27 |
+
]
|
| 28 |
+
if env_kwargs.get("render_camera", None) is None:
|
| 29 |
+
if env_kwargs.get("renderer", "mjviewer") == "mjviewer":
|
| 30 |
+
env_kwargs["render_camera"] = "robot0_oak_egoview"
|
| 31 |
+
else:
|
| 32 |
+
env_kwargs["render_camera"] = [
|
| 33 |
+
"robot0_oak_egoview",
|
| 34 |
+
"robot0_rs_tppview",
|
| 35 |
+
]
|
| 36 |
+
|
| 37 |
+
super().__init__(env_name, "G1", robot_model, env_kwargs=env_kwargs, **kwargs)
|
| 38 |
+
|
| 39 |
+
def init_channel(self):
|
| 40 |
+
|
| 41 |
+
try:
|
| 42 |
+
if self.wbc_config.get("INTERFACE", None):
|
| 43 |
+
ChannelFactoryInitialize(self.wbc_config["DOMAIN_ID"], self.wbc_config["INTERFACE"])
|
| 44 |
+
else:
|
| 45 |
+
ChannelFactoryInitialize(self.wbc_config["DOMAIN_ID"])
|
| 46 |
+
except Exception:
|
| 47 |
+
# If it fails because it's already initialized, that's okay
|
| 48 |
+
pass
|
| 49 |
+
|
| 50 |
+
self.channel_bridge = UnitreeSdk2Bridge(config=self.wbc_config)
|
| 51 |
+
|
| 52 |
+
def publish_obs(self):
|
| 53 |
+
# with self.cache_lock:
|
| 54 |
+
obs = self.caches["obs"]
|
| 55 |
+
self.channel_bridge.PublishLowState(obs)
|
| 56 |
+
|
| 57 |
+
def get_action(self) -> Tuple[Dict[str, Any], bool, bool]:
|
| 58 |
+
q, ready, is_new_action = self.channel_bridge.GetAction()
|
| 59 |
+
return {"q": q}, ready, is_new_action
|
| 60 |
+
|
| 61 |
+
def reset(self):
|
| 62 |
+
super().reset()
|
| 63 |
+
self.channel_bridge.reset()
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/sim_utilts.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Utility functions for working with Mujoco models.
|
| 3 |
+
copied from https://github.com/kevinzakka/mink/blob/main/mink/utils.py
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
from typing import List
|
| 7 |
+
|
| 8 |
+
import mujoco
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def get_body_body_ids(model: mujoco.MjModel, body_id: int) -> List[int]:
|
| 12 |
+
"""Get immediate children bodies belonging to a given body.
|
| 13 |
+
|
| 14 |
+
Args:
|
| 15 |
+
model: Mujoco model.
|
| 16 |
+
body_id: ID of body.
|
| 17 |
+
|
| 18 |
+
Returns:
|
| 19 |
+
A List containing all child body ids.
|
| 20 |
+
"""
|
| 21 |
+
return [
|
| 22 |
+
i
|
| 23 |
+
for i in range(model.nbody)
|
| 24 |
+
if model.body_parentid[i] == body_id and body_id != i # Exclude the body itself.
|
| 25 |
+
]
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def get_subtree_body_ids(model: mujoco.MjModel, body_id: int) -> List[int]:
|
| 29 |
+
"""Get all bodies belonging to subtree starting at a given body.
|
| 30 |
+
|
| 31 |
+
Args:
|
| 32 |
+
model: Mujoco model.
|
| 33 |
+
body_id: ID of body where subtree starts.
|
| 34 |
+
|
| 35 |
+
Returns:
|
| 36 |
+
A List containing all subtree body ids.
|
| 37 |
+
"""
|
| 38 |
+
body_ids: List[int] = []
|
| 39 |
+
stack = [body_id]
|
| 40 |
+
while stack:
|
| 41 |
+
body_id = stack.pop()
|
| 42 |
+
body_ids.append(body_id)
|
| 43 |
+
stack += get_body_body_ids(model, body_id)
|
| 44 |
+
return body_ids
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def get_subtree_body_names(model: mujoco.MjModel, body_id: int) -> List[str]:
|
| 48 |
+
"""Get all bodies belonging to subtree starting at a given body.
|
| 49 |
+
Args:
|
| 50 |
+
model: Mujoco model.
|
| 51 |
+
body_id: ID of body where subtree starts.
|
| 52 |
+
|
| 53 |
+
Returns:
|
| 54 |
+
A List containing all subtree body names.
|
| 55 |
+
"""
|
| 56 |
+
return [model.body(i).name for i in get_subtree_body_ids(model, body_id)]
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def get_body_geom_ids(model: mujoco.MjModel, body_id: int) -> List[int]:
|
| 60 |
+
"""Get immediate geoms belonging to a given body.
|
| 61 |
+
|
| 62 |
+
Here, immediate geoms are those directly attached to the body and not its
|
| 63 |
+
descendants.
|
| 64 |
+
|
| 65 |
+
Args:
|
| 66 |
+
model: Mujoco model.
|
| 67 |
+
body_id: ID of body.
|
| 68 |
+
|
| 69 |
+
Returns:
|
| 70 |
+
A list containing all body geom ids.
|
| 71 |
+
"""
|
| 72 |
+
geom_start = model.body_geomadr[body_id]
|
| 73 |
+
geom_end = geom_start + model.body_geomnum[body_id]
|
| 74 |
+
return list(range(geom_start, geom_end))
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def get_subtree_geom_ids(model: mujoco.MjModel, body_id: int) -> List[int]:
|
| 78 |
+
"""Get all geoms belonging to subtree starting at a given body.
|
| 79 |
+
|
| 80 |
+
Here, a subtree is defined as the kinematic tree starting at the body and including
|
| 81 |
+
all its descendants.
|
| 82 |
+
|
| 83 |
+
Args:
|
| 84 |
+
model: Mujoco model.
|
| 85 |
+
body_id: ID of body where subtree starts.
|
| 86 |
+
|
| 87 |
+
Returns:
|
| 88 |
+
A list containing all subtree geom ids.
|
| 89 |
+
"""
|
| 90 |
+
geom_ids: List[int] = []
|
| 91 |
+
stack = [body_id]
|
| 92 |
+
while stack:
|
| 93 |
+
body_id = stack.pop()
|
| 94 |
+
geom_ids.extend(get_body_geom_ids(model, body_id))
|
| 95 |
+
stack += get_body_body_ids(model, body_id)
|
| 96 |
+
return geom_ids
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/simulator_factory.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import time
|
| 2 |
+
from typing import Any, Dict
|
| 3 |
+
|
| 4 |
+
from unitree_sdk2py.core.channel import ChannelFactoryInitialize
|
| 5 |
+
|
| 6 |
+
from decoupled_wbc.control.envs.g1.sim.base_sim import BaseSimulator
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def init_channel(config: Dict[str, Any]) -> None:
|
| 10 |
+
"""
|
| 11 |
+
Initialize the communication channel for simulator/robot communication.
|
| 12 |
+
|
| 13 |
+
Args:
|
| 14 |
+
config: Configuration dictionary containing DOMAIN_ID and optionally INTERFACE
|
| 15 |
+
"""
|
| 16 |
+
if config.get("INTERFACE", None):
|
| 17 |
+
ChannelFactoryInitialize(config["DOMAIN_ID"], config["INTERFACE"])
|
| 18 |
+
else:
|
| 19 |
+
ChannelFactoryInitialize(config["DOMAIN_ID"])
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class SimulatorFactory:
|
| 23 |
+
"""Factory class for creating different types of simulators."""
|
| 24 |
+
|
| 25 |
+
@staticmethod
|
| 26 |
+
def create_simulator(config: Dict[str, Any], env_name: str = "default", **kwargs):
|
| 27 |
+
"""
|
| 28 |
+
Create a simulator based on the configuration.
|
| 29 |
+
|
| 30 |
+
Args:
|
| 31 |
+
config: Configuration dictionary containing SIMULATOR type
|
| 32 |
+
env_name: Environment name
|
| 33 |
+
**kwargs: Additional keyword arguments for specific simulators
|
| 34 |
+
"""
|
| 35 |
+
simulator_type = config.get("SIMULATOR", "mujoco")
|
| 36 |
+
if simulator_type == "mujoco":
|
| 37 |
+
return SimulatorFactory._create_mujoco_simulator(config, env_name, **kwargs)
|
| 38 |
+
elif simulator_type == "robocasa":
|
| 39 |
+
return SimulatorFactory._create_robocasa_simulator(config, env_name, **kwargs)
|
| 40 |
+
else:
|
| 41 |
+
print(
|
| 42 |
+
f"Warning: Invalid simulator type: {simulator_type}. "
|
| 43 |
+
"If you are using run_sim_loop, please ignore this warning."
|
| 44 |
+
)
|
| 45 |
+
return None
|
| 46 |
+
|
| 47 |
+
@staticmethod
|
| 48 |
+
def _create_mujoco_simulator(config: Dict[str, Any], env_name: str = "default", **kwargs):
|
| 49 |
+
"""Create a MuJoCo simulator instance."""
|
| 50 |
+
env_kwargs = dict(
|
| 51 |
+
onscreen=kwargs.pop("onscreen", True),
|
| 52 |
+
offscreen=kwargs.pop("offscreen", False),
|
| 53 |
+
enable_image_publish=kwargs.get("enable_image_publish", False),
|
| 54 |
+
)
|
| 55 |
+
return BaseSimulator(config=config, env_name=env_name, **env_kwargs)
|
| 56 |
+
|
| 57 |
+
@staticmethod
|
| 58 |
+
def _create_robocasa_simulator(config: Dict[str, Any], env_name: str = "default", **kwargs):
|
| 59 |
+
"""Create a RoboCasa simulator instance."""
|
| 60 |
+
from decoupled_wbc.control.envs.g1.sim.robocasa_sim import RoboCasaG1EnvServer
|
| 61 |
+
from decoupled_wbc.control.envs.robocasa.utils.controller_utils import (
|
| 62 |
+
update_robosuite_controller_configs,
|
| 63 |
+
)
|
| 64 |
+
from decoupled_wbc.control.envs.robocasa.utils.sim_utils import change_simulation_timestep
|
| 65 |
+
|
| 66 |
+
change_simulation_timestep(config["SIMULATE_DT"])
|
| 67 |
+
|
| 68 |
+
# Use default environment if not specified
|
| 69 |
+
if env_name == "default":
|
| 70 |
+
env_name = "GroundOnly"
|
| 71 |
+
|
| 72 |
+
# Get or create controller configurations
|
| 73 |
+
controller_configs = kwargs.get("controller_configs")
|
| 74 |
+
if controller_configs is None:
|
| 75 |
+
wbc_version = kwargs.get("wbc_version", "gear_wbc")
|
| 76 |
+
controller_configs = update_robosuite_controller_configs("G1", wbc_version)
|
| 77 |
+
|
| 78 |
+
# Build environment kwargs
|
| 79 |
+
env_kwargs = dict(
|
| 80 |
+
onscreen=kwargs.pop("onscreen", True),
|
| 81 |
+
offscreen=kwargs.pop("offscreen", False),
|
| 82 |
+
camera_names=kwargs.pop("camera_names", None),
|
| 83 |
+
camera_heights=kwargs.pop("camera_heights", None),
|
| 84 |
+
camera_widths=kwargs.pop("camera_widths", None),
|
| 85 |
+
control_freq=kwargs.pop("control_freq", 50),
|
| 86 |
+
controller_configs=controller_configs,
|
| 87 |
+
ik_indicator=kwargs.pop("ik_indicator", False),
|
| 88 |
+
randomize_cameras=kwargs.pop("randomize_cameras", True),
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
kwargs.update(
|
| 92 |
+
{
|
| 93 |
+
"verbose": config.pop("verbose", False),
|
| 94 |
+
"sim_freq": 1 / config.pop("SIMULATE_DT"),
|
| 95 |
+
}
|
| 96 |
+
)
|
| 97 |
+
|
| 98 |
+
return RoboCasaG1EnvServer(
|
| 99 |
+
env_name=env_name,
|
| 100 |
+
wbc_config=config,
|
| 101 |
+
env_kwargs=env_kwargs,
|
| 102 |
+
**kwargs,
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
@staticmethod
|
| 106 |
+
def start_simulator(
|
| 107 |
+
simulator,
|
| 108 |
+
as_thread: bool = True,
|
| 109 |
+
enable_image_publish: bool = False,
|
| 110 |
+
mp_start_method: str = "spawn",
|
| 111 |
+
camera_port: int = 5555,
|
| 112 |
+
):
|
| 113 |
+
"""
|
| 114 |
+
Start the simulator either as a thread or as a separate process.
|
| 115 |
+
|
| 116 |
+
Args:
|
| 117 |
+
simulator: The simulator instance to start
|
| 118 |
+
config: Configuration dictionary
|
| 119 |
+
as_thread: If True, start as thread; if False, start as subprocess
|
| 120 |
+
enable_offscreen: If True and not as_thread, start image publishing
|
| 121 |
+
"""
|
| 122 |
+
|
| 123 |
+
if as_thread:
|
| 124 |
+
simulator.start_as_thread()
|
| 125 |
+
else:
|
| 126 |
+
# Wrap in try-except to make sure simulator is properly closed upon exit.
|
| 127 |
+
try:
|
| 128 |
+
if enable_image_publish:
|
| 129 |
+
simulator.start_image_publish_subprocess(
|
| 130 |
+
start_method=mp_start_method,
|
| 131 |
+
camera_port=camera_port,
|
| 132 |
+
)
|
| 133 |
+
time.sleep(1)
|
| 134 |
+
simulator.start()
|
| 135 |
+
except KeyboardInterrupt:
|
| 136 |
+
print("+++++Simulator interrupted by user.")
|
| 137 |
+
except Exception as e:
|
| 138 |
+
print(f"++++error in simulator: {e} ++++")
|
| 139 |
+
finally:
|
| 140 |
+
print("++++closing simulator ++++")
|
| 141 |
+
simulator.close()
|
| 142 |
+
|
| 143 |
+
# Allow simulator to initialize
|
| 144 |
+
time.sleep(1)
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/unitree_sdk2py_bridge.py
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import threading
|
| 3 |
+
from typing import Dict, Tuple
|
| 4 |
+
|
| 5 |
+
import glfw
|
| 6 |
+
from loguru import logger
|
| 7 |
+
import mujoco
|
| 8 |
+
import numpy as np
|
| 9 |
+
import pygame
|
| 10 |
+
import scipy.spatial.transform
|
| 11 |
+
from termcolor import colored
|
| 12 |
+
from unitree_sdk2py.core.channel import ChannelPublisher, ChannelSubscriber
|
| 13 |
+
from unitree_sdk2py.idl.default import (
|
| 14 |
+
unitree_go_msg_dds__WirelessController_,
|
| 15 |
+
unitree_hg_msg_dds__HandCmd_ as HandCmd_default,
|
| 16 |
+
unitree_hg_msg_dds__HandState_ as HandState_default,
|
| 17 |
+
)
|
| 18 |
+
from unitree_sdk2py.idl.unitree_go.msg.dds_ import WirelessController_
|
| 19 |
+
from unitree_sdk2py.idl.unitree_hg.msg.dds_ import HandCmd_, HandState_, OdoState_
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class UnitreeSdk2Bridge:
|
| 23 |
+
"""
|
| 24 |
+
This class is responsible for bridging the Unitree SDK2 with the Gr00t environment.
|
| 25 |
+
It is responsible for sending and receiving messages to and from the Unitree SDK2.
|
| 26 |
+
Both the body and hand are supported.
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
def __init__(self, config):
|
| 30 |
+
# Note that we do not give the mjdata and mjmodel to the UnitreeSdk2Bridge.
|
| 31 |
+
# It is unsafe and would be unflexible if we use a hand-plugged robot model
|
| 32 |
+
|
| 33 |
+
robot_type = config["ROBOT_TYPE"]
|
| 34 |
+
if "g1" in robot_type or "h1-2" in robot_type:
|
| 35 |
+
from unitree_sdk2py.idl.default import (
|
| 36 |
+
unitree_hg_msg_dds__IMUState_ as IMUState_default,
|
| 37 |
+
unitree_hg_msg_dds__LowCmd_,
|
| 38 |
+
unitree_hg_msg_dds__LowState_ as LowState_default,
|
| 39 |
+
unitree_hg_msg_dds__OdoState_ as OdoState_default,
|
| 40 |
+
)
|
| 41 |
+
from unitree_sdk2py.idl.unitree_hg.msg.dds_ import IMUState_, LowCmd_, LowState_
|
| 42 |
+
|
| 43 |
+
self.low_cmd = unitree_hg_msg_dds__LowCmd_()
|
| 44 |
+
elif "h1" == robot_type or "go2" == robot_type:
|
| 45 |
+
from unitree_sdk2py.idl.default import (
|
| 46 |
+
unitree_go_msg_dds__LowCmd_,
|
| 47 |
+
unitree_go_msg_dds__LowState_ as LowState_default,
|
| 48 |
+
unitree_hg_msg_dds__IMUState_ as IMUState_default,
|
| 49 |
+
)
|
| 50 |
+
from unitree_sdk2py.idl.unitree_go.msg.dds_ import IMUState_, LowCmd_, LowState_
|
| 51 |
+
|
| 52 |
+
self.low_cmd = unitree_go_msg_dds__LowCmd_()
|
| 53 |
+
else:
|
| 54 |
+
raise ValueError(f"Invalid robot type '{robot_type}'. Expected 'g1', 'h1', or 'go2'.")
|
| 55 |
+
|
| 56 |
+
self.num_body_motor = config["NUM_MOTORS"]
|
| 57 |
+
self.num_hand_motor = config.get("NUM_HAND_MOTORS", 0)
|
| 58 |
+
self.use_sensor = config["USE_SENSOR"]
|
| 59 |
+
|
| 60 |
+
self.have_imu_ = False
|
| 61 |
+
self.have_frame_sensor_ = False
|
| 62 |
+
# if self.use_sensor:
|
| 63 |
+
# MOTOR_SENSOR_NUM = 3
|
| 64 |
+
# self.dim_motor_sensor = MOTOR_SENSOR_NUM * self.num_motor
|
| 65 |
+
# # Check sensor
|
| 66 |
+
# for i in range(self.dim_motor_sensor, self.mj_model.nsensor):
|
| 67 |
+
# name = mujoco.mj_id2name(self.mj_model, mujoco._enums.mjtObj.mjOBJ_SENSOR, i)
|
| 68 |
+
# if name == "imu_quat":
|
| 69 |
+
# self.have_imu_ = True
|
| 70 |
+
# if name == "frame_pos":
|
| 71 |
+
# self.have_frame_sensor_ = True
|
| 72 |
+
|
| 73 |
+
# Unitree sdk2 message
|
| 74 |
+
self.low_state = LowState_default()
|
| 75 |
+
self.low_state_puber = ChannelPublisher("rt/lowstate", LowState_)
|
| 76 |
+
self.low_state_puber.Init()
|
| 77 |
+
|
| 78 |
+
# Only create odo_state for supported robot types
|
| 79 |
+
if "g1" in robot_type or "h1-2" in robot_type:
|
| 80 |
+
self.odo_state = OdoState_default()
|
| 81 |
+
self.odo_state_puber = ChannelPublisher("rt/odostate", OdoState_)
|
| 82 |
+
self.odo_state_puber.Init()
|
| 83 |
+
else:
|
| 84 |
+
self.odo_state = None
|
| 85 |
+
self.odo_state_puber = None
|
| 86 |
+
self.torso_imu_state = IMUState_default()
|
| 87 |
+
self.torso_imu_puber = ChannelPublisher("rt/secondary_imu", IMUState_)
|
| 88 |
+
self.torso_imu_puber.Init()
|
| 89 |
+
|
| 90 |
+
self.left_hand_state = HandState_default()
|
| 91 |
+
self.left_hand_state_puber = ChannelPublisher("rt/dex3/left/state", HandState_)
|
| 92 |
+
self.left_hand_state_puber.Init()
|
| 93 |
+
self.right_hand_state = HandState_default()
|
| 94 |
+
self.right_hand_state_puber = ChannelPublisher("rt/dex3/right/state", HandState_)
|
| 95 |
+
self.right_hand_state_puber.Init()
|
| 96 |
+
|
| 97 |
+
self.low_cmd_suber = ChannelSubscriber("rt/lowcmd", LowCmd_)
|
| 98 |
+
self.low_cmd_suber.Init(self.LowCmdHandler, 1)
|
| 99 |
+
|
| 100 |
+
self.left_hand_cmd = HandCmd_default()
|
| 101 |
+
self.left_hand_cmd_suber = ChannelSubscriber("rt/dex3/left/cmd", HandCmd_)
|
| 102 |
+
self.left_hand_cmd_suber.Init(self.LeftHandCmdHandler, 1)
|
| 103 |
+
self.right_hand_cmd = HandCmd_default()
|
| 104 |
+
self.right_hand_cmd_suber = ChannelSubscriber("rt/dex3/right/cmd", HandCmd_)
|
| 105 |
+
self.right_hand_cmd_suber.Init(self.RightHandCmdHandler, 1)
|
| 106 |
+
|
| 107 |
+
self.low_cmd_lock = threading.Lock()
|
| 108 |
+
self.left_hand_cmd_lock = threading.Lock()
|
| 109 |
+
self.right_hand_cmd_lock = threading.Lock()
|
| 110 |
+
|
| 111 |
+
self.wireless_controller = unitree_go_msg_dds__WirelessController_()
|
| 112 |
+
self.wireless_controller_puber = ChannelPublisher(
|
| 113 |
+
"rt/wirelesscontroller", WirelessController_
|
| 114 |
+
)
|
| 115 |
+
self.wireless_controller_puber.Init()
|
| 116 |
+
|
| 117 |
+
# joystick
|
| 118 |
+
self.key_map = {
|
| 119 |
+
"R1": 0,
|
| 120 |
+
"L1": 1,
|
| 121 |
+
"start": 2,
|
| 122 |
+
"select": 3,
|
| 123 |
+
"R2": 4,
|
| 124 |
+
"L2": 5,
|
| 125 |
+
"F1": 6,
|
| 126 |
+
"F2": 7,
|
| 127 |
+
"A": 8,
|
| 128 |
+
"B": 9,
|
| 129 |
+
"X": 10,
|
| 130 |
+
"Y": 11,
|
| 131 |
+
"up": 12,
|
| 132 |
+
"right": 13,
|
| 133 |
+
"down": 14,
|
| 134 |
+
"left": 15,
|
| 135 |
+
}
|
| 136 |
+
self.joystick = None
|
| 137 |
+
|
| 138 |
+
self.reset()
|
| 139 |
+
|
| 140 |
+
def reset(self):
|
| 141 |
+
with self.low_cmd_lock:
|
| 142 |
+
self.low_cmd_received = False
|
| 143 |
+
self.new_low_cmd = False
|
| 144 |
+
with self.left_hand_cmd_lock:
|
| 145 |
+
self.left_hand_cmd_received = False
|
| 146 |
+
self.new_left_hand_cmd = False
|
| 147 |
+
with self.right_hand_cmd_lock:
|
| 148 |
+
self.right_hand_cmd_received = False
|
| 149 |
+
self.new_right_hand_cmd = False
|
| 150 |
+
|
| 151 |
+
def LowCmdHandler(self, msg):
|
| 152 |
+
with self.low_cmd_lock:
|
| 153 |
+
self.low_cmd = msg
|
| 154 |
+
self.low_cmd_received = True
|
| 155 |
+
self.new_low_cmd = True
|
| 156 |
+
|
| 157 |
+
def LeftHandCmdHandler(self, msg):
|
| 158 |
+
with self.left_hand_cmd_lock:
|
| 159 |
+
self.left_hand_cmd = msg
|
| 160 |
+
self.left_hand_cmd_received = True
|
| 161 |
+
self.new_left_hand_cmd = True
|
| 162 |
+
|
| 163 |
+
def RightHandCmdHandler(self, msg):
|
| 164 |
+
with self.right_hand_cmd_lock:
|
| 165 |
+
self.right_hand_cmd = msg
|
| 166 |
+
self.right_hand_cmd_received = True
|
| 167 |
+
self.new_right_hand_cmd = True
|
| 168 |
+
|
| 169 |
+
def cmd_received(self):
|
| 170 |
+
with self.low_cmd_lock:
|
| 171 |
+
low_cmd_received = self.low_cmd_received
|
| 172 |
+
with self.left_hand_cmd_lock:
|
| 173 |
+
left_hand_cmd_received = self.left_hand_cmd_received
|
| 174 |
+
with self.right_hand_cmd_lock:
|
| 175 |
+
right_hand_cmd_received = self.right_hand_cmd_received
|
| 176 |
+
return low_cmd_received or left_hand_cmd_received or right_hand_cmd_received
|
| 177 |
+
|
| 178 |
+
def PublishLowState(self, obs: Dict[str, any]):
|
| 179 |
+
# publish body state
|
| 180 |
+
if self.use_sensor:
|
| 181 |
+
raise NotImplementedError("Sensor data is not implemented yet.")
|
| 182 |
+
else:
|
| 183 |
+
for i in range(self.num_body_motor):
|
| 184 |
+
self.low_state.motor_state[i].q = obs["body_q"][i]
|
| 185 |
+
self.low_state.motor_state[i].dq = obs["body_dq"][i]
|
| 186 |
+
self.low_state.motor_state[i].ddq = obs["body_ddq"][i]
|
| 187 |
+
self.low_state.motor_state[i].tau_est = obs["body_tau_est"][i]
|
| 188 |
+
|
| 189 |
+
if self.use_sensor and self.have_frame_sensor_:
|
| 190 |
+
raise NotImplementedError("Frame sensor data is not implemented yet.")
|
| 191 |
+
else:
|
| 192 |
+
# Get data from ground truth
|
| 193 |
+
self.odo_state.position[:] = obs["floating_base_pose"][:3]
|
| 194 |
+
self.odo_state.linear_velocity[:] = obs["floating_base_vel"][:3]
|
| 195 |
+
self.odo_state.orientation[:] = obs["floating_base_pose"][3:7]
|
| 196 |
+
self.odo_state.angular_velocity[:] = obs["floating_base_vel"][3:6]
|
| 197 |
+
# quaternion: w, x, y, z
|
| 198 |
+
self.low_state.imu_state.quaternion[:] = obs["floating_base_pose"][3:7]
|
| 199 |
+
# angular velocity
|
| 200 |
+
self.low_state.imu_state.gyroscope[:] = obs["floating_base_vel"][3:6]
|
| 201 |
+
# linear acceleration
|
| 202 |
+
self.low_state.imu_state.accelerometer[:] = obs["floating_base_acc"][:3]
|
| 203 |
+
|
| 204 |
+
self.torso_imu_state.quaternion[:] = obs["secondary_imu_quat"]
|
| 205 |
+
self.torso_imu_state.gyroscope[:] = obs["secondary_imu_vel"][3:6]
|
| 206 |
+
|
| 207 |
+
# acceleration: x, y, z (only available when frame sensor is enabled)
|
| 208 |
+
if self.have_frame_sensor_:
|
| 209 |
+
raise NotImplementedError("Frame sensor data is not implemented yet.")
|
| 210 |
+
self.low_state.tick = int(obs["time"] * 1e3)
|
| 211 |
+
self.low_state_puber.Write(self.low_state)
|
| 212 |
+
|
| 213 |
+
self.odo_state.tick = int(obs["time"] * 1e3)
|
| 214 |
+
self.odo_state_puber.Write(self.odo_state)
|
| 215 |
+
|
| 216 |
+
self.torso_imu_puber.Write(self.torso_imu_state)
|
| 217 |
+
|
| 218 |
+
# publish hand state
|
| 219 |
+
for i in range(self.num_hand_motor):
|
| 220 |
+
self.left_hand_state.motor_state[i].q = obs["left_hand_q"][i]
|
| 221 |
+
self.left_hand_state.motor_state[i].dq = obs["left_hand_dq"][i]
|
| 222 |
+
self.left_hand_state_puber.Write(self.left_hand_state)
|
| 223 |
+
|
| 224 |
+
for i in range(self.num_hand_motor):
|
| 225 |
+
self.right_hand_state.motor_state[i].q = obs["right_hand_q"][i]
|
| 226 |
+
self.right_hand_state.motor_state[i].dq = obs["right_hand_dq"][i]
|
| 227 |
+
self.right_hand_state_puber.Write(self.right_hand_state)
|
| 228 |
+
|
| 229 |
+
def GetAction(self) -> Tuple[np.ndarray, bool, bool]:
|
| 230 |
+
with self.low_cmd_lock:
|
| 231 |
+
body_q = [self.low_cmd.motor_cmd[i].q for i in range(self.num_body_motor)]
|
| 232 |
+
with self.left_hand_cmd_lock:
|
| 233 |
+
left_hand_q = [self.left_hand_cmd.motor_cmd[i].q for i in range(self.num_hand_motor)]
|
| 234 |
+
with self.right_hand_cmd_lock:
|
| 235 |
+
right_hand_q = [self.right_hand_cmd.motor_cmd[i].q for i in range(self.num_hand_motor)]
|
| 236 |
+
with self.low_cmd_lock and self.left_hand_cmd_lock and self.right_hand_cmd_lock:
|
| 237 |
+
is_new_action = self.new_low_cmd and self.new_left_hand_cmd and self.new_right_hand_cmd
|
| 238 |
+
if is_new_action:
|
| 239 |
+
self.new_low_cmd = False
|
| 240 |
+
self.new_left_hand_cmd = False
|
| 241 |
+
self.new_right_hand_cmd = False
|
| 242 |
+
|
| 243 |
+
return (
|
| 244 |
+
np.concatenate([body_q[:-7], left_hand_q, body_q[-7:], right_hand_q]),
|
| 245 |
+
self.cmd_received(),
|
| 246 |
+
is_new_action,
|
| 247 |
+
)
|
| 248 |
+
|
| 249 |
+
def PublishWirelessController(self):
|
| 250 |
+
if self.joystick is not None:
|
| 251 |
+
pygame.event.get()
|
| 252 |
+
key_state = [0] * 16
|
| 253 |
+
key_state[self.key_map["R1"]] = self.joystick.get_button(self.button_id["RB"])
|
| 254 |
+
key_state[self.key_map["L1"]] = self.joystick.get_button(self.button_id["LB"])
|
| 255 |
+
key_state[self.key_map["start"]] = self.joystick.get_button(self.button_id["START"])
|
| 256 |
+
key_state[self.key_map["select"]] = self.joystick.get_button(self.button_id["SELECT"])
|
| 257 |
+
key_state[self.key_map["R2"]] = self.joystick.get_axis(self.axis_id["RT"]) > 0
|
| 258 |
+
key_state[self.key_map["L2"]] = self.joystick.get_axis(self.axis_id["LT"]) > 0
|
| 259 |
+
key_state[self.key_map["F1"]] = 0
|
| 260 |
+
key_state[self.key_map["F2"]] = 0
|
| 261 |
+
key_state[self.key_map["A"]] = self.joystick.get_button(self.button_id["A"])
|
| 262 |
+
key_state[self.key_map["B"]] = self.joystick.get_button(self.button_id["B"])
|
| 263 |
+
key_state[self.key_map["X"]] = self.joystick.get_button(self.button_id["X"])
|
| 264 |
+
key_state[self.key_map["Y"]] = self.joystick.get_button(self.button_id["Y"])
|
| 265 |
+
key_state[self.key_map["up"]] = self.joystick.get_hat(0)[1] > 0
|
| 266 |
+
key_state[self.key_map["right"]] = self.joystick.get_hat(0)[0] > 0
|
| 267 |
+
key_state[self.key_map["down"]] = self.joystick.get_hat(0)[1] < 0
|
| 268 |
+
key_state[self.key_map["left"]] = self.joystick.get_hat(0)[0] < 0
|
| 269 |
+
|
| 270 |
+
key_value = 0
|
| 271 |
+
for i in range(16):
|
| 272 |
+
key_value += key_state[i] << i
|
| 273 |
+
|
| 274 |
+
self.wireless_controller.keys = key_value
|
| 275 |
+
self.wireless_controller.lx = self.joystick.get_axis(self.axis_id["LX"])
|
| 276 |
+
self.wireless_controller.ly = -self.joystick.get_axis(self.axis_id["LY"])
|
| 277 |
+
self.wireless_controller.rx = self.joystick.get_axis(self.axis_id["RX"])
|
| 278 |
+
self.wireless_controller.ry = -self.joystick.get_axis(self.axis_id["RY"])
|
| 279 |
+
|
| 280 |
+
self.wireless_controller_puber.Write(self.wireless_controller)
|
| 281 |
+
|
| 282 |
+
def SetupJoystick(self, device_id=0, js_type="xbox"):
|
| 283 |
+
pygame.init()
|
| 284 |
+
pygame.joystick.init()
|
| 285 |
+
joystick_count = pygame.joystick.get_count()
|
| 286 |
+
if joystick_count > 0:
|
| 287 |
+
self.joystick = pygame.joystick.Joystick(device_id)
|
| 288 |
+
self.joystick.init()
|
| 289 |
+
else:
|
| 290 |
+
print("No gamepad detected.")
|
| 291 |
+
sys.exit()
|
| 292 |
+
|
| 293 |
+
if js_type == "xbox":
|
| 294 |
+
if sys.platform.startswith("linux"):
|
| 295 |
+
self.axis_id = {
|
| 296 |
+
"LX": 0, # Left stick axis x
|
| 297 |
+
"LY": 1, # Left stick axis y
|
| 298 |
+
"RX": 3, # Right stick axis x
|
| 299 |
+
"RY": 4, # Right stick axis y
|
| 300 |
+
"LT": 2, # Left trigger
|
| 301 |
+
"RT": 5, # Right trigger
|
| 302 |
+
"DX": 6, # Directional pad x
|
| 303 |
+
"DY": 7, # Directional pad y
|
| 304 |
+
}
|
| 305 |
+
self.button_id = {
|
| 306 |
+
"X": 2,
|
| 307 |
+
"Y": 3,
|
| 308 |
+
"B": 1,
|
| 309 |
+
"A": 0,
|
| 310 |
+
"LB": 4,
|
| 311 |
+
"RB": 5,
|
| 312 |
+
"SELECT": 6,
|
| 313 |
+
"START": 7,
|
| 314 |
+
"XBOX": 8,
|
| 315 |
+
"LSB": 9,
|
| 316 |
+
"RSB": 10,
|
| 317 |
+
}
|
| 318 |
+
elif sys.platform == "darwin":
|
| 319 |
+
self.axis_id = {
|
| 320 |
+
"LX": 0, # Left stick axis x
|
| 321 |
+
"LY": 1, # Left stick axis y
|
| 322 |
+
"RX": 2, # Right stick axis x
|
| 323 |
+
"RY": 3, # Right stick axis y
|
| 324 |
+
"LT": 4, # Left trigger
|
| 325 |
+
"RT": 5, # Right trigger
|
| 326 |
+
}
|
| 327 |
+
self.button_id = {
|
| 328 |
+
"X": 2,
|
| 329 |
+
"Y": 3,
|
| 330 |
+
"B": 1,
|
| 331 |
+
"A": 0,
|
| 332 |
+
"LB": 9,
|
| 333 |
+
"RB": 10,
|
| 334 |
+
"SELECT": 4,
|
| 335 |
+
"START": 6,
|
| 336 |
+
"XBOX": 5,
|
| 337 |
+
"LSB": 7,
|
| 338 |
+
"RSB": 8,
|
| 339 |
+
"DYU": 11,
|
| 340 |
+
"DYD": 12,
|
| 341 |
+
"DXL": 13,
|
| 342 |
+
"DXR": 14,
|
| 343 |
+
}
|
| 344 |
+
else:
|
| 345 |
+
print("Unsupported OS. ")
|
| 346 |
+
|
| 347 |
+
elif js_type == "switch":
|
| 348 |
+
# Yuanhang: may differ for different OS, need to be checked
|
| 349 |
+
self.axis_id = {
|
| 350 |
+
"LX": 0, # Left stick axis x
|
| 351 |
+
"LY": 1, # Left stick axis y
|
| 352 |
+
"RX": 2, # Right stick axis x
|
| 353 |
+
"RY": 3, # Right stick axis y
|
| 354 |
+
"LT": 5, # Left trigger
|
| 355 |
+
"RT": 4, # Right trigger
|
| 356 |
+
"DX": 6, # Directional pad x
|
| 357 |
+
"DY": 7, # Directional pad y
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
self.button_id = {
|
| 361 |
+
"X": 3,
|
| 362 |
+
"Y": 4,
|
| 363 |
+
"B": 1,
|
| 364 |
+
"A": 0,
|
| 365 |
+
"LB": 6,
|
| 366 |
+
"RB": 7,
|
| 367 |
+
"SELECT": 10,
|
| 368 |
+
"START": 11,
|
| 369 |
+
}
|
| 370 |
+
else:
|
| 371 |
+
print("Unsupported gamepad. ")
|
| 372 |
+
|
| 373 |
+
def PrintSceneInformation(self):
|
| 374 |
+
print(" ")
|
| 375 |
+
logger.info(colored("<<------------- Link ------------->>", "green"))
|
| 376 |
+
for i in range(self.mj_model.nbody):
|
| 377 |
+
name = mujoco.mj_id2name(self.mj_model, mujoco._enums.mjtObj.mjOBJ_BODY, i)
|
| 378 |
+
if name:
|
| 379 |
+
logger.info(f"link_index: {i}, name: {name}")
|
| 380 |
+
print(" ")
|
| 381 |
+
|
| 382 |
+
logger.info(colored("<<------------- Joint ------------->>", "green"))
|
| 383 |
+
for i in range(self.mj_model.njnt):
|
| 384 |
+
name = mujoco.mj_id2name(self.mj_model, mujoco._enums.mjtObj.mjOBJ_JOINT, i)
|
| 385 |
+
if name:
|
| 386 |
+
logger.info(f"joint_index: {i}, name: {name}")
|
| 387 |
+
print(" ")
|
| 388 |
+
|
| 389 |
+
logger.info(colored("<<------------- Actuator ------------->>", "green"))
|
| 390 |
+
for i in range(self.mj_model.nu):
|
| 391 |
+
name = mujoco.mj_id2name(self.mj_model, mujoco._enums.mjtObj.mjOBJ_ACTUATOR, i)
|
| 392 |
+
if name:
|
| 393 |
+
logger.info(f"actuator_index: {i}, name: {name}")
|
| 394 |
+
print(" ")
|
| 395 |
+
|
| 396 |
+
logger.info(colored("<<------------- Sensor ------------->>", "green"))
|
| 397 |
+
index = 0
|
| 398 |
+
for i in range(self.mj_model.nsensor):
|
| 399 |
+
name = mujoco.mj_id2name(self.mj_model, mujoco._enums.mjtObj.mjOBJ_SENSOR, i)
|
| 400 |
+
if name:
|
| 401 |
+
logger.info(
|
| 402 |
+
f"sensor_index: {index}, name: {name}, dim: {self.mj_model.sensor_dim[i]}"
|
| 403 |
+
)
|
| 404 |
+
index = index + self.mj_model.sensor_dim[i]
|
| 405 |
+
print(" ")
|
| 406 |
+
|
| 407 |
+
|
| 408 |
+
class ElasticBand:
|
| 409 |
+
"""
|
| 410 |
+
ref: https://github.com/unitreerobotics/unitree_mujoco
|
| 411 |
+
"""
|
| 412 |
+
|
| 413 |
+
def __init__(self):
|
| 414 |
+
self.kp_pos = 10000
|
| 415 |
+
self.kd_pos = 1000
|
| 416 |
+
self.kp_ang = 1000
|
| 417 |
+
self.kd_ang = 10
|
| 418 |
+
self.point = np.array([0, 0, 1])
|
| 419 |
+
self.length = 0
|
| 420 |
+
self.enable = True
|
| 421 |
+
|
| 422 |
+
def Advance(self, pose):
|
| 423 |
+
"""
|
| 424 |
+
Args:
|
| 425 |
+
pose: 13D array containing:
|
| 426 |
+
- pose[0:3]: position in world frame
|
| 427 |
+
- pose[3:7]: quaternion [w,x,y,z] in world frame
|
| 428 |
+
- pose[7:10]: linear velocity in world frame
|
| 429 |
+
- pose[10:13]: angular velocity in world frame
|
| 430 |
+
Returns:
|
| 431 |
+
np.ndarray: 6D vector [fx, fy, fz, tx, ty, tz]
|
| 432 |
+
"""
|
| 433 |
+
pos = pose[0:3]
|
| 434 |
+
quat = pose[3:7]
|
| 435 |
+
lin_vel = pose[7:10]
|
| 436 |
+
ang_vel = pose[10:13]
|
| 437 |
+
|
| 438 |
+
δx = self.point - pos
|
| 439 |
+
f = self.kp_pos * (δx + np.array([0, 0, self.length])) + self.kd_pos * (0 - lin_vel)
|
| 440 |
+
|
| 441 |
+
# --- Orientation PD control for torque ---
|
| 442 |
+
quat = np.array([quat[1], quat[2], quat[3], quat[0]]) # reorder to [x,y,z,w] for scipy
|
| 443 |
+
rot = scipy.spatial.transform.Rotation.from_quat(quat)
|
| 444 |
+
rotvec = rot.as_rotvec() # axis-angle error
|
| 445 |
+
torque = -self.kp_ang * rotvec - self.kd_ang * ang_vel
|
| 446 |
+
|
| 447 |
+
return np.concatenate([f, torque])
|
| 448 |
+
|
| 449 |
+
def MujuocoKeyCallback(self, key):
|
| 450 |
+
if key == glfw.KEY_7:
|
| 451 |
+
self.length -= 0.1
|
| 452 |
+
if key == glfw.KEY_8:
|
| 453 |
+
self.length += 0.1
|
| 454 |
+
if key == glfw.KEY_9:
|
| 455 |
+
self.enable = not self.enable
|
| 456 |
+
|
| 457 |
+
def handle_keyboard_button(self, key):
|
| 458 |
+
if key == "9":
|
| 459 |
+
self.enable = not self.enable
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/__init__.py
ADDED
|
File without changes
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/command_sender.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Dict
|
| 2 |
+
|
| 3 |
+
import numpy as np
|
| 4 |
+
from unitree_sdk2py.core.channel import ChannelPublisher
|
| 5 |
+
from unitree_sdk2py.idl.default import unitree_hg_msg_dds__HandCmd_
|
| 6 |
+
from unitree_sdk2py.idl.unitree_hg.msg.dds_ import HandCmd_
|
| 7 |
+
from unitree_sdk2py.utils.crc import CRC
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class BodyCommandSender:
|
| 11 |
+
def __init__(self, config: Dict):
|
| 12 |
+
self.config = config
|
| 13 |
+
if self.config["ROBOT_TYPE"] == "h1" or self.config["ROBOT_TYPE"] == "go2":
|
| 14 |
+
from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowCmd_
|
| 15 |
+
from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowCmd_
|
| 16 |
+
|
| 17 |
+
self.low_cmd = unitree_go_msg_dds__LowCmd_()
|
| 18 |
+
elif (
|
| 19 |
+
self.config["ROBOT_TYPE"] == "g1_29dof"
|
| 20 |
+
or self.config["ROBOT_TYPE"] == "h1-2_21dof"
|
| 21 |
+
or self.config["ROBOT_TYPE"] == "h1-2_27dof"
|
| 22 |
+
):
|
| 23 |
+
from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowCmd_
|
| 24 |
+
from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowCmd_
|
| 25 |
+
|
| 26 |
+
self.low_cmd = unitree_hg_msg_dds__LowCmd_()
|
| 27 |
+
else:
|
| 28 |
+
raise NotImplementedError(
|
| 29 |
+
f"Robot type {self.config['ROBOT_TYPE']} is not supported yet"
|
| 30 |
+
)
|
| 31 |
+
# init kp kd
|
| 32 |
+
self.kp_level = 1.0
|
| 33 |
+
self.waist_kp_level = 1.0
|
| 34 |
+
self.robot_kp = np.zeros(self.config["NUM_MOTORS"])
|
| 35 |
+
self.robot_kd = np.zeros(self.config["NUM_MOTORS"])
|
| 36 |
+
# set kp level
|
| 37 |
+
for i in range(len(self.config["MOTOR_KP"])):
|
| 38 |
+
self.robot_kp[i] = self.config["MOTOR_KP"][i] * self.kp_level
|
| 39 |
+
for i in range(len(self.config["MOTOR_KD"])):
|
| 40 |
+
self.robot_kd[i] = self.config["MOTOR_KD"][i] * 1.0
|
| 41 |
+
self.weak_motor_joint_index = []
|
| 42 |
+
for _, value in self.config["WeakMotorJointIndex"].items():
|
| 43 |
+
self.weak_motor_joint_index.append(value)
|
| 44 |
+
# init low cmd publisher
|
| 45 |
+
self.lowcmd_publisher_ = ChannelPublisher("rt/lowcmd", LowCmd_)
|
| 46 |
+
self.lowcmd_publisher_.Init()
|
| 47 |
+
self.InitLowCmd()
|
| 48 |
+
self.low_state = None
|
| 49 |
+
self.crc = CRC()
|
| 50 |
+
|
| 51 |
+
def InitLowCmd(self):
|
| 52 |
+
# h1/go2:
|
| 53 |
+
if self.config["ROBOT_TYPE"] == "h1" or self.config["ROBOT_TYPE"] == "go2":
|
| 54 |
+
self.low_cmd.head[0] = 0xFE
|
| 55 |
+
self.low_cmd.head[1] = 0xEF
|
| 56 |
+
else:
|
| 57 |
+
pass
|
| 58 |
+
|
| 59 |
+
self.low_cmd.level_flag = 0xFF
|
| 60 |
+
self.low_cmd.gpio = 0
|
| 61 |
+
for i in range(self.config["NUM_MOTORS"]):
|
| 62 |
+
if self.is_weak_motor(i):
|
| 63 |
+
self.low_cmd.motor_cmd[i].mode = 0x01
|
| 64 |
+
else:
|
| 65 |
+
self.low_cmd.motor_cmd[i].mode = 0x0A
|
| 66 |
+
self.low_cmd.motor_cmd[i].q = self.config["UNITREE_LEGGED_CONST"]["PosStopF"]
|
| 67 |
+
self.low_cmd.motor_cmd[i].kp = 0
|
| 68 |
+
self.low_cmd.motor_cmd[i].dq = self.config["UNITREE_LEGGED_CONST"]["VelStopF"]
|
| 69 |
+
self.low_cmd.motor_cmd[i].kd = 0
|
| 70 |
+
self.low_cmd.motor_cmd[i].tau = 0
|
| 71 |
+
if (
|
| 72 |
+
self.config["ROBOT_TYPE"] == "g1_29dof"
|
| 73 |
+
or self.config["ROBOT_TYPE"] == "h1-2_21dof"
|
| 74 |
+
or self.config["ROBOT_TYPE"] == "h1-2_27dof"
|
| 75 |
+
):
|
| 76 |
+
self.low_cmd.mode_machine = self.config["UNITREE_LEGGED_CONST"]["MODE_MACHINE"]
|
| 77 |
+
self.low_cmd.mode_pr = self.config["UNITREE_LEGGED_CONST"]["MODE_PR"]
|
| 78 |
+
else:
|
| 79 |
+
pass
|
| 80 |
+
|
| 81 |
+
def is_weak_motor(self, motor_index: int) -> bool:
|
| 82 |
+
return motor_index in self.weak_motor_joint_index
|
| 83 |
+
|
| 84 |
+
def send_command(self, cmd_q: np.ndarray, cmd_dq: np.ndarray, cmd_tau: np.ndarray):
|
| 85 |
+
for i in range(self.config["NUM_MOTORS"]):
|
| 86 |
+
motor_index = self.config["JOINT2MOTOR"][i]
|
| 87 |
+
joint_index = self.config["MOTOR2JOINT"][i]
|
| 88 |
+
# print(f"motor_index: {motor_index}, joint_index: {joint_index}")
|
| 89 |
+
if joint_index == -1:
|
| 90 |
+
# send default joint position command
|
| 91 |
+
self.low_cmd.motor_cmd[motor_index].q = self.config["DEFAULT_MOTOR_ANGLES"][
|
| 92 |
+
motor_index
|
| 93 |
+
]
|
| 94 |
+
self.low_cmd.motor_cmd[motor_index].dq = 0.0
|
| 95 |
+
self.low_cmd.motor_cmd[motor_index].tau = 0.0
|
| 96 |
+
else:
|
| 97 |
+
self.low_cmd.motor_cmd[motor_index].q = cmd_q[joint_index]
|
| 98 |
+
self.low_cmd.motor_cmd[motor_index].dq = cmd_dq[joint_index]
|
| 99 |
+
self.low_cmd.motor_cmd[motor_index].tau = cmd_tau[joint_index]
|
| 100 |
+
# kp kd
|
| 101 |
+
self.low_cmd.motor_cmd[motor_index].kp = self.robot_kp[motor_index]
|
| 102 |
+
self.low_cmd.motor_cmd[motor_index].kd = self.robot_kd[motor_index]
|
| 103 |
+
|
| 104 |
+
self.low_cmd.crc = self.crc.Crc(self.low_cmd)
|
| 105 |
+
self.lowcmd_publisher_.Write(self.low_cmd)
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def make_hand_mode(motor_index: int) -> int:
|
| 109 |
+
status = 0x01
|
| 110 |
+
timeout = 0x01
|
| 111 |
+
mode = motor_index & 0x0F
|
| 112 |
+
mode |= status << 4 # bits [4..6]
|
| 113 |
+
mode |= timeout << 7 # bit 7
|
| 114 |
+
return mode
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
class HandCommandSender:
|
| 118 |
+
def __init__(self, is_left: bool = True):
|
| 119 |
+
self.is_left = is_left
|
| 120 |
+
if self.is_left:
|
| 121 |
+
self.cmd_pub = ChannelPublisher("rt/dex3/left/cmd", HandCmd_)
|
| 122 |
+
else:
|
| 123 |
+
self.cmd_pub = ChannelPublisher("rt/dex3/right/cmd", HandCmd_)
|
| 124 |
+
|
| 125 |
+
self.cmd_pub.Init()
|
| 126 |
+
self.cmd = unitree_hg_msg_dds__HandCmd_()
|
| 127 |
+
|
| 128 |
+
self.hand_dof = 7
|
| 129 |
+
|
| 130 |
+
self.kp = [1.0] * self.hand_dof
|
| 131 |
+
self.kd = [0.2] * self.hand_dof
|
| 132 |
+
self.kp[0] = 2.0
|
| 133 |
+
self.kd[0] = 0.5
|
| 134 |
+
|
| 135 |
+
def send_command(self, cmd: np.ndarray):
|
| 136 |
+
for i in range(self.hand_dof):
|
| 137 |
+
# Build the bitfield mode (see your C++ example)
|
| 138 |
+
mode_val = make_hand_mode(i)
|
| 139 |
+
self.cmd.motor_cmd[i].mode = mode_val
|
| 140 |
+
self.cmd.motor_cmd[i].q = cmd[i]
|
| 141 |
+
self.cmd.motor_cmd[i].dq = 0.0
|
| 142 |
+
self.cmd.motor_cmd[i].tau = 0.0
|
| 143 |
+
self.cmd.motor_cmd[i].kp = self.kp[i]
|
| 144 |
+
self.cmd.motor_cmd[i].kd = self.kd[i]
|
| 145 |
+
|
| 146 |
+
self.cmd_pub.Write(self.cmd)
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/joint_safety.py
ADDED
|
@@ -0,0 +1,534 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Joint safety monitor for G1 robot.
|
| 2 |
+
|
| 3 |
+
This module implements safety monitoring for arm and finger joint velocities using
|
| 4 |
+
joint groups defined in the robot model's supplemental info. Leg joints are not monitored.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from datetime import datetime
|
| 8 |
+
import sys
|
| 9 |
+
import time
|
| 10 |
+
from typing import Dict, List, Optional, Tuple
|
| 11 |
+
|
| 12 |
+
import numpy as np
|
| 13 |
+
|
| 14 |
+
from decoupled_wbc.data.viz.rerun_viz import RerunViz
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class JointSafetyMonitor:
|
| 18 |
+
"""Monitor joint velocities for G1 robot arms and hands."""
|
| 19 |
+
|
| 20 |
+
# Velocity limits in rad/s
|
| 21 |
+
ARM_VELOCITY_LIMIT = 6.0 # rad/s for arm joints
|
| 22 |
+
HAND_VELOCITY_LIMIT = 50.0 # rad/s for finger joints
|
| 23 |
+
|
| 24 |
+
def __init__(self, robot_model, enable_viz: bool = False, env_type: str = "real"):
|
| 25 |
+
"""Initialize joint safety monitor.
|
| 26 |
+
|
| 27 |
+
Args:
|
| 28 |
+
robot_model: The robot model containing joint information
|
| 29 |
+
enable_viz: If True, enable rerun visualization (default False)
|
| 30 |
+
env_type: Environment type - "sim" or "real" (default "real")
|
| 31 |
+
"""
|
| 32 |
+
self.robot_model = robot_model
|
| 33 |
+
self.safety_margin = 1.0 # Hardcoded safety margin
|
| 34 |
+
self.enable_viz = enable_viz
|
| 35 |
+
self.env_type = env_type
|
| 36 |
+
|
| 37 |
+
# Startup ramping parameters
|
| 38 |
+
self.control_frequency = 50 # Hz, hardcoded from run_g1_control_loop.py
|
| 39 |
+
self.ramp_duration_steps = int(2.0 * self.control_frequency) # 2 seconds * 50Hz = 100 steps
|
| 40 |
+
self.startup_counter = 0
|
| 41 |
+
self.initial_positions = None
|
| 42 |
+
self.startup_complete = False
|
| 43 |
+
|
| 44 |
+
# Initialize velocity and position limits for monitored joints
|
| 45 |
+
self.velocity_limits = {}
|
| 46 |
+
self.position_limits = {}
|
| 47 |
+
self._initialize_limits()
|
| 48 |
+
|
| 49 |
+
# Track violations for reporting
|
| 50 |
+
self.violations = []
|
| 51 |
+
|
| 52 |
+
# Initialize visualization
|
| 53 |
+
self.right_arm_indices = None
|
| 54 |
+
self.right_arm_joint_names = []
|
| 55 |
+
self.left_arm_indices = None
|
| 56 |
+
self.left_arm_joint_names = []
|
| 57 |
+
self.right_hand_indices = None
|
| 58 |
+
self.right_hand_joint_names = []
|
| 59 |
+
self.left_hand_indices = None
|
| 60 |
+
self.left_hand_joint_names = []
|
| 61 |
+
try:
|
| 62 |
+
arm_indices = self.robot_model.get_joint_group_indices("arms")
|
| 63 |
+
all_joint_names = [self.robot_model.joint_names[i] for i in arm_indices]
|
| 64 |
+
# Filter for right and left arm joints
|
| 65 |
+
self.right_arm_joint_names = [
|
| 66 |
+
name for name in all_joint_names if name.startswith("right_")
|
| 67 |
+
]
|
| 68 |
+
self.right_arm_indices = [
|
| 69 |
+
self.robot_model.joint_to_dof_index[name] for name in self.right_arm_joint_names
|
| 70 |
+
]
|
| 71 |
+
self.left_arm_joint_names = [
|
| 72 |
+
name for name in all_joint_names if name.startswith("left_")
|
| 73 |
+
]
|
| 74 |
+
self.left_arm_indices = [
|
| 75 |
+
self.robot_model.joint_to_dof_index[name] for name in self.left_arm_joint_names
|
| 76 |
+
]
|
| 77 |
+
# Hand joints
|
| 78 |
+
hand_indices = self.robot_model.get_joint_group_indices("hands")
|
| 79 |
+
all_hand_names = [self.robot_model.joint_names[i] for i in hand_indices]
|
| 80 |
+
self.right_hand_joint_names = [
|
| 81 |
+
name for name in all_hand_names if name.startswith("right_")
|
| 82 |
+
]
|
| 83 |
+
self.right_hand_indices = [
|
| 84 |
+
self.robot_model.joint_to_dof_index[name] for name in self.right_hand_joint_names
|
| 85 |
+
]
|
| 86 |
+
self.left_hand_joint_names = [
|
| 87 |
+
name for name in all_hand_names if name.startswith("left_")
|
| 88 |
+
]
|
| 89 |
+
self.left_hand_indices = [
|
| 90 |
+
self.robot_model.joint_to_dof_index[name] for name in self.left_hand_joint_names
|
| 91 |
+
]
|
| 92 |
+
except ValueError as e:
|
| 93 |
+
print(f"[JointSafetyMonitor] Warning: Could not initialize arm/hand visualization: {e}")
|
| 94 |
+
except Exception:
|
| 95 |
+
pass
|
| 96 |
+
|
| 97 |
+
# Use single tensor_key for each plot
|
| 98 |
+
self.right_arm_pos_key = "right_arm_qpos"
|
| 99 |
+
self.left_arm_pos_key = "left_arm_qpos"
|
| 100 |
+
self.right_arm_vel_key = "right_arm_dq"
|
| 101 |
+
self.left_arm_vel_key = "left_arm_dq"
|
| 102 |
+
self.right_hand_pos_key = "right_hand_qpos"
|
| 103 |
+
self.left_hand_pos_key = "left_hand_qpos"
|
| 104 |
+
self.right_hand_vel_key = "right_hand_dq"
|
| 105 |
+
self.left_hand_vel_key = "left_hand_dq"
|
| 106 |
+
|
| 107 |
+
# Define a consistent color palette for up to 8 joints (tab10 + extra)
|
| 108 |
+
self.joint_colors = [
|
| 109 |
+
[31, 119, 180], # blue
|
| 110 |
+
[255, 127, 14], # orange
|
| 111 |
+
[44, 160, 44], # green
|
| 112 |
+
[214, 39, 40], # red
|
| 113 |
+
[148, 103, 189], # purple
|
| 114 |
+
[140, 86, 75], # brown
|
| 115 |
+
[227, 119, 194], # pink
|
| 116 |
+
[127, 127, 127], # gray (for 8th joint if needed)
|
| 117 |
+
]
|
| 118 |
+
|
| 119 |
+
# Initialize Rerun visualization only if enabled
|
| 120 |
+
self.viz = None
|
| 121 |
+
if self.enable_viz:
|
| 122 |
+
try:
|
| 123 |
+
self.viz = RerunViz(
|
| 124 |
+
image_keys=[],
|
| 125 |
+
tensor_keys=[
|
| 126 |
+
self.right_arm_pos_key,
|
| 127 |
+
self.left_arm_pos_key,
|
| 128 |
+
self.right_arm_vel_key,
|
| 129 |
+
self.left_arm_vel_key,
|
| 130 |
+
self.right_hand_pos_key,
|
| 131 |
+
self.left_hand_pos_key,
|
| 132 |
+
self.right_hand_vel_key,
|
| 133 |
+
self.left_hand_vel_key,
|
| 134 |
+
],
|
| 135 |
+
window_size=10.0,
|
| 136 |
+
app_name="joint_safety_monitor",
|
| 137 |
+
)
|
| 138 |
+
except Exception:
|
| 139 |
+
self.viz = None
|
| 140 |
+
|
| 141 |
+
def _initialize_limits(self):
|
| 142 |
+
"""Initialize velocity and position limits for arm and hand joints using robot model joint groups."""
|
| 143 |
+
if self.robot_model.supplemental_info is None:
|
| 144 |
+
raise ValueError("Robot model must have supplemental_info to use joint groups")
|
| 145 |
+
|
| 146 |
+
# Get arm joint indices from robot model joint groups
|
| 147 |
+
try:
|
| 148 |
+
arm_indices = self.robot_model.get_joint_group_indices("arms")
|
| 149 |
+
arm_joint_names = [self.robot_model.joint_names[i] for i in arm_indices]
|
| 150 |
+
|
| 151 |
+
for joint_name in arm_joint_names:
|
| 152 |
+
# Set velocity limits
|
| 153 |
+
vel_limit = self.ARM_VELOCITY_LIMIT * self.safety_margin
|
| 154 |
+
self.velocity_limits[joint_name] = {"min": -vel_limit, "max": vel_limit}
|
| 155 |
+
|
| 156 |
+
# Set position limits from robot model
|
| 157 |
+
if joint_name in self.robot_model.joint_to_dof_index:
|
| 158 |
+
joint_idx = self.robot_model.joint_to_dof_index[joint_name]
|
| 159 |
+
# Adjust index for floating base if present
|
| 160 |
+
limit_idx = joint_idx - (7 if self.robot_model.is_floating_base_model else 0)
|
| 161 |
+
|
| 162 |
+
if 0 <= limit_idx < len(self.robot_model.lower_joint_limits):
|
| 163 |
+
pos_min = self.robot_model.lower_joint_limits[limit_idx]
|
| 164 |
+
pos_max = self.robot_model.upper_joint_limits[limit_idx]
|
| 165 |
+
|
| 166 |
+
# Apply safety margin to position limits
|
| 167 |
+
pos_range = pos_max - pos_min
|
| 168 |
+
margin = pos_range * (1.0 - self.safety_margin) / 2.0
|
| 169 |
+
|
| 170 |
+
self.position_limits[joint_name] = {
|
| 171 |
+
"min": pos_min + margin,
|
| 172 |
+
"max": pos_max - margin,
|
| 173 |
+
}
|
| 174 |
+
except ValueError as e:
|
| 175 |
+
print(f"[JointSafetyMonitor] Warning: Could not find 'arms' joint group: {e}")
|
| 176 |
+
|
| 177 |
+
# Get hand joint indices from robot model joint groups
|
| 178 |
+
try:
|
| 179 |
+
hand_indices = self.robot_model.get_joint_group_indices("hands")
|
| 180 |
+
hand_joint_names = [self.robot_model.joint_names[i] for i in hand_indices]
|
| 181 |
+
|
| 182 |
+
for joint_name in hand_joint_names:
|
| 183 |
+
# Set velocity limits only for hands (no position limits for now)
|
| 184 |
+
vel_limit = self.HAND_VELOCITY_LIMIT * self.safety_margin
|
| 185 |
+
self.velocity_limits[joint_name] = {"min": -vel_limit, "max": vel_limit}
|
| 186 |
+
except ValueError as e:
|
| 187 |
+
print(f"[JointSafetyMonitor] Warning: Could not find 'hands' joint group: {e}")
|
| 188 |
+
|
| 189 |
+
def check_safety(self, obs: Dict, action: Dict) -> Tuple[bool, List[Dict]]:
|
| 190 |
+
"""Check if current velocities and positions are within safe bounds.
|
| 191 |
+
|
| 192 |
+
Args:
|
| 193 |
+
obs: Observation dictionary containing joint positions and velocities
|
| 194 |
+
action: Action dictionary containing target positions
|
| 195 |
+
|
| 196 |
+
Returns:
|
| 197 |
+
(is_safe, violations): Tuple of safety status and list of violations
|
| 198 |
+
Note: is_safe=False only for velocity violations (triggers shutdown)
|
| 199 |
+
Position violations are warnings only (don't affect is_safe)
|
| 200 |
+
"""
|
| 201 |
+
self.violations = []
|
| 202 |
+
is_safe = True
|
| 203 |
+
joint_names = self.robot_model.joint_names
|
| 204 |
+
|
| 205 |
+
# Check current joint velocities (critical - triggers shutdown)
|
| 206 |
+
if "dq" in obs:
|
| 207 |
+
joint_velocities = obs["dq"]
|
| 208 |
+
|
| 209 |
+
for i, joint_name in enumerate(joint_names):
|
| 210 |
+
# Only check monitored joints
|
| 211 |
+
if joint_name not in self.velocity_limits:
|
| 212 |
+
continue
|
| 213 |
+
|
| 214 |
+
if i < len(joint_velocities):
|
| 215 |
+
velocity = joint_velocities[i]
|
| 216 |
+
limits = self.velocity_limits[joint_name]
|
| 217 |
+
|
| 218 |
+
if velocity < limits["min"] or velocity > limits["max"]:
|
| 219 |
+
violation = {
|
| 220 |
+
"joint": joint_name,
|
| 221 |
+
"type": "velocity",
|
| 222 |
+
"value": velocity,
|
| 223 |
+
"limit_min": limits["min"],
|
| 224 |
+
"limit_max": limits["max"],
|
| 225 |
+
"exceeded_by": self._calculate_exceeded_percentage(
|
| 226 |
+
velocity, limits["min"], limits["max"]
|
| 227 |
+
),
|
| 228 |
+
"critical": True, # Velocity violations are critical
|
| 229 |
+
}
|
| 230 |
+
self.violations.append(violation)
|
| 231 |
+
is_safe = False
|
| 232 |
+
|
| 233 |
+
# Check current joint positions (warning only - no shutdown)
|
| 234 |
+
if "q" in obs:
|
| 235 |
+
joint_positions = obs["q"]
|
| 236 |
+
|
| 237 |
+
for i, joint_name in enumerate(joint_names):
|
| 238 |
+
# Only check joints with position limits (arms)
|
| 239 |
+
if joint_name not in self.position_limits:
|
| 240 |
+
continue
|
| 241 |
+
|
| 242 |
+
if i < len(joint_positions):
|
| 243 |
+
position = joint_positions[i]
|
| 244 |
+
limits = self.position_limits[joint_name]
|
| 245 |
+
|
| 246 |
+
if position < limits["min"] or position > limits["max"]:
|
| 247 |
+
violation = {
|
| 248 |
+
"joint": joint_name,
|
| 249 |
+
"type": "position",
|
| 250 |
+
"value": position,
|
| 251 |
+
"limit_min": limits["min"],
|
| 252 |
+
"limit_max": limits["max"],
|
| 253 |
+
"exceeded_by": self._calculate_exceeded_percentage(
|
| 254 |
+
position, limits["min"], limits["max"]
|
| 255 |
+
),
|
| 256 |
+
"critical": False, # Position violations are warnings only
|
| 257 |
+
}
|
| 258 |
+
self.violations.append(violation)
|
| 259 |
+
# Don't set is_safe = False for position violations
|
| 260 |
+
|
| 261 |
+
return is_safe, self.violations
|
| 262 |
+
|
| 263 |
+
def _calculate_exceeded_percentage(
|
| 264 |
+
self, value: float, limit_min: float, limit_max: float
|
| 265 |
+
) -> float:
|
| 266 |
+
"""Calculate by how much percentage a value exceeds the limits."""
|
| 267 |
+
if value < limit_min:
|
| 268 |
+
return abs((value - limit_min) / limit_min) * 100
|
| 269 |
+
elif value > limit_max:
|
| 270 |
+
return abs((value - limit_max) / limit_max) * 100
|
| 271 |
+
return 0.0
|
| 272 |
+
|
| 273 |
+
def get_safe_action(self, obs: Dict, original_action: Dict) -> Dict:
|
| 274 |
+
"""Generate a safe action with startup ramping for smooth initialization.
|
| 275 |
+
|
| 276 |
+
Args:
|
| 277 |
+
obs: Observation dictionary containing current joint positions
|
| 278 |
+
original_action: The original action that may cause violations
|
| 279 |
+
|
| 280 |
+
Returns:
|
| 281 |
+
Safe action with startup ramping applied if within ramp duration
|
| 282 |
+
"""
|
| 283 |
+
safe_action = original_action.copy()
|
| 284 |
+
|
| 285 |
+
# Handle startup ramping for arm joints
|
| 286 |
+
if not self.startup_complete:
|
| 287 |
+
if self.initial_positions is None and "q" in obs:
|
| 288 |
+
# Store initial positions from first observation
|
| 289 |
+
self.initial_positions = obs["q"].copy()
|
| 290 |
+
|
| 291 |
+
if (
|
| 292 |
+
self.startup_counter < self.ramp_duration_steps
|
| 293 |
+
and self.initial_positions is not None
|
| 294 |
+
and "q" in safe_action
|
| 295 |
+
):
|
| 296 |
+
# Ramp factor: 0.0 at start → 1.0 at end
|
| 297 |
+
ramp_factor = self.startup_counter / self.ramp_duration_steps
|
| 298 |
+
|
| 299 |
+
# Apply ramping only to monitored arm joints
|
| 300 |
+
for joint_name in self.velocity_limits: # Only monitored arm joints
|
| 301 |
+
if joint_name in self.robot_model.joint_to_dof_index:
|
| 302 |
+
joint_idx = self.robot_model.joint_to_dof_index[joint_name]
|
| 303 |
+
if joint_idx < len(safe_action["q"]) and joint_idx < len(
|
| 304 |
+
self.initial_positions
|
| 305 |
+
):
|
| 306 |
+
initial_pos = self.initial_positions[joint_idx]
|
| 307 |
+
target_pos = original_action["q"][joint_idx]
|
| 308 |
+
# Linear interpolation: initial + ramp_factor * (target - initial)
|
| 309 |
+
safe_action["q"][joint_idx] = initial_pos + ramp_factor * (
|
| 310 |
+
target_pos - initial_pos
|
| 311 |
+
)
|
| 312 |
+
|
| 313 |
+
# Increment counter for next iteration
|
| 314 |
+
self.startup_counter += 1
|
| 315 |
+
else:
|
| 316 |
+
# Ramping complete - use original actions
|
| 317 |
+
self.startup_complete = True
|
| 318 |
+
|
| 319 |
+
return safe_action
|
| 320 |
+
|
| 321 |
+
def get_violation_report(self, violations: Optional[List[Dict]] = None) -> str:
|
| 322 |
+
"""Generate a formatted error report for violations.
|
| 323 |
+
|
| 324 |
+
Args:
|
| 325 |
+
violations: List of violations to report (uses self.violations if None)
|
| 326 |
+
|
| 327 |
+
Returns:
|
| 328 |
+
Formatted error message string
|
| 329 |
+
"""
|
| 330 |
+
if violations is None:
|
| 331 |
+
violations = self.violations
|
| 332 |
+
|
| 333 |
+
if not violations:
|
| 334 |
+
return "No violations detected."
|
| 335 |
+
|
| 336 |
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
| 337 |
+
|
| 338 |
+
# Check if these are critical violations or warnings
|
| 339 |
+
critical_violations = [v for v in violations if v.get("critical", True)]
|
| 340 |
+
warning_violations = [v for v in violations if not v.get("critical", True)]
|
| 341 |
+
|
| 342 |
+
if critical_violations and warning_violations:
|
| 343 |
+
report = f"Joint safety bounds exceeded!\nTimestamp: {timestamp}\nViolations:\n"
|
| 344 |
+
elif critical_violations:
|
| 345 |
+
report = f"Joint safety bounds exceeded!\nTimestamp: {timestamp}\nViolations:\n"
|
| 346 |
+
else:
|
| 347 |
+
report = f"Joint position warnings!\nTimestamp: {timestamp}\nWarnings:\n"
|
| 348 |
+
|
| 349 |
+
for violation in violations:
|
| 350 |
+
joint = violation["joint"]
|
| 351 |
+
vtype = violation["type"]
|
| 352 |
+
value = violation["value"]
|
| 353 |
+
exceeded = violation["exceeded_by"]
|
| 354 |
+
limit_min = violation["limit_min"]
|
| 355 |
+
limit_max = violation["limit_max"]
|
| 356 |
+
|
| 357 |
+
if vtype == "velocity":
|
| 358 |
+
report += f" - {joint}: {vtype}={value:.3f} rad/s "
|
| 359 |
+
report += f"(limit: ±{limit_max:.3f} rad/s) - "
|
| 360 |
+
report += f"EXCEEDED by {exceeded:.1f}%\n"
|
| 361 |
+
elif vtype == "position":
|
| 362 |
+
report += f" - {joint}: {vtype}={value:.3f} rad "
|
| 363 |
+
report += f"(limits: [{limit_min:.3f}, {limit_max:.3f}] rad) - "
|
| 364 |
+
report += f"EXCEEDED by {exceeded:.1f}%\n"
|
| 365 |
+
|
| 366 |
+
# Add appropriate action message
|
| 367 |
+
if critical_violations:
|
| 368 |
+
report += "Action: Safe mode engaged (kp=0, tau=0). System shutdown initiated.\n"
|
| 369 |
+
report += "Please restart Docker container to resume operation."
|
| 370 |
+
else:
|
| 371 |
+
report += "Action: Position warning only. Robot continues operation."
|
| 372 |
+
|
| 373 |
+
return report
|
| 374 |
+
|
| 375 |
+
def handle_violations(self, obs: Dict, action: Dict) -> Dict:
|
| 376 |
+
"""Check safety and handle violations appropriately.
|
| 377 |
+
|
| 378 |
+
Args:
|
| 379 |
+
obs: Observation dictionary
|
| 380 |
+
action: Action dictionary
|
| 381 |
+
|
| 382 |
+
Returns:
|
| 383 |
+
Dict with keys:
|
| 384 |
+
- 'safe_to_continue': bool - whether robot should continue operation
|
| 385 |
+
- 'action': Dict - potentially modified safe action
|
| 386 |
+
- 'shutdown_required': bool - whether system shutdown is needed
|
| 387 |
+
"""
|
| 388 |
+
is_safe, violations = self.check_safety(obs, action)
|
| 389 |
+
|
| 390 |
+
# Apply startup ramping (always, regardless of violations)
|
| 391 |
+
safe_action = self.get_safe_action(obs, action)
|
| 392 |
+
|
| 393 |
+
# Visualize arm and hand joint positions and velocities if enabled
|
| 394 |
+
if self.enable_viz:
|
| 395 |
+
if (
|
| 396 |
+
self.right_arm_indices is not None
|
| 397 |
+
and self.left_arm_indices is not None
|
| 398 |
+
and self.right_hand_indices is not None
|
| 399 |
+
and self.left_hand_indices is not None
|
| 400 |
+
and "q" in obs
|
| 401 |
+
and "dq" in obs
|
| 402 |
+
and self.viz is not None
|
| 403 |
+
):
|
| 404 |
+
try:
|
| 405 |
+
right_arm_positions = obs["q"][self.right_arm_indices]
|
| 406 |
+
left_arm_positions = obs["q"][self.left_arm_indices]
|
| 407 |
+
right_arm_velocities = obs["dq"][self.right_arm_indices]
|
| 408 |
+
left_arm_velocities = obs["dq"][self.left_arm_indices]
|
| 409 |
+
right_hand_positions = obs["q"][self.right_hand_indices]
|
| 410 |
+
left_hand_positions = obs["q"][self.left_hand_indices]
|
| 411 |
+
right_hand_velocities = obs["dq"][self.right_hand_indices]
|
| 412 |
+
left_hand_velocities = obs["dq"][self.left_hand_indices]
|
| 413 |
+
tensor_dict = {
|
| 414 |
+
self.right_arm_pos_key: right_arm_positions,
|
| 415 |
+
self.left_arm_pos_key: left_arm_positions,
|
| 416 |
+
self.right_arm_vel_key: right_arm_velocities,
|
| 417 |
+
self.left_arm_vel_key: left_arm_velocities,
|
| 418 |
+
self.right_hand_pos_key: right_hand_positions,
|
| 419 |
+
self.left_hand_pos_key: left_hand_positions,
|
| 420 |
+
self.right_hand_vel_key: right_hand_velocities,
|
| 421 |
+
self.left_hand_vel_key: left_hand_velocities,
|
| 422 |
+
}
|
| 423 |
+
self.viz.plot_tensors(tensor_dict, time.time())
|
| 424 |
+
except Exception:
|
| 425 |
+
pass
|
| 426 |
+
|
| 427 |
+
if not violations:
|
| 428 |
+
return {"safe_to_continue": True, "action": safe_action, "shutdown_required": False}
|
| 429 |
+
|
| 430 |
+
# Separate critical (velocity) and warning (position) violations
|
| 431 |
+
critical_violations = [v for v in violations if v.get("critical", True)]
|
| 432 |
+
# warning_violations = [v for v in violations if not v.get('critical', True)]
|
| 433 |
+
|
| 434 |
+
# Print warnings for position violations
|
| 435 |
+
# if warning_violations:
|
| 436 |
+
# warning_msg = self.get_violation_report(warning_violations)
|
| 437 |
+
# print(f"[SAFETY WARNING] {warning_msg}")
|
| 438 |
+
|
| 439 |
+
# Handle critical violations (velocity) - trigger shutdown
|
| 440 |
+
if not is_safe and critical_violations:
|
| 441 |
+
error_msg = self.get_violation_report(critical_violations)
|
| 442 |
+
if self.env_type == "real":
|
| 443 |
+
print(f"[SAFETY VIOLATION] {error_msg}")
|
| 444 |
+
self.trigger_system_shutdown()
|
| 445 |
+
|
| 446 |
+
return {"safe_to_continue": False, "action": safe_action, "shutdown_required": True}
|
| 447 |
+
|
| 448 |
+
# Only position violations - continue with safe action
|
| 449 |
+
return {"safe_to_continue": True, "action": safe_action, "shutdown_required": False}
|
| 450 |
+
|
| 451 |
+
def trigger_system_shutdown(self):
|
| 452 |
+
"""Trigger system shutdown after safety violation."""
|
| 453 |
+
print("\n[SAFETY] Initiating system shutdown due to safety violation...")
|
| 454 |
+
sys.exit(1)
|
| 455 |
+
|
| 456 |
+
|
| 457 |
+
def main():
|
| 458 |
+
"""Test the joint safety monitor with joint groups."""
|
| 459 |
+
print("Testing joint safety monitor with joint groups...")
|
| 460 |
+
|
| 461 |
+
try:
|
| 462 |
+
from decoupled_wbc.control.robot_model.instantiation.g1 import instantiate_g1_robot_model
|
| 463 |
+
|
| 464 |
+
# Instantiate robot model
|
| 465 |
+
robot_model = instantiate_g1_robot_model()
|
| 466 |
+
print(f"Robot model created with {len(robot_model.joint_names)} joints")
|
| 467 |
+
|
| 468 |
+
# Create safety monitor
|
| 469 |
+
safety_monitor = JointSafetyMonitor(robot_model)
|
| 470 |
+
print("Safety monitor created successfully!")
|
| 471 |
+
print(f"Monitoring {len(safety_monitor.velocity_limits)} joints")
|
| 472 |
+
|
| 473 |
+
# Print monitored joints
|
| 474 |
+
print("\nVelocity limits:")
|
| 475 |
+
for joint_name, limits in safety_monitor.velocity_limits.items():
|
| 476 |
+
print(f" - {joint_name}: ±{limits['max']:.2f} rad/s")
|
| 477 |
+
|
| 478 |
+
print(f"\nPosition limits (arms only): {len(safety_monitor.position_limits)} joints")
|
| 479 |
+
for joint_name, limits in safety_monitor.position_limits.items():
|
| 480 |
+
print(f" - {joint_name}: [{limits['min']:.3f}, {limits['max']:.3f}] rad")
|
| 481 |
+
|
| 482 |
+
# Test safety checking with safe values
|
| 483 |
+
print("\n--- Testing Safety Checking ---")
|
| 484 |
+
|
| 485 |
+
# Create mock observation with safe values
|
| 486 |
+
safe_obs = {
|
| 487 |
+
"q": np.zeros(robot_model.num_dofs), # All joints at zero position
|
| 488 |
+
"dq": np.zeros(robot_model.num_dofs), # All joints at zero velocity
|
| 489 |
+
}
|
| 490 |
+
safe_action = {"q": np.zeros(robot_model.num_dofs)}
|
| 491 |
+
|
| 492 |
+
# Test handle_violations method
|
| 493 |
+
result = safety_monitor.handle_violations(safe_obs, safe_action)
|
| 494 |
+
print(
|
| 495 |
+
f"Safe values test: safe_to_continue={result['safe_to_continue']}, "
|
| 496 |
+
f"shutdown_required={result['shutdown_required']}"
|
| 497 |
+
)
|
| 498 |
+
|
| 499 |
+
# Test with unsafe velocity
|
| 500 |
+
unsafe_obs = safe_obs.copy()
|
| 501 |
+
unsafe_obs["dq"] = np.zeros(robot_model.num_dofs)
|
| 502 |
+
# Set left shoulder pitch velocity to exceed limit
|
| 503 |
+
left_shoulder_idx = robot_model.dof_index("left_shoulder_pitch_joint")
|
| 504 |
+
unsafe_obs["dq"][left_shoulder_idx] = 6.0 # Exceeds 5.0 rad/s limit
|
| 505 |
+
|
| 506 |
+
print("\nUnsafe velocity test:")
|
| 507 |
+
result = safety_monitor.handle_violations(unsafe_obs, safe_action)
|
| 508 |
+
print(
|
| 509 |
+
f" safe_to_continue={result['safe_to_continue']}, shutdown_required={result['shutdown_required']}"
|
| 510 |
+
)
|
| 511 |
+
|
| 512 |
+
# Test with unsafe position only
|
| 513 |
+
unsafe_pos_obs = safe_obs.copy()
|
| 514 |
+
unsafe_pos_obs["q"] = np.zeros(robot_model.num_dofs)
|
| 515 |
+
# Set left shoulder pitch position to exceed limit
|
| 516 |
+
unsafe_pos_obs["q"][left_shoulder_idx] = -4.0 # Exceeds lower limit of -3.089
|
| 517 |
+
|
| 518 |
+
print("\nUnsafe position test:")
|
| 519 |
+
result = safety_monitor.handle_violations(unsafe_pos_obs, safe_action)
|
| 520 |
+
print(
|
| 521 |
+
f" safe_to_continue={result['safe_to_continue']}, shutdown_required={result['shutdown_required']}"
|
| 522 |
+
)
|
| 523 |
+
|
| 524 |
+
print("\nAll tests completed successfully!")
|
| 525 |
+
|
| 526 |
+
except Exception as e:
|
| 527 |
+
print(f"Test failed with error: {e}")
|
| 528 |
+
import traceback
|
| 529 |
+
|
| 530 |
+
traceback.print_exc()
|
| 531 |
+
|
| 532 |
+
|
| 533 |
+
if __name__ == "__main__":
|
| 534 |
+
main()
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/state_processor.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import time
|
| 2 |
+
|
| 3 |
+
import numpy as np
|
| 4 |
+
from unitree_sdk2py.comm.motion_switcher.motion_switcher_client import (
|
| 5 |
+
MotionSwitcherClient,
|
| 6 |
+
)
|
| 7 |
+
from unitree_sdk2py.core.channel import ChannelSubscriber
|
| 8 |
+
from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowState_ as LowState_go
|
| 9 |
+
from unitree_sdk2py.idl.unitree_hg.msg.dds_ import (
|
| 10 |
+
HandState_,
|
| 11 |
+
IMUState_,
|
| 12 |
+
LowState_ as LowState_hg,
|
| 13 |
+
OdoState_,
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class BodyStateProcessor:
|
| 18 |
+
def __init__(self, config):
|
| 19 |
+
self.config = config
|
| 20 |
+
|
| 21 |
+
# Enter debug mode for real robot
|
| 22 |
+
if self.config["ENV_TYPE"] == "real":
|
| 23 |
+
msc = MotionSwitcherClient()
|
| 24 |
+
msc.SetTimeout(5.0)
|
| 25 |
+
msc.Init()
|
| 26 |
+
|
| 27 |
+
status, result = msc.CheckMode()
|
| 28 |
+
print(status, result)
|
| 29 |
+
while result["name"]:
|
| 30 |
+
msc.ReleaseMode()
|
| 31 |
+
status, result = msc.CheckMode()
|
| 32 |
+
print(status, result)
|
| 33 |
+
time.sleep(1)
|
| 34 |
+
|
| 35 |
+
if self.config["ROBOT_TYPE"] == "h1" or self.config["ROBOT_TYPE"] == "go2":
|
| 36 |
+
self.robot_lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_go)
|
| 37 |
+
self.robot_lowstate_subscriber.Init(None, 0)
|
| 38 |
+
self.robot_lowstate_subscriber.Init(None, 0)
|
| 39 |
+
elif (
|
| 40 |
+
self.config["ROBOT_TYPE"] == "g1_29dof"
|
| 41 |
+
or self.config["ROBOT_TYPE"] == "h1-2_27dof"
|
| 42 |
+
or self.config["ROBOT_TYPE"] == "h1-2_21dof"
|
| 43 |
+
):
|
| 44 |
+
self.robot_lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_hg)
|
| 45 |
+
self.robot_lowstate_subscriber.Init(None, 0)
|
| 46 |
+
|
| 47 |
+
self.secondary_imu_subscriber = ChannelSubscriber("rt/secondary_imu", IMUState_)
|
| 48 |
+
self.secondary_imu_subscriber.Init(None, 0)
|
| 49 |
+
|
| 50 |
+
# Subscribe to odo state (only available in simulation)
|
| 51 |
+
if self.config["ENV_TYPE"] == "sim":
|
| 52 |
+
self.odo_state_subscriber = ChannelSubscriber("rt/odostate", OdoState_)
|
| 53 |
+
self.odo_state_subscriber.Init(None, 0)
|
| 54 |
+
else:
|
| 55 |
+
raise NotImplementedError(f"Robot type {self.config['ROBOT_TYPE']} is not supported")
|
| 56 |
+
|
| 57 |
+
self.num_dof = self.config["NUM_JOINTS"]
|
| 58 |
+
# 3 + 4 + 19
|
| 59 |
+
self._init_q = np.zeros(3 + 4 + self.num_dof)
|
| 60 |
+
self.q = self._init_q
|
| 61 |
+
self.dq = np.zeros(3 + 3 + self.num_dof)
|
| 62 |
+
self.ddq = np.zeros(3 + 3 + self.num_dof)
|
| 63 |
+
self.tau_est = np.zeros(3 + 3 + self.num_dof)
|
| 64 |
+
self.torso_quat = np.zeros(4)
|
| 65 |
+
self.torso_ang_vel = np.zeros(3)
|
| 66 |
+
self.temp_first = np.zeros(self.num_dof)
|
| 67 |
+
self.temp_second = np.zeros(self.num_dof)
|
| 68 |
+
self.robot_low_state = None
|
| 69 |
+
self.secondary_imu_state = None
|
| 70 |
+
self.odo_state = None
|
| 71 |
+
|
| 72 |
+
def _prepare_low_state(self) -> np.ndarray:
|
| 73 |
+
self.robot_low_state = self.robot_lowstate_subscriber.Read()
|
| 74 |
+
self.secondary_imu_state = self.secondary_imu_subscriber.Read()
|
| 75 |
+
|
| 76 |
+
if not self.robot_low_state:
|
| 77 |
+
print("No low state received")
|
| 78 |
+
return
|
| 79 |
+
imu_state = self.robot_low_state.imu_state
|
| 80 |
+
|
| 81 |
+
# Use odo_state for position and velocity if available, otherwise set to zero
|
| 82 |
+
if self.config["ENV_TYPE"] == "sim":
|
| 83 |
+
self.odo_state = self.odo_state_subscriber.Read()
|
| 84 |
+
self.q[0:3] = self.odo_state.position
|
| 85 |
+
self.dq[0:3] = self.odo_state.linear_velocity
|
| 86 |
+
else:
|
| 87 |
+
self.q[0:3] = [0.0, 0.0, 0.0]
|
| 88 |
+
self.dq[0:3] = [0.0, 0.0, 0.0]
|
| 89 |
+
|
| 90 |
+
self.q[3:7] = imu_state.quaternion # w, x, y, z
|
| 91 |
+
self.dq[3:6] = imu_state.gyroscope
|
| 92 |
+
self.ddq[0:3] = imu_state.accelerometer
|
| 93 |
+
unitree_joint_state = self.robot_low_state.motor_state
|
| 94 |
+
self.torso_quat = self.secondary_imu_state.quaternion
|
| 95 |
+
self.torso_ang_vel = self.secondary_imu_state.gyroscope
|
| 96 |
+
|
| 97 |
+
for i in range(self.num_dof):
|
| 98 |
+
self.q[7 + i] = unitree_joint_state[self.config["JOINT2MOTOR"][i]].q
|
| 99 |
+
self.dq[6 + i] = unitree_joint_state[self.config["JOINT2MOTOR"][i]].dq
|
| 100 |
+
self.tau_est[6 + i] = unitree_joint_state[self.config["JOINT2MOTOR"][i]].tau_est
|
| 101 |
+
|
| 102 |
+
robot_state_data = np.concatenate(
|
| 103 |
+
[self.q, self.dq, self.tau_est, self.ddq, self.torso_quat, self.torso_ang_vel], axis=0
|
| 104 |
+
).reshape(1, -1)
|
| 105 |
+
# (7 + 29) + (6 + 29) + (6 + 29) + (6 + 29) = 141 dim
|
| 106 |
+
|
| 107 |
+
return robot_state_data
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
class HandStateProcessor:
|
| 111 |
+
def __init__(self, is_left: bool = True):
|
| 112 |
+
self.is_left = is_left
|
| 113 |
+
if self.is_left:
|
| 114 |
+
self.state_sub = ChannelSubscriber("rt/dex3/left/state", HandState_)
|
| 115 |
+
else:
|
| 116 |
+
self.state_sub = ChannelSubscriber("rt/dex3/right/state", HandState_)
|
| 117 |
+
|
| 118 |
+
self.state_sub.Init(None, 0)
|
| 119 |
+
self.state_sub.Init(None, 0)
|
| 120 |
+
self.state = None
|
| 121 |
+
self.num_dof = 7 # for single hand
|
| 122 |
+
|
| 123 |
+
def _prepare_low_state(self) -> np.ndarray:
|
| 124 |
+
self.state = self.state_sub.Read()
|
| 125 |
+
|
| 126 |
+
if not self.state:
|
| 127 |
+
print("No state received")
|
| 128 |
+
return
|
| 129 |
+
|
| 130 |
+
state_data = (
|
| 131 |
+
np.concatenate(
|
| 132 |
+
[
|
| 133 |
+
[self.state.motor_state[i].q for i in range(self.num_dof)],
|
| 134 |
+
[self.state.motor_state[i].dq for i in range(self.num_dof)],
|
| 135 |
+
[self.state.motor_state[i].tau_est for i in range(self.num_dof)],
|
| 136 |
+
[self.state.motor_state[i].ddq for i in range(self.num_dof)],
|
| 137 |
+
],
|
| 138 |
+
axis=0,
|
| 139 |
+
)
|
| 140 |
+
.astype(np.float64)
|
| 141 |
+
.reshape(1, -1)
|
| 142 |
+
)
|
| 143 |
+
return state_data
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/__init__.py
ADDED
|
File without changes
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/async_env_server.py
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from abc import abstractmethod
|
| 2 |
+
import threading
|
| 3 |
+
import time
|
| 4 |
+
from typing import Any, Dict, Tuple
|
| 5 |
+
|
| 6 |
+
import mujoco
|
| 7 |
+
import numpy as np
|
| 8 |
+
import rclpy
|
| 9 |
+
|
| 10 |
+
from decoupled_wbc.control.envs.g1.sim.image_publish_utils import ImagePublishProcess
|
| 11 |
+
from decoupled_wbc.control.envs.robocasa.utils.robocasa_env import (
|
| 12 |
+
Gr00tLocomanipRoboCasaEnv,
|
| 13 |
+
) # noqa: F401
|
| 14 |
+
from decoupled_wbc.control.robot_model.robot_model import RobotModel
|
| 15 |
+
from decoupled_wbc.control.utils.keyboard_dispatcher import KeyboardListenerSubscriber
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class RoboCasaEnvServer:
|
| 19 |
+
"""
|
| 20 |
+
This class is responsible for running the simulation environment loop in a separate thread.
|
| 21 |
+
It communicates with the main thread via the `publish_obs` and `get_action` methods through `channel_bridge`.
|
| 22 |
+
It will also handle the viewer sync when `onscreen` is True.
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
def __init__(
|
| 26 |
+
self,
|
| 27 |
+
env_name: str,
|
| 28 |
+
robot_name: str,
|
| 29 |
+
robot_model: RobotModel,
|
| 30 |
+
env_kwargs: Dict[str, Any],
|
| 31 |
+
**kwargs,
|
| 32 |
+
):
|
| 33 |
+
# initialize environment
|
| 34 |
+
if env_kwargs.get("onscreen", False):
|
| 35 |
+
env_kwargs["onscreen"] = False
|
| 36 |
+
self.onscreen = True # onscreen render in the main thread
|
| 37 |
+
self.render_camera = env_kwargs.get("render_camera", None)
|
| 38 |
+
else:
|
| 39 |
+
self.onscreen = False
|
| 40 |
+
self.env_name = env_name
|
| 41 |
+
self.env = Gr00tLocomanipRoboCasaEnv(env_name, robot_name, robot_model, **env_kwargs)
|
| 42 |
+
self.init_caches()
|
| 43 |
+
self.cache_lock = threading.Lock()
|
| 44 |
+
|
| 45 |
+
# initialize channel
|
| 46 |
+
self.init_channel()
|
| 47 |
+
|
| 48 |
+
# initialize ROS2 node
|
| 49 |
+
if not rclpy.ok():
|
| 50 |
+
rclpy.init()
|
| 51 |
+
self.node = rclpy.create_node("sim_robocasa")
|
| 52 |
+
self.thread = threading.Thread(target=rclpy.spin, args=(self.node,), daemon=True)
|
| 53 |
+
self.thread.start()
|
| 54 |
+
else:
|
| 55 |
+
self.thread = None
|
| 56 |
+
executor = rclpy.get_global_executor()
|
| 57 |
+
self.node = executor.get_nodes()[0] # will only take the first node
|
| 58 |
+
|
| 59 |
+
self.control_freq = env_kwargs.get("control_freq", 1 / 0.02)
|
| 60 |
+
self.sim_freq = kwargs.get("sim_freq", 1 / 0.005)
|
| 61 |
+
self.control_rate = self.node.create_rate(self.control_freq)
|
| 62 |
+
|
| 63 |
+
self.running = False
|
| 64 |
+
self.sim_thread = None
|
| 65 |
+
self.sync_lock = threading.Lock()
|
| 66 |
+
|
| 67 |
+
self.sync_mode = kwargs.get("sync_mode", False)
|
| 68 |
+
self.steps_per_action = kwargs.get("steps_per_action", 1)
|
| 69 |
+
|
| 70 |
+
self.image_dt = kwargs.get("image_dt", 0.04)
|
| 71 |
+
self.image_publish_process = None
|
| 72 |
+
self.viewer_freq = kwargs.get("viewer_freq", 1 / 0.02)
|
| 73 |
+
self.viewer = None
|
| 74 |
+
|
| 75 |
+
self.verbose = kwargs.get("verbose", True)
|
| 76 |
+
|
| 77 |
+
# Initialize keyboard listener for env reset
|
| 78 |
+
self.keyboard_listener = KeyboardListenerSubscriber()
|
| 79 |
+
|
| 80 |
+
self.reset()
|
| 81 |
+
|
| 82 |
+
@property
|
| 83 |
+
def base_env(self):
|
| 84 |
+
return self.env.env
|
| 85 |
+
|
| 86 |
+
def start_image_publish_subprocess(self, start_method: str = "spawn", camera_port: int = 5555):
|
| 87 |
+
"""Initialize image publishing subprocess if cameras are configured"""
|
| 88 |
+
if len(self.env.camera_names) == 0:
|
| 89 |
+
print(
|
| 90 |
+
"Warning: No camera configs provided, image publishing subprocess will not be started"
|
| 91 |
+
)
|
| 92 |
+
return
|
| 93 |
+
|
| 94 |
+
# Build camera configs from env camera settings
|
| 95 |
+
camera_configs = {}
|
| 96 |
+
for env_cam_name in self.env.camera_names:
|
| 97 |
+
camera_config = self.env.camera_key_mapper.get_camera_config(env_cam_name)
|
| 98 |
+
mapped_cam_name, cam_width, cam_height = camera_config
|
| 99 |
+
camera_configs[mapped_cam_name] = {"height": cam_height, "width": cam_width}
|
| 100 |
+
|
| 101 |
+
self.image_publish_process = ImagePublishProcess(
|
| 102 |
+
camera_configs=camera_configs,
|
| 103 |
+
image_dt=self.image_dt,
|
| 104 |
+
zmq_port=camera_port,
|
| 105 |
+
start_method=start_method,
|
| 106 |
+
verbose=self.verbose,
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
self.image_publish_process.start_process()
|
| 110 |
+
|
| 111 |
+
def update_render_caches(self, obs: Dict[str, Any]):
|
| 112 |
+
"""Update render cache and shared memory for subprocess"""
|
| 113 |
+
if self.image_publish_process is None:
|
| 114 |
+
return
|
| 115 |
+
|
| 116 |
+
# Extract image observations from obs dict
|
| 117 |
+
render_caches = {
|
| 118 |
+
k: v for k, v in obs.items() if k.endswith("_image") and isinstance(v, np.ndarray)
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
# Update shared memory if image publishing process is available
|
| 122 |
+
if render_caches:
|
| 123 |
+
self.image_publish_process.update_shared_memory(render_caches)
|
| 124 |
+
|
| 125 |
+
def init_caches(self):
|
| 126 |
+
self.caches = {
|
| 127 |
+
"obs": None,
|
| 128 |
+
"reward": None,
|
| 129 |
+
"terminated": None,
|
| 130 |
+
"truncated": None,
|
| 131 |
+
"info": None,
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
def reset(self, **kwargs):
|
| 135 |
+
if self.viewer is not None:
|
| 136 |
+
self.viewer.close()
|
| 137 |
+
|
| 138 |
+
obs, info = self.env.reset(**kwargs)
|
| 139 |
+
self.caches["obs"] = obs
|
| 140 |
+
self.caches["reward"] = 0
|
| 141 |
+
self.caches["terminated"] = False
|
| 142 |
+
self.caches["truncated"] = False
|
| 143 |
+
self.caches["info"] = info
|
| 144 |
+
|
| 145 |
+
# initialize viewer
|
| 146 |
+
if self.onscreen:
|
| 147 |
+
self.viewer = mujoco.viewer.launch_passive(
|
| 148 |
+
self.base_env.sim.model._model,
|
| 149 |
+
self.base_env.sim.data._data,
|
| 150 |
+
show_left_ui=False,
|
| 151 |
+
show_right_ui=False,
|
| 152 |
+
)
|
| 153 |
+
self.viewer.opt.geomgroup[0] = 0 # disable collision visualization
|
| 154 |
+
if self.render_camera is not None:
|
| 155 |
+
self.viewer.cam.type = mujoco.mjtCamera.mjCAMERA_FIXED
|
| 156 |
+
self.viewer.cam.fixedcamid = self.base_env.sim.model._model.cam(
|
| 157 |
+
self.render_camera
|
| 158 |
+
).id
|
| 159 |
+
|
| 160 |
+
# self.episode_state.reset_state()
|
| 161 |
+
return obs, info
|
| 162 |
+
|
| 163 |
+
@abstractmethod
|
| 164 |
+
def init_channel(self):
|
| 165 |
+
raise NotImplementedError("init_channel must be implemented by the subclass")
|
| 166 |
+
|
| 167 |
+
@abstractmethod
|
| 168 |
+
def publish_obs(self):
|
| 169 |
+
raise NotImplementedError("publish_obs must be implemented by the subclass")
|
| 170 |
+
|
| 171 |
+
@abstractmethod
|
| 172 |
+
def get_action(self) -> Tuple[Dict[str, Any], bool, bool]:
|
| 173 |
+
raise NotImplementedError("get_action must be implemented by the subclass")
|
| 174 |
+
|
| 175 |
+
def start_as_thread(self):
|
| 176 |
+
"""Start the simulation thread"""
|
| 177 |
+
if self.sim_thread is not None and self.sim_thread.is_alive():
|
| 178 |
+
return
|
| 179 |
+
|
| 180 |
+
self.sim_thread = threading.Thread(target=self.start)
|
| 181 |
+
self.sim_thread.daemon = True
|
| 182 |
+
self.sim_thread.start()
|
| 183 |
+
|
| 184 |
+
def set_sync_mode(self, sync_mode: bool, steps_per_action: int = 4):
|
| 185 |
+
"""Set the sync mode of the environment server"""
|
| 186 |
+
with self.sync_lock:
|
| 187 |
+
self.sync_mode = sync_mode
|
| 188 |
+
self.steps_per_action = steps_per_action
|
| 189 |
+
|
| 190 |
+
def _check_keyboard_input(self):
|
| 191 |
+
"""Check for keyboard input and handle state transitions"""
|
| 192 |
+
key = self.keyboard_listener.read_msg()
|
| 193 |
+
if key == "k":
|
| 194 |
+
print("\033[1;32m[Sim env]\033[0m Resetting sim environment")
|
| 195 |
+
self.reset()
|
| 196 |
+
|
| 197 |
+
def start(self):
|
| 198 |
+
"""Function executed by the simulation thread"""
|
| 199 |
+
iter_idx = 0
|
| 200 |
+
steps_per_cur_action = 0
|
| 201 |
+
t_start = time.monotonic()
|
| 202 |
+
|
| 203 |
+
self.running = True
|
| 204 |
+
|
| 205 |
+
while self.running:
|
| 206 |
+
# Check keyboard input for state transitions
|
| 207 |
+
self._check_keyboard_input()
|
| 208 |
+
|
| 209 |
+
# Publish observations and get new action
|
| 210 |
+
self.publish_obs()
|
| 211 |
+
action, ready, is_new_action = self.get_action()
|
| 212 |
+
# ready is True if the action is received from the control loop
|
| 213 |
+
# is_new_action is True if the action is new (not the same as the previous action)
|
| 214 |
+
with self.sync_lock:
|
| 215 |
+
sync_mode = self.sync_mode
|
| 216 |
+
max_steps_per_action = self.steps_per_action
|
| 217 |
+
|
| 218 |
+
# Process action if ready and within step limits
|
| 219 |
+
action_should_apply = ready and (
|
| 220 |
+
(not sync_mode) or steps_per_cur_action < max_steps_per_action
|
| 221 |
+
)
|
| 222 |
+
if action_should_apply:
|
| 223 |
+
obs, reward, terminated, truncated, info = self.env.step(action)
|
| 224 |
+
with self.cache_lock:
|
| 225 |
+
self.caches["obs"] = obs
|
| 226 |
+
self.caches["reward"] = reward
|
| 227 |
+
self.caches["terminated"] = terminated
|
| 228 |
+
self.caches["truncated"] = truncated
|
| 229 |
+
self.caches["info"] = info
|
| 230 |
+
|
| 231 |
+
if reward == 1.0 and iter_idx % 50 == 0:
|
| 232 |
+
print("\033[92mTask successful. Can save data now.\033[0m")
|
| 233 |
+
|
| 234 |
+
iter_idx += 1
|
| 235 |
+
steps_per_cur_action += 1
|
| 236 |
+
if self.verbose and sync_mode:
|
| 237 |
+
print("steps_per_cur_action: ", steps_per_cur_action)
|
| 238 |
+
|
| 239 |
+
# Update render caches at image publishing rate
|
| 240 |
+
if action_should_apply and iter_idx % int(self.image_dt * self.control_freq) == 0:
|
| 241 |
+
with self.cache_lock:
|
| 242 |
+
obs_copy = self.caches["obs"].copy()
|
| 243 |
+
self.update_render_caches(obs_copy)
|
| 244 |
+
|
| 245 |
+
# Reset step counter for new actions
|
| 246 |
+
if is_new_action:
|
| 247 |
+
steps_per_cur_action = 0
|
| 248 |
+
|
| 249 |
+
# Update viewer at specified frequency
|
| 250 |
+
if self.onscreen and iter_idx % (self.control_freq / self.viewer_freq) == 0:
|
| 251 |
+
self.viewer.sync()
|
| 252 |
+
|
| 253 |
+
# Check if we're meeting the desired control frequency
|
| 254 |
+
if iter_idx % 100 == 0:
|
| 255 |
+
end_time = time.monotonic()
|
| 256 |
+
if self.verbose:
|
| 257 |
+
print(
|
| 258 |
+
f"sim FPS: {100.0 / (end_time - t_start) * (self.sim_freq / self.control_freq)}"
|
| 259 |
+
)
|
| 260 |
+
if (end_time - t_start) > ((110.0 / self.control_freq)): # for tolerance
|
| 261 |
+
print(
|
| 262 |
+
f"Warning: Sim runs at "
|
| 263 |
+
"{100.0/(end_time - t_start) * (self.sim_freq / self.control_freq):.1f}Hz, "
|
| 264 |
+
f"but should run at {self.sim_freq:.1f}Hz"
|
| 265 |
+
)
|
| 266 |
+
t_start = end_time
|
| 267 |
+
|
| 268 |
+
# reset obj pos every 200 steps
|
| 269 |
+
if iter_idx % 200 == 0:
|
| 270 |
+
if hasattr(self.base_env, "reset_obj_pos"):
|
| 271 |
+
self.base_env.reset_obj_pos()
|
| 272 |
+
|
| 273 |
+
self.control_rate.sleep()
|
| 274 |
+
|
| 275 |
+
def get_privileged_obs(self):
|
| 276 |
+
"""Get privileged observation. Should be implemented by subclasses."""
|
| 277 |
+
obs = {}
|
| 278 |
+
with self.cache_lock:
|
| 279 |
+
if hasattr(self.base_env, "get_privileged_obs_keys"):
|
| 280 |
+
for key in self.base_env.get_privileged_obs_keys():
|
| 281 |
+
obs[key] = self.caches["obs"][key]
|
| 282 |
+
|
| 283 |
+
for key in self.caches["obs"].keys():
|
| 284 |
+
if key.endswith("_image"):
|
| 285 |
+
obs[key] = self.caches["obs"][key]
|
| 286 |
+
|
| 287 |
+
return obs
|
| 288 |
+
|
| 289 |
+
def stop(self):
|
| 290 |
+
"""Stop the simulation thread"""
|
| 291 |
+
self.running = False
|
| 292 |
+
if self.sim_thread is not None:
|
| 293 |
+
self.sim_thread.join(timeout=1.0) # Wait for thread to finish with timeout
|
| 294 |
+
self.sim_thread = None
|
| 295 |
+
|
| 296 |
+
def close(self):
|
| 297 |
+
self.stop()
|
| 298 |
+
if self.image_publish_process is not None:
|
| 299 |
+
self.image_publish_process.stop()
|
| 300 |
+
if self.onscreen:
|
| 301 |
+
self.viewer.close()
|
| 302 |
+
self.env.close()
|
| 303 |
+
|
| 304 |
+
def get_reward(self):
|
| 305 |
+
return self.base_env.reward()
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/sync_env.py
ADDED
|
@@ -0,0 +1,586 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
from typing import Any, Dict, Tuple
|
| 3 |
+
|
| 4 |
+
import gymnasium as gym
|
| 5 |
+
from gymnasium.envs.registration import register
|
| 6 |
+
import numpy as np
|
| 7 |
+
from robocasa.environments.locomanipulation import REGISTERED_LOCOMANIPULATION_ENVS
|
| 8 |
+
from robocasa.models.robots import GR00T_LOCOMANIP_ENVS_ROBOTS
|
| 9 |
+
from robosuite.environments.robot_env import RobotEnv
|
| 10 |
+
from scipy.spatial.transform import Rotation as R
|
| 11 |
+
|
| 12 |
+
from decoupled_wbc.control.envs.g1.utils.joint_safety import JointSafetyMonitor
|
| 13 |
+
from decoupled_wbc.control.envs.robocasa.utils.controller_utils import (
|
| 14 |
+
update_robosuite_controller_configs,
|
| 15 |
+
)
|
| 16 |
+
from decoupled_wbc.control.envs.robocasa.utils.robocasa_env import ( # noqa: F401
|
| 17 |
+
ALLOWED_LANGUAGE_CHARSET,
|
| 18 |
+
Gr00tLocomanipRoboCasaEnv,
|
| 19 |
+
)
|
| 20 |
+
from decoupled_wbc.control.robot_model.instantiation import get_robot_type_and_model
|
| 21 |
+
from decoupled_wbc.control.utils.n1_utils import (
|
| 22 |
+
prepare_gym_space_for_eval,
|
| 23 |
+
prepare_observation_for_eval,
|
| 24 |
+
)
|
| 25 |
+
from decoupled_wbc.data.constants import RS_VIEW_CAMERA_HEIGHT, RS_VIEW_CAMERA_WIDTH
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class SyncEnv(gym.Env):
|
| 29 |
+
MAX_MUJOCO_STATE_LEN = 800
|
| 30 |
+
|
| 31 |
+
def __init__(self, env_name, robot_name, **kwargs):
|
| 32 |
+
self.env_name = env_name
|
| 33 |
+
self.robot_name = robot_name
|
| 34 |
+
self.onscreen = kwargs.get("onscreen", True)
|
| 35 |
+
self.enable_gravity_compensation = kwargs.pop("enable_gravity_compensation", False)
|
| 36 |
+
self.gravity_compensation_joints = kwargs.pop("gravity_compensation_joints", ["arms"])
|
| 37 |
+
_, self.robot_model = get_robot_type_and_model(
|
| 38 |
+
robot_name, enable_waist_ik=kwargs.pop("enable_waist", False)
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
env_kwargs = {
|
| 42 |
+
"onscreen": kwargs.get("onscreen", True),
|
| 43 |
+
"offscreen": kwargs.get("offscreen", False),
|
| 44 |
+
"renderer": kwargs.get("renderer", "mjviewer"),
|
| 45 |
+
"render_camera": kwargs.get("render_camera", "frontview"),
|
| 46 |
+
"camera_names": kwargs.get("camera_names", ["frontview"]),
|
| 47 |
+
"camera_heights": kwargs.get("camera_heights", None),
|
| 48 |
+
"camera_widths": kwargs.get("camera_widths", None),
|
| 49 |
+
"controller_configs": kwargs["controller_configs"],
|
| 50 |
+
"control_freq": kwargs.get("control_freq", 50),
|
| 51 |
+
"translucent_robot": kwargs.get("translucent_robot", True),
|
| 52 |
+
"ik_indicator": kwargs.get("ik_indicator", False),
|
| 53 |
+
"randomize_cameras": kwargs.get("randomize_cameras", True),
|
| 54 |
+
}
|
| 55 |
+
self.env = Gr00tLocomanipRoboCasaEnv(
|
| 56 |
+
env_name, robot_name, robot_model=self.robot_model, **env_kwargs
|
| 57 |
+
)
|
| 58 |
+
self.init_cache()
|
| 59 |
+
|
| 60 |
+
self.reset()
|
| 61 |
+
|
| 62 |
+
@property
|
| 63 |
+
def base_env(self) -> RobotEnv:
|
| 64 |
+
return self.env.env
|
| 65 |
+
|
| 66 |
+
def overwrite_floating_base_action(self, navigate_cmd):
|
| 67 |
+
if self.base_env.robots[0].robot_model.default_base == "FloatingLeggedBase":
|
| 68 |
+
self.env.unwrapped.overridden_floating_base_action = navigate_cmd
|
| 69 |
+
|
| 70 |
+
def get_mujoco_state_info(self):
|
| 71 |
+
mujoco_state = self.base_env.sim.get_state().flatten()
|
| 72 |
+
assert len(mujoco_state) < SyncEnv.MAX_MUJOCO_STATE_LEN
|
| 73 |
+
padding_width = SyncEnv.MAX_MUJOCO_STATE_LEN - len(mujoco_state)
|
| 74 |
+
padded_mujoco_state = np.pad(
|
| 75 |
+
mujoco_state, (0, padding_width), mode="constant", constant_values=0
|
| 76 |
+
)
|
| 77 |
+
max_mujoco_state_len = SyncEnv.MAX_MUJOCO_STATE_LEN
|
| 78 |
+
mujoco_state_len = len(mujoco_state)
|
| 79 |
+
mujoco_state = padded_mujoco_state.copy()
|
| 80 |
+
return max_mujoco_state_len, mujoco_state_len, mujoco_state
|
| 81 |
+
|
| 82 |
+
def reset_to(self, state: Dict[str, Any]) -> Dict[str, Any] | None:
|
| 83 |
+
if hasattr(self.base_env, "reset_to"):
|
| 84 |
+
self.base_env.reset_to(state)
|
| 85 |
+
else:
|
| 86 |
+
# todo: maybe update robosuite to have reset_to()
|
| 87 |
+
env = self.base_env
|
| 88 |
+
if "model_file" in state:
|
| 89 |
+
xml = env.edit_model_xml(state["model_file"])
|
| 90 |
+
env.reset_from_xml_string(xml)
|
| 91 |
+
env.sim.reset()
|
| 92 |
+
if "states" in state:
|
| 93 |
+
env.sim.set_state_from_flattened(state["states"])
|
| 94 |
+
env.sim.forward()
|
| 95 |
+
|
| 96 |
+
obs = self.env.force_update_observation(timestep=0)
|
| 97 |
+
self.cache["obs"] = obs
|
| 98 |
+
return
|
| 99 |
+
|
| 100 |
+
def get_state(self) -> Dict[str, Any]:
|
| 101 |
+
return self.base_env.get_state()
|
| 102 |
+
|
| 103 |
+
def is_success(self):
|
| 104 |
+
"""
|
| 105 |
+
Check if the task condition(s) is reached. Should return a dictionary
|
| 106 |
+
{ str: bool } with at least a "task" key for the overall task success,
|
| 107 |
+
and additional optional keys corresponding to other task criteria.
|
| 108 |
+
"""
|
| 109 |
+
# First, try to use the base environment's is_success method if it exists
|
| 110 |
+
if hasattr(self.base_env, "is_success"):
|
| 111 |
+
return self.base_env.is_success()
|
| 112 |
+
|
| 113 |
+
# Fall back to using _check_success if available
|
| 114 |
+
elif hasattr(self.base_env, "_check_success"):
|
| 115 |
+
succ = self.base_env._check_success()
|
| 116 |
+
if isinstance(succ, dict):
|
| 117 |
+
assert "task" in succ
|
| 118 |
+
return succ
|
| 119 |
+
return {"task": succ}
|
| 120 |
+
|
| 121 |
+
# If neither method exists, return failure
|
| 122 |
+
else:
|
| 123 |
+
return {"task": False}
|
| 124 |
+
|
| 125 |
+
def init_cache(self):
|
| 126 |
+
self.cache = {
|
| 127 |
+
"obs": None,
|
| 128 |
+
"reward": None,
|
| 129 |
+
"terminated": None,
|
| 130 |
+
"truncated": None,
|
| 131 |
+
"info": None,
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
def reset(self, seed=None, options=None) -> Tuple[Dict[str, any], Dict[str, any]]:
|
| 135 |
+
self.init_cache()
|
| 136 |
+
obs, info = self.env.reset(seed=seed, options=options)
|
| 137 |
+
self.cache["obs"] = obs
|
| 138 |
+
self.cache["reward"] = 0
|
| 139 |
+
self.cache["terminated"] = False
|
| 140 |
+
self.cache["truncated"] = False
|
| 141 |
+
self.cache["info"] = info
|
| 142 |
+
return self.observe(), info
|
| 143 |
+
|
| 144 |
+
def observe(self) -> Dict[str, any]:
|
| 145 |
+
# Get observations from body and hands
|
| 146 |
+
assert (
|
| 147 |
+
self.cache["obs"] is not None
|
| 148 |
+
), "Observation cache is not initialized, please reset the environment first"
|
| 149 |
+
raw_obs = self.cache["obs"]
|
| 150 |
+
|
| 151 |
+
# Body and hand joint measurements come in actuator order, so we need to convert them to joint order
|
| 152 |
+
whole_q = self.robot_model.get_configuration_from_actuated_joints(
|
| 153 |
+
body_actuated_joint_values=raw_obs["body_q"],
|
| 154 |
+
left_hand_actuated_joint_values=raw_obs["left_hand_q"],
|
| 155 |
+
right_hand_actuated_joint_values=raw_obs["right_hand_q"],
|
| 156 |
+
)
|
| 157 |
+
whole_dq = self.robot_model.get_configuration_from_actuated_joints(
|
| 158 |
+
body_actuated_joint_values=raw_obs["body_dq"],
|
| 159 |
+
left_hand_actuated_joint_values=raw_obs["left_hand_dq"],
|
| 160 |
+
right_hand_actuated_joint_values=raw_obs["right_hand_dq"],
|
| 161 |
+
)
|
| 162 |
+
whole_ddq = self.robot_model.get_configuration_from_actuated_joints(
|
| 163 |
+
body_actuated_joint_values=raw_obs["body_ddq"],
|
| 164 |
+
left_hand_actuated_joint_values=raw_obs["left_hand_ddq"],
|
| 165 |
+
right_hand_actuated_joint_values=raw_obs["right_hand_ddq"],
|
| 166 |
+
)
|
| 167 |
+
whole_tau_est = self.robot_model.get_configuration_from_actuated_joints(
|
| 168 |
+
body_actuated_joint_values=raw_obs["body_tau_est"],
|
| 169 |
+
left_hand_actuated_joint_values=raw_obs["left_hand_tau_est"],
|
| 170 |
+
right_hand_actuated_joint_values=raw_obs["right_hand_tau_est"],
|
| 171 |
+
)
|
| 172 |
+
eef_obs = self.get_eef_obs(whole_q)
|
| 173 |
+
|
| 174 |
+
obs = {
|
| 175 |
+
"q": whole_q,
|
| 176 |
+
"dq": whole_dq,
|
| 177 |
+
"ddq": whole_ddq,
|
| 178 |
+
"tau_est": whole_tau_est,
|
| 179 |
+
"floating_base_pose": raw_obs["floating_base_pose"],
|
| 180 |
+
"floating_base_vel": raw_obs["floating_base_vel"],
|
| 181 |
+
"floating_base_acc": raw_obs["floating_base_acc"],
|
| 182 |
+
"wrist_pose": np.concatenate([eef_obs["left_wrist_pose"], eef_obs["right_wrist_pose"]]),
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
# Add state keys for model input
|
| 186 |
+
obs = prepare_observation_for_eval(self.robot_model, obs)
|
| 187 |
+
|
| 188 |
+
obs["annotation.human.task_description"] = raw_obs["language.language_instruction"]
|
| 189 |
+
|
| 190 |
+
if hasattr(self.base_env, "get_privileged_obs_keys"):
|
| 191 |
+
for key in self.base_env.get_privileged_obs_keys():
|
| 192 |
+
obs[key] = raw_obs[key]
|
| 193 |
+
|
| 194 |
+
for key in raw_obs.keys():
|
| 195 |
+
if key.endswith("_image"):
|
| 196 |
+
obs[key] = raw_obs[key]
|
| 197 |
+
# TODO: add video.key without _image suffix for evaluation, convert to uint8, remove later
|
| 198 |
+
obs[f"video.{key.replace('_image', '')}"] = raw_obs[key]
|
| 199 |
+
return obs
|
| 200 |
+
|
| 201 |
+
def step(
|
| 202 |
+
self, action: Dict[str, any]
|
| 203 |
+
) -> Tuple[Dict[str, any], float, bool, bool, Dict[str, any]]:
|
| 204 |
+
self.queue_action(action)
|
| 205 |
+
return self.get_step_info()
|
| 206 |
+
|
| 207 |
+
def get_observation(self):
|
| 208 |
+
return self.base_env._get_observations() # assumes base env is robosuite
|
| 209 |
+
|
| 210 |
+
def get_step_info(self) -> Tuple[Dict[str, any], float, bool, bool, Dict[str, any]]:
|
| 211 |
+
return (
|
| 212 |
+
self.observe(),
|
| 213 |
+
self.cache["reward"],
|
| 214 |
+
self.cache["terminated"],
|
| 215 |
+
self.cache["truncated"],
|
| 216 |
+
self.cache["info"],
|
| 217 |
+
)
|
| 218 |
+
|
| 219 |
+
def convert_q_to_actuated_joint_order(self, q: np.ndarray) -> np.ndarray:
|
| 220 |
+
body_q = self.robot_model.get_body_actuated_joints(q)
|
| 221 |
+
left_hand_q = self.robot_model.get_hand_actuated_joints(q, side="left")
|
| 222 |
+
right_hand_q = self.robot_model.get_hand_actuated_joints(q, side="right")
|
| 223 |
+
whole_q = np.zeros_like(q)
|
| 224 |
+
whole_q[self.robot_model.get_joint_group_indices("body")] = body_q
|
| 225 |
+
whole_q[self.robot_model.get_joint_group_indices("left_hand")] = left_hand_q
|
| 226 |
+
whole_q[self.robot_model.get_joint_group_indices("right_hand")] = right_hand_q
|
| 227 |
+
|
| 228 |
+
return whole_q
|
| 229 |
+
|
| 230 |
+
def set_ik_indicator(self, teleop_cmd):
|
| 231 |
+
"""Set the IK indicators for the simulator"""
|
| 232 |
+
if "left_wrist" in teleop_cmd and "right_wrist" in teleop_cmd:
|
| 233 |
+
left_wrist_input_pose = teleop_cmd["left_wrist"]
|
| 234 |
+
right_wrist_input_pose = teleop_cmd["right_wrist"]
|
| 235 |
+
ik_wrapper = self.base_env
|
| 236 |
+
ik_wrapper.set_target_poses_outside_env([left_wrist_input_pose, right_wrist_input_pose])
|
| 237 |
+
|
| 238 |
+
def render(self):
|
| 239 |
+
if self.base_env.viewer is not None:
|
| 240 |
+
self.base_env.viewer.update()
|
| 241 |
+
if self.onscreen:
|
| 242 |
+
self.base_env.render()
|
| 243 |
+
|
| 244 |
+
def queue_action(self, action: Dict[str, any]):
|
| 245 |
+
# action is in pinocchio joint order, we need to convert it to actuator order
|
| 246 |
+
action_q = self.convert_q_to_actuated_joint_order(action["q"])
|
| 247 |
+
|
| 248 |
+
# Compute gravity compensation torques if enabled
|
| 249 |
+
tau_q = np.zeros_like(action_q)
|
| 250 |
+
if self.enable_gravity_compensation and self.robot_model is not None:
|
| 251 |
+
try:
|
| 252 |
+
# Get current robot configuration from cache (more efficient than observe())
|
| 253 |
+
raw_obs = self.cache["obs"]
|
| 254 |
+
|
| 255 |
+
# Convert from actuated joint order to joint order for Pinocchio
|
| 256 |
+
current_q_joint_order = self.robot_model.get_configuration_from_actuated_joints(
|
| 257 |
+
body_actuated_joint_values=raw_obs["body_q"],
|
| 258 |
+
left_hand_actuated_joint_values=raw_obs["left_hand_q"],
|
| 259 |
+
right_hand_actuated_joint_values=raw_obs["right_hand_q"],
|
| 260 |
+
)
|
| 261 |
+
|
| 262 |
+
# Compute gravity compensation in joint order using current robot configuration
|
| 263 |
+
gravity_torques_joint_order = self.robot_model.compute_gravity_compensation_torques(
|
| 264 |
+
current_q_joint_order, joint_groups=self.gravity_compensation_joints
|
| 265 |
+
)
|
| 266 |
+
|
| 267 |
+
# Convert gravity torques to actuated joint order
|
| 268 |
+
gravity_torques_actuated = self.convert_q_to_actuated_joint_order(
|
| 269 |
+
gravity_torques_joint_order
|
| 270 |
+
)
|
| 271 |
+
|
| 272 |
+
# Add gravity compensation to torques
|
| 273 |
+
tau_q += gravity_torques_actuated
|
| 274 |
+
|
| 275 |
+
except Exception as e:
|
| 276 |
+
print(f"Error applying gravity compensation in sync_env: {e}")
|
| 277 |
+
|
| 278 |
+
obs, reward, terminated, truncated, info = self.env.step({"q": action_q, "tau": tau_q})
|
| 279 |
+
self.cache["obs"] = obs
|
| 280 |
+
self.cache["reward"] = reward
|
| 281 |
+
self.cache["terminated"] = terminated
|
| 282 |
+
self.cache["truncated"] = truncated
|
| 283 |
+
self.cache["info"] = info
|
| 284 |
+
|
| 285 |
+
def queue_state(self, state: Dict[str, any]):
|
| 286 |
+
# This function is for debugging or cross-playback between sim and real only.
|
| 287 |
+
state_q = self.convert_q_to_actuated_joint_order(state["q"])
|
| 288 |
+
obs, reward, terminated, truncated, info = self.env.unwrapped.step_only_kinematics(
|
| 289 |
+
{"q": state_q}
|
| 290 |
+
)
|
| 291 |
+
self.cache["obs"] = obs
|
| 292 |
+
self.cache["reward"] = reward
|
| 293 |
+
self.cache["terminated"] = terminated
|
| 294 |
+
self.cache["truncated"] = truncated
|
| 295 |
+
self.cache["info"] = info
|
| 296 |
+
|
| 297 |
+
@property
|
| 298 |
+
def observation_space(self) -> gym.Space:
|
| 299 |
+
# @todo: check if the low and high bounds are correct for body_obs.
|
| 300 |
+
q_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(self.robot_model.num_dofs,))
|
| 301 |
+
dq_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(self.robot_model.num_dofs,))
|
| 302 |
+
ddq_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(self.robot_model.num_dofs,))
|
| 303 |
+
tau_est_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(self.robot_model.num_dofs,))
|
| 304 |
+
floating_base_pose_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(7,))
|
| 305 |
+
floating_base_vel_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(6,))
|
| 306 |
+
floating_base_acc_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(6,))
|
| 307 |
+
wrist_pose_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(7 + 7,))
|
| 308 |
+
|
| 309 |
+
obs_space = gym.spaces.Dict(
|
| 310 |
+
{
|
| 311 |
+
"floating_base_pose": floating_base_pose_space,
|
| 312 |
+
"floating_base_vel": floating_base_vel_space,
|
| 313 |
+
"floating_base_acc": floating_base_acc_space,
|
| 314 |
+
"q": q_space,
|
| 315 |
+
"dq": dq_space,
|
| 316 |
+
"ddq": ddq_space,
|
| 317 |
+
"tau_est": tau_est_space,
|
| 318 |
+
"wrist_pose": wrist_pose_space,
|
| 319 |
+
}
|
| 320 |
+
)
|
| 321 |
+
|
| 322 |
+
obs_space = prepare_gym_space_for_eval(self.robot_model, obs_space)
|
| 323 |
+
|
| 324 |
+
obs_space["annotation.human.task_description"] = gym.spaces.Text(
|
| 325 |
+
max_length=256, charset=ALLOWED_LANGUAGE_CHARSET
|
| 326 |
+
)
|
| 327 |
+
|
| 328 |
+
if hasattr(self.base_env, "get_privileged_obs_keys"):
|
| 329 |
+
for key, shape in self.base_env.get_privileged_obs_keys().items():
|
| 330 |
+
space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=shape)
|
| 331 |
+
obs_space[key] = space
|
| 332 |
+
|
| 333 |
+
robocasa_obs_space = self.env.observation_space
|
| 334 |
+
for key in robocasa_obs_space.keys():
|
| 335 |
+
if key.endswith("_image"):
|
| 336 |
+
space = gym.spaces.Box(
|
| 337 |
+
low=-np.inf, high=np.inf, shape=robocasa_obs_space[key].shape
|
| 338 |
+
)
|
| 339 |
+
obs_space[key] = space
|
| 340 |
+
# TODO: add video.key without _image suffix for evaluation, remove later
|
| 341 |
+
space_uint = gym.spaces.Box(low=0, high=255, shape=space.shape, dtype=np.uint8)
|
| 342 |
+
obs_space[f"video.{key.replace('_image', '')}"] = space_uint
|
| 343 |
+
|
| 344 |
+
return obs_space
|
| 345 |
+
|
| 346 |
+
def reset_obj_pos(self):
|
| 347 |
+
# For Tairan's goal-reaching task, a hacky way to reset the object position is needed.
|
| 348 |
+
if hasattr(self.base_env, "reset_obj_pos"):
|
| 349 |
+
self.base_env.reset_obj_pos()
|
| 350 |
+
|
| 351 |
+
@property
|
| 352 |
+
def action_space(self) -> gym.Space:
|
| 353 |
+
return self.env.action_space
|
| 354 |
+
|
| 355 |
+
def close(self):
|
| 356 |
+
self.env.close()
|
| 357 |
+
|
| 358 |
+
def __repr__(self):
|
| 359 |
+
return (
|
| 360 |
+
f"SyncEnv(env_name={self.env_name}, \n"
|
| 361 |
+
f" observation_space={self.observation_space}, \n"
|
| 362 |
+
f" action_space={self.action_space})"
|
| 363 |
+
)
|
| 364 |
+
|
| 365 |
+
def get_joint_gains(self):
|
| 366 |
+
controller = self.base_env.robots[0].composite_controller
|
| 367 |
+
|
| 368 |
+
gains = {}
|
| 369 |
+
key_mapping = {
|
| 370 |
+
"left": "left_arm",
|
| 371 |
+
"right": "right_arm",
|
| 372 |
+
"legs": "legs",
|
| 373 |
+
"torso": "waist",
|
| 374 |
+
"head": "neck",
|
| 375 |
+
}
|
| 376 |
+
for k in controller.part_controllers.keys():
|
| 377 |
+
if hasattr(controller.part_controllers[k], "kp"):
|
| 378 |
+
if k in key_mapping:
|
| 379 |
+
gains[key_mapping[k]] = controller.part_controllers[k].kp
|
| 380 |
+
else:
|
| 381 |
+
gains[k] = controller.part_controllers[k].kp
|
| 382 |
+
gains.update(
|
| 383 |
+
{
|
| 384 |
+
"left_hand": self.base_env.sim.model.actuator_gainprm[
|
| 385 |
+
self.base_env.robots[0]._ref_actuators_indexes_dict["left_gripper"], 0
|
| 386 |
+
],
|
| 387 |
+
"right_hand": self.base_env.sim.model.actuator_gainprm[
|
| 388 |
+
self.base_env.robots[0]._ref_actuators_indexes_dict["right_gripper"], 0
|
| 389 |
+
],
|
| 390 |
+
}
|
| 391 |
+
)
|
| 392 |
+
joint_gains = np.zeros(self.robot_model.num_dofs)
|
| 393 |
+
for k in gains.keys():
|
| 394 |
+
joint_gains[self.robot_model.get_joint_group_indices(k)] = gains[k]
|
| 395 |
+
return joint_gains
|
| 396 |
+
|
| 397 |
+
def get_joint_damping(self):
|
| 398 |
+
controller = self.base_env.robots[0].composite_controller
|
| 399 |
+
damping = {}
|
| 400 |
+
key_mapping = {
|
| 401 |
+
"left": "left_arm",
|
| 402 |
+
"right": "right_arm",
|
| 403 |
+
"legs": "legs",
|
| 404 |
+
"torso": "waist",
|
| 405 |
+
"head": "neck",
|
| 406 |
+
}
|
| 407 |
+
for k in controller.part_controllers.keys():
|
| 408 |
+
if hasattr(controller.part_controllers[k], "kd"):
|
| 409 |
+
if k in key_mapping:
|
| 410 |
+
damping[key_mapping[k]] = controller.part_controllers[k].kd
|
| 411 |
+
else:
|
| 412 |
+
damping[k] = controller.part_controllers[k].kd
|
| 413 |
+
damping.update(
|
| 414 |
+
{
|
| 415 |
+
"left_hand": -self.base_env.sim.model.actuator_biasprm[
|
| 416 |
+
self.base_env.robots[0]._ref_actuators_indexes_dict["left_gripper"], 2
|
| 417 |
+
],
|
| 418 |
+
"right_hand": -self.base_env.sim.model.actuator_biasprm[
|
| 419 |
+
self.base_env.robots[0]._ref_actuators_indexes_dict["right_gripper"], 2
|
| 420 |
+
],
|
| 421 |
+
}
|
| 422 |
+
)
|
| 423 |
+
joint_damping = np.zeros(self.robot_model.num_dofs)
|
| 424 |
+
for k in damping.keys():
|
| 425 |
+
joint_damping[self.robot_model.get_joint_group_indices(k)] = damping[k]
|
| 426 |
+
return joint_damping
|
| 427 |
+
|
| 428 |
+
def get_eef_obs(self, q: np.ndarray) -> Dict[str, np.ndarray]:
|
| 429 |
+
self.robot_model.cache_forward_kinematics(q)
|
| 430 |
+
eef_obs = {}
|
| 431 |
+
for side in ["left", "right"]:
|
| 432 |
+
wrist_placement = self.robot_model.frame_placement(
|
| 433 |
+
self.robot_model.supplemental_info.hand_frame_names[side]
|
| 434 |
+
)
|
| 435 |
+
wrist_pos, wrist_quat = wrist_placement.translation[:3], R.from_matrix(
|
| 436 |
+
wrist_placement.rotation
|
| 437 |
+
).as_quat(scalar_first=True)
|
| 438 |
+
eef_obs[f"{side}_wrist_pose"] = np.concatenate([wrist_pos, wrist_quat])
|
| 439 |
+
|
| 440 |
+
return eef_obs
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
class G1SyncEnv(SyncEnv):
|
| 444 |
+
def __init__(
|
| 445 |
+
self,
|
| 446 |
+
env_name,
|
| 447 |
+
robot_name,
|
| 448 |
+
**kwargs,
|
| 449 |
+
):
|
| 450 |
+
renderer = kwargs.get("renderer", "mjviewer")
|
| 451 |
+
if renderer == "mjviewer":
|
| 452 |
+
default_render_camera = ["robot0_oak_egoview"]
|
| 453 |
+
elif renderer in ["mujoco", "rerun"]:
|
| 454 |
+
default_render_camera = [
|
| 455 |
+
"robot0_oak_egoview",
|
| 456 |
+
"robot0_oak_left_monoview",
|
| 457 |
+
"robot0_oak_right_monoview",
|
| 458 |
+
]
|
| 459 |
+
else:
|
| 460 |
+
raise NotImplementedError
|
| 461 |
+
default_camera_names = [
|
| 462 |
+
"robot0_oak_egoview",
|
| 463 |
+
"robot0_oak_left_monoview",
|
| 464 |
+
"robot0_oak_right_monoview",
|
| 465 |
+
]
|
| 466 |
+
default_camera_heights = [
|
| 467 |
+
RS_VIEW_CAMERA_HEIGHT,
|
| 468 |
+
RS_VIEW_CAMERA_HEIGHT,
|
| 469 |
+
RS_VIEW_CAMERA_HEIGHT,
|
| 470 |
+
]
|
| 471 |
+
default_camera_widths = [
|
| 472 |
+
RS_VIEW_CAMERA_WIDTH,
|
| 473 |
+
RS_VIEW_CAMERA_WIDTH,
|
| 474 |
+
RS_VIEW_CAMERA_WIDTH,
|
| 475 |
+
]
|
| 476 |
+
|
| 477 |
+
kwargs.update(
|
| 478 |
+
{
|
| 479 |
+
"onscreen": kwargs.get("onscreen", True),
|
| 480 |
+
"offscreen": kwargs.get("offscreen", False),
|
| 481 |
+
"render_camera": kwargs.get("render_camera", default_render_camera),
|
| 482 |
+
"camera_names": kwargs.get("camera_names", default_camera_names),
|
| 483 |
+
"camera_heights": kwargs.get("camera_heights", default_camera_heights),
|
| 484 |
+
"camera_widths": kwargs.get("camera_widths", default_camera_widths),
|
| 485 |
+
"translucent_robot": kwargs.get("translucent_robot", False),
|
| 486 |
+
}
|
| 487 |
+
)
|
| 488 |
+
super().__init__(env_name=env_name, robot_name=robot_name, **kwargs)
|
| 489 |
+
|
| 490 |
+
# Initialize safety monitor (visualization disabled) - G1 specific
|
| 491 |
+
self.safety_monitor = JointSafetyMonitor(
|
| 492 |
+
self.robot_model,
|
| 493 |
+
enable_viz=False,
|
| 494 |
+
env_type="sim", # G1SyncEnv is always simulation
|
| 495 |
+
)
|
| 496 |
+
self.safety_monitor.ramp_duration_steps = 0
|
| 497 |
+
self.safety_monitor.startup_complete = True
|
| 498 |
+
self.safety_monitor.LOWER_BODY_VELOCITY_LIMIT = (
|
| 499 |
+
1e10 # disable lower body velocity limits since it impacts WBC
|
| 500 |
+
)
|
| 501 |
+
self.last_safety_ok = True # Track last safety status from queue_action
|
| 502 |
+
|
| 503 |
+
@property
|
| 504 |
+
def observation_space(self):
|
| 505 |
+
obs_space = super().observation_space
|
| 506 |
+
obs_space["torso_quat"] = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(4,))
|
| 507 |
+
obs_space["torso_ang_vel"] = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(3,))
|
| 508 |
+
return obs_space
|
| 509 |
+
|
| 510 |
+
def observe(self):
|
| 511 |
+
obs = super().observe()
|
| 512 |
+
obs["torso_quat"] = self.cache["obs"]["secondary_imu_quat"]
|
| 513 |
+
obs["torso_ang_vel"] = self.cache["obs"]["secondary_imu_vel"][3:6]
|
| 514 |
+
return obs
|
| 515 |
+
|
| 516 |
+
def queue_action(self, action: Dict[str, any]):
|
| 517 |
+
# Safety check before queuing action
|
| 518 |
+
obs = self.observe()
|
| 519 |
+
safety_result = self.safety_monitor.handle_violations(obs, action)
|
| 520 |
+
action = safety_result["action"]
|
| 521 |
+
# Save safety status for efficient access
|
| 522 |
+
self.last_safety_ok = not safety_result.get("shutdown_required", False)
|
| 523 |
+
# Check if shutdown is required
|
| 524 |
+
if safety_result["shutdown_required"]:
|
| 525 |
+
self.safety_monitor.trigger_system_shutdown()
|
| 526 |
+
|
| 527 |
+
# Call parent queue_action with potentially modified action
|
| 528 |
+
super().queue_action(action)
|
| 529 |
+
|
| 530 |
+
def get_joint_safety_status(self) -> bool:
|
| 531 |
+
"""Get current joint safety status from the last queue_action safety check.
|
| 532 |
+
|
| 533 |
+
Returns:
|
| 534 |
+
bool: True if joints are safe (no shutdown required), False if unsafe
|
| 535 |
+
"""
|
| 536 |
+
return self.last_safety_ok
|
| 537 |
+
|
| 538 |
+
|
| 539 |
+
def create_gym_sync_env_class(env, robot, robot_alias, wbc_version):
|
| 540 |
+
class_name = f"{env}_{robot}_{wbc_version}"
|
| 541 |
+
id_name = f"gr00tlocomanip_{robot_alias}/{class_name}"
|
| 542 |
+
|
| 543 |
+
if robot_alias.startswith("g1"):
|
| 544 |
+
env_class_type = G1SyncEnv
|
| 545 |
+
elif robot_alias.startswith("gr1"):
|
| 546 |
+
env_class_type = globals().get("GR1SyncEnv", SyncEnv)
|
| 547 |
+
else:
|
| 548 |
+
env_class_type = SyncEnv
|
| 549 |
+
|
| 550 |
+
controller_configs = update_robosuite_controller_configs(
|
| 551 |
+
robot=robot,
|
| 552 |
+
wbc_version=wbc_version,
|
| 553 |
+
)
|
| 554 |
+
|
| 555 |
+
env_class_type = type(
|
| 556 |
+
class_name,
|
| 557 |
+
(env_class_type,),
|
| 558 |
+
{
|
| 559 |
+
"__init__": lambda self, **kwargs: super(self.__class__, self).__init__(
|
| 560 |
+
env_name=env,
|
| 561 |
+
robot_name=robot,
|
| 562 |
+
controller_configs=controller_configs,
|
| 563 |
+
**kwargs,
|
| 564 |
+
)
|
| 565 |
+
},
|
| 566 |
+
)
|
| 567 |
+
|
| 568 |
+
current_module = sys.modules["decoupled_wbc.control.envs.robocasa.sync_env"]
|
| 569 |
+
setattr(current_module, class_name, env_class_type)
|
| 570 |
+
register(
|
| 571 |
+
id=id_name, # Unique ID for the environment
|
| 572 |
+
entry_point=f"decoupled_wbc.control.envs.robocasa.sync_env:{class_name}",
|
| 573 |
+
)
|
| 574 |
+
|
| 575 |
+
|
| 576 |
+
WBC_VERSION = "gear_wbc"
|
| 577 |
+
|
| 578 |
+
for ENV in REGISTERED_LOCOMANIPULATION_ENVS:
|
| 579 |
+
for ROBOT, ROBOT_ALIAS in GR00T_LOCOMANIP_ENVS_ROBOTS.items():
|
| 580 |
+
create_gym_sync_env_class(ENV, ROBOT, ROBOT_ALIAS, WBC_VERSION)
|
| 581 |
+
|
| 582 |
+
|
| 583 |
+
if __name__ == "__main__":
|
| 584 |
+
|
| 585 |
+
env = gym.make("gr00tlocomanip_g1_sim/PnPBottle_g1_gear_wbc")
|
| 586 |
+
print(env.observation_space)
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/__init__.py
ADDED
|
File without changes
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/cam_key_converter.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass
|
| 2 |
+
from typing import Dict, Optional, Tuple
|
| 3 |
+
|
| 4 |
+
from decoupled_wbc.data.constants import RS_VIEW_CAMERA_HEIGHT, RS_VIEW_CAMERA_WIDTH
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
@dataclass
|
| 8 |
+
class CameraConfig:
|
| 9 |
+
width: int
|
| 10 |
+
height: int
|
| 11 |
+
mapped_key: str
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
class CameraKeyMapper:
|
| 15 |
+
def __init__(self):
|
| 16 |
+
# Default camera dimensions
|
| 17 |
+
self.default_width = RS_VIEW_CAMERA_WIDTH
|
| 18 |
+
self.default_height = RS_VIEW_CAMERA_HEIGHT
|
| 19 |
+
|
| 20 |
+
# Camera key mapping with custom dimensions
|
| 21 |
+
self.camera_configs: Dict[str, CameraConfig] = {
|
| 22 |
+
# GR1
|
| 23 |
+
"egoview": CameraConfig(self.default_width, self.default_height, "ego_view"),
|
| 24 |
+
"frontview": CameraConfig(self.default_width, self.default_height, "front_view"),
|
| 25 |
+
# G1
|
| 26 |
+
"robot0_rs_egoview": CameraConfig(self.default_width, self.default_height, "ego_view"),
|
| 27 |
+
"robot0_rs_tppview": CameraConfig(self.default_width, self.default_height, "tpp_view"),
|
| 28 |
+
"robot0_oak_egoview": CameraConfig(self.default_width, self.default_height, "ego_view"),
|
| 29 |
+
"robot0_oak_left_monoview": CameraConfig(
|
| 30 |
+
self.default_width, self.default_height, "ego_view_left_mono"
|
| 31 |
+
),
|
| 32 |
+
"robot0_oak_right_monoview": CameraConfig(
|
| 33 |
+
self.default_width, self.default_height, "ego_view_right_mono"
|
| 34 |
+
),
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
def get_camera_config(self, key: str) -> Optional[Tuple[str, int, int]]:
|
| 38 |
+
"""
|
| 39 |
+
Get the mapped camera key and dimensions for a given camera key.
|
| 40 |
+
|
| 41 |
+
Args:
|
| 42 |
+
key: The input camera key
|
| 43 |
+
|
| 44 |
+
Returns:
|
| 45 |
+
Tuple of (mapped_key, width, height) if key exists, None otherwise
|
| 46 |
+
"""
|
| 47 |
+
config = self.camera_configs.get(key.lower())
|
| 48 |
+
if config is None:
|
| 49 |
+
return None
|
| 50 |
+
return config.mapped_key, config.width, config.height
|
| 51 |
+
|
| 52 |
+
def add_camera_config(
|
| 53 |
+
self, key: str, mapped_key: str, width: int = 256, height: int = 256
|
| 54 |
+
) -> None:
|
| 55 |
+
"""
|
| 56 |
+
Add a new camera configuration or update an existing one.
|
| 57 |
+
|
| 58 |
+
Args:
|
| 59 |
+
key: The camera key to add/update
|
| 60 |
+
mapped_key: The actual camera key to map to
|
| 61 |
+
width: Camera width in pixels
|
| 62 |
+
height: Camera height in pixels
|
| 63 |
+
"""
|
| 64 |
+
self.camera_configs[key.lower()] = CameraConfig(width, height, mapped_key)
|
| 65 |
+
|
| 66 |
+
def get_all_camera_keys(self) -> list:
|
| 67 |
+
"""
|
| 68 |
+
Get all available camera keys.
|
| 69 |
+
|
| 70 |
+
Returns:
|
| 71 |
+
List of all camera keys
|
| 72 |
+
"""
|
| 73 |
+
return list(self.camera_configs.keys())
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/controller_utils.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
def get_body_ik_solver_settings_type(robot: str):
|
| 2 |
+
robot2body_ik_solver_settings_type = {
|
| 3 |
+
"G1FixedLowerBody": "sim_optimized",
|
| 4 |
+
"G1FixedBase": "sim_optimized",
|
| 5 |
+
"G1FloatingBody": "sim_optimized",
|
| 6 |
+
"G1ArmsOnly": "sim_optimized",
|
| 7 |
+
"G1ArmsOnlyFloating": "sim_optimized",
|
| 8 |
+
"G1": "default",
|
| 9 |
+
"GR1ArmsAndWaistFourierHands": "default",
|
| 10 |
+
"GR1FixedLowerBody": "default",
|
| 11 |
+
"GR1ArmsOnlyFourierHands": "default",
|
| 12 |
+
"GR1ArmsOnly": "default",
|
| 13 |
+
}
|
| 14 |
+
return robot2body_ik_solver_settings_type[robot]
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def update_robosuite_controller_configs(
|
| 18 |
+
robot: str,
|
| 19 |
+
wbc_version: str = None,
|
| 20 |
+
enable_gravity_compensation: bool = False,
|
| 21 |
+
):
|
| 22 |
+
"""
|
| 23 |
+
Update the robosuite controller configs based on the robot type and wbc version.
|
| 24 |
+
"""
|
| 25 |
+
body_ik_solver_settings_type = get_body_ik_solver_settings_type(robot)
|
| 26 |
+
if robot.startswith("G1"):
|
| 27 |
+
if wbc_version == "gear_wbc":
|
| 28 |
+
if enable_gravity_compensation:
|
| 29 |
+
robosuite_controller_configs = (
|
| 30 |
+
"robocasa/examples/third_party_controller/default_mink_ik_g1_gear_wbc_gc.json"
|
| 31 |
+
)
|
| 32 |
+
else:
|
| 33 |
+
robosuite_controller_configs = (
|
| 34 |
+
"robocasa/examples/third_party_controller/default_mink_ik_g1_gear_wbc.json"
|
| 35 |
+
)
|
| 36 |
+
else:
|
| 37 |
+
if body_ik_solver_settings_type == "default":
|
| 38 |
+
robosuite_controller_configs = (
|
| 39 |
+
"robocasa/examples/third_party_controller/default_mink_ik_g1_wbc.json"
|
| 40 |
+
)
|
| 41 |
+
elif body_ik_solver_settings_type == "sim_optimized":
|
| 42 |
+
robosuite_controller_configs = (
|
| 43 |
+
"robocasa/examples/third_party_controller/"
|
| 44 |
+
"default_mink_ik_g1_wbc_sim_optimized.json"
|
| 45 |
+
)
|
| 46 |
+
else:
|
| 47 |
+
raise ValueError(
|
| 48 |
+
f"Invalid body_ik_solver_settings_type: {body_ik_solver_settings_type}"
|
| 49 |
+
)
|
| 50 |
+
elif robot.startswith("GR1"):
|
| 51 |
+
return "robocasa/examples/third_party_controller/default_mink_ik_gr1_smallkd.json"
|
| 52 |
+
else:
|
| 53 |
+
raise ValueError(f"Invalid robot: {robot}")
|
| 54 |
+
return robosuite_controller_configs
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/robocasa_env.py
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from typing import Any, Dict, List, Tuple
|
| 3 |
+
|
| 4 |
+
from gymnasium import spaces
|
| 5 |
+
import mujoco
|
| 6 |
+
import numpy as np
|
| 7 |
+
import robocasa
|
| 8 |
+
from robocasa.utils.gym_utils.gymnasium_basic import (
|
| 9 |
+
RoboCasaEnv,
|
| 10 |
+
create_env_robosuite,
|
| 11 |
+
)
|
| 12 |
+
from robocasa.wrappers.ik_wrapper import IKWrapper
|
| 13 |
+
from robosuite.controllers import load_composite_controller_config
|
| 14 |
+
from robosuite.utils.log_utils import ROBOSUITE_DEFAULT_LOGGER
|
| 15 |
+
|
| 16 |
+
from decoupled_wbc.control.envs.robocasa.utils.cam_key_converter import CameraKeyMapper
|
| 17 |
+
from decoupled_wbc.control.envs.robocasa.utils.robot_key_converter import Gr00tObsActionConverter
|
| 18 |
+
from decoupled_wbc.control.robot_model.robot_model import RobotModel
|
| 19 |
+
|
| 20 |
+
ALLOWED_LANGUAGE_CHARSET = (
|
| 21 |
+
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.\n\t[]{}()!?'_:"
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class Gr00tLocomanipRoboCasaEnv(RoboCasaEnv):
|
| 26 |
+
def __init__(
|
| 27 |
+
self,
|
| 28 |
+
env_name: str,
|
| 29 |
+
robots_name: str,
|
| 30 |
+
robot_model: RobotModel, # gr00t robot model
|
| 31 |
+
input_space: str = "JOINT_SPACE", # either "JOINT_SPACE" or "EEF_SPACE"
|
| 32 |
+
camera_names: List[str] = ["egoview"],
|
| 33 |
+
camera_heights: List[int] | None = None,
|
| 34 |
+
camera_widths: List[int] | None = None,
|
| 35 |
+
onscreen: bool = False,
|
| 36 |
+
offscreen: bool = False,
|
| 37 |
+
dump_rollout_dataset_dir: str | None = None,
|
| 38 |
+
rollout_hdf5: str | None = None,
|
| 39 |
+
rollout_trainset: int | None = None,
|
| 40 |
+
controller_configs: str | None = None,
|
| 41 |
+
ik_indicator: bool = False,
|
| 42 |
+
**kwargs,
|
| 43 |
+
):
|
| 44 |
+
# ========= Create env =========
|
| 45 |
+
if controller_configs is None:
|
| 46 |
+
if "G1" in robots_name:
|
| 47 |
+
controller_configs = (
|
| 48 |
+
"robocasa/examples/third_party_controller/default_mink_ik_g1_wbc.json"
|
| 49 |
+
)
|
| 50 |
+
elif "GR1" in robots_name:
|
| 51 |
+
controller_configs = (
|
| 52 |
+
"robocasa/examples/third_party_controller/default_mink_ik_gr1_smallkd.json"
|
| 53 |
+
)
|
| 54 |
+
else:
|
| 55 |
+
assert False, f"Unsupported robot name: {robots_name}"
|
| 56 |
+
controller_configs = os.path.join(
|
| 57 |
+
os.path.dirname(robocasa.__file__),
|
| 58 |
+
"../",
|
| 59 |
+
controller_configs,
|
| 60 |
+
)
|
| 61 |
+
controller_configs = load_composite_controller_config(
|
| 62 |
+
controller=controller_configs,
|
| 63 |
+
robot=robots_name.split("_")[0],
|
| 64 |
+
)
|
| 65 |
+
if input_space == "JOINT_SPACE":
|
| 66 |
+
controller_configs["type"] = "BASIC"
|
| 67 |
+
controller_configs["composite_controller_specific_configs"] = {}
|
| 68 |
+
controller_configs["control_delta"] = False
|
| 69 |
+
|
| 70 |
+
self.camera_key_mapper = CameraKeyMapper()
|
| 71 |
+
self.camera_names = camera_names
|
| 72 |
+
|
| 73 |
+
if camera_widths is None:
|
| 74 |
+
self.camera_widths = [
|
| 75 |
+
self.camera_key_mapper.get_camera_config(name)[1] for name in camera_names
|
| 76 |
+
]
|
| 77 |
+
else:
|
| 78 |
+
self.camera_widths = camera_widths
|
| 79 |
+
if camera_heights is None:
|
| 80 |
+
self.camera_heights = [
|
| 81 |
+
self.camera_key_mapper.get_camera_config(name)[2] for name in camera_names
|
| 82 |
+
]
|
| 83 |
+
else:
|
| 84 |
+
self.camera_heights = camera_heights
|
| 85 |
+
|
| 86 |
+
self.env, self.env_kwargs = create_env_robosuite(
|
| 87 |
+
env_name=env_name,
|
| 88 |
+
robots=robots_name.split("_"),
|
| 89 |
+
controller_configs=controller_configs,
|
| 90 |
+
camera_names=camera_names,
|
| 91 |
+
camera_widths=self.camera_widths,
|
| 92 |
+
camera_heights=self.camera_heights,
|
| 93 |
+
enable_render=offscreen,
|
| 94 |
+
onscreen=onscreen,
|
| 95 |
+
**kwargs, # Forward kwargs to create_env_robosuite
|
| 96 |
+
)
|
| 97 |
+
|
| 98 |
+
if ik_indicator:
|
| 99 |
+
self.env = IKWrapper(self.env, ik_indicator=True)
|
| 100 |
+
|
| 101 |
+
# ========= create converters first to get total DOFs =========
|
| 102 |
+
# For now, assume single robot (multi-robot support can be added later)
|
| 103 |
+
self.obs_action_converter: List[Gr00tObsActionConverter] = [
|
| 104 |
+
Gr00tObsActionConverter(
|
| 105 |
+
robot_model=robot_model,
|
| 106 |
+
robosuite_robot_model=self.env.robots[i],
|
| 107 |
+
)
|
| 108 |
+
for i in range(len(self.env.robots))
|
| 109 |
+
]
|
| 110 |
+
|
| 111 |
+
self.body_dofs = sum(converter.body_dof for converter in self.obs_action_converter)
|
| 112 |
+
self.gripper_dofs = sum(converter.gripper_dof for converter in self.obs_action_converter)
|
| 113 |
+
self.total_dofs = self.body_dofs + self.gripper_dofs
|
| 114 |
+
self.body_nu = sum(converter.body_nu for converter in self.obs_action_converter)
|
| 115 |
+
self.gripper_nu = sum(converter.gripper_nu for converter in self.obs_action_converter)
|
| 116 |
+
self.total_nu = self.body_nu + self.gripper_nu
|
| 117 |
+
|
| 118 |
+
# ========= create spaces to match total DOFs =========
|
| 119 |
+
self.get_observation_space()
|
| 120 |
+
self.get_action_space()
|
| 121 |
+
|
| 122 |
+
self.enable_render = offscreen
|
| 123 |
+
self.render_obs_key = f"{camera_names[0]}_image"
|
| 124 |
+
self.render_cache = None
|
| 125 |
+
|
| 126 |
+
self.dump_rollout_dataset_dir = dump_rollout_dataset_dir
|
| 127 |
+
self.gr00t_exporter = None
|
| 128 |
+
self.np_exporter = None
|
| 129 |
+
|
| 130 |
+
self.rollout_hdf5 = rollout_hdf5
|
| 131 |
+
self.rollout_trainset = rollout_trainset
|
| 132 |
+
self.rollout_initial_state = {}
|
| 133 |
+
|
| 134 |
+
self.verbose = False
|
| 135 |
+
for k, v in self.observation_space.items():
|
| 136 |
+
self.verbose and print("{OBS}", k, v)
|
| 137 |
+
for k, v in self.action_space.items():
|
| 138 |
+
self.verbose and print("{ACTION}", k, v)
|
| 139 |
+
|
| 140 |
+
self.overridden_floating_base_action = None
|
| 141 |
+
|
| 142 |
+
def get_observation_space(self):
|
| 143 |
+
self.observation_space = spaces.Dict({})
|
| 144 |
+
|
| 145 |
+
# Add all the observation spaces
|
| 146 |
+
self.observation_space["time"] = spaces.Box(
|
| 147 |
+
low=-np.inf, high=np.inf, shape=(1,), dtype=np.float32
|
| 148 |
+
)
|
| 149 |
+
self.observation_space["floating_base_pose"] = spaces.Box(
|
| 150 |
+
low=-np.inf, high=np.inf, shape=(7,), dtype=np.float32
|
| 151 |
+
)
|
| 152 |
+
self.observation_space["floating_base_vel"] = spaces.Box(
|
| 153 |
+
low=-np.inf, high=np.inf, shape=(6,), dtype=np.float32
|
| 154 |
+
)
|
| 155 |
+
self.observation_space["floating_base_acc"] = spaces.Box(
|
| 156 |
+
low=-np.inf, high=np.inf, shape=(6,), dtype=np.float32
|
| 157 |
+
)
|
| 158 |
+
self.observation_space["body_q"] = spaces.Box(
|
| 159 |
+
low=-np.inf, high=np.inf, shape=(self.body_dofs,), dtype=np.float32
|
| 160 |
+
)
|
| 161 |
+
self.observation_space["body_dq"] = spaces.Box(
|
| 162 |
+
low=-np.inf, high=np.inf, shape=(self.body_dofs,), dtype=np.float32
|
| 163 |
+
)
|
| 164 |
+
self.observation_space["body_ddq"] = spaces.Box(
|
| 165 |
+
low=-np.inf, high=np.inf, shape=(self.body_dofs,), dtype=np.float32
|
| 166 |
+
)
|
| 167 |
+
self.observation_space["body_tau_est"] = spaces.Box(
|
| 168 |
+
low=-np.inf, high=np.inf, shape=(self.body_nu,), dtype=np.float32
|
| 169 |
+
)
|
| 170 |
+
self.observation_space["left_hand_q"] = spaces.Box(
|
| 171 |
+
low=-np.inf, high=np.inf, shape=(self.gripper_dofs // 2,), dtype=np.float32
|
| 172 |
+
)
|
| 173 |
+
self.observation_space["left_hand_dq"] = spaces.Box(
|
| 174 |
+
low=-np.inf, high=np.inf, shape=(self.gripper_dofs // 2,), dtype=np.float32
|
| 175 |
+
)
|
| 176 |
+
self.observation_space["left_hand_ddq"] = spaces.Box(
|
| 177 |
+
low=-np.inf, high=np.inf, shape=(self.gripper_dofs // 2,), dtype=np.float32
|
| 178 |
+
)
|
| 179 |
+
self.observation_space["left_hand_tau_est"] = spaces.Box(
|
| 180 |
+
low=-np.inf, high=np.inf, shape=(self.gripper_nu // 2,), dtype=np.float32
|
| 181 |
+
)
|
| 182 |
+
self.observation_space["right_hand_q"] = spaces.Box(
|
| 183 |
+
low=-np.inf, high=np.inf, shape=(self.gripper_dofs // 2,), dtype=np.float32
|
| 184 |
+
)
|
| 185 |
+
self.observation_space["right_hand_dq"] = spaces.Box(
|
| 186 |
+
low=-np.inf, high=np.inf, shape=(self.gripper_dofs // 2,), dtype=np.float32
|
| 187 |
+
)
|
| 188 |
+
self.observation_space["right_hand_ddq"] = spaces.Box(
|
| 189 |
+
low=-np.inf, high=np.inf, shape=(self.gripper_dofs // 2,), dtype=np.float32
|
| 190 |
+
)
|
| 191 |
+
self.observation_space["right_hand_tau_est"] = spaces.Box(
|
| 192 |
+
low=-np.inf, high=np.inf, shape=(self.gripper_nu // 2,), dtype=np.float32
|
| 193 |
+
)
|
| 194 |
+
|
| 195 |
+
self.observation_space["language.language_instruction"] = spaces.Text(
|
| 196 |
+
max_length=256, charset=ALLOWED_LANGUAGE_CHARSET
|
| 197 |
+
)
|
| 198 |
+
|
| 199 |
+
# Add camera observation spaces
|
| 200 |
+
for camera_name, w, h in zip(self.camera_names, self.camera_widths, self.camera_heights):
|
| 201 |
+
k = self.camera_key_mapper.get_camera_config(camera_name)[0]
|
| 202 |
+
self.observation_space[f"{k}_image"] = spaces.Box(
|
| 203 |
+
low=0, high=255, shape=(h, w, 3), dtype=np.uint8
|
| 204 |
+
)
|
| 205 |
+
|
| 206 |
+
# Add extra privileged observation spaces
|
| 207 |
+
if hasattr(self.env, "get_privileged_obs_keys"):
|
| 208 |
+
for key, shape in self.env.get_privileged_obs_keys().items():
|
| 209 |
+
self.observation_space[key] = spaces.Box(
|
| 210 |
+
low=-np.inf, high=np.inf, shape=shape, dtype=np.float32
|
| 211 |
+
)
|
| 212 |
+
|
| 213 |
+
# Add robot-specific observation spaces
|
| 214 |
+
if hasattr(self.env.robots[0].robot_model, "torso_body"):
|
| 215 |
+
self.observation_space["secondary_imu_quat"] = spaces.Box(
|
| 216 |
+
low=-np.inf, high=np.inf, shape=(4,), dtype=np.float32
|
| 217 |
+
)
|
| 218 |
+
self.observation_space["secondary_imu_vel"] = spaces.Box(
|
| 219 |
+
low=-np.inf, high=np.inf, shape=(6,), dtype=np.float32
|
| 220 |
+
)
|
| 221 |
+
|
| 222 |
+
def get_action_space(self):
|
| 223 |
+
self.action_space = spaces.Dict(
|
| 224 |
+
{"q": spaces.Box(low=-np.inf, high=np.inf, shape=(self.total_dofs,), dtype=np.float32)}
|
| 225 |
+
)
|
| 226 |
+
|
| 227 |
+
def reset(self, seed=None, options=None):
|
| 228 |
+
raw_obs, info = super().reset(seed=seed, options=options)
|
| 229 |
+
obs = self.get_gr00t_observation(raw_obs)
|
| 230 |
+
|
| 231 |
+
lang = self.env.get_ep_meta().get("lang", "")
|
| 232 |
+
ROBOSUITE_DEFAULT_LOGGER.info(f"Instruction: {lang}")
|
| 233 |
+
|
| 234 |
+
return obs, info
|
| 235 |
+
|
| 236 |
+
def step(
|
| 237 |
+
self, action: Dict[str, Any]
|
| 238 |
+
) -> Tuple[Dict[str, Any], float, bool, bool, Dict[str, Any]]:
|
| 239 |
+
# action={"q": xxx, "tau": xxx}
|
| 240 |
+
for k, v in action.items():
|
| 241 |
+
self.verbose and print("<ACTION>", k, v)
|
| 242 |
+
|
| 243 |
+
joint_actoin_vec = action["q"]
|
| 244 |
+
action_dict = {}
|
| 245 |
+
for ii, robot in enumerate(self.env.robots):
|
| 246 |
+
pf = robot.robot_model.naming_prefix
|
| 247 |
+
_action_dict = self.obs_action_converter[ii].gr00t_to_robocasa_action_dict(
|
| 248 |
+
joint_actoin_vec
|
| 249 |
+
)
|
| 250 |
+
action_dict.update({f"{pf}{k}": v for k, v in _action_dict.items()})
|
| 251 |
+
if action.get("tau", None) is not None:
|
| 252 |
+
_torque_dict = self.obs_action_converter[ii].gr00t_to_robocasa_action_dict(
|
| 253 |
+
action["tau"]
|
| 254 |
+
)
|
| 255 |
+
action_dict.update({f"{pf}{k}_tau": v for k, v in _torque_dict.items()})
|
| 256 |
+
if self.overridden_floating_base_action is not None:
|
| 257 |
+
action_dict["robot0_base"] = self.overridden_floating_base_action
|
| 258 |
+
raw_obs, reward, terminated, truncated, info = super().step(action_dict)
|
| 259 |
+
obs = self.get_gr00t_observation(raw_obs)
|
| 260 |
+
|
| 261 |
+
for k, v in obs.items():
|
| 262 |
+
self.verbose and print("<OBS>", k, v.shape if k.startswith("video.") else v)
|
| 263 |
+
self.verbose = False
|
| 264 |
+
|
| 265 |
+
return obs, reward, terminated, truncated, info
|
| 266 |
+
|
| 267 |
+
def step_only_kinematics(
|
| 268 |
+
self, action: Dict[str, Any]
|
| 269 |
+
) -> Tuple[Dict[str, Any], float, bool, bool, Dict[str, Any]]:
|
| 270 |
+
joint_actoin_vec = action["q"]
|
| 271 |
+
for ii, robot in enumerate(self.env.robots):
|
| 272 |
+
joint_names = np.array(self.env.sim.model.joint_names)[robot._ref_joint_indexes]
|
| 273 |
+
body_q = self.obs_action_converter[ii].gr00t_to_robocasa_joint_order(
|
| 274 |
+
joint_names, joint_actoin_vec
|
| 275 |
+
)
|
| 276 |
+
self.env.sim.data.qpos[robot._ref_joint_pos_indexes] = body_q
|
| 277 |
+
|
| 278 |
+
for side in ["left", "right"]:
|
| 279 |
+
joint_names = np.array(self.env.sim.model.joint_names)[
|
| 280 |
+
robot._ref_joints_indexes_dict[side + "_gripper"]
|
| 281 |
+
]
|
| 282 |
+
gripper_q = self.obs_action_converter[ii].gr00t_to_robocasa_joint_order(
|
| 283 |
+
joint_names, joint_actoin_vec
|
| 284 |
+
)
|
| 285 |
+
self.env.sim.data.qpos[robot._ref_gripper_joint_pos_indexes[side]] = gripper_q
|
| 286 |
+
|
| 287 |
+
mujoco.mj_forward(self.env.sim.model._model, self.env.sim.data._data)
|
| 288 |
+
|
| 289 |
+
obs = self.force_update_observation()
|
| 290 |
+
return obs, 0, False, False, {"success": False}
|
| 291 |
+
|
| 292 |
+
def force_update_observation(self, timestep=0):
|
| 293 |
+
raw_obs = self.env._get_observations(force_update=True, timestep=timestep)
|
| 294 |
+
obs = self.get_basic_observation(raw_obs)
|
| 295 |
+
obs = self.get_gr00t_observation(obs)
|
| 296 |
+
return obs
|
| 297 |
+
|
| 298 |
+
def get_basic_observation(self, raw_obs):
|
| 299 |
+
# this function takes a lot of time, so we disable it for now
|
| 300 |
+
# raw_obs.update(gather_robot_observations(self.env, format_gripper_space=False))
|
| 301 |
+
|
| 302 |
+
# Image are in (H, W, C), flip it upside down
|
| 303 |
+
def process_img(img):
|
| 304 |
+
return np.copy(img[::-1, :, :])
|
| 305 |
+
|
| 306 |
+
for obs_name, obs_value in raw_obs.items():
|
| 307 |
+
if obs_name.endswith("_image"):
|
| 308 |
+
# image observations
|
| 309 |
+
raw_obs[obs_name] = process_img(obs_value)
|
| 310 |
+
else:
|
| 311 |
+
# non-image observations
|
| 312 |
+
raw_obs[obs_name] = obs_value.astype(np.float32)
|
| 313 |
+
|
| 314 |
+
# Return black image if rendering is disabled
|
| 315 |
+
if not self.enable_render:
|
| 316 |
+
for ii, name in enumerate(self.camera_names):
|
| 317 |
+
raw_obs[f"{name}_image"] = np.zeros(
|
| 318 |
+
(self.camera_heights[ii], self.camera_widths[ii], 3), dtype=np.uint8
|
| 319 |
+
)
|
| 320 |
+
|
| 321 |
+
self.render_cache = raw_obs[self.render_obs_key]
|
| 322 |
+
raw_obs["language"] = self.env.get_ep_meta().get("lang", "")
|
| 323 |
+
|
| 324 |
+
return raw_obs
|
| 325 |
+
|
| 326 |
+
def convert_body_q(self, q: np.ndarray) -> np.ndarray:
|
| 327 |
+
# q is in the order of the joints
|
| 328 |
+
robot = self.env.robots[0]
|
| 329 |
+
joint_names = np.array(self.env.sim.model.joint_names)[robot._ref_joint_indexes]
|
| 330 |
+
# this joint names are in the order of the obs_vec
|
| 331 |
+
actuated_q = self.obs_action_converter[0].robocasa_to_gr00t_actuated_order(
|
| 332 |
+
joint_names, q, "body"
|
| 333 |
+
)
|
| 334 |
+
return actuated_q
|
| 335 |
+
|
| 336 |
+
def convert_gripper_q(self, q: np.ndarray, side: str = "left") -> np.ndarray:
|
| 337 |
+
# q is in the order of the joints
|
| 338 |
+
robot = self.env.robots[0]
|
| 339 |
+
joint_names = np.array(self.env.sim.model.joint_names)[
|
| 340 |
+
robot._ref_joints_indexes_dict[side + "_gripper"]
|
| 341 |
+
]
|
| 342 |
+
actuated_q = self.obs_action_converter[0].robocasa_to_gr00t_actuated_order(
|
| 343 |
+
joint_names, q, side + "_gripper"
|
| 344 |
+
)
|
| 345 |
+
return actuated_q
|
| 346 |
+
|
| 347 |
+
def convert_gripper_tau(self, tau: np.ndarray, side: str = "left") -> np.ndarray:
|
| 348 |
+
# tau is in the order of the actuators
|
| 349 |
+
robot = self.env.robots[0]
|
| 350 |
+
actuator_idx = robot._ref_actuators_indexes_dict[side + "_gripper"]
|
| 351 |
+
actuated_joint_names = [
|
| 352 |
+
self.env.sim.model.joint_id2name(self.env.sim.model.actuator_trnid[i][0])
|
| 353 |
+
for i in actuator_idx
|
| 354 |
+
]
|
| 355 |
+
actuated_tau = self.obs_action_converter[0].robocasa_to_gr00t_actuated_order(
|
| 356 |
+
actuated_joint_names, tau, side + "_gripper"
|
| 357 |
+
)
|
| 358 |
+
return actuated_tau
|
| 359 |
+
|
| 360 |
+
def get_gr00t_observation(self, raw_obs: Dict[str, Any]) -> Dict[str, Any]:
|
| 361 |
+
obs = {}
|
| 362 |
+
|
| 363 |
+
if self.env.sim.model.jnt_type[0] == mujoco.mjtJoint.mjJNT_FREE:
|
| 364 |
+
# If the first joint is a free joint, use this way to get the floating base data
|
| 365 |
+
obs["floating_base_pose"] = self.env.sim.data.qpos[:7]
|
| 366 |
+
obs["floating_base_vel"] = self.env.sim.data.qvel[:6]
|
| 367 |
+
obs["floating_base_acc"] = self.env.sim.data.qacc[:6]
|
| 368 |
+
else:
|
| 369 |
+
# Otherwise, use self.env.sim.model to fetch the floating base pose
|
| 370 |
+
root_body_id = self.env.sim.model.body_name2id("robot0_base")
|
| 371 |
+
|
| 372 |
+
# Get position and orientation from body state
|
| 373 |
+
root_pos = self.env.sim.data.body_xpos[root_body_id]
|
| 374 |
+
root_quat = self.env.sim.data.body_xquat[root_body_id] # quaternion in wxyz format
|
| 375 |
+
|
| 376 |
+
# Combine position and quaternion to form 7-DOF pose
|
| 377 |
+
obs["floating_base_pose"] = np.concatenate([root_pos, root_quat])
|
| 378 |
+
# set vel and acc to 0
|
| 379 |
+
obs["floating_base_vel"] = np.zeros(6)
|
| 380 |
+
obs["floating_base_acc"] = np.zeros(6)
|
| 381 |
+
|
| 382 |
+
obs["body_q"] = self.convert_body_q(raw_obs["robot0_joint_pos"])
|
| 383 |
+
obs["body_dq"] = self.convert_body_q(raw_obs["robot0_joint_vel"])
|
| 384 |
+
obs["body_ddq"] = self.convert_body_q(raw_obs["robot0_joint_acc"])
|
| 385 |
+
|
| 386 |
+
obs["left_hand_q"] = self.convert_gripper_q(raw_obs["robot0_left_gripper_qpos"], "left")
|
| 387 |
+
obs["left_hand_dq"] = self.convert_gripper_q(raw_obs["robot0_left_gripper_qvel"], "left")
|
| 388 |
+
obs["left_hand_ddq"] = self.convert_gripper_q(raw_obs["robot0_left_gripper_qacc"], "left")
|
| 389 |
+
obs["right_hand_q"] = self.convert_gripper_q(raw_obs["robot0_right_gripper_qpos"], "right")
|
| 390 |
+
obs["right_hand_dq"] = self.convert_gripper_q(raw_obs["robot0_right_gripper_qvel"], "right")
|
| 391 |
+
obs["right_hand_ddq"] = self.convert_gripper_q(
|
| 392 |
+
raw_obs["robot0_right_gripper_qacc"], "right"
|
| 393 |
+
)
|
| 394 |
+
|
| 395 |
+
robot = self.env.robots[0]
|
| 396 |
+
body_tau_idx_list = []
|
| 397 |
+
left_gripper_tau_idx_list = []
|
| 398 |
+
right_gripper_tau_idx_list = []
|
| 399 |
+
for part_name, actuator_idx in robot._ref_actuators_indexes_dict.items():
|
| 400 |
+
if "left_gripper" in part_name:
|
| 401 |
+
left_gripper_tau_idx_list.extend(actuator_idx)
|
| 402 |
+
elif "right_gripper" in part_name:
|
| 403 |
+
right_gripper_tau_idx_list.extend(actuator_idx)
|
| 404 |
+
elif "base" in part_name:
|
| 405 |
+
assert (
|
| 406 |
+
len(actuator_idx) == 0 or robot.robot_model.default_base == "FloatingLeggedBase"
|
| 407 |
+
)
|
| 408 |
+
else:
|
| 409 |
+
body_tau_idx_list.extend(actuator_idx)
|
| 410 |
+
|
| 411 |
+
body_tau_idx_list = sorted(body_tau_idx_list)
|
| 412 |
+
left_gripper_tau_idx_list = sorted(left_gripper_tau_idx_list)
|
| 413 |
+
right_gripper_tau_idx_list = sorted(right_gripper_tau_idx_list)
|
| 414 |
+
obs["body_tau_est"] = self.convert_body_q(
|
| 415 |
+
self.env.sim.data.actuator_force[body_tau_idx_list]
|
| 416 |
+
)
|
| 417 |
+
obs["right_hand_tau_est"] = self.convert_gripper_tau(
|
| 418 |
+
self.env.sim.data.actuator_force[right_gripper_tau_idx_list], "right"
|
| 419 |
+
)
|
| 420 |
+
obs["left_hand_tau_est"] = self.convert_gripper_tau(
|
| 421 |
+
self.env.sim.data.actuator_force[left_gripper_tau_idx_list], "left"
|
| 422 |
+
)
|
| 423 |
+
|
| 424 |
+
obs["time"] = self.env.sim.data.time
|
| 425 |
+
|
| 426 |
+
# Add camera images
|
| 427 |
+
for ii, camera_name in enumerate(self.camera_names):
|
| 428 |
+
mapped_camera_name = self.camera_key_mapper.get_camera_config(camera_name)[0]
|
| 429 |
+
obs[f"{mapped_camera_name}_image"] = raw_obs[f"{camera_name}_image"]
|
| 430 |
+
|
| 431 |
+
# Add privileged observations
|
| 432 |
+
if hasattr(self.env, "get_privileged_obs_keys"):
|
| 433 |
+
for key in self.env.get_privileged_obs_keys():
|
| 434 |
+
obs[key] = raw_obs[key]
|
| 435 |
+
|
| 436 |
+
# Add robot-specific observations
|
| 437 |
+
if hasattr(self.env.robots[0].robot_model, "torso_body"):
|
| 438 |
+
obs["secondary_imu_quat"] = raw_obs["robot0_torso_link_imu_quat"]
|
| 439 |
+
obs["secondary_imu_vel"] = raw_obs["robot0_torso_link_imu_vel"]
|
| 440 |
+
|
| 441 |
+
obs["language.language_instruction"] = raw_obs["language"]
|
| 442 |
+
|
| 443 |
+
return obs
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/robot_key_converter.py
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass
|
| 2 |
+
from typing import Any, Dict, List, Tuple
|
| 3 |
+
|
| 4 |
+
import numpy as np
|
| 5 |
+
from robocasa.models.robots import remove_mimic_joints
|
| 6 |
+
from robosuite.models.robots import RobotModel as RobosuiteRobotModel
|
| 7 |
+
|
| 8 |
+
from decoupled_wbc.control.robot_model import RobotModel
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class Gr00tJointInfo:
|
| 12 |
+
"""
|
| 13 |
+
Mapping from decoupled_wbc actuated joint names to robocasa joint names.
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
def __init__(self, robot_model: RobosuiteRobotModel):
|
| 17 |
+
self.robocasa_body_prefix = "robot0_"
|
| 18 |
+
self.robocasa_gripper_prefix = "gripper0_"
|
| 19 |
+
|
| 20 |
+
self.robot_model: RobotModel = robot_model
|
| 21 |
+
self.body_actuated_joint_names: List[str] = (
|
| 22 |
+
self.robot_model.supplemental_info.body_actuated_joints
|
| 23 |
+
)
|
| 24 |
+
self.left_hand_actuated_joint_names: List[str] = (
|
| 25 |
+
self.robot_model.supplemental_info.left_hand_actuated_joints
|
| 26 |
+
)
|
| 27 |
+
self.right_hand_actuated_joint_names: List[str] = (
|
| 28 |
+
self.robot_model.supplemental_info.right_hand_actuated_joints
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
self.actuated_joint_names: List[str] = self._get_gr00t_actuated_joint_names()
|
| 32 |
+
self.body_actuated_joint_to_index: Dict[str, int] = (
|
| 33 |
+
self._get_gr00t_body_actuated_joint_name_to_index()
|
| 34 |
+
)
|
| 35 |
+
self.gripper_actuated_joint_to_index: Tuple[Dict[str, int], Dict[str, int]] = (
|
| 36 |
+
self._get_gr00t_gripper_actuated_joint_name_to_index()
|
| 37 |
+
)
|
| 38 |
+
self.actuated_joint_name_to_index: Dict[str, int] = (
|
| 39 |
+
self._get_gr00t_actuated_joint_name_to_index()
|
| 40 |
+
)
|
| 41 |
+
|
| 42 |
+
def _get_gr00t_actuated_joint_names(self) -> List[str]:
|
| 43 |
+
"""Get list of gr00t actuated joint names ordered by their indices."""
|
| 44 |
+
if self.robot_model.supplemental_info is None:
|
| 45 |
+
raise ValueError("Robot model must have supplemental_info")
|
| 46 |
+
|
| 47 |
+
# Get joint names and indices
|
| 48 |
+
body_names = self.robot_model.supplemental_info.body_actuated_joints
|
| 49 |
+
left_hand_names = self.robot_model.supplemental_info.left_hand_actuated_joints
|
| 50 |
+
right_hand_names = self.robot_model.supplemental_info.right_hand_actuated_joints
|
| 51 |
+
|
| 52 |
+
body_indices = self.robot_model.get_joint_group_indices("body")
|
| 53 |
+
left_hand_indices = self.robot_model.get_joint_group_indices("left_hand")
|
| 54 |
+
right_hand_indices = self.robot_model.get_joint_group_indices("right_hand")
|
| 55 |
+
|
| 56 |
+
# Create a dictionary mapping index to name
|
| 57 |
+
index_to_name = {}
|
| 58 |
+
for name, idx in zip(body_names, body_indices):
|
| 59 |
+
index_to_name[idx] = self.robocasa_body_prefix + name
|
| 60 |
+
for name, idx in zip(left_hand_names, left_hand_indices):
|
| 61 |
+
index_to_name[idx] = self.robocasa_gripper_prefix + "left_" + name
|
| 62 |
+
for name, idx in zip(right_hand_names, right_hand_indices):
|
| 63 |
+
index_to_name[idx] = self.robocasa_gripper_prefix + "right_" + name
|
| 64 |
+
sorted_indices = sorted(index_to_name.keys())
|
| 65 |
+
all_actuated_joint_names = [index_to_name[idx] for idx in sorted_indices]
|
| 66 |
+
return all_actuated_joint_names
|
| 67 |
+
|
| 68 |
+
def _get_gr00t_body_actuated_joint_name_to_index(self) -> Dict[str, int]:
|
| 69 |
+
"""Get dictionary mapping gr00t actuated joint names to indices."""
|
| 70 |
+
if self.robot_model.supplemental_info is None:
|
| 71 |
+
raise ValueError("Robot model must have supplemental_info")
|
| 72 |
+
body_names = self.robot_model.supplemental_info.body_actuated_joints
|
| 73 |
+
body_indices = self.robot_model.get_joint_group_indices("body")
|
| 74 |
+
sorted_indices = np.argsort(body_indices)
|
| 75 |
+
sorted_names = [body_names[i] for i in sorted_indices]
|
| 76 |
+
return {self.robocasa_body_prefix + name: ii for ii, name in enumerate(sorted_names)}
|
| 77 |
+
|
| 78 |
+
def _get_gr00t_gripper_actuated_joint_name_to_index(
|
| 79 |
+
self,
|
| 80 |
+
) -> Tuple[Dict[str, int], Dict[str, int]]:
|
| 81 |
+
"""Get dictionary mapping gr00t actuated joint names to indices."""
|
| 82 |
+
if self.robot_model.supplemental_info is None:
|
| 83 |
+
raise ValueError("Robot model must have supplemental_info")
|
| 84 |
+
left_hand_names = self.robot_model.supplemental_info.left_hand_actuated_joints
|
| 85 |
+
right_hand_names = self.robot_model.supplemental_info.right_hand_actuated_joints
|
| 86 |
+
left_hand_indices = self.robot_model.get_joint_group_indices("left_hand")
|
| 87 |
+
right_hand_indices = self.robot_model.get_joint_group_indices("right_hand")
|
| 88 |
+
sorted_left_hand_indices = np.argsort(left_hand_indices)
|
| 89 |
+
sorted_right_hand_indices = np.argsort(right_hand_indices)
|
| 90 |
+
sorted_left_hand_names = [left_hand_names[i] for i in sorted_left_hand_indices]
|
| 91 |
+
sorted_right_hand_names = [right_hand_names[i] for i in sorted_right_hand_indices]
|
| 92 |
+
return (
|
| 93 |
+
{
|
| 94 |
+
self.robocasa_gripper_prefix + "left_" + name: ii
|
| 95 |
+
for ii, name in enumerate(sorted_left_hand_names)
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
self.robocasa_gripper_prefix + "right_" + name: ii
|
| 99 |
+
for ii, name in enumerate(sorted_right_hand_names)
|
| 100 |
+
},
|
| 101 |
+
)
|
| 102 |
+
|
| 103 |
+
def _get_gr00t_actuated_joint_name_to_index(self) -> Dict[str, int]:
|
| 104 |
+
"""Get dictionary mapping gr00t actuated joint names to indices."""
|
| 105 |
+
return {name: ii for ii, name in enumerate(self.actuated_joint_names)}
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
@dataclass
|
| 109 |
+
class Gr00tObsActionConverter:
|
| 110 |
+
"""
|
| 111 |
+
Converter to align simulation environment joint action space with real environment joint action space.
|
| 112 |
+
Handles joint order and range conversion.
|
| 113 |
+
"""
|
| 114 |
+
|
| 115 |
+
robot_model: RobotModel
|
| 116 |
+
robosuite_robot_model: RobosuiteRobotModel
|
| 117 |
+
robocasa_body_prefix: str = "robot0_"
|
| 118 |
+
robocasa_gripper_prefix: str = "gripper0_"
|
| 119 |
+
|
| 120 |
+
def __post_init__(self):
|
| 121 |
+
"""Initialize converter with robot configuration."""
|
| 122 |
+
|
| 123 |
+
self.robot_key = self.robot_model.supplemental_info.name
|
| 124 |
+
self.gr00t_joint_info = Gr00tJointInfo(self.robot_model)
|
| 125 |
+
self.robocasa_joint_names_for_each_part: Dict[str, List[str]] = (
|
| 126 |
+
self._get_robocasa_joint_names_for_each_part()
|
| 127 |
+
)
|
| 128 |
+
self.robocasa_actuator_names_for_each_part: Dict[str, List[str]] = (
|
| 129 |
+
self._get_robotcasa_actuator_names_for_each_part()
|
| 130 |
+
)
|
| 131 |
+
|
| 132 |
+
# Store mappings directly as class attributes
|
| 133 |
+
self.gr00t_joint_name_to_index = self.gr00t_joint_info.actuated_joint_name_to_index
|
| 134 |
+
self.gr00t_body_joint_name_to_index = self.gr00t_joint_info.body_actuated_joint_to_index
|
| 135 |
+
self.gr00t_gripper_joint_name_to_index = {
|
| 136 |
+
"left": self.gr00t_joint_info.gripper_actuated_joint_to_index[0],
|
| 137 |
+
"right": self.gr00t_joint_info.gripper_actuated_joint_to_index[1],
|
| 138 |
+
}
|
| 139 |
+
self.gr00t_to_robocasa_actuator_indices = self._get_actuator_mapping()
|
| 140 |
+
|
| 141 |
+
if self.robot_key == "GR1_Fourier":
|
| 142 |
+
self.joint_multiplier = (
|
| 143 |
+
lambda x: np.array([-1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1]) * x
|
| 144 |
+
)
|
| 145 |
+
self.actuator_multiplier = (
|
| 146 |
+
lambda x: np.array([-1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1]) * x
|
| 147 |
+
)
|
| 148 |
+
else:
|
| 149 |
+
self.joint_multiplier = lambda x: x
|
| 150 |
+
self.actuator_multiplier = lambda x: x
|
| 151 |
+
|
| 152 |
+
# Store DOF counts directly
|
| 153 |
+
self.body_dof = len(self.gr00t_joint_info.body_actuated_joint_names)
|
| 154 |
+
self.gripper_dof = len(self.gr00t_joint_info.left_hand_actuated_joint_names) + len(
|
| 155 |
+
self.gr00t_joint_info.right_hand_actuated_joint_names
|
| 156 |
+
)
|
| 157 |
+
self.whole_dof = self.body_dof + self.gripper_dof
|
| 158 |
+
self.body_nu = len(self.gr00t_joint_info.body_actuated_joint_names)
|
| 159 |
+
self.gripper_nu = len(self.gr00t_joint_info.left_hand_actuated_joint_names) + len(
|
| 160 |
+
self.gr00t_joint_info.right_hand_actuated_joint_names
|
| 161 |
+
)
|
| 162 |
+
self.whole_nu = self.body_nu + self.gripper_nu
|
| 163 |
+
|
| 164 |
+
def _get_robocasa_joint_names_for_each_part(self) -> Dict[str, List[str]]:
|
| 165 |
+
part_names = self.robosuite_robot_model._ref_joints_indexes_dict.keys()
|
| 166 |
+
robocasa_joint_names_for_each_part = {}
|
| 167 |
+
for part_name in part_names:
|
| 168 |
+
joint_indices = self.robosuite_robot_model._ref_joints_indexes_dict[part_name]
|
| 169 |
+
joint_names = [
|
| 170 |
+
self.robosuite_robot_model.sim.model.joint_id2name(j) for j in joint_indices
|
| 171 |
+
]
|
| 172 |
+
robocasa_joint_names_for_each_part[part_name] = joint_names
|
| 173 |
+
return robocasa_joint_names_for_each_part
|
| 174 |
+
|
| 175 |
+
def _get_robotcasa_actuator_names_for_each_part(self) -> Dict[str, List[str]]:
|
| 176 |
+
part_names = self.robosuite_robot_model._ref_actuators_indexes_dict.keys()
|
| 177 |
+
robocasa_actuator_names_for_each_part = {}
|
| 178 |
+
for part_name in part_names:
|
| 179 |
+
if part_name == "base":
|
| 180 |
+
continue
|
| 181 |
+
actuator_indices = self.robosuite_robot_model._ref_actuators_indexes_dict[part_name]
|
| 182 |
+
actuator_names = [
|
| 183 |
+
self.robosuite_robot_model.sim.model.actuator_id2name(j) for j in actuator_indices
|
| 184 |
+
]
|
| 185 |
+
robocasa_actuator_names_for_each_part[part_name] = actuator_names
|
| 186 |
+
return robocasa_actuator_names_for_each_part
|
| 187 |
+
|
| 188 |
+
def _get_actuator_mapping(self) -> Dict[str, List[int]]:
|
| 189 |
+
"""Get mapping from decoupled_wbc actuatored joint order to robocasa actuatored joint order for whole body."""
|
| 190 |
+
return {
|
| 191 |
+
part_name: [
|
| 192 |
+
self.gr00t_joint_info.actuated_joint_name_to_index[j]
|
| 193 |
+
for j in self.robocasa_actuator_names_for_each_part[part_name]
|
| 194 |
+
]
|
| 195 |
+
for part_name in self.robocasa_actuator_names_for_each_part.keys()
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
def check_action_dim_match(self, vec_dim: int) -> bool:
|
| 199 |
+
"""
|
| 200 |
+
Check if input vector dimension matches expected dimension.
|
| 201 |
+
|
| 202 |
+
Args:
|
| 203 |
+
vec_dim: Dimension of input vector
|
| 204 |
+
|
| 205 |
+
Returns:
|
| 206 |
+
bool: True if dimensions match
|
| 207 |
+
"""
|
| 208 |
+
return vec_dim == self.whole_dof
|
| 209 |
+
|
| 210 |
+
def gr00t_to_robocasa_action_dict(self, action_vec: np.ndarray) -> Dict[str, Any]:
|
| 211 |
+
"""
|
| 212 |
+
Convert gr00t flat action vector to robocasa dictionary mapping part names to actions.
|
| 213 |
+
|
| 214 |
+
Args:
|
| 215 |
+
robot: Robocasa robot model instance
|
| 216 |
+
action_vec: Full action vector array in gr00t actuated joint order
|
| 217 |
+
|
| 218 |
+
Returns:
|
| 219 |
+
dict: Mapping from part names to action vectors for robocasa
|
| 220 |
+
"""
|
| 221 |
+
if not self.check_action_dim_match(len(action_vec)):
|
| 222 |
+
raise ValueError(
|
| 223 |
+
f"Action vector dimension mismatch: {len(action_vec)} != {self.whole_dof}"
|
| 224 |
+
)
|
| 225 |
+
|
| 226 |
+
action_dict = {}
|
| 227 |
+
cc = self.robosuite_robot_model.composite_controller
|
| 228 |
+
|
| 229 |
+
for part_name, controller in cc.part_controllers.items():
|
| 230 |
+
if "gripper" in part_name:
|
| 231 |
+
robocasa_action = action_vec[self.gr00t_to_robocasa_actuator_indices[part_name]]
|
| 232 |
+
if self.actuator_multiplier is not None:
|
| 233 |
+
robocasa_action = self.actuator_multiplier(robocasa_action)
|
| 234 |
+
action_dict[part_name] = remove_mimic_joints(
|
| 235 |
+
cc.grippers[part_name], robocasa_action
|
| 236 |
+
)
|
| 237 |
+
elif "base" in part_name:
|
| 238 |
+
assert (
|
| 239 |
+
len(self.gr00t_to_robocasa_actuator_indices.get(part_name, [])) == 0
|
| 240 |
+
or self.robosuite_robot_model.default_base == "FloatingLeggedBase"
|
| 241 |
+
)
|
| 242 |
+
else:
|
| 243 |
+
action_dict[part_name] = action_vec[
|
| 244 |
+
self.gr00t_to_robocasa_actuator_indices[part_name]
|
| 245 |
+
]
|
| 246 |
+
|
| 247 |
+
return action_dict
|
| 248 |
+
|
| 249 |
+
def robocasa_to_gr00t_actuated_order(
|
| 250 |
+
self, joint_names: List[str], q: np.ndarray, obs_type: str = "body"
|
| 251 |
+
) -> np.ndarray:
|
| 252 |
+
"""
|
| 253 |
+
Convert observation from robocasa joint order to gr00t actuated joint order.
|
| 254 |
+
|
| 255 |
+
Args:
|
| 256 |
+
joint_names: List of joint names in robocasa order (with prefixes)
|
| 257 |
+
q: Joint positions corresponding to joint_names
|
| 258 |
+
obs_type: Type of observation ("body", "left_gripper", "right_gripper", or "whole")
|
| 259 |
+
|
| 260 |
+
Returns:
|
| 261 |
+
Joint positions in gr00t actuated joint order
|
| 262 |
+
"""
|
| 263 |
+
assert len(joint_names) == len(q), "Joint names and q must have the same length"
|
| 264 |
+
|
| 265 |
+
if obs_type == "body":
|
| 266 |
+
actuated_q = np.zeros(self.body_dof)
|
| 267 |
+
for i, jn in enumerate(joint_names):
|
| 268 |
+
actuated_q[self.gr00t_body_joint_name_to_index[jn]] = q[i]
|
| 269 |
+
elif obs_type == "left_gripper":
|
| 270 |
+
actuated_q = np.zeros(self.gripper_dof // 2)
|
| 271 |
+
for i, jn in enumerate(joint_names):
|
| 272 |
+
actuated_q[self.gr00t_gripper_joint_name_to_index["left"][jn]] = q[i]
|
| 273 |
+
elif obs_type == "right_gripper":
|
| 274 |
+
actuated_q = np.zeros(self.gripper_dof // 2)
|
| 275 |
+
for i, jn in enumerate(joint_names):
|
| 276 |
+
actuated_q[self.gr00t_gripper_joint_name_to_index["right"][jn]] = q[i]
|
| 277 |
+
elif obs_type == "whole":
|
| 278 |
+
actuated_q = np.zeros(self.whole_dof)
|
| 279 |
+
for i, jn in enumerate(joint_names):
|
| 280 |
+
actuated_q[self.gr00t_joint_name_to_index[jn]] = q[i]
|
| 281 |
+
else:
|
| 282 |
+
raise ValueError(f"Unknown observation type: {obs_type}")
|
| 283 |
+
return actuated_q
|
| 284 |
+
|
| 285 |
+
def gr00t_to_robocasa_joint_order(
|
| 286 |
+
self, joint_names: List[str], q_in_actuated_order: np.ndarray
|
| 287 |
+
) -> np.ndarray:
|
| 288 |
+
"""
|
| 289 |
+
Convert gr00t actuated joint order to robocasa joint order.
|
| 290 |
+
|
| 291 |
+
Args:
|
| 292 |
+
joint_names: List of joint names in robocasa order (with prefixes)
|
| 293 |
+
q_in_actuated_order: Joint positions corresponding to joint_names in gr00t actuated joint order
|
| 294 |
+
|
| 295 |
+
Returns:
|
| 296 |
+
Joint positions in robocasa joint order
|
| 297 |
+
"""
|
| 298 |
+
q = np.zeros(len(joint_names))
|
| 299 |
+
for i, jn in enumerate(joint_names):
|
| 300 |
+
q[i] = q_in_actuated_order[self.gr00t_joint_name_to_index[jn]]
|
| 301 |
+
return q
|
GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/sim_utils.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
try:
|
| 2 |
+
import robosuite.macros_private as macros
|
| 3 |
+
except ImportError:
|
| 4 |
+
import robosuite.macros as macros
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def change_simulation_timestep(timestep: float):
|
| 8 |
+
macros.SIMULATION_TIMESTEP = timestep
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/__init__.py
ADDED
|
File without changes
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/configs.py
ADDED
|
@@ -0,0 +1,483 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass
|
| 2 |
+
import os
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from typing import Literal, Optional
|
| 5 |
+
|
| 6 |
+
import yaml
|
| 7 |
+
|
| 8 |
+
import decoupled_wbc
|
| 9 |
+
from decoupled_wbc.control.main.config_template import ArgsConfig as ArgsConfigTemplate
|
| 10 |
+
from decoupled_wbc.control.policy.wbc_policy_factory import WBC_VERSIONS
|
| 11 |
+
from decoupled_wbc.control.utils.network_utils import resolve_interface
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def override_wbc_config(
|
| 15 |
+
wbc_config: dict, config: "BaseConfig", missed_keys_only: bool = False
|
| 16 |
+
) -> dict:
|
| 17 |
+
"""Override WBC YAML values with dataclass values.
|
| 18 |
+
|
| 19 |
+
Args:
|
| 20 |
+
wbc_config: The loaded WBC YAML configuration dictionary
|
| 21 |
+
config: The BaseConfig dataclass instance with override values
|
| 22 |
+
missed_keys_only: If True, only add keys that don't exist in wbc_config.
|
| 23 |
+
If False, validate all keys exist and override all.
|
| 24 |
+
|
| 25 |
+
Returns:
|
| 26 |
+
Updated wbc_config dictionary with overridden values
|
| 27 |
+
|
| 28 |
+
Raises:
|
| 29 |
+
KeyError: If any required keys are missing from the WBC YAML configuration
|
| 30 |
+
(only when missed_keys_only=False)
|
| 31 |
+
"""
|
| 32 |
+
# Override yaml values with dataclass values
|
| 33 |
+
key_to_value = {
|
| 34 |
+
"INTERFACE": config.interface,
|
| 35 |
+
"ENV_TYPE": config.env_type,
|
| 36 |
+
"VERSION": config.wbc_version,
|
| 37 |
+
"SIMULATOR": config.simulator,
|
| 38 |
+
"SIMULATE_DT": 1 / float(config.sim_frequency),
|
| 39 |
+
"ENABLE_OFFSCREEN": config.enable_offscreen,
|
| 40 |
+
"ENABLE_ONSCREEN": config.enable_onscreen,
|
| 41 |
+
"model_path": config.wbc_model_path,
|
| 42 |
+
"enable_waist": config.enable_waist,
|
| 43 |
+
"with_hands": config.with_hands,
|
| 44 |
+
"verbose": config.verbose,
|
| 45 |
+
"verbose_timing": config.verbose_timing,
|
| 46 |
+
"upper_body_max_joint_speed": config.upper_body_joint_speed,
|
| 47 |
+
"keyboard_dispatcher_type": config.keyboard_dispatcher_type,
|
| 48 |
+
"enable_gravity_compensation": config.enable_gravity_compensation,
|
| 49 |
+
"gravity_compensation_joints": config.gravity_compensation_joints,
|
| 50 |
+
"high_elbow_pose": config.high_elbow_pose,
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
if missed_keys_only:
|
| 54 |
+
# Only add keys that don't exist in wbc_config
|
| 55 |
+
for key in key_to_value:
|
| 56 |
+
if key not in wbc_config:
|
| 57 |
+
wbc_config[key] = key_to_value[key]
|
| 58 |
+
else:
|
| 59 |
+
# Set all keys (overwrite existing)
|
| 60 |
+
for key in key_to_value:
|
| 61 |
+
wbc_config[key] = key_to_value[key]
|
| 62 |
+
|
| 63 |
+
# g1 kp, kd, sim2real gap
|
| 64 |
+
if config.env_type == "real":
|
| 65 |
+
# update waist pitch damping, index 14
|
| 66 |
+
wbc_config["MOTOR_KD"][14] = wbc_config["MOTOR_KD"][14] - 10
|
| 67 |
+
|
| 68 |
+
return wbc_config
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
@dataclass
|
| 72 |
+
class BaseConfig(ArgsConfigTemplate):
|
| 73 |
+
"""Base config inherited by all G1 control loops"""
|
| 74 |
+
|
| 75 |
+
# WBC Configuration
|
| 76 |
+
wbc_version: Literal[tuple(WBC_VERSIONS)] = "gear_wbc"
|
| 77 |
+
"""Version of the whole body controller."""
|
| 78 |
+
|
| 79 |
+
wbc_model_path: str = (
|
| 80 |
+
"policy/GR00T-WholeBodyControl-Balance.onnx," "policy/GR00T-WholeBodyControl-Walk.onnx"
|
| 81 |
+
)
|
| 82 |
+
"""Path to WBC model file (relative to decoupled_wbc/sim2mujoco/resources/robots/g1)"""
|
| 83 |
+
"""gear_wbc model path: policy/GR00T-WholeBodyControl-Balance.onnx,policy/GR00T-WholeBodyControl-Walk.onnx"""
|
| 84 |
+
|
| 85 |
+
wbc_policy_class: str = "G1DecoupledWholeBodyPolicy"
|
| 86 |
+
"""Whole body policy class."""
|
| 87 |
+
|
| 88 |
+
# System Configuration
|
| 89 |
+
interface: str = "sim"
|
| 90 |
+
"""Interface to use for the control loop. [sim, real, lo, enxe8ea6a9c4e09]"""
|
| 91 |
+
|
| 92 |
+
simulator: str = "mujoco"
|
| 93 |
+
"""Simulator to use."""
|
| 94 |
+
|
| 95 |
+
sim_sync_mode: bool = False
|
| 96 |
+
"""Whether to run the control loop in sync mode."""
|
| 97 |
+
|
| 98 |
+
control_frequency: int = 50
|
| 99 |
+
"""Frequency of the control loop."""
|
| 100 |
+
|
| 101 |
+
sim_frequency: int = 200
|
| 102 |
+
"""Frequency of the simulation loop."""
|
| 103 |
+
|
| 104 |
+
# Robot Configuration
|
| 105 |
+
enable_waist: bool = False
|
| 106 |
+
"""Whether to include waist joints in IK."""
|
| 107 |
+
|
| 108 |
+
with_hands: bool = True
|
| 109 |
+
"""Enable hand functionality. When False, robot operates without hands."""
|
| 110 |
+
|
| 111 |
+
high_elbow_pose: bool = False
|
| 112 |
+
"""Enable high elbow pose configuration for default joint positions."""
|
| 113 |
+
|
| 114 |
+
verbose: bool = True
|
| 115 |
+
"""Whether to print verbose output."""
|
| 116 |
+
|
| 117 |
+
# Additional common fields
|
| 118 |
+
enable_offscreen: bool = False
|
| 119 |
+
"""Whether to enable offscreen rendering."""
|
| 120 |
+
|
| 121 |
+
enable_onscreen: bool = True
|
| 122 |
+
"""Whether to enable onscreen rendering."""
|
| 123 |
+
|
| 124 |
+
upper_body_joint_speed: float = 1000
|
| 125 |
+
"""Upper body joint speed."""
|
| 126 |
+
|
| 127 |
+
env_name: str = "default"
|
| 128 |
+
"""Environment name."""
|
| 129 |
+
|
| 130 |
+
ik_indicator: bool = False
|
| 131 |
+
"""Whether to draw IK indicators."""
|
| 132 |
+
|
| 133 |
+
verbose_timing: bool = False
|
| 134 |
+
"""Enable verbose timing output every iteration."""
|
| 135 |
+
|
| 136 |
+
keyboard_dispatcher_type: str = "raw"
|
| 137 |
+
"""Keyboard dispatcher to use. [raw, ros]"""
|
| 138 |
+
|
| 139 |
+
# Gravity Compensation Configuration
|
| 140 |
+
enable_gravity_compensation: bool = False
|
| 141 |
+
"""Enable gravity compensation using pinocchio dynamics."""
|
| 142 |
+
|
| 143 |
+
gravity_compensation_joints: Optional[list[str]] = None
|
| 144 |
+
"""Joint groups to apply gravity compensation to (e.g., ['arms', 'left_arm', 'right_arm'])."""
|
| 145 |
+
# Teleop/Device Configuration
|
| 146 |
+
body_control_device: str = "dummy"
|
| 147 |
+
"""Device to use for body control. Options: dummy, vive, iphone, leapmotion, joycon."""
|
| 148 |
+
|
| 149 |
+
hand_control_device: Optional[str] = "dummy"
|
| 150 |
+
"""Device to use for hand control. Options: None, manus, joycon, iphone."""
|
| 151 |
+
|
| 152 |
+
body_streamer_ip: str = "10.112.210.229"
|
| 153 |
+
"""IP address for body streamer (vive only)."""
|
| 154 |
+
|
| 155 |
+
body_streamer_keyword: str = "knee"
|
| 156 |
+
"""Body streamer keyword (vive only)."""
|
| 157 |
+
|
| 158 |
+
enable_visualization: bool = False
|
| 159 |
+
"""Whether to enable visualization."""
|
| 160 |
+
|
| 161 |
+
enable_real_device: bool = True
|
| 162 |
+
"""Whether to enable real device."""
|
| 163 |
+
|
| 164 |
+
teleop_frequency: int = 20
|
| 165 |
+
"""Teleoperation frequency (Hz)."""
|
| 166 |
+
|
| 167 |
+
teleop_replay_path: Optional[str] = None
|
| 168 |
+
"""Path to teleop replay data."""
|
| 169 |
+
|
| 170 |
+
# Deployment/Camera Configuration
|
| 171 |
+
robot_ip: str = "192.168.123.164"
|
| 172 |
+
"""Robot IP address"""
|
| 173 |
+
# Data collection settings
|
| 174 |
+
data_collection: bool = True
|
| 175 |
+
"""Enable data collection"""
|
| 176 |
+
|
| 177 |
+
data_collection_frequency: int = 20
|
| 178 |
+
"""Data collection frequency (Hz)"""
|
| 179 |
+
|
| 180 |
+
root_output_dir: str = "outputs"
|
| 181 |
+
"""Root output directory"""
|
| 182 |
+
|
| 183 |
+
# Policy settings
|
| 184 |
+
enable_upper_body_operation: bool = True
|
| 185 |
+
"""Enable upper body operation"""
|
| 186 |
+
|
| 187 |
+
upper_body_operation_mode: Literal["teleop", "inference"] = "teleop"
|
| 188 |
+
"""Upper body operation mode"""
|
| 189 |
+
|
| 190 |
+
def __post_init__(self):
|
| 191 |
+
# Resolve interface (handles sim/real shortcuts, platform differences, and error handling)
|
| 192 |
+
self.interface, self.env_type = resolve_interface(self.interface)
|
| 193 |
+
|
| 194 |
+
def load_wbc_yaml(self) -> dict:
|
| 195 |
+
"""Load and merge wbc yaml with dataclass overrides"""
|
| 196 |
+
# Get the base path to decoupled_wbc and convert to Path object
|
| 197 |
+
package_path = Path(os.path.dirname(decoupled_wbc.__file__))
|
| 198 |
+
|
| 199 |
+
if self.wbc_version == "gear_wbc":
|
| 200 |
+
config_path = str(package_path / "control/main/teleop/configs/g1_29dof_gear_wbc.yaml")
|
| 201 |
+
else:
|
| 202 |
+
raise ValueError(
|
| 203 |
+
f"Invalid wbc_version: {self.wbc_version}, please use one of: " f"gear_wbc"
|
| 204 |
+
)
|
| 205 |
+
|
| 206 |
+
with open(config_path) as file:
|
| 207 |
+
wbc_config = yaml.load(file, Loader=yaml.FullLoader)
|
| 208 |
+
|
| 209 |
+
# Override yaml values with dataclass values
|
| 210 |
+
wbc_config = override_wbc_config(wbc_config, self)
|
| 211 |
+
|
| 212 |
+
return wbc_config
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
@dataclass
|
| 216 |
+
class ControlLoopConfig(BaseConfig):
|
| 217 |
+
"""Config for running the G1 control loop."""
|
| 218 |
+
|
| 219 |
+
pass
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
@dataclass
|
| 223 |
+
class TeleopConfig(BaseConfig):
|
| 224 |
+
"""Config for running the G1 teleop policy loop."""
|
| 225 |
+
|
| 226 |
+
robot: Literal["g1"] = "g1"
|
| 227 |
+
"""Name of the robot to use, e.g., 'g1'."""
|
| 228 |
+
|
| 229 |
+
lerobot_replay_path: Optional[str] = None
|
| 230 |
+
"""Path to lerobot replay data."""
|
| 231 |
+
|
| 232 |
+
# Override defaults for teleop-specific values
|
| 233 |
+
body_streamer_ip: str = "10.110.67.24"
|
| 234 |
+
"""IP address for body streamer (vive only)."""
|
| 235 |
+
|
| 236 |
+
body_streamer_keyword: str = "foot"
|
| 237 |
+
"""Keyword for body streamer (vive only)."""
|
| 238 |
+
|
| 239 |
+
teleop_frequency: float = 20 # Override to be float instead of int
|
| 240 |
+
"""Frequency of the teleop loop."""
|
| 241 |
+
|
| 242 |
+
binary_hand_ik: bool = True
|
| 243 |
+
"""Whether to use binary IK."""
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
@dataclass
|
| 247 |
+
class ComposedCameraClientConfig:
|
| 248 |
+
"""Config for running the composed camera client."""
|
| 249 |
+
|
| 250 |
+
camera_port: int = 5555
|
| 251 |
+
"""Port number"""
|
| 252 |
+
|
| 253 |
+
camera_host: str = "localhost"
|
| 254 |
+
"""Host IP address"""
|
| 255 |
+
|
| 256 |
+
fps: float = 20.0
|
| 257 |
+
"""FPS of the camera viewer"""
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
@dataclass
|
| 261 |
+
class DataExporterConfig(BaseConfig, ComposedCameraClientConfig):
|
| 262 |
+
"""Config for running the G1 data exporter."""
|
| 263 |
+
|
| 264 |
+
dataset_name: Optional[str] = None
|
| 265 |
+
"""Name of the dataset to save the data to. If the dataset already exists,
|
| 266 |
+
the new episodes will be appended to existing dataset. If the dataset does not exist,
|
| 267 |
+
episodes will be saved under root_output_dir/dataset_name.
|
| 268 |
+
"""
|
| 269 |
+
|
| 270 |
+
task_prompt: str = "demo"
|
| 271 |
+
"""Language Task prompt for the dataset."""
|
| 272 |
+
|
| 273 |
+
state_dim: int = 43
|
| 274 |
+
"""Size of the state."""
|
| 275 |
+
|
| 276 |
+
action_dim: int = 43
|
| 277 |
+
"""Size of the action."""
|
| 278 |
+
|
| 279 |
+
teleoperator_username: Optional[str] = None
|
| 280 |
+
"""Teleoperator username."""
|
| 281 |
+
|
| 282 |
+
support_operator_username: Optional[str] = None
|
| 283 |
+
"""Support operator username."""
|
| 284 |
+
|
| 285 |
+
robot_id: Optional[str] = None
|
| 286 |
+
"""Robot ID."""
|
| 287 |
+
|
| 288 |
+
lower_body_policy: Optional[str] = None
|
| 289 |
+
"""Lower body policy."""
|
| 290 |
+
|
| 291 |
+
img_stream_viewer: bool = False
|
| 292 |
+
"""Whether to open a matplot lib window to view the camera images."""
|
| 293 |
+
|
| 294 |
+
text_to_speech: bool = True
|
| 295 |
+
"""Whether to use text-to-speech for voice feedback."""
|
| 296 |
+
|
| 297 |
+
add_stereo_camera: bool = True
|
| 298 |
+
"""Whether to add stereo camera for data collection. If False, only use a signle ego view camera."""
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
@dataclass
|
| 302 |
+
class SyncSimDataCollectionConfig(ControlLoopConfig, TeleopConfig):
|
| 303 |
+
"""Args Config for running the data collection loop."""
|
| 304 |
+
|
| 305 |
+
robot: str = "G1"
|
| 306 |
+
"""Name of the robot to collect data for (e.g., G1 variants)."""
|
| 307 |
+
|
| 308 |
+
task_name: str = "GroundOnly"
|
| 309 |
+
"""Name of the task to collect data for. [PnPBottle, GroundOnly, ...]"""
|
| 310 |
+
|
| 311 |
+
body_control_device: str = "dummy"
|
| 312 |
+
"""Device to use for body control. Options: dummy, vive, iphone, leapmotion, joycon."""
|
| 313 |
+
|
| 314 |
+
hand_control_device: Optional[str] = "dummy"
|
| 315 |
+
"""Device to use for hand control. Options: None, manus, joycon, iphone."""
|
| 316 |
+
|
| 317 |
+
remove_existing_dir: bool = False
|
| 318 |
+
"""Whether to remove existing output directory if it exists."""
|
| 319 |
+
|
| 320 |
+
hardcode_teleop_cmd: bool = False
|
| 321 |
+
"""Whether to hardcode the teleop command for testing purposes."""
|
| 322 |
+
|
| 323 |
+
ik_indicator: bool = False
|
| 324 |
+
"""Whether to draw IK indicators."""
|
| 325 |
+
|
| 326 |
+
enable_onscreen: bool = True
|
| 327 |
+
"""Whether to show the onscreen rendering."""
|
| 328 |
+
|
| 329 |
+
save_img_obs: bool = False
|
| 330 |
+
"""Whether to save image observations."""
|
| 331 |
+
|
| 332 |
+
success_hold_steps: int = 50
|
| 333 |
+
"""Number of steps to collect after task completion before saving."""
|
| 334 |
+
|
| 335 |
+
renderer: Literal["mjviewer", "mujoco", "rerun"] = "mjviewer"
|
| 336 |
+
"""Renderer to use for the environment. """
|
| 337 |
+
|
| 338 |
+
replay_data_path: str | None = None
|
| 339 |
+
"""Path to the data (.pkl) to replay. If None, will not replay. Used for CI/CD."""
|
| 340 |
+
|
| 341 |
+
replay_speed: float = 2.5
|
| 342 |
+
"""Speed multiplier for replay data. Higher values make replay slower (e.g., 2.5 for sync sim tests)."""
|
| 343 |
+
|
| 344 |
+
ci_test: bool = False
|
| 345 |
+
"""Whether to run the CI test."""
|
| 346 |
+
|
| 347 |
+
ci_test_mode: Literal["unit", "pre_merge"] = "pre_merge"
|
| 348 |
+
"""'unit' for fast 50-step tests, 'pre_merge' for 500-step test with tracking checks."""
|
| 349 |
+
|
| 350 |
+
manual_control: bool = False
|
| 351 |
+
"""Enable manual control of data collection start/save. When True, use toggle_data_collection
|
| 352 |
+
to manually control episode states (idle -> recording -> need_to_save -> idle).
|
| 353 |
+
When False (default), automatically starts and stops data collection based on task completion."""
|
| 354 |
+
|
| 355 |
+
|
| 356 |
+
@dataclass
|
| 357 |
+
class SyncSimPlaybackConfig(SyncSimDataCollectionConfig):
|
| 358 |
+
"""Configuration class for playback script arguments."""
|
| 359 |
+
|
| 360 |
+
enable_real_device: bool = False
|
| 361 |
+
"""Whether to enable real device"""
|
| 362 |
+
|
| 363 |
+
dataset: str | None = None
|
| 364 |
+
"""Path to the demonstration dataset, either an HDF5 file or a LeRobot folder path."""
|
| 365 |
+
|
| 366 |
+
use_actions: bool = False
|
| 367 |
+
"""Whether to use actions for playback"""
|
| 368 |
+
|
| 369 |
+
use_wbc_goals: bool = False
|
| 370 |
+
"""Whether to use WBC goals for control"""
|
| 371 |
+
|
| 372 |
+
use_teleop_cmd: bool = False
|
| 373 |
+
"""Whether to use teleop IK for action generation"""
|
| 374 |
+
|
| 375 |
+
# Video recording arguments.
|
| 376 |
+
# Warning: enabling this key will leads to divergence between playback and recording.
|
| 377 |
+
save_video: bool = False
|
| 378 |
+
"""Whether to save video of the playback"""
|
| 379 |
+
|
| 380 |
+
# Saving to LeRobot dataset.
|
| 381 |
+
# Warning: enabling this key will leads to divergence between playback and recording.
|
| 382 |
+
save_lerobot: bool = False
|
| 383 |
+
"""Whether to save the playback as a new LeRobot dataset"""
|
| 384 |
+
|
| 385 |
+
video_path: str | None = None
|
| 386 |
+
"""Path to save the output video. If not specified,
|
| 387 |
+
will use the nearest folder to dataset and save as playback_video.mp4"""
|
| 388 |
+
|
| 389 |
+
num_episodes: int = 1
|
| 390 |
+
"""Number of episodes to load and playback/record (loads only the first N episodes from dataset)"""
|
| 391 |
+
|
| 392 |
+
intervention: bool = False
|
| 393 |
+
"""Whether to denote intervention timesteps with colored borders in video frames"""
|
| 394 |
+
|
| 395 |
+
ci_test: bool = False
|
| 396 |
+
"""Whether this is a CI test run, which limits the number of steps for testing purposes"""
|
| 397 |
+
|
| 398 |
+
def validate_args(self):
|
| 399 |
+
# Validate argument combinations
|
| 400 |
+
if self.use_teleop_cmd and not self.use_actions:
|
| 401 |
+
raise ValueError("--use-teleop-cmd requires --use-actions to be set")
|
| 402 |
+
|
| 403 |
+
# Note: using teleop cmd has playback divergence unlike using wbc goals, as TeleopPolicy has a warmup loop
|
| 404 |
+
if self.use_teleop_cmd and self.use_wbc_goals:
|
| 405 |
+
raise ValueError("--use-teleop-cmd and --use-wbc-goals are mutually exclusive")
|
| 406 |
+
|
| 407 |
+
if (self.use_teleop_cmd or self.use_wbc_goals) and not self.use_actions:
|
| 408 |
+
raise ValueError(
|
| 409 |
+
"You are using --use-teleop-cmd or --use-wbc-goals but not --use-actions. "
|
| 410 |
+
"This will not play back actions whether via teleop or wbc goals. "
|
| 411 |
+
"Instead, it'll play back states only."
|
| 412 |
+
)
|
| 413 |
+
|
| 414 |
+
if self.save_img_obs and not self.save_lerobot:
|
| 415 |
+
raise ValueError("--save-img-obs is only supported with --save-lerobot")
|
| 416 |
+
|
| 417 |
+
if self.intervention and not self.save_video:
|
| 418 |
+
raise ValueError("--intervention requires --save-video to be enabled for visualization")
|
| 419 |
+
|
| 420 |
+
|
| 421 |
+
@dataclass
|
| 422 |
+
class WebcamRecorderConfig(BaseConfig):
|
| 423 |
+
"""Config for running the webcam recorder."""
|
| 424 |
+
|
| 425 |
+
output_dir: str = "logs_experiment"
|
| 426 |
+
"""Output directory for webcam recordings"""
|
| 427 |
+
|
| 428 |
+
device_id: int = 0
|
| 429 |
+
"""Camera device ID"""
|
| 430 |
+
|
| 431 |
+
fps: int = 30
|
| 432 |
+
"""Recording frame rate"""
|
| 433 |
+
|
| 434 |
+
duration: Optional[int] = None
|
| 435 |
+
"""Recording duration in seconds (None for continuous)"""
|
| 436 |
+
|
| 437 |
+
|
| 438 |
+
@dataclass
|
| 439 |
+
class SimLoopConfig(BaseConfig):
|
| 440 |
+
"""Config for running the simulation loop."""
|
| 441 |
+
|
| 442 |
+
mp_start_method: str = "spawn"
|
| 443 |
+
"""Multiprocessing start method"""
|
| 444 |
+
|
| 445 |
+
enable_image_publish: bool = False
|
| 446 |
+
"""Enable image publishing in simulation"""
|
| 447 |
+
|
| 448 |
+
camera_port: int = 5555
|
| 449 |
+
"""Camera port for image publishing"""
|
| 450 |
+
|
| 451 |
+
verbose: bool = False
|
| 452 |
+
"""Verbose output, override the base config verbose"""
|
| 453 |
+
|
| 454 |
+
|
| 455 |
+
@dataclass
|
| 456 |
+
class DeploymentConfig(BaseConfig, ComposedCameraClientConfig):
|
| 457 |
+
"""G1 Robot Deployment Configuration
|
| 458 |
+
|
| 459 |
+
Simplified deployment config that inherits all common fields from G1BaseConfig.
|
| 460 |
+
All deployment settings are now available in the base config.
|
| 461 |
+
"""
|
| 462 |
+
|
| 463 |
+
camera_publish_rate: float = 30.0
|
| 464 |
+
"""Camera publish rate (Hz)"""
|
| 465 |
+
|
| 466 |
+
view_camera: bool = True
|
| 467 |
+
"""Enable camera viewer"""
|
| 468 |
+
# Webcam recording settings
|
| 469 |
+
enable_webcam_recording: bool = True
|
| 470 |
+
"""Enable webcam recording for real robot deployment monitoring"""
|
| 471 |
+
|
| 472 |
+
webcam_output_dir: str = "logs_experiment"
|
| 473 |
+
"""Output directory for webcam recordings"""
|
| 474 |
+
|
| 475 |
+
skip_img_transform: bool = False
|
| 476 |
+
"""Skip image transformation in the model (for faster internet)"""
|
| 477 |
+
|
| 478 |
+
sim_in_single_process: bool = False
|
| 479 |
+
"""Run simulator in a separate process. When True, sets simulator to None in main control loop
|
| 480 |
+
and launches run_sim_loop.py separately."""
|
| 481 |
+
|
| 482 |
+
image_publish: bool = False
|
| 483 |
+
"""Enable image publishing in simulation loop (passed to run_sim_loop.py)"""
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/g1_29dof_gear_wbc.yaml
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
GEAR_WBC_CONFIG: "decoupled_wbc/sim2mujoco/resources/robots/g1/g1_gear_wbc.yaml"
|
| 2 |
+
|
| 3 |
+
# copy from g1_43dof_hist.yaml
|
| 4 |
+
ROBOT_TYPE: 'g1_29dof' # Robot name, "go2", "b2", "b2w", "h1", "go2w", "g1"
|
| 5 |
+
ROBOT_SCENE: "decoupled_wbc/control/robot_model/model_data/g1/scene_43dof.xml" # Robot scene, for Sim2Sim
|
| 6 |
+
# ROBOT_SCENE: "decoupled_wbc/control/robot_model/model_data/g1/scene_29dof_activated3dex.xml"
|
| 7 |
+
|
| 8 |
+
DOMAIN_ID: 0 # Domain id
|
| 9 |
+
# Network Interface, "lo" for simulation and the one with "192.168.123.222" for real robot
|
| 10 |
+
# INTERFACE: "enxe8ea6a9c4e09"
|
| 11 |
+
# INTERFACE: "enxc8a3623c9cb7"
|
| 12 |
+
INTERFACE: "lo"
|
| 13 |
+
SIMULATOR: "mujoco" # "robocasa"
|
| 14 |
+
|
| 15 |
+
USE_JOYSTICK: 0 # Simulate Unitree WirelessController using a gamepad (0: disable, 1: enable)
|
| 16 |
+
JOYSTICK_TYPE: "xbox" # support "xbox" and "switch" gamepad layout
|
| 17 |
+
JOYSTICK_DEVICE: 0 # Joystick number
|
| 18 |
+
|
| 19 |
+
FREE_BASE: False
|
| 20 |
+
|
| 21 |
+
PRINT_SCENE_INFORMATION: True # Print link, joint and sensors information of robot
|
| 22 |
+
ENABLE_ELASTIC_BAND: True # Virtual spring band, used for lifting h1
|
| 23 |
+
|
| 24 |
+
SIMULATE_DT: 0.005 # Need to be larger than the runtime of viewer.sync()
|
| 25 |
+
VIEWER_DT: 0.02 # Viewer update time
|
| 26 |
+
REWARD_DT: 0.02
|
| 27 |
+
USE_SENSOR: False
|
| 28 |
+
USE_HISTORY: True
|
| 29 |
+
USE_HISTORY_LOCO: True
|
| 30 |
+
USE_HISTORY_MIMIC: True
|
| 31 |
+
|
| 32 |
+
GAIT_PERIOD: 0.9 # 1.25
|
| 33 |
+
|
| 34 |
+
MOTOR2JOINT: [0, 1, 2, 3, 4, 5,
|
| 35 |
+
6, 7, 8, 9, 10, 11,
|
| 36 |
+
12, 13, 14,
|
| 37 |
+
15, 16, 17, 18, 19, 20, 21,
|
| 38 |
+
22, 23, 24, 25, 26, 27, 28]
|
| 39 |
+
|
| 40 |
+
JOINT2MOTOR: [0, 1, 2, 3, 4, 5,
|
| 41 |
+
6, 7, 8, 9, 10, 11,
|
| 42 |
+
12, 13, 14,
|
| 43 |
+
15, 16, 17, 18, 19, 20, 21,
|
| 44 |
+
22, 23, 24, 25, 26, 27, 28]
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
UNITREE_LEGGED_CONST:
|
| 48 |
+
HIGHLEVEL: 0xEE
|
| 49 |
+
LOWLEVEL: 0xFF
|
| 50 |
+
TRIGERLEVEL: 0xF0
|
| 51 |
+
PosStopF: 2146000000.0
|
| 52 |
+
VelStopF: 16000.0
|
| 53 |
+
MODE_MACHINE: 5
|
| 54 |
+
MODE_PR: 0
|
| 55 |
+
|
| 56 |
+
JOINT_KP: [
|
| 57 |
+
100, 100, 100, 200, 20, 20,
|
| 58 |
+
100, 100, 100, 200, 20, 20,
|
| 59 |
+
400, 400, 400,
|
| 60 |
+
90, 60, 20, 60, 4, 4, 4,
|
| 61 |
+
90, 60, 20, 60, 4, 4, 4
|
| 62 |
+
]
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
JOINT_KD: [
|
| 66 |
+
2.5, 2.5, 2.5, 5, 0.2, 0.1,
|
| 67 |
+
2.5, 2.5, 2.5, 5, 0.2, 0.1,
|
| 68 |
+
5.0, 5.0, 5.0,
|
| 69 |
+
2.0, 1.0, 0.4, 1.0, 0.2, 0.2, 0.2,
|
| 70 |
+
2.0, 1.0, 0.4, 1.0, 0.2, 0.2, 0.2
|
| 71 |
+
]
|
| 72 |
+
|
| 73 |
+
# arm kp
|
| 74 |
+
# soft kp, safe, test it first
|
| 75 |
+
# 50, 50, 20, 20, 10, 10, 10
|
| 76 |
+
# hard kp, use only if policy is safe
|
| 77 |
+
# 200, 200, 80, 80, 50, 50, 50,
|
| 78 |
+
|
| 79 |
+
# MOTOR_KP: [
|
| 80 |
+
# 100, 100, 100, 200, 20, 20,
|
| 81 |
+
# 100, 100, 100, 200, 20, 20,
|
| 82 |
+
# 400, 400, 400,
|
| 83 |
+
# 50, 50, 20, 20, 10, 10, 10,
|
| 84 |
+
# 50, 50, 20, 20, 10, 10, 10
|
| 85 |
+
# ]
|
| 86 |
+
|
| 87 |
+
MOTOR_KP: [
|
| 88 |
+
150, 150, 150, 200, 40, 40,
|
| 89 |
+
150, 150, 150, 200, 40, 40,
|
| 90 |
+
250, 250, 250,
|
| 91 |
+
100, 100, 40, 40, 20, 20, 20,
|
| 92 |
+
100, 100, 40, 40, 20, 20, 20
|
| 93 |
+
]
|
| 94 |
+
|
| 95 |
+
MOTOR_KD: [
|
| 96 |
+
2, 2, 2, 4, 2, 2,
|
| 97 |
+
2, 2, 2, 4, 2, 2,
|
| 98 |
+
5, 5, 5,
|
| 99 |
+
5, 5, 2, 2, 2, 2, 2,
|
| 100 |
+
5, 5, 2, 2, 2, 2, 2
|
| 101 |
+
]
|
| 102 |
+
|
| 103 |
+
# MOTOR_KP: [
|
| 104 |
+
# 100, 100, 100, 200, 20, 20,
|
| 105 |
+
# 100, 100, 100, 200, 20, 20,
|
| 106 |
+
# 400, 400, 400,
|
| 107 |
+
# 90, 60, 20, 60, 4, 4, 4,
|
| 108 |
+
# 90, 60, 20, 60, 4, 4, 4
|
| 109 |
+
# ]
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
# MOTOR_KD: [
|
| 113 |
+
# 2.5, 2.5, 2.5, 5, 0.2, 0.1,
|
| 114 |
+
# 2.5, 2.5, 2.5, 5, 0.2, 0.1,
|
| 115 |
+
# 5.0, 5.0, 5.0,
|
| 116 |
+
# 2.0, 1.0, 0.4, 1.0, 0.2, 0.2, 0.2,
|
| 117 |
+
# 2.0, 1.0, 0.4, 1.0, 0.2, 0.2, 0.2
|
| 118 |
+
# ]
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
WeakMotorJointIndex:
|
| 122 |
+
left_hip_yaw_joint: 0
|
| 123 |
+
left_hip_roll_joint: 1
|
| 124 |
+
left_hip_pitch_joint: 2
|
| 125 |
+
left_knee_joint: 3
|
| 126 |
+
left_ankle_pitch_joint: 4
|
| 127 |
+
left_ankle_roll_joint: 5
|
| 128 |
+
right_hip_yaw_joint: 6
|
| 129 |
+
right_hip_roll_joint: 7
|
| 130 |
+
right_hip_pitch_joint: 8
|
| 131 |
+
right_knee_joint: 9
|
| 132 |
+
right_ankle_pitch_joint: 10
|
| 133 |
+
right_ankle_roll_joint: 11
|
| 134 |
+
waist_yaw_joint : 12
|
| 135 |
+
waist_roll_joint : 13
|
| 136 |
+
waist_pitch_joint : 14
|
| 137 |
+
left_shoulder_pitch_joint: 15
|
| 138 |
+
left_shoulder_roll_joint: 16
|
| 139 |
+
left_shoulder_yaw_joint: 17
|
| 140 |
+
left_elbow_joint: 18
|
| 141 |
+
left_wrist_roll_joint: 19
|
| 142 |
+
left_wrist_pitch_joint: 20
|
| 143 |
+
left_wrist_yaw_joint: 21
|
| 144 |
+
right_shoulder_pitch_joint: 22
|
| 145 |
+
right_shoulder_roll_joint: 23
|
| 146 |
+
right_shoulder_yaw_joint: 24
|
| 147 |
+
right_elbow_joint: 25
|
| 148 |
+
right_wrist_roll_joint: 26
|
| 149 |
+
right_wrist_pitch_joint: 27
|
| 150 |
+
right_wrist_yaw_joint: 28
|
| 151 |
+
|
| 152 |
+
NUM_MOTORS: 29
|
| 153 |
+
NUM_JOINTS: 29
|
| 154 |
+
NUM_HAND_MOTORS: 7
|
| 155 |
+
NUM_HAND_JOINTS: 7
|
| 156 |
+
NUM_UPPER_BODY_JOINTS: 17
|
| 157 |
+
|
| 158 |
+
DEFAULT_DOF_ANGLES: [
|
| 159 |
+
-0.1, # left_hip_pitch_joint
|
| 160 |
+
0.0, # left_hip_roll_joint
|
| 161 |
+
0.0, # left_hip_yaw_joint
|
| 162 |
+
0.3, # left_knee_joint
|
| 163 |
+
-0.2, # left_ankle_pitch_joint
|
| 164 |
+
0.0, # left_ankle_roll_joint
|
| 165 |
+
-0.1, # right_hip_pitch_joint
|
| 166 |
+
0.0, # right_hip_roll_joint
|
| 167 |
+
0.0, # right_hip_yaw_joint
|
| 168 |
+
0.3, # right_knee_joint
|
| 169 |
+
-0.2, # right_ankle_pitch_joint
|
| 170 |
+
0.0, # right_ankle_roll_joint
|
| 171 |
+
0.0, # waist_yaw_joint
|
| 172 |
+
0.0, # waist_roll_joint
|
| 173 |
+
0.0, # waist_pitch_joint
|
| 174 |
+
0.0, # left_shoulder_pitch_joint
|
| 175 |
+
0.0, # left_shoulder_roll_joint
|
| 176 |
+
0.0, # left_shoulder_yaw_joint
|
| 177 |
+
0.0, # left_elbow_joint
|
| 178 |
+
0.0, # left_wrist_roll_joint
|
| 179 |
+
0.0, # left_wrist_pitch_joint
|
| 180 |
+
0.0, # left_wrist_yaw_joint
|
| 181 |
+
0.0, # right_shoulder_pitch_joint
|
| 182 |
+
0.0, # right_shoulder_roll_joint
|
| 183 |
+
0.0, # right_shoulder_yaw_joint
|
| 184 |
+
0.0, # right_elbow_joint
|
| 185 |
+
0.0, # right_wrist_roll_joint
|
| 186 |
+
0.0, # right_wrist_pitch_joint
|
| 187 |
+
0.0 # right_wrist_yaw_joint
|
| 188 |
+
]
|
| 189 |
+
|
| 190 |
+
DEFAULT_MOTOR_ANGLES: [
|
| 191 |
+
-0.1, # left_hip_pitch_joint
|
| 192 |
+
0.0, # left_hip_roll_joint
|
| 193 |
+
0.0, # left_hip_yaw_joint
|
| 194 |
+
0.3, # left_knee_joint
|
| 195 |
+
-0.2, # left_ankle_pitch_joint
|
| 196 |
+
0.0, # left_ankle_roll_joint
|
| 197 |
+
-0.1, # right_hip_pitch_joint
|
| 198 |
+
0.0, # right_hip_roll_joint
|
| 199 |
+
0.0, # right_hip_yaw_joint
|
| 200 |
+
0.3, # right_knee_joint
|
| 201 |
+
-0.2, # right_ankle_pitch_joint
|
| 202 |
+
0.0, # right_ankle_roll_joint
|
| 203 |
+
0.0, # waist_yaw_joint
|
| 204 |
+
0.0, # waist_roll_joint
|
| 205 |
+
0.0, # waist_pitch_joint
|
| 206 |
+
0.0, # left_shoulder_pitch_joint
|
| 207 |
+
0.0, # left_shoulder_roll_joint
|
| 208 |
+
0.0, # left_shoulder_yaw_joint
|
| 209 |
+
0.0, # left_elbow_joint
|
| 210 |
+
0.0, # left_wrist_roll_joint
|
| 211 |
+
0.0, # left_wrist_pitch_joint
|
| 212 |
+
0.0, # left_wrist_yaw_joint
|
| 213 |
+
0.0, # right_shoulder_pitch_joint
|
| 214 |
+
0.0, # right_shoulder_roll_joint
|
| 215 |
+
0.0, # right_shoulder_yaw_joint
|
| 216 |
+
0.0, # right_elbow_joint
|
| 217 |
+
0.0, # right_wrist_roll_joint
|
| 218 |
+
0.0, # right_wrist_pitch_joint
|
| 219 |
+
0.0 # right_wrist_yaw_joint
|
| 220 |
+
]
|
| 221 |
+
|
| 222 |
+
motor_pos_lower_limit_list: [-2.5307, -0.5236, -2.7576, -0.087267, -0.87267, -0.2618,
|
| 223 |
+
-2.5307, -2.9671, -2.7576, -0.087267, -0.87267, -0.2618,
|
| 224 |
+
-2.618, -0.52, -0.52,
|
| 225 |
+
-3.0892, -1.5882, -2.618, -1.0472,
|
| 226 |
+
-1.972222054, -1.61443, -1.61443,
|
| 227 |
+
-3.0892, -2.2515, -2.618, -1.0472,
|
| 228 |
+
-1.972222054, -1.61443, -1.61443]
|
| 229 |
+
motor_pos_upper_limit_list: [2.8798, 2.9671, 2.7576, 2.8798, 0.5236, 0.2618,
|
| 230 |
+
2.8798, 0.5236, 2.7576, 2.8798, 0.5236, 0.2618,
|
| 231 |
+
2.618, 0.52, 0.52,
|
| 232 |
+
2.6704, 2.2515, 2.618, 2.0944,
|
| 233 |
+
1.972222054, 1.61443, 1.61443,
|
| 234 |
+
2.6704, 1.5882, 2.618, 2.0944,
|
| 235 |
+
1.972222054, 1.61443, 1.61443]
|
| 236 |
+
motor_vel_limit_list: [32.0, 32.0, 32.0, 20.0, 37.0, 37.0,
|
| 237 |
+
32.0, 32.0, 32.0, 20.0, 37.0, 37.0,
|
| 238 |
+
32.0, 37.0, 37.0,
|
| 239 |
+
37.0, 37.0, 37.0, 37.0,
|
| 240 |
+
37.0, 22.0, 22.0,
|
| 241 |
+
37.0, 37.0, 37.0, 37.0,
|
| 242 |
+
37.0, 22.0, 22.0]
|
| 243 |
+
motor_effort_limit_list: [88.0, 88.0, 88.0, 139.0, 50.0, 50.0,
|
| 244 |
+
88.0, 88.0, 88.0, 139.0, 50.0, 50.0,
|
| 245 |
+
88.0, 50.0, 50.0,
|
| 246 |
+
25.0, 25.0, 25.0, 25.0,
|
| 247 |
+
25.0, 5.0, 5.0,
|
| 248 |
+
2.45, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7,
|
| 249 |
+
25.0, 25.0, 25.0, 25.0,
|
| 250 |
+
25.0, 5.0, 5.0,
|
| 251 |
+
2.45, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7]
|
| 252 |
+
history_config: {
|
| 253 |
+
base_ang_vel: 4,
|
| 254 |
+
projected_gravity: 4,
|
| 255 |
+
command_lin_vel: 4,
|
| 256 |
+
command_ang_vel: 4,
|
| 257 |
+
command_base_height: 4,
|
| 258 |
+
command_stand: 4,
|
| 259 |
+
ref_upper_dof_pos: 4,
|
| 260 |
+
dof_pos: 4,
|
| 261 |
+
dof_vel: 4,
|
| 262 |
+
actions: 4,
|
| 263 |
+
# phase_time: 4,
|
| 264 |
+
ref_motion_phase: 4,
|
| 265 |
+
sin_phase: 4,
|
| 266 |
+
cos_phase: 4
|
| 267 |
+
}
|
| 268 |
+
history_loco_config: {
|
| 269 |
+
base_ang_vel: 4,
|
| 270 |
+
projected_gravity: 4,
|
| 271 |
+
command_lin_vel: 4,
|
| 272 |
+
command_ang_vel: 4,
|
| 273 |
+
# command_base_height: 4,
|
| 274 |
+
command_stand: 4,
|
| 275 |
+
ref_upper_dof_pos: 4,
|
| 276 |
+
dof_pos: 4,
|
| 277 |
+
dof_vel: 4,
|
| 278 |
+
actions: 4,
|
| 279 |
+
# phase_time: 4,
|
| 280 |
+
sin_phase: 4,
|
| 281 |
+
cos_phase: 4
|
| 282 |
+
}
|
| 283 |
+
history_loco_height_config: {
|
| 284 |
+
base_ang_vel: 4,
|
| 285 |
+
projected_gravity: 4,
|
| 286 |
+
command_lin_vel: 4,
|
| 287 |
+
command_ang_vel: 4,
|
| 288 |
+
command_base_height: 4,
|
| 289 |
+
command_stand: 4,
|
| 290 |
+
ref_upper_dof_pos: 4,
|
| 291 |
+
dof_pos: 4,
|
| 292 |
+
dof_vel: 4,
|
| 293 |
+
actions: 4,
|
| 294 |
+
# phase_time: 4,
|
| 295 |
+
sin_phase: 4,
|
| 296 |
+
cos_phase: 4
|
| 297 |
+
}
|
| 298 |
+
history_mimic_config: {
|
| 299 |
+
base_ang_vel: 4,
|
| 300 |
+
projected_gravity: 4,
|
| 301 |
+
dof_pos: 4,
|
| 302 |
+
dof_vel: 4,
|
| 303 |
+
actions: 4,
|
| 304 |
+
ref_motion_phase: 4,
|
| 305 |
+
}
|
| 306 |
+
obs_dims: {
|
| 307 |
+
base_lin_vel: 3,
|
| 308 |
+
base_ang_vel: 3,
|
| 309 |
+
projected_gravity: 3,
|
| 310 |
+
command_lin_vel: 2,
|
| 311 |
+
command_ang_vel: 1,
|
| 312 |
+
command_stand: 1,
|
| 313 |
+
command_base_height: 1,
|
| 314 |
+
ref_upper_dof_pos: 17, # upper body actions
|
| 315 |
+
dof_pos: 29,
|
| 316 |
+
dof_vel: 29,
|
| 317 |
+
# actions: 12, # lower body actions
|
| 318 |
+
actions: 29, # full body actions
|
| 319 |
+
phase_time: 1,
|
| 320 |
+
ref_motion_phase: 1, # mimic motion phase
|
| 321 |
+
sin_phase: 1,
|
| 322 |
+
cos_phase: 1,
|
| 323 |
+
}
|
| 324 |
+
obs_loco_dims: {
|
| 325 |
+
base_lin_vel: 3,
|
| 326 |
+
base_ang_vel: 3,
|
| 327 |
+
projected_gravity: 3,
|
| 328 |
+
command_lin_vel: 2,
|
| 329 |
+
command_ang_vel: 1,
|
| 330 |
+
command_stand: 1,
|
| 331 |
+
command_base_height: 1,
|
| 332 |
+
ref_upper_dof_pos: 17, # upper body actions
|
| 333 |
+
dof_pos: 29,
|
| 334 |
+
dof_vel: 29,
|
| 335 |
+
actions: 12, # lower body actions
|
| 336 |
+
phase_time: 1,
|
| 337 |
+
sin_phase: 1,
|
| 338 |
+
cos_phase: 1,
|
| 339 |
+
}
|
| 340 |
+
obs_mimic_dims: {
|
| 341 |
+
base_lin_vel: 3,
|
| 342 |
+
base_ang_vel: 3,
|
| 343 |
+
projected_gravity: 3,
|
| 344 |
+
dof_pos: 29,
|
| 345 |
+
dof_vel: 29,
|
| 346 |
+
actions: 29, # full body actions
|
| 347 |
+
ref_motion_phase: 1, # mimic motion phase
|
| 348 |
+
}
|
| 349 |
+
obs_scales: {
|
| 350 |
+
base_lin_vel: 2.0,
|
| 351 |
+
base_ang_vel: 0.25,
|
| 352 |
+
projected_gravity: 1.0,
|
| 353 |
+
command_lin_vel: 1,
|
| 354 |
+
command_ang_vel: 1,
|
| 355 |
+
command_stand: 1,
|
| 356 |
+
command_base_height: 2, # Yuanhang: it's 2, not 1!
|
| 357 |
+
ref_upper_dof_pos: 1.0,
|
| 358 |
+
dof_pos: 1.0,
|
| 359 |
+
dof_vel: 0.05,
|
| 360 |
+
history: 1.0,
|
| 361 |
+
history_loco: 1.0,
|
| 362 |
+
history_mimic: 1.0,
|
| 363 |
+
actions: 1.0,
|
| 364 |
+
phase_time: 1.0,
|
| 365 |
+
ref_motion_phase: 1.0,
|
| 366 |
+
sin_phase: 1.0,
|
| 367 |
+
cos_phase: 1.0
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
loco_upper_body_dof_pos: [
|
| 371 |
+
0.0, 0.0, 0.0, # waist
|
| 372 |
+
0.0, 0.3, 0.0, 1.0, # left shoulder and elbow
|
| 373 |
+
0.0, 0.0, 0.0, # left wrist
|
| 374 |
+
0.0, -0.3, 0.0, 1.0, # right shoulder and elbow
|
| 375 |
+
0.0, 0.0, 0.0 # right wrist
|
| 376 |
+
]
|
| 377 |
+
|
| 378 |
+
robot_dofs: {
|
| 379 |
+
"g1_29dof": [1, 1, 1, 1, 1, 1,
|
| 380 |
+
1, 1, 1, 1, 1, 1,
|
| 381 |
+
1, 1, 1,
|
| 382 |
+
1, 1, 1, 1, 1, 1, 1,
|
| 383 |
+
1, 1, 1, 1, 1, 1, 1],
|
| 384 |
+
"g1_29dof_anneal_23dof": [1, 1, 1, 1, 1, 1,
|
| 385 |
+
1, 1, 1, 1, 1, 1,
|
| 386 |
+
1, 1, 1,
|
| 387 |
+
1, 1, 1, 1, 0, 0, 0,
|
| 388 |
+
1, 1, 1, 1, 0, 0, 0],
|
| 389 |
+
}
|
| 390 |
+
|
| 391 |
+
mimic_robot_types: {
|
| 392 |
+
|
| 393 |
+
"APT_level1": "g1_29dof_anneal_23dof",
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
# 01281657
|
| 400 |
+
mimic_models: {
|
| 401 |
+
"APT_level1": "20250116_225127-TairanTestbed_G129dofANNEAL23dof_dm_APT_video_APT_level1_MinimalFriction-0.3_RfiTrue_Far0.325_RESUME_LARGENOISE-motion_tracking-g1_29dof_anneal_23dof/exported/model_176500.onnx",
|
| 402 |
+
|
| 403 |
+
}
|
| 404 |
+
|
| 405 |
+
|
| 406 |
+
|
| 407 |
+
start_upper_body_dof_pos: {
|
| 408 |
+
|
| 409 |
+
"APT_level1":
|
| 410 |
+
[0.19964170455932617, 0.07710712403059006, -0.2882401943206787,
|
| 411 |
+
0.21672365069389343, 0.15629297494888306, -0.5167576670646667, 0.5782126784324646,
|
| 412 |
+
0.0, 0.0, 0.0,
|
| 413 |
+
0.25740593671798706, -0.2504104673862457, 0.22500675916671753, 0.5127624273300171,
|
| 414 |
+
0.0, 0.0, 0.0],
|
| 415 |
+
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
motion_length_s: {
|
| 419 |
+
"APT_level1": 7.66,
|
| 420 |
+
|
| 421 |
+
}
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/g1_gear_wbc.yaml
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
# Simulation parameters
|
| 3 |
+
simulation_duration: 60.0
|
| 4 |
+
simulation_dt: 0.002
|
| 5 |
+
control_decimation: 10
|
| 6 |
+
|
| 7 |
+
# PD gains
|
| 8 |
+
kps: [
|
| 9 |
+
150, 150, 150, 300, 40, 40,
|
| 10 |
+
150, 150, 150, 300, 40, 40,
|
| 11 |
+
250, 250, 250,
|
| 12 |
+
100, 100, 40, 40, 20, 20, 20,
|
| 13 |
+
100, 100, 40, 40, 20, 20, 20
|
| 14 |
+
]
|
| 15 |
+
kds: [
|
| 16 |
+
2, 2, 2, 4, 2, 2,
|
| 17 |
+
2, 2, 2, 4, 2, 2,
|
| 18 |
+
5, 5, 5,
|
| 19 |
+
5, 5, 2, 2, 2, 2, 2,
|
| 20 |
+
5, 5, 2, 2, 2, 2, 2
|
| 21 |
+
]
|
| 22 |
+
|
| 23 |
+
# Default joint angles for legs
|
| 24 |
+
default_angles: [-0.1, 0.0, 0.0, 0.3, -0.2, 0.0,
|
| 25 |
+
-0.1, 0.0, 0.0, 0.3, -0.2, 0.0,
|
| 26 |
+
0.0, 0.0, 0.0]
|
| 27 |
+
# Scaling factors
|
| 28 |
+
ang_vel_scale: 0.25
|
| 29 |
+
dof_pos_scale: 1.0
|
| 30 |
+
dof_vel_scale: 0.05
|
| 31 |
+
action_scale: 0.25
|
| 32 |
+
cmd_scale: [2.0, 2.0, 0.25]
|
| 33 |
+
|
| 34 |
+
# Number of actions and observations
|
| 35 |
+
num_actions: 15
|
| 36 |
+
num_obs: 570 # 76 * 6 (observation dimension * history length)
|
| 37 |
+
obs_history_len: 6
|
| 38 |
+
|
| 39 |
+
# Initial commands
|
| 40 |
+
cmd_init: [0.0, 0.0, 0.0]
|
| 41 |
+
height_cmd: 0.74
|
| 42 |
+
freq_cmd: 1.50
|
| 43 |
+
roll_cmd: 0.0
|
| 44 |
+
pitch_cmd: 0.0
|
| 45 |
+
yaw_cmd: 0.0
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/identifiers.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Constants required during data collection, such as operator usernames and robot IDs.
|
| 3 |
+
Additional constants needed for data collection can be added to this file.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
OPERATOR_USERNAMES = [
|
| 7 |
+
"NEW_USER",
|
| 8 |
+
]
|
| 9 |
+
|
| 10 |
+
G1_ROBOT_IDS = [
|
| 11 |
+
"sim",
|
| 12 |
+
"0001",
|
| 13 |
+
"0002",
|
| 14 |
+
]
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/playback_sync_sim_data.py
ADDED
|
@@ -0,0 +1,627 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
A convenience script to playback random demonstrations using the decoupled_wbc controller from
|
| 3 |
+
a set of demonstrations stored in a hdf5 file.
|
| 4 |
+
|
| 5 |
+
Arguments:
|
| 6 |
+
--dataset (str): Path to demonstrations
|
| 7 |
+
--use-actions (optional): If this flag is provided, the actions are played back
|
| 8 |
+
through the MuJoCo simulator, instead of loading the simulator states
|
| 9 |
+
one by one.
|
| 10 |
+
--use-wbc-goals (optional): If set, will use the stored WBC goals to control the robot,
|
| 11 |
+
otherwise will use the actions directly. Only relevant if --use-actions is set.
|
| 12 |
+
--use-teleop-cmd (optional): If set, will use teleop IK directly with WBC timing
|
| 13 |
+
for action generation. Only relevant if --use-actions is set.
|
| 14 |
+
--visualize-gripper (optional): If set, will visualize the gripper site
|
| 15 |
+
--save-video (optional): If set, will save video of the playback using offscreen rendering
|
| 16 |
+
--video-path (optional): Path to save the output video. If not specified, will use the nearest
|
| 17 |
+
folder to dataset and save as playback_video.mp4
|
| 18 |
+
--num-episodes (optional): Number of episodes to playback/record (if None, plays random episodes)
|
| 19 |
+
|
| 20 |
+
Example:
|
| 21 |
+
$ python decoupled_wbc/control/main/teleop/playback_sync_sim_data.py --dataset output/robocasa_datasets/
|
| 22 |
+
--use-actions --use-wbc-goals
|
| 23 |
+
|
| 24 |
+
$ python decoupled_wbc/control/main/teleop/playback_sync_sim_data.py --dataset output/robocasa_datasets/
|
| 25 |
+
--use-actions --use-teleop-cmd
|
| 26 |
+
|
| 27 |
+
# Record video of the first 5 episodes using WBC goals
|
| 28 |
+
$ python decoupled_wbc/control/main/teleop/playback_sync_sim_data.py --dataset output/robocasa_datasets/
|
| 29 |
+
--use-actions --use-wbc-goals --save-video --num-episodes 5
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
import json
|
| 33 |
+
import os
|
| 34 |
+
from pathlib import Path
|
| 35 |
+
import time
|
| 36 |
+
from typing import Optional
|
| 37 |
+
|
| 38 |
+
import cv2
|
| 39 |
+
import numpy as np
|
| 40 |
+
import rclpy
|
| 41 |
+
from robosuite.environments.robot_env import RobotEnv
|
| 42 |
+
from tqdm import tqdm
|
| 43 |
+
import tyro
|
| 44 |
+
|
| 45 |
+
from decoupled_wbc.control.main.teleop.configs.configs import SyncSimPlaybackConfig
|
| 46 |
+
from decoupled_wbc.control.robot_model.instantiation import get_robot_type_and_model
|
| 47 |
+
from decoupled_wbc.control.utils.sync_sim_utils import (
|
| 48 |
+
generate_frame,
|
| 49 |
+
get_data_exporter,
|
| 50 |
+
get_env,
|
| 51 |
+
get_policies,
|
| 52 |
+
)
|
| 53 |
+
from decoupled_wbc.data.constants import RS_VIEW_CAMERA_HEIGHT, RS_VIEW_CAMERA_WIDTH
|
| 54 |
+
from decoupled_wbc.data.exporter import TypedLeRobotDataset
|
| 55 |
+
|
| 56 |
+
CONTROL_NODE_NAME = "playback_node"
|
| 57 |
+
GREEN_BOLD = "\033[1;32m"
|
| 58 |
+
RED_BOLD = "\033[1;31m"
|
| 59 |
+
RESET = "\033[0m"
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def load_lerobot_dataset(root_path, max_episodes=None):
|
| 63 |
+
task_name = None
|
| 64 |
+
episodes = []
|
| 65 |
+
start_index = 0
|
| 66 |
+
with open(Path(root_path) / "meta/episodes.jsonl", "r") as f:
|
| 67 |
+
for line in f:
|
| 68 |
+
episode = json.loads(line)
|
| 69 |
+
episode["start_index"] = start_index
|
| 70 |
+
start_index += episode["length"]
|
| 71 |
+
assert (
|
| 72 |
+
task_name is None or task_name == episode["tasks"][0]
|
| 73 |
+
), "All episodes should have the same task name"
|
| 74 |
+
task_name = episode["tasks"][0]
|
| 75 |
+
episodes.append(episode)
|
| 76 |
+
|
| 77 |
+
dataset = TypedLeRobotDataset(
|
| 78 |
+
repo_id="tmp/test",
|
| 79 |
+
root=root_path,
|
| 80 |
+
load_video=False,
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
script_config = dataset.meta.info["script_config"]
|
| 84 |
+
|
| 85 |
+
assert len(dataset) == start_index, "Dataset length does not match expected length"
|
| 86 |
+
|
| 87 |
+
# Limit episodes if specified
|
| 88 |
+
if max_episodes is not None:
|
| 89 |
+
episodes = episodes[:max_episodes]
|
| 90 |
+
print(
|
| 91 |
+
f"Loading only first {len(episodes)} episodes (limited by max_episodes={max_episodes})"
|
| 92 |
+
)
|
| 93 |
+
|
| 94 |
+
f = {}
|
| 95 |
+
seeds = []
|
| 96 |
+
for ep in tqdm(range(len(episodes))):
|
| 97 |
+
seed = None
|
| 98 |
+
f[f"data/demo_{ep + 1}/states"] = []
|
| 99 |
+
f[f"data/demo_{ep + 1}/actions"] = []
|
| 100 |
+
f[f"data/demo_{ep + 1}/teleop_cmd"] = []
|
| 101 |
+
f[f"data/demo_{ep + 1}/wbc_goal"] = []
|
| 102 |
+
start_index = episodes[ep]["start_index"]
|
| 103 |
+
end_index = start_index + episodes[ep]["length"]
|
| 104 |
+
for i in tqdm(range(start_index, end_index)):
|
| 105 |
+
frame = dataset[i]
|
| 106 |
+
# load the seed
|
| 107 |
+
assert (
|
| 108 |
+
seed is None or seed == np.array(frame["observation.sim.seed"]).item()
|
| 109 |
+
), "All observations in an episode should have the same seed"
|
| 110 |
+
seed = np.array(frame["observation.sim.seed"]).item()
|
| 111 |
+
# load the state
|
| 112 |
+
mujoco_state_len = frame["observation.sim.mujoco_state_len"]
|
| 113 |
+
mujoco_state = frame["observation.sim.mujoco_state"]
|
| 114 |
+
f[f"data/demo_{ep + 1}/states"].append(np.array(mujoco_state[:mujoco_state_len]))
|
| 115 |
+
# load the action
|
| 116 |
+
action = frame["action"]
|
| 117 |
+
f[f"data/demo_{ep + 1}/actions"].append(np.array(action))
|
| 118 |
+
|
| 119 |
+
# load the teleop command
|
| 120 |
+
teleop_cmd = {
|
| 121 |
+
"left_wrist": np.array(frame["observation.sim.left_wrist"].reshape(4, 4)),
|
| 122 |
+
"right_wrist": np.array(frame["observation.sim.right_wrist"].reshape(4, 4)),
|
| 123 |
+
"left_fingers": {
|
| 124 |
+
"position": np.array(frame["observation.sim.left_fingers"].reshape(25, 4, 4)),
|
| 125 |
+
},
|
| 126 |
+
"right_fingers": {
|
| 127 |
+
"position": np.array(frame["observation.sim.right_fingers"].reshape(25, 4, 4)),
|
| 128 |
+
},
|
| 129 |
+
"target_upper_body_pose": np.array(frame["observation.sim.target_upper_body_pose"]),
|
| 130 |
+
"base_height_command": np.array(frame["teleop.base_height_command"]),
|
| 131 |
+
"navigate_cmd": np.array(frame["teleop.navigate_command"]),
|
| 132 |
+
}
|
| 133 |
+
f[f"data/demo_{ep + 1}/teleop_cmd"].append(teleop_cmd)
|
| 134 |
+
# load the WBC goal
|
| 135 |
+
wbc_goal = {
|
| 136 |
+
"wrist_pose": np.array(frame["action.eef"]),
|
| 137 |
+
"target_upper_body_pose": np.array(frame["observation.sim.target_upper_body_pose"]),
|
| 138 |
+
"navigate_cmd": np.array(frame["teleop.navigate_command"]),
|
| 139 |
+
"base_height_command": np.array(frame["teleop.base_height_command"]),
|
| 140 |
+
}
|
| 141 |
+
f[f"data/demo_{ep + 1}/wbc_goal"].append(wbc_goal)
|
| 142 |
+
|
| 143 |
+
seeds.append(seed)
|
| 144 |
+
|
| 145 |
+
return seeds, f, script_config
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
def validate_state(recorded_state, playback_state, ep, step, tolerance=1e-5):
|
| 149 |
+
"""Validate that playback state matches recorded state within tolerance."""
|
| 150 |
+
if not np.allclose(recorded_state, playback_state, atol=tolerance):
|
| 151 |
+
err = np.linalg.norm(recorded_state - playback_state)
|
| 152 |
+
print(f"[warning] state diverged by {err:.12f} for ep {ep} at step {step}")
|
| 153 |
+
return False
|
| 154 |
+
return True
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def generate_and_save_frame(
|
| 158 |
+
config, sync_env, obs, wbc_action, seed, teleop_cmd, wbc_goal, gr00t_exporter
|
| 159 |
+
):
|
| 160 |
+
"""Generate and save a frame to LeRobot dataset if enabled."""
|
| 161 |
+
if config.save_lerobot:
|
| 162 |
+
max_mujoco_state_len, mujoco_state_len, mujoco_state = sync_env.get_mujoco_state_info()
|
| 163 |
+
frame = generate_frame(
|
| 164 |
+
obs,
|
| 165 |
+
wbc_action,
|
| 166 |
+
seed,
|
| 167 |
+
mujoco_state,
|
| 168 |
+
mujoco_state_len,
|
| 169 |
+
max_mujoco_state_len,
|
| 170 |
+
teleop_cmd,
|
| 171 |
+
wbc_goal,
|
| 172 |
+
config.save_img_obs,
|
| 173 |
+
)
|
| 174 |
+
gr00t_exporter.add_frame(frame)
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def playback_wbc_goals(
|
| 178 |
+
sync_env,
|
| 179 |
+
wbc_policy,
|
| 180 |
+
wbc_goals,
|
| 181 |
+
teleop_cmds,
|
| 182 |
+
states,
|
| 183 |
+
env,
|
| 184 |
+
onscreen,
|
| 185 |
+
config,
|
| 186 |
+
video_writer,
|
| 187 |
+
ep,
|
| 188 |
+
seed,
|
| 189 |
+
gr00t_exporter,
|
| 190 |
+
end_steps,
|
| 191 |
+
):
|
| 192 |
+
"""Playback using WBC goals to control the robot."""
|
| 193 |
+
ret = True
|
| 194 |
+
num_wbc_goals = len(wbc_goals) if end_steps == -1 else min(end_steps, len(wbc_goals))
|
| 195 |
+
|
| 196 |
+
for jj in range(num_wbc_goals):
|
| 197 |
+
wbc_goal = wbc_goals[jj]
|
| 198 |
+
obs = sync_env.observe()
|
| 199 |
+
wbc_policy.set_observation(obs)
|
| 200 |
+
wbc_policy.set_goal(wbc_goal)
|
| 201 |
+
wbc_action = wbc_policy.get_action()
|
| 202 |
+
sync_env.queue_action(wbc_action)
|
| 203 |
+
|
| 204 |
+
# Save frame if needed
|
| 205 |
+
if config.save_lerobot:
|
| 206 |
+
teleop_cmd = teleop_cmds[jj]
|
| 207 |
+
generate_and_save_frame(
|
| 208 |
+
config, sync_env, obs, wbc_action, seed, teleop_cmd, wbc_goal, gr00t_exporter
|
| 209 |
+
)
|
| 210 |
+
|
| 211 |
+
capture_or_render_frame(env, onscreen, config, video_writer)
|
| 212 |
+
|
| 213 |
+
if jj < len(states) - 1:
|
| 214 |
+
state_playback = env.sim.get_state().flatten()
|
| 215 |
+
if not validate_state(states[jj + 1], state_playback, ep, jj):
|
| 216 |
+
ret = False
|
| 217 |
+
|
| 218 |
+
return ret
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
def playback_teleop_cmd(
|
| 222 |
+
sync_env,
|
| 223 |
+
wbc_policy,
|
| 224 |
+
teleop_policy,
|
| 225 |
+
wbc_goals,
|
| 226 |
+
teleop_cmds,
|
| 227 |
+
states,
|
| 228 |
+
env,
|
| 229 |
+
onscreen,
|
| 230 |
+
config,
|
| 231 |
+
video_writer,
|
| 232 |
+
ep,
|
| 233 |
+
seed,
|
| 234 |
+
gr00t_exporter,
|
| 235 |
+
end_steps,
|
| 236 |
+
):
|
| 237 |
+
"""Playback using teleop commands to control the robot."""
|
| 238 |
+
ret = True
|
| 239 |
+
num_steps = len(wbc_goals) if end_steps == -1 else min(end_steps, len(wbc_goals))
|
| 240 |
+
|
| 241 |
+
for jj in range(num_steps):
|
| 242 |
+
wbc_goal = wbc_goals[jj]
|
| 243 |
+
teleop_cmd = teleop_cmds[jj]
|
| 244 |
+
|
| 245 |
+
# Set IK goal from teleop command
|
| 246 |
+
ik_data = {
|
| 247 |
+
"body_data": {
|
| 248 |
+
teleop_policy.retargeting_ik.body.supplemental_info.hand_frame_names[
|
| 249 |
+
"left"
|
| 250 |
+
]: teleop_cmd["left_wrist"],
|
| 251 |
+
teleop_policy.retargeting_ik.body.supplemental_info.hand_frame_names[
|
| 252 |
+
"right"
|
| 253 |
+
]: teleop_cmd["right_wrist"],
|
| 254 |
+
},
|
| 255 |
+
"left_hand_data": teleop_cmd["left_fingers"],
|
| 256 |
+
"right_hand_data": teleop_cmd["right_fingers"],
|
| 257 |
+
}
|
| 258 |
+
teleop_policy.retargeting_ik.set_goal(ik_data)
|
| 259 |
+
|
| 260 |
+
# Store original and get new upper body pose
|
| 261 |
+
target_upper_body_pose = wbc_goal["target_upper_body_pose"].copy()
|
| 262 |
+
wbc_goal["target_upper_body_pose"] = teleop_policy.retargeting_ik.get_action()
|
| 263 |
+
|
| 264 |
+
# Execute WBC policy
|
| 265 |
+
obs = sync_env.observe()
|
| 266 |
+
wbc_policy.set_observation(obs)
|
| 267 |
+
wbc_policy.set_goal(wbc_goal)
|
| 268 |
+
wbc_action = wbc_policy.get_action()
|
| 269 |
+
sync_env.queue_action(wbc_action)
|
| 270 |
+
|
| 271 |
+
# Save frame if needed
|
| 272 |
+
generate_and_save_frame(
|
| 273 |
+
config, sync_env, obs, wbc_action, seed, teleop_cmd, wbc_goal, gr00t_exporter
|
| 274 |
+
)
|
| 275 |
+
|
| 276 |
+
# Render or capture frame
|
| 277 |
+
capture_or_render_frame(env, onscreen, config, video_writer)
|
| 278 |
+
|
| 279 |
+
# Validate states
|
| 280 |
+
if jj < len(states) - 1:
|
| 281 |
+
if not np.allclose(
|
| 282 |
+
target_upper_body_pose, wbc_goal["target_upper_body_pose"], atol=1e-5
|
| 283 |
+
):
|
| 284 |
+
err = np.linalg.norm(target_upper_body_pose - wbc_goal["target_upper_body_pose"])
|
| 285 |
+
print(
|
| 286 |
+
f"[warning] target_upper_body_pose diverged by {err:.12f} for ep {ep} at step {jj}"
|
| 287 |
+
)
|
| 288 |
+
ret = False
|
| 289 |
+
|
| 290 |
+
state_playback = env.sim.get_state().flatten()
|
| 291 |
+
if not validate_state(states[jj + 1], state_playback, ep, jj):
|
| 292 |
+
ret = False
|
| 293 |
+
|
| 294 |
+
return ret
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
def playback_actions(
|
| 298 |
+
sync_env,
|
| 299 |
+
actions,
|
| 300 |
+
teleop_cmds,
|
| 301 |
+
wbc_goals,
|
| 302 |
+
states,
|
| 303 |
+
env,
|
| 304 |
+
onscreen,
|
| 305 |
+
config,
|
| 306 |
+
video_writer,
|
| 307 |
+
ep,
|
| 308 |
+
seed,
|
| 309 |
+
gr00t_exporter,
|
| 310 |
+
end_steps,
|
| 311 |
+
):
|
| 312 |
+
"""Playback using actions directly."""
|
| 313 |
+
ret = True
|
| 314 |
+
num_actions = len(actions) if end_steps == -1 else min(end_steps, len(actions))
|
| 315 |
+
|
| 316 |
+
for j in range(num_actions):
|
| 317 |
+
sync_env.queue_action({"q": actions[j]})
|
| 318 |
+
|
| 319 |
+
# Save frame if needed
|
| 320 |
+
if config.save_lerobot:
|
| 321 |
+
obs = sync_env.observe()
|
| 322 |
+
teleop_cmd = teleop_cmds[j]
|
| 323 |
+
wbc_goal = wbc_goals[j]
|
| 324 |
+
wbc_action = {"q": actions[j]}
|
| 325 |
+
generate_and_save_frame(
|
| 326 |
+
config, sync_env, obs, wbc_action, seed, teleop_cmd, wbc_goal, gr00t_exporter
|
| 327 |
+
)
|
| 328 |
+
|
| 329 |
+
capture_or_render_frame(env, onscreen, config, video_writer)
|
| 330 |
+
|
| 331 |
+
if j < len(states) - 1:
|
| 332 |
+
state_playback = env.sim.get_state().flatten()
|
| 333 |
+
if not validate_state(states[j + 1], state_playback, ep, j):
|
| 334 |
+
ret = False
|
| 335 |
+
|
| 336 |
+
return ret
|
| 337 |
+
|
| 338 |
+
|
| 339 |
+
def playback_states(
|
| 340 |
+
sync_env,
|
| 341 |
+
states,
|
| 342 |
+
actions,
|
| 343 |
+
teleop_cmds,
|
| 344 |
+
wbc_goals,
|
| 345 |
+
env,
|
| 346 |
+
onscreen,
|
| 347 |
+
config,
|
| 348 |
+
video_writer,
|
| 349 |
+
seed,
|
| 350 |
+
gr00t_exporter,
|
| 351 |
+
end_steps,
|
| 352 |
+
ep,
|
| 353 |
+
):
|
| 354 |
+
"""Playback by forcing mujoco states directly."""
|
| 355 |
+
ret = True
|
| 356 |
+
num_states = len(states) if end_steps == -1 else min(end_steps, len(states))
|
| 357 |
+
|
| 358 |
+
for i in range(num_states):
|
| 359 |
+
sync_env.reset_to({"states": states[i]})
|
| 360 |
+
sync_env.render()
|
| 361 |
+
|
| 362 |
+
# Validate that the state was set correctly
|
| 363 |
+
if i < len(states):
|
| 364 |
+
state_playback = env.sim.get_state().flatten()
|
| 365 |
+
if not validate_state(states[i], state_playback, ep, i):
|
| 366 |
+
ret = False
|
| 367 |
+
|
| 368 |
+
# Save frame if needed
|
| 369 |
+
if config.save_lerobot:
|
| 370 |
+
obs = sync_env.observe()
|
| 371 |
+
teleop_cmd = teleop_cmds[i]
|
| 372 |
+
wbc_goal = wbc_goals[i]
|
| 373 |
+
wbc_action = {"q": actions[i]}
|
| 374 |
+
generate_and_save_frame(
|
| 375 |
+
config, sync_env, obs, wbc_action, seed, teleop_cmd, wbc_goal, gr00t_exporter
|
| 376 |
+
)
|
| 377 |
+
|
| 378 |
+
capture_or_render_frame(env, onscreen, config, video_writer)
|
| 379 |
+
|
| 380 |
+
return ret
|
| 381 |
+
|
| 382 |
+
|
| 383 |
+
def main(config: SyncSimPlaybackConfig):
|
| 384 |
+
ret = True
|
| 385 |
+
start_time = time.time()
|
| 386 |
+
|
| 387 |
+
np.set_printoptions(precision=5, suppress=True, linewidth=120)
|
| 388 |
+
|
| 389 |
+
assert config.dataset is not None, "Folder must be specified for playback"
|
| 390 |
+
|
| 391 |
+
seeds, f, script_config = load_lerobot_dataset(config.dataset)
|
| 392 |
+
|
| 393 |
+
config.update(
|
| 394 |
+
script_config,
|
| 395 |
+
allowed_keys=[
|
| 396 |
+
"wbc_version",
|
| 397 |
+
"wbc_model_path",
|
| 398 |
+
"wbc_policy_class",
|
| 399 |
+
"control_frequency",
|
| 400 |
+
"enable_waist",
|
| 401 |
+
"with_hands",
|
| 402 |
+
"env_name",
|
| 403 |
+
"robot",
|
| 404 |
+
"task_name",
|
| 405 |
+
"teleop_frequency",
|
| 406 |
+
"data_collection_frequency",
|
| 407 |
+
"enable_gravity_compensation",
|
| 408 |
+
"gravity_compensation_joints",
|
| 409 |
+
],
|
| 410 |
+
)
|
| 411 |
+
config.validate_args()
|
| 412 |
+
|
| 413 |
+
robot_type, robot_model = get_robot_type_and_model(config.robot, config.enable_waist)
|
| 414 |
+
|
| 415 |
+
# Setup rendering
|
| 416 |
+
if config.save_video or config.save_img_obs:
|
| 417 |
+
onscreen = False
|
| 418 |
+
offscreen = True
|
| 419 |
+
else:
|
| 420 |
+
onscreen = True
|
| 421 |
+
offscreen = False
|
| 422 |
+
|
| 423 |
+
# Set default video path if not specified
|
| 424 |
+
if config.save_video and config.video_path is None:
|
| 425 |
+
if os.path.isfile(config.dataset):
|
| 426 |
+
video_folder = Path(config.dataset).parent
|
| 427 |
+
else:
|
| 428 |
+
video_folder = Path(config.dataset)
|
| 429 |
+
video_folder.mkdir(parents=True, exist_ok=True)
|
| 430 |
+
config.video_path = str(video_folder / "playback_video.mp4")
|
| 431 |
+
print(f"Video recording enabled. Output: {config.video_path}")
|
| 432 |
+
|
| 433 |
+
sync_env = get_env(config, onscreen=onscreen, offscreen=offscreen)
|
| 434 |
+
|
| 435 |
+
gr00t_exporter = None
|
| 436 |
+
if config.save_lerobot:
|
| 437 |
+
obs = sync_env.observe()
|
| 438 |
+
gr00t_exporter = get_data_exporter(config, obs, robot_model)
|
| 439 |
+
|
| 440 |
+
# Initialize policies
|
| 441 |
+
wbc_policy, teleop_policy = get_policies(
|
| 442 |
+
config, robot_type, robot_model, activate_keyboard_listener=False
|
| 443 |
+
)
|
| 444 |
+
|
| 445 |
+
# List of all demonstrations episodes
|
| 446 |
+
demos = [f"demo_{i + 1}" for i in range(len(seeds))]
|
| 447 |
+
print(f"Loaded and will playback {len(demos)} episodes")
|
| 448 |
+
env = sync_env.base_env
|
| 449 |
+
|
| 450 |
+
# Setup video writer
|
| 451 |
+
video_writer = None
|
| 452 |
+
fourcc = None
|
| 453 |
+
if config.save_video:
|
| 454 |
+
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
|
| 455 |
+
video_writer = cv2.VideoWriter(
|
| 456 |
+
config.video_path, fourcc, 20, (RS_VIEW_CAMERA_WIDTH, RS_VIEW_CAMERA_HEIGHT)
|
| 457 |
+
)
|
| 458 |
+
|
| 459 |
+
print("Loaded {} episodes from {}".format(len(demos), config.dataset))
|
| 460 |
+
print("seeds:", seeds)
|
| 461 |
+
print("demos:", demos, "\n\n")
|
| 462 |
+
|
| 463 |
+
# Handle episode selection - either limited number or infinite random
|
| 464 |
+
max_episodes = len(demos)
|
| 465 |
+
episode_count = 0
|
| 466 |
+
while True:
|
| 467 |
+
if episode_count >= max_episodes:
|
| 468 |
+
break
|
| 469 |
+
ep = demos[episode_count]
|
| 470 |
+
print(f"Playing back episode: {ep}")
|
| 471 |
+
episode_count += 1
|
| 472 |
+
|
| 473 |
+
# read the model xml, using the metadata stored in the attribute for this episode
|
| 474 |
+
seed = seeds[int(ep.split("_")[-1]) - 1]
|
| 475 |
+
sync_env.reset(seed=seed)
|
| 476 |
+
|
| 477 |
+
# load the actions and states
|
| 478 |
+
states = f["data/{}/states".format(ep)]
|
| 479 |
+
actions = f["data/{}/actions".format(ep)]
|
| 480 |
+
teleop_cmds = f["data/{}/teleop_cmd".format(ep)]
|
| 481 |
+
wbc_goals = f["data/{}/wbc_goal".format(ep)]
|
| 482 |
+
|
| 483 |
+
# reset the policies
|
| 484 |
+
wbc_policy, teleop_policy, _ = get_policies(
|
| 485 |
+
config, robot_type, robot_model, activate_keyboard_listener=False
|
| 486 |
+
)
|
| 487 |
+
end_steps = 20 if config.ci_test else -1
|
| 488 |
+
|
| 489 |
+
if config.use_actions:
|
| 490 |
+
# load the initial state
|
| 491 |
+
sync_env.reset_to({"states": states[0]})
|
| 492 |
+
# load the actions and play them back open-loop
|
| 493 |
+
if config.use_wbc_goals:
|
| 494 |
+
# use the wbc_goals to control the robot
|
| 495 |
+
episode_ret = playback_wbc_goals(
|
| 496 |
+
sync_env,
|
| 497 |
+
wbc_policy,
|
| 498 |
+
wbc_goals,
|
| 499 |
+
teleop_cmds,
|
| 500 |
+
states,
|
| 501 |
+
env,
|
| 502 |
+
onscreen,
|
| 503 |
+
config,
|
| 504 |
+
video_writer,
|
| 505 |
+
ep,
|
| 506 |
+
seed,
|
| 507 |
+
gr00t_exporter,
|
| 508 |
+
end_steps,
|
| 509 |
+
)
|
| 510 |
+
ret = ret and episode_ret
|
| 511 |
+
elif config.use_teleop_cmd:
|
| 512 |
+
# use the teleop commands to control the robot
|
| 513 |
+
episode_ret = playback_teleop_cmd(
|
| 514 |
+
sync_env,
|
| 515 |
+
wbc_policy,
|
| 516 |
+
teleop_policy,
|
| 517 |
+
wbc_goals,
|
| 518 |
+
teleop_cmds,
|
| 519 |
+
states,
|
| 520 |
+
env,
|
| 521 |
+
onscreen,
|
| 522 |
+
config,
|
| 523 |
+
video_writer,
|
| 524 |
+
ep,
|
| 525 |
+
seed,
|
| 526 |
+
gr00t_exporter,
|
| 527 |
+
end_steps,
|
| 528 |
+
)
|
| 529 |
+
ret = ret and episode_ret
|
| 530 |
+
else:
|
| 531 |
+
episode_ret = playback_actions(
|
| 532 |
+
sync_env,
|
| 533 |
+
actions,
|
| 534 |
+
teleop_cmds,
|
| 535 |
+
wbc_goals,
|
| 536 |
+
states,
|
| 537 |
+
env,
|
| 538 |
+
onscreen,
|
| 539 |
+
config,
|
| 540 |
+
video_writer,
|
| 541 |
+
ep,
|
| 542 |
+
seed,
|
| 543 |
+
gr00t_exporter,
|
| 544 |
+
end_steps,
|
| 545 |
+
)
|
| 546 |
+
ret = ret and episode_ret
|
| 547 |
+
else:
|
| 548 |
+
# force the sequence of internal mujoco states one by one
|
| 549 |
+
episode_ret = playback_states(
|
| 550 |
+
sync_env,
|
| 551 |
+
states,
|
| 552 |
+
actions,
|
| 553 |
+
teleop_cmds,
|
| 554 |
+
wbc_goals,
|
| 555 |
+
env,
|
| 556 |
+
onscreen,
|
| 557 |
+
config,
|
| 558 |
+
video_writer,
|
| 559 |
+
seed,
|
| 560 |
+
gr00t_exporter,
|
| 561 |
+
end_steps,
|
| 562 |
+
ep,
|
| 563 |
+
)
|
| 564 |
+
ret = ret and episode_ret
|
| 565 |
+
|
| 566 |
+
if config.save_lerobot:
|
| 567 |
+
gr00t_exporter.save_episode()
|
| 568 |
+
|
| 569 |
+
print(f"Episode {ep} playback finished.\n\n")
|
| 570 |
+
|
| 571 |
+
# close the env
|
| 572 |
+
sync_env.close()
|
| 573 |
+
|
| 574 |
+
# Cleanup
|
| 575 |
+
if video_writer is not None:
|
| 576 |
+
video_writer.release()
|
| 577 |
+
print(f"Video saved to: {config.video_path}")
|
| 578 |
+
|
| 579 |
+
end_time = time.time()
|
| 580 |
+
elapsed_time = end_time - start_time
|
| 581 |
+
|
| 582 |
+
if config.save_lerobot:
|
| 583 |
+
print(f"LeRobot dataset saved to: {gr00t_exporter.root}")
|
| 584 |
+
|
| 585 |
+
print(
|
| 586 |
+
f"{GREEN_BOLD}Playback with WBC version: {config.wbc_version}, {config.wbc_model_path}, "
|
| 587 |
+
f"{config.wbc_policy_class}, use_actions: {config.use_actions}, use_wbc_goals: {config.use_wbc_goals}, "
|
| 588 |
+
f"use_teleop_cmd: {config.use_teleop_cmd}{RESET}"
|
| 589 |
+
)
|
| 590 |
+
if ret:
|
| 591 |
+
print(f"{GREEN_BOLD}Playback completed successfully in {elapsed_time:.2f} seconds!{RESET}")
|
| 592 |
+
else:
|
| 593 |
+
print(f"{RED_BOLD}Playback encountered an error in {elapsed_time:.2f} seconds!{RESET}")
|
| 594 |
+
|
| 595 |
+
return ret
|
| 596 |
+
|
| 597 |
+
|
| 598 |
+
def capture_or_render_frame(
|
| 599 |
+
env: RobotEnv,
|
| 600 |
+
onscreen: bool,
|
| 601 |
+
config: SyncSimPlaybackConfig,
|
| 602 |
+
video_writer: Optional[cv2.VideoWriter],
|
| 603 |
+
):
|
| 604 |
+
"""Capture frame for video recording if enabled, or render the environment."""
|
| 605 |
+
if config.save_video:
|
| 606 |
+
if hasattr(env, "sim") and hasattr(env.sim, "render"):
|
| 607 |
+
img = env.sim.render(
|
| 608 |
+
width=RS_VIEW_CAMERA_WIDTH,
|
| 609 |
+
height=RS_VIEW_CAMERA_HEIGHT,
|
| 610 |
+
camera_name=env.render_camera[0],
|
| 611 |
+
)
|
| 612 |
+
img_bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
|
| 613 |
+
img_bgr = np.flipud(img_bgr)
|
| 614 |
+
video_writer.write(img_bgr)
|
| 615 |
+
elif onscreen:
|
| 616 |
+
env.render()
|
| 617 |
+
|
| 618 |
+
|
| 619 |
+
if __name__ == "__main__":
|
| 620 |
+
config = tyro.cli(SyncSimPlaybackConfig)
|
| 621 |
+
|
| 622 |
+
rclpy.init(args=None)
|
| 623 |
+
node = rclpy.create_node("playback_decoupled_wbc_control")
|
| 624 |
+
|
| 625 |
+
main(config)
|
| 626 |
+
|
| 627 |
+
rclpy.shutdown()
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_camera_viewer.py
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Camera viewer with manual recording support.
|
| 3 |
+
|
| 4 |
+
This script provides a camera viewer that can display multiple camera streams
|
| 5 |
+
and record them to video files with manual start/stop controls.
|
| 6 |
+
|
| 7 |
+
Features:
|
| 8 |
+
- Onscreen mode: Display camera feeds with optional recording
|
| 9 |
+
- Offscreen mode: No display, recording only when triggered
|
| 10 |
+
- Manual recording control with keyboard (R key to start/stop)
|
| 11 |
+
|
| 12 |
+
Usage Examples:
|
| 13 |
+
|
| 14 |
+
1. Basic onscreen viewing (with recording capability):
|
| 15 |
+
python run_camera_viewer.py --camera-host localhost --camera-port 5555
|
| 16 |
+
|
| 17 |
+
2. Offscreen mode (no display, recording only):
|
| 18 |
+
python run_camera_viewer.py --offscreen --camera-host localhost --camera-port 5555
|
| 19 |
+
|
| 20 |
+
3. Custom output directory:
|
| 21 |
+
python run_camera_viewer.py --output-path ./my_recordings --camera-host localhost
|
| 22 |
+
|
| 23 |
+
Controls:
|
| 24 |
+
- R key: Start/Stop recording
|
| 25 |
+
- Q key: Quit application
|
| 26 |
+
|
| 27 |
+
Output Structure:
|
| 28 |
+
camera_output_20241211_143052/
|
| 29 |
+
├── rec_143205/
|
| 30 |
+
│ ├── ego_view_color_image.mp4
|
| 31 |
+
│ ├── head_left_color_image.mp4
|
| 32 |
+
│ └── head_right_color_image.mp4
|
| 33 |
+
└── rec_143410/
|
| 34 |
+
├── ego_view_color_image.mp4
|
| 35 |
+
└── head_left_color_image.mp4
|
| 36 |
+
"""
|
| 37 |
+
|
| 38 |
+
from dataclasses import dataclass
|
| 39 |
+
from pathlib import Path
|
| 40 |
+
import threading
|
| 41 |
+
import time
|
| 42 |
+
from typing import Any, Optional
|
| 43 |
+
|
| 44 |
+
import cv2
|
| 45 |
+
import rclpy
|
| 46 |
+
from sshkeyboard import listen_keyboard, stop_listening
|
| 47 |
+
import tyro
|
| 48 |
+
|
| 49 |
+
from decoupled_wbc.control.main.teleop.configs.configs import ComposedCameraClientConfig
|
| 50 |
+
from decoupled_wbc.control.sensor.composed_camera import ComposedCameraClientSensor
|
| 51 |
+
from decoupled_wbc.control.utils.img_viewer import ImageViewer
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
@dataclass
|
| 55 |
+
class CameraViewerConfig(ComposedCameraClientConfig):
|
| 56 |
+
"""Config for running the camera viewer with recording support."""
|
| 57 |
+
|
| 58 |
+
offscreen: bool = False
|
| 59 |
+
"""Run in offscreen mode (no display, manual recording with R key)."""
|
| 60 |
+
|
| 61 |
+
output_path: Optional[str] = None
|
| 62 |
+
"""Output path for saving videos. If None, auto-generates path."""
|
| 63 |
+
|
| 64 |
+
codec: str = "mp4v"
|
| 65 |
+
"""Video codec to use for saving (e.g., 'mp4v', 'XVID')."""
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
ArgsConfig = CameraViewerConfig
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def _get_camera_titles(image_data: dict[str, Any]) -> list[str]:
|
| 72 |
+
"""
|
| 73 |
+
Detect all the individual camera streams from the image data.
|
| 74 |
+
|
| 75 |
+
schema format:
|
| 76 |
+
{
|
| 77 |
+
"timestamps": {"ego_view": 123.45, "ego_view_left_mono": 123.46},
|
| 78 |
+
"images": {"ego_view": np.ndarray, "ego_view_left_mono": np.ndarray}
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
Returns list of camera keys (e.g., ["ego_view", "ego_view_left_mono", "ego_view_right_mono"])
|
| 82 |
+
"""
|
| 83 |
+
# Extract all camera keys from the images dictionary
|
| 84 |
+
camera_titles = list(image_data.get("images", {}).keys())
|
| 85 |
+
return camera_titles
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def main(config: ArgsConfig):
|
| 89 |
+
"""Main function to run the camera viewer."""
|
| 90 |
+
# Initialize ROS
|
| 91 |
+
rclpy.init(args=None)
|
| 92 |
+
node = rclpy.create_node("camera_viewer")
|
| 93 |
+
|
| 94 |
+
# Start ROS spin in a separate thread
|
| 95 |
+
thread = threading.Thread(target=rclpy.spin, args=(node,), daemon=True)
|
| 96 |
+
thread.start()
|
| 97 |
+
|
| 98 |
+
image_sub = ComposedCameraClientSensor(server_ip=config.camera_host, port=config.camera_port)
|
| 99 |
+
|
| 100 |
+
# pre-fetch a sample image to get the number of camera angles
|
| 101 |
+
retry_count = 0
|
| 102 |
+
while True:
|
| 103 |
+
_sample_image = image_sub.read()
|
| 104 |
+
if _sample_image:
|
| 105 |
+
break
|
| 106 |
+
retry_count += 1
|
| 107 |
+
time.sleep(0.1)
|
| 108 |
+
if retry_count > 10:
|
| 109 |
+
raise Exception("Failed to get sample image")
|
| 110 |
+
|
| 111 |
+
camera_titles = _get_camera_titles(_sample_image)
|
| 112 |
+
|
| 113 |
+
# Setup output directory
|
| 114 |
+
if config.output_path is None:
|
| 115 |
+
output_dir = Path("camera_recordings")
|
| 116 |
+
else:
|
| 117 |
+
output_dir = Path(config.output_path)
|
| 118 |
+
|
| 119 |
+
# Recording state
|
| 120 |
+
is_recording = False
|
| 121 |
+
video_writers = {}
|
| 122 |
+
frame_count = 0
|
| 123 |
+
recording_start_time = None
|
| 124 |
+
should_quit = False
|
| 125 |
+
|
| 126 |
+
def on_press(key):
|
| 127 |
+
nonlocal is_recording, video_writers, frame_count, recording_start_time, should_quit
|
| 128 |
+
|
| 129 |
+
if key == "r":
|
| 130 |
+
if not is_recording:
|
| 131 |
+
# Start recording
|
| 132 |
+
recording_dir = output_dir / f"rec_{time.strftime('%Y%m%d_%H%M%S')}"
|
| 133 |
+
recording_dir.mkdir(parents=True, exist_ok=True)
|
| 134 |
+
|
| 135 |
+
# Create video writers
|
| 136 |
+
fourcc = cv2.VideoWriter_fourcc(*config.codec)
|
| 137 |
+
video_writers = {}
|
| 138 |
+
|
| 139 |
+
for title in camera_titles:
|
| 140 |
+
img = _sample_image["images"].get(title)
|
| 141 |
+
if img is not None:
|
| 142 |
+
height, width = img.shape[:2]
|
| 143 |
+
video_path = recording_dir / f"{title}.mp4"
|
| 144 |
+
writer = cv2.VideoWriter(
|
| 145 |
+
str(video_path), fourcc, config.fps, (width, height)
|
| 146 |
+
)
|
| 147 |
+
video_writers[title] = writer
|
| 148 |
+
|
| 149 |
+
is_recording = True
|
| 150 |
+
recording_start_time = time.time()
|
| 151 |
+
frame_count = 0
|
| 152 |
+
print(f"🔴 Recording started: {recording_dir}")
|
| 153 |
+
else:
|
| 154 |
+
# Stop recording
|
| 155 |
+
is_recording = False
|
| 156 |
+
for title, writer in video_writers.items():
|
| 157 |
+
writer.release()
|
| 158 |
+
video_writers = {}
|
| 159 |
+
|
| 160 |
+
duration = time.time() - recording_start_time if recording_start_time else 0
|
| 161 |
+
print(f"⏹️ Recording stopped - {duration:.1f}s, {frame_count} frames")
|
| 162 |
+
elif key == "q":
|
| 163 |
+
should_quit = True
|
| 164 |
+
stop_listening()
|
| 165 |
+
|
| 166 |
+
# Setup keyboard listener in a separate thread
|
| 167 |
+
keyboard_thread = threading.Thread(
|
| 168 |
+
target=lambda: listen_keyboard(on_press=on_press), daemon=True
|
| 169 |
+
)
|
| 170 |
+
keyboard_thread.start()
|
| 171 |
+
|
| 172 |
+
# Setup viewer for onscreen mode
|
| 173 |
+
viewer = None
|
| 174 |
+
if not config.offscreen:
|
| 175 |
+
viewer = ImageViewer(
|
| 176 |
+
title="Camera Viewer",
|
| 177 |
+
figsize=(10, 8),
|
| 178 |
+
num_images=len(camera_titles),
|
| 179 |
+
image_titles=camera_titles,
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
# Print instructions
|
| 183 |
+
mode = "Offscreen" if config.offscreen else "Onscreen"
|
| 184 |
+
print(f"{mode} mode - Target FPS: {config.fps}")
|
| 185 |
+
print(f"Videos will be saved to: {output_dir}")
|
| 186 |
+
print("Controls: R key to start/stop recording, Q key to quit, Ctrl+C to exit")
|
| 187 |
+
|
| 188 |
+
# Create ROS rate controller
|
| 189 |
+
rate = node.create_rate(config.fps)
|
| 190 |
+
|
| 191 |
+
try:
|
| 192 |
+
while rclpy.ok() and not should_quit:
|
| 193 |
+
# Get images from all subscribers
|
| 194 |
+
images = []
|
| 195 |
+
image_data = image_sub.read()
|
| 196 |
+
if image_data:
|
| 197 |
+
for title in camera_titles:
|
| 198 |
+
img = image_data["images"].get(title)
|
| 199 |
+
images.append(img)
|
| 200 |
+
|
| 201 |
+
# Save frame if recording
|
| 202 |
+
if is_recording and img is not None and title in video_writers:
|
| 203 |
+
# Convert from RGB to BGR for OpenCV
|
| 204 |
+
if len(img.shape) == 3 and img.shape[2] == 3:
|
| 205 |
+
img_bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
|
| 206 |
+
else:
|
| 207 |
+
img_bgr = img
|
| 208 |
+
video_writers[title].write(img_bgr)
|
| 209 |
+
|
| 210 |
+
# Display images if not offscreen
|
| 211 |
+
if not config.offscreen and viewer and any(img is not None for img in images):
|
| 212 |
+
status = "🔴 REC" if is_recording else "⏸️ Ready"
|
| 213 |
+
viewer._fig.suptitle(f"Camera Viewer - {status}")
|
| 214 |
+
viewer.show_multiple(images)
|
| 215 |
+
|
| 216 |
+
# Progress feedback
|
| 217 |
+
if is_recording:
|
| 218 |
+
frame_count += 1
|
| 219 |
+
if frame_count % 100 == 0:
|
| 220 |
+
duration = time.time() - recording_start_time
|
| 221 |
+
print(f"Recording: {frame_count} frames ({duration:.1f}s)")
|
| 222 |
+
|
| 223 |
+
rate.sleep()
|
| 224 |
+
|
| 225 |
+
except KeyboardInterrupt:
|
| 226 |
+
print("\nExiting...")
|
| 227 |
+
finally:
|
| 228 |
+
# Cleanup
|
| 229 |
+
try:
|
| 230 |
+
stop_listening()
|
| 231 |
+
except Exception:
|
| 232 |
+
pass
|
| 233 |
+
|
| 234 |
+
if video_writers:
|
| 235 |
+
for title, writer in video_writers.items():
|
| 236 |
+
writer.release()
|
| 237 |
+
if is_recording:
|
| 238 |
+
duration = time.time() - recording_start_time
|
| 239 |
+
print(f"Final: {duration:.1f}s, {frame_count} frames")
|
| 240 |
+
|
| 241 |
+
if viewer:
|
| 242 |
+
viewer.close()
|
| 243 |
+
|
| 244 |
+
rclpy.shutdown()
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
if __name__ == "__main__":
|
| 248 |
+
config = tyro.cli(ArgsConfig)
|
| 249 |
+
main(config)
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_g1_control_loop.py
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from copy import deepcopy
|
| 2 |
+
import time
|
| 3 |
+
|
| 4 |
+
import tyro
|
| 5 |
+
|
| 6 |
+
from decoupled_wbc.control.envs.g1.g1_env import G1Env
|
| 7 |
+
from decoupled_wbc.control.main.constants import (
|
| 8 |
+
CONTROL_GOAL_TOPIC,
|
| 9 |
+
DEFAULT_BASE_HEIGHT,
|
| 10 |
+
DEFAULT_NAV_CMD,
|
| 11 |
+
DEFAULT_WRIST_POSE,
|
| 12 |
+
JOINT_SAFETY_STATUS_TOPIC,
|
| 13 |
+
LOWER_BODY_POLICY_STATUS_TOPIC,
|
| 14 |
+
ROBOT_CONFIG_TOPIC,
|
| 15 |
+
STATE_TOPIC_NAME,
|
| 16 |
+
)
|
| 17 |
+
from decoupled_wbc.control.main.teleop.configs.configs import ControlLoopConfig
|
| 18 |
+
from decoupled_wbc.control.policy.wbc_policy_factory import get_wbc_policy
|
| 19 |
+
from decoupled_wbc.control.robot_model.instantiation.g1 import (
|
| 20 |
+
instantiate_g1_robot_model,
|
| 21 |
+
)
|
| 22 |
+
from decoupled_wbc.control.utils.keyboard_dispatcher import (
|
| 23 |
+
KeyboardDispatcher,
|
| 24 |
+
KeyboardEStop,
|
| 25 |
+
KeyboardListenerPublisher,
|
| 26 |
+
ROSKeyboardDispatcher,
|
| 27 |
+
)
|
| 28 |
+
from decoupled_wbc.control.utils.ros_utils import (
|
| 29 |
+
ROSManager,
|
| 30 |
+
ROSMsgPublisher,
|
| 31 |
+
ROSMsgSubscriber,
|
| 32 |
+
ROSServiceServer,
|
| 33 |
+
)
|
| 34 |
+
from decoupled_wbc.control.utils.telemetry import Telemetry
|
| 35 |
+
|
| 36 |
+
CONTROL_NODE_NAME = "ControlPolicy"
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def main(config: ControlLoopConfig):
|
| 40 |
+
ros_manager = ROSManager(node_name=CONTROL_NODE_NAME)
|
| 41 |
+
node = ros_manager.node
|
| 42 |
+
|
| 43 |
+
# start the robot config server
|
| 44 |
+
ROSServiceServer(ROBOT_CONFIG_TOPIC, config.to_dict())
|
| 45 |
+
|
| 46 |
+
wbc_config = config.load_wbc_yaml()
|
| 47 |
+
|
| 48 |
+
data_exp_pub = ROSMsgPublisher(STATE_TOPIC_NAME)
|
| 49 |
+
lower_body_policy_status_pub = ROSMsgPublisher(LOWER_BODY_POLICY_STATUS_TOPIC)
|
| 50 |
+
joint_safety_status_pub = ROSMsgPublisher(JOINT_SAFETY_STATUS_TOPIC)
|
| 51 |
+
|
| 52 |
+
# Initialize telemetry
|
| 53 |
+
telemetry = Telemetry(window_size=100)
|
| 54 |
+
|
| 55 |
+
waist_location = "lower_and_upper_body" if config.enable_waist else "lower_body"
|
| 56 |
+
robot_model = instantiate_g1_robot_model(
|
| 57 |
+
waist_location=waist_location, high_elbow_pose=config.high_elbow_pose
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
env = G1Env(
|
| 61 |
+
env_name=config.env_name,
|
| 62 |
+
robot_model=robot_model,
|
| 63 |
+
config=wbc_config,
|
| 64 |
+
wbc_version=config.wbc_version,
|
| 65 |
+
)
|
| 66 |
+
if env.sim and not config.sim_sync_mode:
|
| 67 |
+
env.start_simulator()
|
| 68 |
+
|
| 69 |
+
wbc_policy = get_wbc_policy("g1", robot_model, wbc_config, config.upper_body_joint_speed)
|
| 70 |
+
|
| 71 |
+
keyboard_listener_pub = KeyboardListenerPublisher()
|
| 72 |
+
keyboard_estop = KeyboardEStop()
|
| 73 |
+
if config.keyboard_dispatcher_type == "raw":
|
| 74 |
+
dispatcher = KeyboardDispatcher()
|
| 75 |
+
elif config.keyboard_dispatcher_type == "ros":
|
| 76 |
+
dispatcher = ROSKeyboardDispatcher()
|
| 77 |
+
else:
|
| 78 |
+
raise ValueError(
|
| 79 |
+
f"Invalid keyboard dispatcher: {config.keyboard_dispatcher_type}, please use 'raw' or 'ros'"
|
| 80 |
+
)
|
| 81 |
+
dispatcher.register(env)
|
| 82 |
+
dispatcher.register(wbc_policy)
|
| 83 |
+
dispatcher.register(keyboard_listener_pub)
|
| 84 |
+
dispatcher.register(keyboard_estop)
|
| 85 |
+
dispatcher.start()
|
| 86 |
+
|
| 87 |
+
rate = node.create_rate(config.control_frequency)
|
| 88 |
+
|
| 89 |
+
upper_body_policy_subscriber = ROSMsgSubscriber(CONTROL_GOAL_TOPIC)
|
| 90 |
+
|
| 91 |
+
last_teleop_cmd = None
|
| 92 |
+
try:
|
| 93 |
+
while ros_manager.ok():
|
| 94 |
+
t_start = time.monotonic()
|
| 95 |
+
with telemetry.timer("total_loop"):
|
| 96 |
+
# Step simulator if in sync mode
|
| 97 |
+
with telemetry.timer("step_simulator"):
|
| 98 |
+
if env.sim and config.sim_sync_mode:
|
| 99 |
+
env.step_simulator()
|
| 100 |
+
|
| 101 |
+
# Measure observation time
|
| 102 |
+
with telemetry.timer("observe"):
|
| 103 |
+
obs = env.observe()
|
| 104 |
+
wbc_policy.set_observation(obs)
|
| 105 |
+
|
| 106 |
+
# Measure policy setup time
|
| 107 |
+
with telemetry.timer("policy_setup"):
|
| 108 |
+
upper_body_cmd = upper_body_policy_subscriber.get_msg()
|
| 109 |
+
|
| 110 |
+
t_now = time.monotonic()
|
| 111 |
+
|
| 112 |
+
wbc_goal = {}
|
| 113 |
+
if upper_body_cmd:
|
| 114 |
+
wbc_goal = upper_body_cmd.copy()
|
| 115 |
+
last_teleop_cmd = upper_body_cmd.copy()
|
| 116 |
+
if config.ik_indicator:
|
| 117 |
+
env.set_ik_indicator(upper_body_cmd)
|
| 118 |
+
# Send goal to policy
|
| 119 |
+
if wbc_goal:
|
| 120 |
+
wbc_goal["interpolation_garbage_collection_time"] = t_now - 2 * (
|
| 121 |
+
1 / config.control_frequency
|
| 122 |
+
)
|
| 123 |
+
wbc_policy.set_goal(wbc_goal)
|
| 124 |
+
|
| 125 |
+
# Measure policy action calculation time
|
| 126 |
+
with telemetry.timer("policy_action"):
|
| 127 |
+
wbc_action = wbc_policy.get_action(time=t_now)
|
| 128 |
+
|
| 129 |
+
# Measure action queue time
|
| 130 |
+
with telemetry.timer("queue_action"):
|
| 131 |
+
env.queue_action(wbc_action)
|
| 132 |
+
|
| 133 |
+
# Publish status information for InteractiveModeController
|
| 134 |
+
with telemetry.timer("publish_status"):
|
| 135 |
+
# Get policy status - check if the lower body policy has use_policy_action enabled
|
| 136 |
+
policy_use_action = False
|
| 137 |
+
try:
|
| 138 |
+
# Access the lower body policy through the decoupled whole body policy
|
| 139 |
+
if hasattr(wbc_policy, "lower_body_policy"):
|
| 140 |
+
policy_use_action = getattr(
|
| 141 |
+
wbc_policy.lower_body_policy, "use_policy_action", False
|
| 142 |
+
)
|
| 143 |
+
except (AttributeError, TypeError):
|
| 144 |
+
policy_use_action = False
|
| 145 |
+
|
| 146 |
+
policy_status_msg = {"use_policy_action": policy_use_action, "timestamp": t_now}
|
| 147 |
+
lower_body_policy_status_pub.publish(policy_status_msg)
|
| 148 |
+
|
| 149 |
+
# Get joint safety status from G1Env (which already runs the safety monitor)
|
| 150 |
+
joint_safety_ok = env.get_joint_safety_status()
|
| 151 |
+
|
| 152 |
+
joint_safety_status_msg = {
|
| 153 |
+
"joint_safety_ok": joint_safety_ok,
|
| 154 |
+
"timestamp": t_now,
|
| 155 |
+
}
|
| 156 |
+
joint_safety_status_pub.publish(joint_safety_status_msg)
|
| 157 |
+
|
| 158 |
+
# Start or Stop data collection
|
| 159 |
+
if wbc_goal.get("toggle_data_collection", False):
|
| 160 |
+
dispatcher.handle_key("c")
|
| 161 |
+
|
| 162 |
+
# Abort the current episode
|
| 163 |
+
if wbc_goal.get("toggle_data_abort", False):
|
| 164 |
+
dispatcher.handle_key("x")
|
| 165 |
+
|
| 166 |
+
if env.use_sim and wbc_goal.get("reset_env_and_policy", False):
|
| 167 |
+
print("Resetting sim environment and policy")
|
| 168 |
+
# Reset teleop policy & sim env
|
| 169 |
+
dispatcher.handle_key("k")
|
| 170 |
+
|
| 171 |
+
# Clear upper body commands
|
| 172 |
+
upper_body_policy_subscriber._msg = None
|
| 173 |
+
upper_body_cmd = {
|
| 174 |
+
"target_upper_body_pose": obs["q"][
|
| 175 |
+
robot_model.get_joint_group_indices("upper_body")
|
| 176 |
+
],
|
| 177 |
+
"wrist_pose": DEFAULT_WRIST_POSE,
|
| 178 |
+
"base_height_command": DEFAULT_BASE_HEIGHT,
|
| 179 |
+
"navigate_cmd": DEFAULT_NAV_CMD,
|
| 180 |
+
}
|
| 181 |
+
last_teleop_cmd = upper_body_cmd.copy()
|
| 182 |
+
|
| 183 |
+
time.sleep(0.5)
|
| 184 |
+
|
| 185 |
+
msg = deepcopy(obs)
|
| 186 |
+
for key in obs.keys():
|
| 187 |
+
if key.endswith("_image"):
|
| 188 |
+
del msg[key]
|
| 189 |
+
|
| 190 |
+
# exporting data
|
| 191 |
+
if last_teleop_cmd:
|
| 192 |
+
msg.update(
|
| 193 |
+
{
|
| 194 |
+
"action": wbc_action["q"],
|
| 195 |
+
"action.eef": last_teleop_cmd.get("wrist_pose", DEFAULT_WRIST_POSE),
|
| 196 |
+
"base_height_command": last_teleop_cmd.get(
|
| 197 |
+
"base_height_command", DEFAULT_BASE_HEIGHT
|
| 198 |
+
),
|
| 199 |
+
"navigate_command": last_teleop_cmd.get(
|
| 200 |
+
"navigate_cmd", DEFAULT_NAV_CMD
|
| 201 |
+
),
|
| 202 |
+
"timestamps": {
|
| 203 |
+
"main_loop": time.time(),
|
| 204 |
+
"proprio": time.time(),
|
| 205 |
+
},
|
| 206 |
+
}
|
| 207 |
+
)
|
| 208 |
+
data_exp_pub.publish(msg)
|
| 209 |
+
end_time = time.monotonic()
|
| 210 |
+
|
| 211 |
+
if env.sim and (not env.sim.sim_thread or not env.sim.sim_thread.is_alive()):
|
| 212 |
+
raise RuntimeError("Simulator thread is not alive")
|
| 213 |
+
|
| 214 |
+
rate.sleep()
|
| 215 |
+
|
| 216 |
+
# Log timing information every 100 iterations (roughly every 2 seconds at 50Hz)
|
| 217 |
+
if config.verbose_timing:
|
| 218 |
+
# When verbose timing is enabled, always show timing
|
| 219 |
+
telemetry.log_timing_info(context="G1 Control Loop", threshold=0.0)
|
| 220 |
+
elif (end_time - t_start) > (1 / config.control_frequency) and not config.sim_sync_mode:
|
| 221 |
+
# Only show timing when loop is slow and verbose_timing is disabled
|
| 222 |
+
telemetry.log_timing_info(context="G1 Control Loop Missed", threshold=0.001)
|
| 223 |
+
|
| 224 |
+
except ros_manager.exceptions() as e:
|
| 225 |
+
print(f"ROSManager interrupted by user: {e}")
|
| 226 |
+
finally:
|
| 227 |
+
print("Cleaning up...")
|
| 228 |
+
# the order of the following is important
|
| 229 |
+
dispatcher.stop()
|
| 230 |
+
ros_manager.shutdown()
|
| 231 |
+
env.close()
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
if __name__ == "__main__":
|
| 235 |
+
config = tyro.cli(ControlLoopConfig)
|
| 236 |
+
main(config)
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_g1_data_exporter.py
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections import deque
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
import threading
|
| 4 |
+
import time
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
import rclpy
|
| 8 |
+
import tyro
|
| 9 |
+
|
| 10 |
+
from decoupled_wbc.control.main.constants import ROBOT_CONFIG_TOPIC, STATE_TOPIC_NAME
|
| 11 |
+
from decoupled_wbc.control.main.teleop.configs.configs import DataExporterConfig
|
| 12 |
+
from decoupled_wbc.control.robot_model.instantiation import g1
|
| 13 |
+
from decoupled_wbc.control.sensor.composed_camera import ComposedCameraClientSensor
|
| 14 |
+
from decoupled_wbc.control.utils.episode_state import EpisodeState
|
| 15 |
+
from decoupled_wbc.control.utils.keyboard_dispatcher import KeyboardListenerSubscriber
|
| 16 |
+
from decoupled_wbc.control.utils.ros_utils import ROSMsgSubscriber, ROSServiceClient
|
| 17 |
+
from decoupled_wbc.control.utils.telemetry import Telemetry
|
| 18 |
+
from decoupled_wbc.control.utils.text_to_speech import TextToSpeech
|
| 19 |
+
from decoupled_wbc.data.constants import BUCKET_BASE_PATH
|
| 20 |
+
from decoupled_wbc.data.exporter import DataCollectionInfo, Gr00tDataExporter
|
| 21 |
+
from decoupled_wbc.data.utils import get_dataset_features, get_modality_config
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class TimeDeltaException(Exception):
|
| 25 |
+
def __init__(self, failure_count: int, reset_timeout_sec: float):
|
| 26 |
+
"""
|
| 27 |
+
Exception raised when the time delta between two messages exceeds
|
| 28 |
+
a threshold for a consecutive number of times
|
| 29 |
+
"""
|
| 30 |
+
self.failure_count = failure_count
|
| 31 |
+
self.reset_timeout_sec = reset_timeout_sec
|
| 32 |
+
self.message = f"{self.failure_count} failures in {self.reset_timeout_sec} seconds"
|
| 33 |
+
super().__init__(self.message)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
class TimingThresholdMonitor:
|
| 37 |
+
def __init__(self, max_failures=3, reset_timeout_sec=5, time_delta=0.2, raise_exception=False):
|
| 38 |
+
"""
|
| 39 |
+
Monitor the time diff (between two messages) and optionally raise an exception
|
| 40 |
+
if there is a consistent violations
|
| 41 |
+
"""
|
| 42 |
+
self.max_failures = max_failures
|
| 43 |
+
self.reset_timeout_sec = reset_timeout_sec
|
| 44 |
+
self.failure_count = 0
|
| 45 |
+
self.last_failure_time = 0
|
| 46 |
+
self.time_delta = time_delta
|
| 47 |
+
self.raise_exception = raise_exception
|
| 48 |
+
|
| 49 |
+
def reset(self):
|
| 50 |
+
self.failure_count = 0
|
| 51 |
+
self.last_failure_time = 0
|
| 52 |
+
|
| 53 |
+
def log_time_delta(self, time_delta_sec: float):
|
| 54 |
+
time_delta = abs(time_delta_sec)
|
| 55 |
+
if time_delta > self.time_delta:
|
| 56 |
+
self.failure_count += 1
|
| 57 |
+
self.last_failure_time = time.monotonic()
|
| 58 |
+
|
| 59 |
+
if self.is_threshold_exceeded():
|
| 60 |
+
print(
|
| 61 |
+
f"Time delta exception: {self.failure_count} failures in {self.reset_timeout_sec} seconds"
|
| 62 |
+
f", time delta: {time_delta}"
|
| 63 |
+
)
|
| 64 |
+
if self.raise_exception:
|
| 65 |
+
raise TimeDeltaException(self.failure_count, self.reset_timeout_sec)
|
| 66 |
+
|
| 67 |
+
def is_threshold_exceeded(self):
|
| 68 |
+
if self.failure_count >= self.max_failures:
|
| 69 |
+
return True
|
| 70 |
+
if time.monotonic() - self.last_failure_time > self.reset_timeout_sec:
|
| 71 |
+
self.reset()
|
| 72 |
+
return False
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class Gr00tDataCollector:
|
| 76 |
+
def __init__(
|
| 77 |
+
self,
|
| 78 |
+
node,
|
| 79 |
+
camera_host: str,
|
| 80 |
+
camera_port: int,
|
| 81 |
+
state_topic_name: str,
|
| 82 |
+
data_exporter: Gr00tDataExporter,
|
| 83 |
+
text_to_speech=None,
|
| 84 |
+
frequency=20,
|
| 85 |
+
state_act_msg_frequency=50,
|
| 86 |
+
):
|
| 87 |
+
|
| 88 |
+
self.text_to_speech = text_to_speech
|
| 89 |
+
self.frequency = frequency
|
| 90 |
+
self.data_exporter = data_exporter
|
| 91 |
+
|
| 92 |
+
self.node = node
|
| 93 |
+
|
| 94 |
+
thread = threading.Thread(target=rclpy.spin, args=(self.node,), daemon=True)
|
| 95 |
+
thread.start()
|
| 96 |
+
time.sleep(0.5)
|
| 97 |
+
|
| 98 |
+
self._episode_state = EpisodeState()
|
| 99 |
+
self._keyboard_listener = KeyboardListenerSubscriber()
|
| 100 |
+
self._state_subscriber = ROSMsgSubscriber(state_topic_name)
|
| 101 |
+
self._image_subscriber = ComposedCameraClientSensor(server_ip=camera_host, port=camera_port)
|
| 102 |
+
self.rate = self.node.create_rate(self.frequency)
|
| 103 |
+
|
| 104 |
+
self.obs_act_buffer = deque(maxlen=100)
|
| 105 |
+
self.latest_image_msg = None
|
| 106 |
+
self.latest_proprio_msg = None
|
| 107 |
+
|
| 108 |
+
self.state_polling_rate = 1 / state_act_msg_frequency
|
| 109 |
+
self.last_state_poll_time = time.monotonic()
|
| 110 |
+
|
| 111 |
+
self.telemetry = Telemetry(window_size=100)
|
| 112 |
+
self.timing_threshold_monitor = TimingThresholdMonitor()
|
| 113 |
+
|
| 114 |
+
print(f"Recording to {self.data_exporter.meta.root}")
|
| 115 |
+
|
| 116 |
+
@property
|
| 117 |
+
def current_episode_index(self):
|
| 118 |
+
return self.data_exporter.episode_buffer["episode_index"]
|
| 119 |
+
|
| 120 |
+
def _print_and_say(self, message: str, say: bool = True):
|
| 121 |
+
"""Helper to use TextToSpeech print_and_say or fallback to print."""
|
| 122 |
+
if self.text_to_speech is not None:
|
| 123 |
+
self.text_to_speech.print_and_say(message, say)
|
| 124 |
+
else:
|
| 125 |
+
print(message)
|
| 126 |
+
|
| 127 |
+
def _check_keyboard_input(self):
|
| 128 |
+
key = self._keyboard_listener.read_msg()
|
| 129 |
+
if key == "c":
|
| 130 |
+
self._episode_state.change_state()
|
| 131 |
+
if self._episode_state.get_state() == self._episode_state.RECORDING:
|
| 132 |
+
self._print_and_say(f"Started recording {self.current_episode_index}")
|
| 133 |
+
elif self._episode_state.get_state() == self._episode_state.NEED_TO_SAVE:
|
| 134 |
+
self._print_and_say("Stopping recording, preparing to save")
|
| 135 |
+
elif self._episode_state.get_state() == self._episode_state.IDLE:
|
| 136 |
+
self._print_and_say("Saved episode and back to idle state")
|
| 137 |
+
elif key == "x":
|
| 138 |
+
if self._episode_state.get_state() == self._episode_state.RECORDING:
|
| 139 |
+
self.data_exporter.save_episode_as_discarded()
|
| 140 |
+
self._episode_state.reset_state()
|
| 141 |
+
self._print_and_say("Discarded episode")
|
| 142 |
+
|
| 143 |
+
def _add_data_frame(self):
|
| 144 |
+
t_start = time.monotonic()
|
| 145 |
+
|
| 146 |
+
if self.latest_proprio_msg is None or self.latest_image_msg is None:
|
| 147 |
+
self._print_and_say(
|
| 148 |
+
f"Waiting for message. "
|
| 149 |
+
f"Avail msg: proprio {self.latest_proprio_msg is not None} | "
|
| 150 |
+
f"image {self.latest_image_msg is not None}",
|
| 151 |
+
say=False,
|
| 152 |
+
)
|
| 153 |
+
return False
|
| 154 |
+
|
| 155 |
+
if self._episode_state.get_state() == self._episode_state.RECORDING:
|
| 156 |
+
|
| 157 |
+
# Calculate max time delta between images and proprio
|
| 158 |
+
max_time_delta = 0
|
| 159 |
+
for _, image_time in self.latest_image_msg["timestamps"].items():
|
| 160 |
+
time_delta = abs(image_time - self.latest_proprio_msg["timestamps"]["proprio"])
|
| 161 |
+
max_time_delta = max(max_time_delta, time_delta)
|
| 162 |
+
|
| 163 |
+
self.timing_threshold_monitor.log_time_delta(max_time_delta)
|
| 164 |
+
if (self.timing_threshold_monitor.failure_count + 1) % 100 == 0:
|
| 165 |
+
self._print_and_say("Image state delta too high, please discard data")
|
| 166 |
+
|
| 167 |
+
frame_data = {
|
| 168 |
+
"observation.state": self.latest_proprio_msg["q"],
|
| 169 |
+
"observation.eef_state": self.latest_proprio_msg["wrist_pose"],
|
| 170 |
+
"action": self.latest_proprio_msg["action"],
|
| 171 |
+
"action.eef": self.latest_proprio_msg["action.eef"],
|
| 172 |
+
"observation.img_state_delta": (
|
| 173 |
+
np.array(
|
| 174 |
+
[max_time_delta],
|
| 175 |
+
dtype=np.float32,
|
| 176 |
+
)
|
| 177 |
+
), # lerobot only supports adding numpy arrays
|
| 178 |
+
"teleop.navigate_command": np.array(
|
| 179 |
+
self.latest_proprio_msg["navigate_command"], dtype=np.float64
|
| 180 |
+
),
|
| 181 |
+
"teleop.base_height_command": np.array(
|
| 182 |
+
[self.latest_proprio_msg["base_height_command"]], dtype=np.float64
|
| 183 |
+
),
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
# Add images based on dataset features
|
| 187 |
+
images = self.latest_image_msg["images"]
|
| 188 |
+
for feature_name, feature_info in self.data_exporter.features.items():
|
| 189 |
+
if feature_info.get("dtype") in ["image", "video"]:
|
| 190 |
+
# Extract image key from feature name (e.g., "observation.images.ego_view" -> "ego_view")
|
| 191 |
+
image_key = feature_name.split(".")[-1]
|
| 192 |
+
|
| 193 |
+
if image_key not in images:
|
| 194 |
+
raise ValueError(
|
| 195 |
+
f"Required image '{image_key}' for feature '{feature_name}' "
|
| 196 |
+
f"not found in image message. Available images: {list(images.keys())}"
|
| 197 |
+
)
|
| 198 |
+
frame_data[feature_name] = images[image_key]
|
| 199 |
+
|
| 200 |
+
self.data_exporter.add_frame(frame_data)
|
| 201 |
+
|
| 202 |
+
t_end = time.monotonic()
|
| 203 |
+
if t_end - t_start > (1 / self.frequency):
|
| 204 |
+
print(f"DataExporter Missed: {t_end - t_start} sec")
|
| 205 |
+
|
| 206 |
+
if self._episode_state.get_state() == self._episode_state.NEED_TO_SAVE:
|
| 207 |
+
self.data_exporter.save_episode()
|
| 208 |
+
self.timing_threshold_monitor.reset()
|
| 209 |
+
self._print_and_say("Finished saving episode")
|
| 210 |
+
self._episode_state.change_state()
|
| 211 |
+
|
| 212 |
+
return True
|
| 213 |
+
|
| 214 |
+
def save_and_cleanup(self):
|
| 215 |
+
try:
|
| 216 |
+
self._print_and_say("saving episode done")
|
| 217 |
+
# save on going episode if any
|
| 218 |
+
buffer_size = self.data_exporter.episode_buffer.get("size", 0)
|
| 219 |
+
if buffer_size > 0:
|
| 220 |
+
self.data_exporter.save_episode()
|
| 221 |
+
self._print_and_say(f"Recording complete: {self.data_exporter.meta.root}", say=False)
|
| 222 |
+
except Exception as e:
|
| 223 |
+
self._print_and_say(f"Error saving episode: {e}")
|
| 224 |
+
|
| 225 |
+
self.node.destroy_node()
|
| 226 |
+
rclpy.shutdown()
|
| 227 |
+
self._print_and_say("Shutting down data exporter...", say=False)
|
| 228 |
+
|
| 229 |
+
def run(self):
|
| 230 |
+
try:
|
| 231 |
+
while rclpy.ok():
|
| 232 |
+
t_start = time.monotonic()
|
| 233 |
+
with self.telemetry.timer("total_loop"):
|
| 234 |
+
# 1. poll proprio msg
|
| 235 |
+
with self.telemetry.timer("poll_state"):
|
| 236 |
+
msg = self._state_subscriber.get_msg()
|
| 237 |
+
if msg is not None:
|
| 238 |
+
self.latest_proprio_msg = msg
|
| 239 |
+
|
| 240 |
+
# 2. poll image msg
|
| 241 |
+
with self.telemetry.timer("poll_image"):
|
| 242 |
+
msg = self._image_subscriber.read()
|
| 243 |
+
if msg is not None:
|
| 244 |
+
self.latest_image_msg = msg
|
| 245 |
+
|
| 246 |
+
# 3. check keyboard input
|
| 247 |
+
with self.telemetry.timer("check_keyboard"):
|
| 248 |
+
self._check_keyboard_input()
|
| 249 |
+
|
| 250 |
+
# 4. add frame
|
| 251 |
+
with self.telemetry.timer("add_frame"):
|
| 252 |
+
self._add_data_frame()
|
| 253 |
+
|
| 254 |
+
end_time = time.monotonic()
|
| 255 |
+
|
| 256 |
+
self.rate.sleep()
|
| 257 |
+
|
| 258 |
+
# Log timing information if we missed our target frequency
|
| 259 |
+
if (end_time - t_start) > (1 / self.frequency):
|
| 260 |
+
self.telemetry.log_timing_info(
|
| 261 |
+
context="Data Exporter Loop Missed", threshold=0.001
|
| 262 |
+
)
|
| 263 |
+
|
| 264 |
+
except KeyboardInterrupt:
|
| 265 |
+
print("Data exporter terminated by user")
|
| 266 |
+
# The user will trigger a keyboard interrupt if there's something wrong,
|
| 267 |
+
# so we flag the ongoing episode as discarded
|
| 268 |
+
buffer_size = self.data_exporter.episode_buffer.get("size", 0)
|
| 269 |
+
if buffer_size > 0:
|
| 270 |
+
self.data_exporter.save_episode_as_discarded()
|
| 271 |
+
|
| 272 |
+
finally:
|
| 273 |
+
self.save_and_cleanup()
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
def main(config: DataExporterConfig):
|
| 277 |
+
|
| 278 |
+
rclpy.init(args=None)
|
| 279 |
+
node = rclpy.create_node("data_exporter")
|
| 280 |
+
|
| 281 |
+
waist_location = "lower_and_upper_body" if config.enable_waist else "lower_body"
|
| 282 |
+
g1_rm = g1.instantiate_g1_robot_model(
|
| 283 |
+
waist_location=waist_location, high_elbow_pose=config.high_elbow_pose
|
| 284 |
+
)
|
| 285 |
+
|
| 286 |
+
dataset_features = get_dataset_features(g1_rm, config.add_stereo_camera)
|
| 287 |
+
modality_config = get_modality_config(g1_rm, config.add_stereo_camera)
|
| 288 |
+
|
| 289 |
+
text_to_speech = TextToSpeech() if config.text_to_speech else None
|
| 290 |
+
|
| 291 |
+
# Only set DataCollectionInfo if we're creating a new dataset
|
| 292 |
+
# When adding to existing dataset, DataCollectionInfo will be ignored
|
| 293 |
+
if config.robot_id is not None:
|
| 294 |
+
data_collection_info = DataCollectionInfo(
|
| 295 |
+
teleoperator_username=config.teleoperator_username,
|
| 296 |
+
support_operator_username=config.support_operator_username,
|
| 297 |
+
robot_type="g1",
|
| 298 |
+
robot_id=config.robot_id,
|
| 299 |
+
lower_body_policy=config.lower_body_policy,
|
| 300 |
+
wbc_model_path=config.wbc_model_path,
|
| 301 |
+
)
|
| 302 |
+
else:
|
| 303 |
+
# Use default DataCollectionInfo when adding to existing dataset
|
| 304 |
+
# This will be ignored if the dataset already exists
|
| 305 |
+
data_collection_info = DataCollectionInfo()
|
| 306 |
+
|
| 307 |
+
robot_config_client = ROSServiceClient(ROBOT_CONFIG_TOPIC)
|
| 308 |
+
robot_config = robot_config_client.get_config()
|
| 309 |
+
|
| 310 |
+
data_exporter = Gr00tDataExporter.create(
|
| 311 |
+
save_root=f"{config.root_output_dir}/{config.dataset_name}",
|
| 312 |
+
fps=config.data_collection_frequency,
|
| 313 |
+
features=dataset_features,
|
| 314 |
+
modality_config=modality_config,
|
| 315 |
+
task=config.task_prompt,
|
| 316 |
+
upload_bucket_path=BUCKET_BASE_PATH,
|
| 317 |
+
data_collection_info=data_collection_info,
|
| 318 |
+
script_config=robot_config,
|
| 319 |
+
)
|
| 320 |
+
|
| 321 |
+
data_collector = Gr00tDataCollector(
|
| 322 |
+
node=node,
|
| 323 |
+
frequency=config.data_collection_frequency,
|
| 324 |
+
data_exporter=data_exporter,
|
| 325 |
+
state_topic_name=STATE_TOPIC_NAME,
|
| 326 |
+
camera_host=config.camera_host,
|
| 327 |
+
camera_port=config.camera_port,
|
| 328 |
+
text_to_speech=text_to_speech,
|
| 329 |
+
)
|
| 330 |
+
data_collector.run()
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
if __name__ == "__main__":
|
| 334 |
+
config = tyro.cli(DataExporterConfig)
|
| 335 |
+
config.task_prompt = input("Enter the task prompt: ").strip().lower()
|
| 336 |
+
add_to_existing_dataset = input("Add to existing dataset? (y/n): ").strip().lower()
|
| 337 |
+
|
| 338 |
+
if add_to_existing_dataset == "y":
|
| 339 |
+
config.dataset_name = input("Enter the dataset name: ").strip().lower()
|
| 340 |
+
# When adding to existing dataset, we don't need robot_id or operator usernames
|
| 341 |
+
# as they should already be set in the existing dataset
|
| 342 |
+
elif add_to_existing_dataset == "n":
|
| 343 |
+
# robot_id = input("Enter the robot ID: ").strip().lower()
|
| 344 |
+
# if robot_id not in G1_ROBOT_IDS:
|
| 345 |
+
# raise ValueError(f"Invalid robot ID: {robot_id}. Available robot IDs: {G1_ROBOT_IDS}")
|
| 346 |
+
config.robot_id = "sim"
|
| 347 |
+
config.dataset_name = f"{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}-G1-{config.robot_id}"
|
| 348 |
+
|
| 349 |
+
# Only ask for operator usernames when creating a new dataset
|
| 350 |
+
# print("Available teleoperator usernames:")
|
| 351 |
+
# for i, username in enumerate(OPERATOR_USERNAMES):
|
| 352 |
+
# print(f"{i}: {username}")
|
| 353 |
+
# teleop_idx = int(input("Select teleoperator username index: "))
|
| 354 |
+
# config.teleoperator_username = OPERATOR_USERNAMES[teleop_idx]
|
| 355 |
+
config.teleoperator_username = "NEW_USER"
|
| 356 |
+
|
| 357 |
+
# print("\nAvailable support operator usernames:")
|
| 358 |
+
# for i, username in enumerate(OPERATOR_USERNAMES):
|
| 359 |
+
# print(f"{i}: {username}")
|
| 360 |
+
# support_idx = int(input("Select support operator username index: "))
|
| 361 |
+
# config.support_operator_username = OPERATOR_USERNAMES[support_idx]
|
| 362 |
+
config.support_operator_username = "NEW_USER"
|
| 363 |
+
|
| 364 |
+
main(config)
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_navigation_policy_loop.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import threading
|
| 2 |
+
import time
|
| 3 |
+
|
| 4 |
+
import rclpy
|
| 5 |
+
|
| 6 |
+
from decoupled_wbc.control.main.constants import NAV_CMD_TOPIC
|
| 7 |
+
from decoupled_wbc.control.policy.keyboard_navigation_policy import KeyboardNavigationPolicy
|
| 8 |
+
from decoupled_wbc.control.utils.keyboard_dispatcher import KeyboardListenerSubscriber
|
| 9 |
+
from decoupled_wbc.control.utils.ros_utils import ROSMsgPublisher
|
| 10 |
+
|
| 11 |
+
FREQUENCY = 10
|
| 12 |
+
NAV_NODE_NAME = "NavigationPolicy"
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def main():
|
| 16 |
+
rclpy.init(args=None)
|
| 17 |
+
node = rclpy.create_node(NAV_NODE_NAME)
|
| 18 |
+
|
| 19 |
+
# Start ROS spin in a separate thread
|
| 20 |
+
thread = threading.Thread(target=rclpy.spin, args=(node,), daemon=True)
|
| 21 |
+
thread.start()
|
| 22 |
+
time.sleep(0.5)
|
| 23 |
+
|
| 24 |
+
dict_publisher = ROSMsgPublisher(NAV_CMD_TOPIC)
|
| 25 |
+
keyboard_listener = KeyboardListenerSubscriber()
|
| 26 |
+
|
| 27 |
+
# Initialize navigation policy
|
| 28 |
+
navigation_policy = KeyboardNavigationPolicy()
|
| 29 |
+
|
| 30 |
+
# Create rate controller
|
| 31 |
+
rate = node.create_rate(FREQUENCY)
|
| 32 |
+
|
| 33 |
+
try:
|
| 34 |
+
while rclpy.ok():
|
| 35 |
+
t_now = time.monotonic()
|
| 36 |
+
# get keyboard input
|
| 37 |
+
|
| 38 |
+
navigation_policy.handle_keyboard_button(keyboard_listener.read_msg())
|
| 39 |
+
# Get action from navigation policy
|
| 40 |
+
action = navigation_policy.get_action(time=t_now)
|
| 41 |
+
|
| 42 |
+
# Add timestamp to the data
|
| 43 |
+
action["timestamp"] = t_now
|
| 44 |
+
|
| 45 |
+
# Create and publish ByteMultiArray message
|
| 46 |
+
dict_publisher.publish(action)
|
| 47 |
+
|
| 48 |
+
# Print status periodically (optional)
|
| 49 |
+
if int(t_now * 10) % 10 == 0:
|
| 50 |
+
nav_cmd = action["navigate_cmd"]
|
| 51 |
+
node.get_logger().info(
|
| 52 |
+
f"Nav cmd: linear=({nav_cmd[0]:.2f}, {nav_cmd[1]:.2f}), "
|
| 53 |
+
f"angular={nav_cmd[2]:.2f}"
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
rate.sleep()
|
| 57 |
+
|
| 58 |
+
except KeyboardInterrupt:
|
| 59 |
+
print("Navigation control loop terminated by user")
|
| 60 |
+
|
| 61 |
+
finally:
|
| 62 |
+
# Clean shutdown
|
| 63 |
+
node.destroy_node()
|
| 64 |
+
rclpy.shutdown()
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
if __name__ == "__main__":
|
| 68 |
+
main()
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_sim_loop.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Dict
|
| 2 |
+
|
| 3 |
+
import tyro
|
| 4 |
+
|
| 5 |
+
from decoupled_wbc.control.envs.g1.sim.simulator_factory import SimulatorFactory, init_channel
|
| 6 |
+
from decoupled_wbc.control.main.teleop.configs.configs import SimLoopConfig
|
| 7 |
+
from decoupled_wbc.control.robot_model.instantiation.g1 import (
|
| 8 |
+
instantiate_g1_robot_model,
|
| 9 |
+
)
|
| 10 |
+
from decoupled_wbc.control.robot_model.robot_model import RobotModel
|
| 11 |
+
|
| 12 |
+
ArgsConfig = SimLoopConfig
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class SimWrapper:
|
| 16 |
+
def __init__(self, robot_model: RobotModel, env_name: str, config: Dict[str, any], **kwargs):
|
| 17 |
+
self.robot_model = robot_model
|
| 18 |
+
self.config = config
|
| 19 |
+
|
| 20 |
+
init_channel(config=self.config)
|
| 21 |
+
|
| 22 |
+
# Create simulator using factory
|
| 23 |
+
self.sim = SimulatorFactory.create_simulator(
|
| 24 |
+
config=self.config,
|
| 25 |
+
env_name=env_name,
|
| 26 |
+
**kwargs,
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def main(config: ArgsConfig):
|
| 31 |
+
wbc_config = config.load_wbc_yaml()
|
| 32 |
+
# NOTE: we will override the interface to local if it is not specified
|
| 33 |
+
wbc_config["ENV_NAME"] = config.env_name
|
| 34 |
+
|
| 35 |
+
if config.enable_image_publish:
|
| 36 |
+
assert (
|
| 37 |
+
config.enable_offscreen
|
| 38 |
+
), "enable_offscreen must be True when enable_image_publish is True"
|
| 39 |
+
|
| 40 |
+
robot_model = instantiate_g1_robot_model()
|
| 41 |
+
|
| 42 |
+
sim_wrapper = SimWrapper(
|
| 43 |
+
robot_model=robot_model,
|
| 44 |
+
env_name=config.env_name,
|
| 45 |
+
config=wbc_config,
|
| 46 |
+
onscreen=wbc_config.get("ENABLE_ONSCREEN", True),
|
| 47 |
+
offscreen=wbc_config.get("ENABLE_OFFSCREEN", False),
|
| 48 |
+
)
|
| 49 |
+
# Start simulator as independent process
|
| 50 |
+
SimulatorFactory.start_simulator(
|
| 51 |
+
sim_wrapper.sim,
|
| 52 |
+
as_thread=False,
|
| 53 |
+
enable_image_publish=config.enable_image_publish,
|
| 54 |
+
mp_start_method=config.mp_start_method,
|
| 55 |
+
camera_port=config.camera_port,
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
if __name__ == "__main__":
|
| 60 |
+
config = tyro.cli(ArgsConfig)
|
| 61 |
+
main(config)
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_sync_sim_data_collection.py
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
import time
|
| 3 |
+
|
| 4 |
+
import tyro
|
| 5 |
+
|
| 6 |
+
from decoupled_wbc.control.main.teleop.configs.configs import SyncSimDataCollectionConfig
|
| 7 |
+
from decoupled_wbc.control.robot_model.instantiation import get_robot_type_and_model
|
| 8 |
+
from decoupled_wbc.control.utils.keyboard_dispatcher import (
|
| 9 |
+
KeyboardDispatcher,
|
| 10 |
+
KeyboardListener,
|
| 11 |
+
)
|
| 12 |
+
from decoupled_wbc.control.utils.ros_utils import ROSManager
|
| 13 |
+
from decoupled_wbc.control.utils.sync_sim_utils import (
|
| 14 |
+
COLLECTION_KEY,
|
| 15 |
+
SKIP_KEY,
|
| 16 |
+
CITestManager,
|
| 17 |
+
EpisodeManager,
|
| 18 |
+
generate_frame,
|
| 19 |
+
get_data_exporter,
|
| 20 |
+
get_env,
|
| 21 |
+
get_policies,
|
| 22 |
+
)
|
| 23 |
+
from decoupled_wbc.control.utils.telemetry import Telemetry
|
| 24 |
+
|
| 25 |
+
CONTROL_NODE_NAME = "ControlPolicy"
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
CONTROL_CMD_TOPIC = CONTROL_NODE_NAME + "/q_target"
|
| 29 |
+
ENV_NODE_NAME = "SyncEnv"
|
| 30 |
+
ENV_OBS_TOPIC = ENV_NODE_NAME + "/obs"
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def display_controls(config: SyncSimDataCollectionConfig):
|
| 34 |
+
"""
|
| 35 |
+
Method to pretty print controls.
|
| 36 |
+
"""
|
| 37 |
+
|
| 38 |
+
def print_command(char, info):
|
| 39 |
+
char += " " * (30 - len(char))
|
| 40 |
+
print("{}\t{}".format(char, info))
|
| 41 |
+
|
| 42 |
+
print("")
|
| 43 |
+
print_command("Keys", "Command")
|
| 44 |
+
if config.manual_control:
|
| 45 |
+
print_command(COLLECTION_KEY, "start/stop data collection")
|
| 46 |
+
print_command(SKIP_KEY, "skip and collect new episodes")
|
| 47 |
+
print_command("w-s-a-d", "move horizontally in x-y plane (press '=' first to enable)")
|
| 48 |
+
print_command("q", "rotate (counter-clockwise)")
|
| 49 |
+
print_command("e", "rotate (clockwise)")
|
| 50 |
+
print_command("space", "reset all velocity to zero")
|
| 51 |
+
print("")
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def main(config: SyncSimDataCollectionConfig):
|
| 55 |
+
ros_manager = ROSManager(node_name=CONTROL_NODE_NAME)
|
| 56 |
+
node = ros_manager.node
|
| 57 |
+
|
| 58 |
+
# Initialize telemetry
|
| 59 |
+
telemetry = Telemetry(window_size=100)
|
| 60 |
+
|
| 61 |
+
# Initialize robot model
|
| 62 |
+
robot_type, robot_model = get_robot_type_and_model(
|
| 63 |
+
config.robot,
|
| 64 |
+
enable_waist_ik=config.enable_waist,
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
# Initialize sim env
|
| 68 |
+
env = get_env(config, onscreen=config.enable_onscreen, offscreen=config.save_img_obs)
|
| 69 |
+
seed = int(time.time())
|
| 70 |
+
env.reset(seed)
|
| 71 |
+
env.render()
|
| 72 |
+
obs = env.observe()
|
| 73 |
+
robot_model.set_initial_body_pose(obs["q"])
|
| 74 |
+
|
| 75 |
+
# Initialize data exporter
|
| 76 |
+
exporter = get_data_exporter(
|
| 77 |
+
config,
|
| 78 |
+
obs,
|
| 79 |
+
robot_model,
|
| 80 |
+
save_path=Path("./outputs/ci_test/") if config.ci_test else None,
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
# Display control signals
|
| 84 |
+
display_controls(config)
|
| 85 |
+
|
| 86 |
+
# Initialize policies
|
| 87 |
+
wbc_policy, teleop_policy = get_policies(config, robot_type, robot_model)
|
| 88 |
+
|
| 89 |
+
dispatcher = KeyboardDispatcher()
|
| 90 |
+
keyboard_listener = KeyboardListener() # for data collection keys
|
| 91 |
+
dispatcher.register(keyboard_listener)
|
| 92 |
+
dispatcher.register(wbc_policy)
|
| 93 |
+
dispatcher.register(teleop_policy)
|
| 94 |
+
|
| 95 |
+
dispatcher.start()
|
| 96 |
+
|
| 97 |
+
rate = node.create_rate(config.control_frequency)
|
| 98 |
+
|
| 99 |
+
# Initialize episode manager to handle state transitions and data collection
|
| 100 |
+
episode_manager = EpisodeManager(config)
|
| 101 |
+
|
| 102 |
+
# Initialize CI test manager
|
| 103 |
+
ci_test_manager = CITestManager(config) if config.ci_test else None
|
| 104 |
+
|
| 105 |
+
try:
|
| 106 |
+
while ros_manager.ok():
|
| 107 |
+
|
| 108 |
+
need_reset = False
|
| 109 |
+
keyboard_input = keyboard_listener.pop_key()
|
| 110 |
+
|
| 111 |
+
with telemetry.timer("total_loop"):
|
| 112 |
+
max_mujoco_state_len, mujoco_state_len, mujoco_state = env.get_mujoco_state_info()
|
| 113 |
+
|
| 114 |
+
# Measure observation time
|
| 115 |
+
with telemetry.timer("observe"):
|
| 116 |
+
obs = env.observe()
|
| 117 |
+
wbc_policy.set_observation(obs)
|
| 118 |
+
|
| 119 |
+
# Measure policy setup time
|
| 120 |
+
with telemetry.timer("policy_setup"):
|
| 121 |
+
teleop_cmd = teleop_policy.get_action()
|
| 122 |
+
|
| 123 |
+
wbc_goal = {}
|
| 124 |
+
|
| 125 |
+
# Note that wbc_goal["navigation_cmd'] could be overwritten by teleop_cmd
|
| 126 |
+
if teleop_cmd:
|
| 127 |
+
for key, value in teleop_cmd.items():
|
| 128 |
+
wbc_goal[key] = value
|
| 129 |
+
# Draw IK indicators
|
| 130 |
+
if config.ik_indicator:
|
| 131 |
+
env.set_ik_indicator(teleop_cmd)
|
| 132 |
+
if wbc_goal:
|
| 133 |
+
wbc_policy.set_goal(wbc_goal)
|
| 134 |
+
|
| 135 |
+
# Measure policy action calculation time
|
| 136 |
+
with telemetry.timer("policy_action"):
|
| 137 |
+
wbc_action = wbc_policy.get_action()
|
| 138 |
+
|
| 139 |
+
if config.ci_test:
|
| 140 |
+
ci_test_manager.check_upper_body_motion(robot_model, wbc_action, config)
|
| 141 |
+
|
| 142 |
+
# Measure action queue time
|
| 143 |
+
with telemetry.timer("step"):
|
| 144 |
+
obs, _, _, _, step_info = env.step(wbc_action)
|
| 145 |
+
env.render()
|
| 146 |
+
episode_manager.increment_step()
|
| 147 |
+
|
| 148 |
+
if config.ci_test and config.ci_test_mode == "pre_merge":
|
| 149 |
+
ci_test_manager.check_end_effector_tracking(
|
| 150 |
+
teleop_cmd, obs, config, episode_manager.get_step_count()
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
# Handle data collection trigger
|
| 154 |
+
episode_manager.handle_collection_trigger(wbc_goal, keyboard_input, step_info)
|
| 155 |
+
|
| 156 |
+
# Collect data frame
|
| 157 |
+
if episode_manager.should_collect_data():
|
| 158 |
+
frame = generate_frame(
|
| 159 |
+
obs,
|
| 160 |
+
wbc_action,
|
| 161 |
+
seed,
|
| 162 |
+
mujoco_state,
|
| 163 |
+
mujoco_state_len,
|
| 164 |
+
max_mujoco_state_len,
|
| 165 |
+
teleop_cmd,
|
| 166 |
+
wbc_goal,
|
| 167 |
+
config.save_img_obs,
|
| 168 |
+
)
|
| 169 |
+
# exporting data
|
| 170 |
+
exporter.add_frame(frame)
|
| 171 |
+
|
| 172 |
+
# if done and task_completion_hold_count is 0, save the episode
|
| 173 |
+
need_reset = episode_manager.check_export_and_completion(exporter)
|
| 174 |
+
|
| 175 |
+
# check data abort
|
| 176 |
+
if episode_manager.handle_skip(wbc_goal, keyboard_input, exporter):
|
| 177 |
+
need_reset = True
|
| 178 |
+
|
| 179 |
+
if need_reset:
|
| 180 |
+
if config.ci_test:
|
| 181 |
+
print("CI test: Completed...")
|
| 182 |
+
raise KeyboardInterrupt
|
| 183 |
+
|
| 184 |
+
seed = int(time.time())
|
| 185 |
+
env.reset(seed)
|
| 186 |
+
env.render()
|
| 187 |
+
|
| 188 |
+
print("Sleeping for 3 seconds before resetting teleop policy...")
|
| 189 |
+
for j in range(3, 0, -1):
|
| 190 |
+
print(f"Starting in {j}...")
|
| 191 |
+
time.sleep(1)
|
| 192 |
+
|
| 193 |
+
wbc_policy, teleop_policy = get_policies(config, robot_type, robot_model)
|
| 194 |
+
episode_manager.reset_step_count()
|
| 195 |
+
|
| 196 |
+
rate.sleep()
|
| 197 |
+
|
| 198 |
+
except ros_manager.exceptions() as e:
|
| 199 |
+
print(f"ROSManager interrupted by user: {e}")
|
| 200 |
+
finally:
|
| 201 |
+
# Cleanup resources
|
| 202 |
+
teleop_policy.close()
|
| 203 |
+
dispatcher.stop()
|
| 204 |
+
ros_manager.shutdown()
|
| 205 |
+
env.close()
|
| 206 |
+
print("Sync sim data collection loop terminated.")
|
| 207 |
+
|
| 208 |
+
return True
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
if __name__ == "__main__":
|
| 212 |
+
config = tyro.cli(SyncSimDataCollectionConfig)
|
| 213 |
+
main(config)
|
GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_teleop_policy_loop.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import time
|
| 2 |
+
|
| 3 |
+
import rclpy
|
| 4 |
+
import tyro
|
| 5 |
+
|
| 6 |
+
from decoupled_wbc.control.main.constants import CONTROL_GOAL_TOPIC
|
| 7 |
+
from decoupled_wbc.control.main.teleop.configs.configs import TeleopConfig
|
| 8 |
+
from decoupled_wbc.control.policy.lerobot_replay_policy import LerobotReplayPolicy
|
| 9 |
+
from decoupled_wbc.control.policy.teleop_policy import TeleopPolicy
|
| 10 |
+
from decoupled_wbc.control.robot_model.instantiation.g1 import instantiate_g1_robot_model
|
| 11 |
+
from decoupled_wbc.control.teleop.solver.hand.instantiation.g1_hand_ik_instantiation import (
|
| 12 |
+
instantiate_g1_hand_ik_solver,
|
| 13 |
+
)
|
| 14 |
+
from decoupled_wbc.control.teleop.teleop_retargeting_ik import TeleopRetargetingIK
|
| 15 |
+
from decoupled_wbc.control.utils.ros_utils import ROSManager, ROSMsgPublisher
|
| 16 |
+
from decoupled_wbc.control.utils.telemetry import Telemetry
|
| 17 |
+
|
| 18 |
+
TELEOP_NODE_NAME = "TeleopPolicy"
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def main(config: TeleopConfig):
|
| 22 |
+
ros_manager = ROSManager(node_name=TELEOP_NODE_NAME)
|
| 23 |
+
node = ros_manager.node
|
| 24 |
+
|
| 25 |
+
if config.robot == "g1":
|
| 26 |
+
waist_location = "lower_and_upper_body" if config.enable_waist else "lower_body"
|
| 27 |
+
robot_model = instantiate_g1_robot_model(
|
| 28 |
+
waist_location=waist_location, high_elbow_pose=config.high_elbow_pose
|
| 29 |
+
)
|
| 30 |
+
left_hand_ik_solver, right_hand_ik_solver = instantiate_g1_hand_ik_solver()
|
| 31 |
+
else:
|
| 32 |
+
raise ValueError(f"Unsupported robot name: {config.robot}")
|
| 33 |
+
|
| 34 |
+
if config.lerobot_replay_path:
|
| 35 |
+
teleop_policy = LerobotReplayPolicy(
|
| 36 |
+
robot_model=robot_model, parquet_path=config.lerobot_replay_path
|
| 37 |
+
)
|
| 38 |
+
else:
|
| 39 |
+
print("running teleop policy, waiting teleop policy to be initialized...")
|
| 40 |
+
retargeting_ik = TeleopRetargetingIK(
|
| 41 |
+
robot_model=robot_model,
|
| 42 |
+
left_hand_ik_solver=left_hand_ik_solver,
|
| 43 |
+
right_hand_ik_solver=right_hand_ik_solver,
|
| 44 |
+
enable_visualization=config.enable_visualization,
|
| 45 |
+
body_active_joint_groups=["upper_body"],
|
| 46 |
+
)
|
| 47 |
+
teleop_policy = TeleopPolicy(
|
| 48 |
+
robot_model=robot_model,
|
| 49 |
+
retargeting_ik=retargeting_ik,
|
| 50 |
+
body_control_device=config.body_control_device,
|
| 51 |
+
hand_control_device=config.hand_control_device,
|
| 52 |
+
body_streamer_ip=config.body_streamer_ip, # vive tracker, leap motion does not require
|
| 53 |
+
body_streamer_keyword=config.body_streamer_keyword,
|
| 54 |
+
enable_real_device=config.enable_real_device,
|
| 55 |
+
replay_data_path=config.teleop_replay_path,
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
# Create a publisher for the navigation commands
|
| 59 |
+
control_publisher = ROSMsgPublisher(CONTROL_GOAL_TOPIC)
|
| 60 |
+
|
| 61 |
+
# Create rate controller
|
| 62 |
+
rate = node.create_rate(config.teleop_frequency)
|
| 63 |
+
iteration = 0
|
| 64 |
+
time_to_get_to_initial_pose = 2 # seconds
|
| 65 |
+
|
| 66 |
+
telemetry = Telemetry(window_size=100)
|
| 67 |
+
|
| 68 |
+
try:
|
| 69 |
+
while rclpy.ok():
|
| 70 |
+
with telemetry.timer("total_loop"):
|
| 71 |
+
t_start = time.monotonic()
|
| 72 |
+
# Get the current teleop action
|
| 73 |
+
with telemetry.timer("get_action"):
|
| 74 |
+
data = teleop_policy.get_action()
|
| 75 |
+
|
| 76 |
+
# Add timing information to the message
|
| 77 |
+
t_now = time.monotonic()
|
| 78 |
+
data["timestamp"] = t_now
|
| 79 |
+
|
| 80 |
+
# Set target completion time - longer for initial pose, then match control frequency
|
| 81 |
+
if iteration == 0:
|
| 82 |
+
data["target_time"] = t_now + time_to_get_to_initial_pose
|
| 83 |
+
else:
|
| 84 |
+
data["target_time"] = t_now + (1 / config.teleop_frequency)
|
| 85 |
+
|
| 86 |
+
# Publish the teleop command
|
| 87 |
+
with telemetry.timer("publish_teleop_command"):
|
| 88 |
+
control_publisher.publish(data)
|
| 89 |
+
|
| 90 |
+
# For the initial pose, wait the full duration before continuing
|
| 91 |
+
if iteration == 0:
|
| 92 |
+
print(f"Moving to initial pose for {time_to_get_to_initial_pose} seconds")
|
| 93 |
+
time.sleep(time_to_get_to_initial_pose)
|
| 94 |
+
iteration += 1
|
| 95 |
+
end_time = time.monotonic()
|
| 96 |
+
if (end_time - t_start) > (1 / config.teleop_frequency):
|
| 97 |
+
telemetry.log_timing_info(context="Teleop Policy Loop Missed", threshold=0.001)
|
| 98 |
+
rate.sleep()
|
| 99 |
+
|
| 100 |
+
except ros_manager.exceptions() as e:
|
| 101 |
+
print(f"ROSManager interrupted by user: {e}")
|
| 102 |
+
|
| 103 |
+
finally:
|
| 104 |
+
print("Cleaning up...")
|
| 105 |
+
ros_manager.shutdown()
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
if __name__ == "__main__":
|
| 109 |
+
config = tyro.cli(TeleopConfig)
|
| 110 |
+
main(config)
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/instantiation/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .g1 import instantiate_g1_robot_model
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def get_robot_type_and_model(robot: str, enable_waist_ik: bool = False):
|
| 5 |
+
"""Get the robot type from the robot name."""
|
| 6 |
+
if robot.lower().startswith("g1"):
|
| 7 |
+
if "FixedLowerBody" in robot or "FloatingBody" in robot:
|
| 8 |
+
waist_location = "upper_body"
|
| 9 |
+
elif enable_waist_ik:
|
| 10 |
+
waist_location = "lower_and_upper_body"
|
| 11 |
+
else:
|
| 12 |
+
waist_location = "lower_body"
|
| 13 |
+
return "g1", instantiate_g1_robot_model(waist_location=waist_location)
|
| 14 |
+
else:
|
| 15 |
+
raise ValueError(f"Invalid robot name: {robot}")
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/instantiation/g1.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from typing import Literal
|
| 4 |
+
|
| 5 |
+
from decoupled_wbc.control.robot_model.robot_model import RobotModel
|
| 6 |
+
from decoupled_wbc.control.robot_model.supplemental_info.g1.g1_supplemental_info import (
|
| 7 |
+
ElbowPose,
|
| 8 |
+
G1SupplementalInfo,
|
| 9 |
+
WaistLocation,
|
| 10 |
+
)
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def instantiate_g1_robot_model(
|
| 14 |
+
waist_location: Literal["lower_body", "upper_body", "lower_and_upper_body"] = "lower_body",
|
| 15 |
+
high_elbow_pose: bool = False,
|
| 16 |
+
):
|
| 17 |
+
"""
|
| 18 |
+
Instantiate a G1 robot model with configurable waist location and pose.
|
| 19 |
+
|
| 20 |
+
Args:
|
| 21 |
+
waist_location: Whether to put waist in "lower_body" (default G1 behavior),
|
| 22 |
+
"upper_body" (waist controlled with arms/manipulation via IK),
|
| 23 |
+
or "lower_and_upper_body" (waist reference from arms/manipulation
|
| 24 |
+
via IK then passed to lower body policy)
|
| 25 |
+
high_elbow_pose: Whether to use high elbow pose configuration for default joint positions
|
| 26 |
+
|
| 27 |
+
Returns:
|
| 28 |
+
RobotModel: Configured G1 robot model
|
| 29 |
+
"""
|
| 30 |
+
project_root = Path(__file__).resolve().parent.parent.parent.parent.parent
|
| 31 |
+
robot_model_config = {
|
| 32 |
+
"asset_path": os.path.join(project_root, "decoupled_wbc/control/robot_model/model_data/g1"),
|
| 33 |
+
"urdf_path": os.path.join(
|
| 34 |
+
project_root, "decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_with_hand.urdf"
|
| 35 |
+
),
|
| 36 |
+
}
|
| 37 |
+
assert waist_location in [
|
| 38 |
+
"lower_body",
|
| 39 |
+
"upper_body",
|
| 40 |
+
"lower_and_upper_body",
|
| 41 |
+
], f"Invalid waist_location: {waist_location}. Must be 'lower_body' or 'upper_body' or 'lower_and_upper_body'"
|
| 42 |
+
|
| 43 |
+
# Map string values to enums
|
| 44 |
+
waist_location_enum = {
|
| 45 |
+
"lower_body": WaistLocation.LOWER_BODY,
|
| 46 |
+
"upper_body": WaistLocation.UPPER_BODY,
|
| 47 |
+
"lower_and_upper_body": WaistLocation.LOWER_AND_UPPER_BODY,
|
| 48 |
+
}[waist_location]
|
| 49 |
+
|
| 50 |
+
elbow_pose_enum = ElbowPose.HIGH if high_elbow_pose else ElbowPose.LOW
|
| 51 |
+
|
| 52 |
+
# Create single configurable supplemental info instance
|
| 53 |
+
robot_model_supplemental_info = G1SupplementalInfo(
|
| 54 |
+
waist_location=waist_location_enum, elbow_pose=elbow_pose_enum
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
robot_model = RobotModel(
|
| 58 |
+
robot_model_config["urdf_path"],
|
| 59 |
+
robot_model_config["asset_path"],
|
| 60 |
+
supplemental_info=robot_model_supplemental_info,
|
| 61 |
+
)
|
| 62 |
+
return robot_model
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof.urdf
ADDED
|
@@ -0,0 +1,1091 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<robot name="g1_29dof">
|
| 2 |
+
<mujoco>
|
| 3 |
+
<compiler meshdir="meshes" discardvisual="false"/>
|
| 4 |
+
</mujoco>
|
| 5 |
+
|
| 6 |
+
<!-- [CAUTION] uncomment when convert to mujoco -->
|
| 7 |
+
<!-- <link name="world"></link>
|
| 8 |
+
<joint name="floating_base_joint" type="floating">
|
| 9 |
+
<parent link="world"/>
|
| 10 |
+
<child link="pelvis"/>
|
| 11 |
+
</joint> -->
|
| 12 |
+
|
| 13 |
+
<link name="pelvis">
|
| 14 |
+
<inertial>
|
| 15 |
+
<origin xyz="0 0 -0.07605" rpy="0 0 0"/>
|
| 16 |
+
<mass value="3.813"/>
|
| 17 |
+
<inertia ixx="0.010549" ixy="0" ixz="2.1E-06" iyy="0.0093089" iyz="0" izz="0.0079184"/>
|
| 18 |
+
</inertial>
|
| 19 |
+
<visual>
|
| 20 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 21 |
+
<geometry>
|
| 22 |
+
<mesh filename="meshes/pelvis.STL"/>
|
| 23 |
+
</geometry>
|
| 24 |
+
<material name="dark">
|
| 25 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 26 |
+
</material>
|
| 27 |
+
</visual>
|
| 28 |
+
</link>
|
| 29 |
+
<link name="pelvis_contour_link">
|
| 30 |
+
<inertial>
|
| 31 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 32 |
+
<mass value="0.001"/>
|
| 33 |
+
<inertia ixx="1e-7" ixy="0" ixz="0" iyy="1e-7" iyz="0" izz="1e-7"/>
|
| 34 |
+
</inertial>
|
| 35 |
+
<visual>
|
| 36 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 37 |
+
<geometry>
|
| 38 |
+
<mesh filename="meshes/pelvis_contour_link.STL"/>
|
| 39 |
+
</geometry>
|
| 40 |
+
<material name="white">
|
| 41 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 42 |
+
</material>
|
| 43 |
+
</visual>
|
| 44 |
+
<collision>
|
| 45 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 46 |
+
<geometry>
|
| 47 |
+
<mesh filename="meshes/pelvis_contour_link.STL"/>
|
| 48 |
+
</geometry>
|
| 49 |
+
</collision>
|
| 50 |
+
</link>
|
| 51 |
+
<joint name="pelvis_contour_joint" type="fixed">
|
| 52 |
+
<parent link="pelvis"/>
|
| 53 |
+
<child link="pelvis_contour_link"/>
|
| 54 |
+
</joint>
|
| 55 |
+
|
| 56 |
+
<!-- Legs -->
|
| 57 |
+
<link name="left_hip_pitch_link">
|
| 58 |
+
<inertial>
|
| 59 |
+
<origin xyz="0.002741 0.047791 -0.02606" rpy="0 0 0"/>
|
| 60 |
+
<mass value="1.35"/>
|
| 61 |
+
<inertia ixx="0.001811" ixy="3.68E-05" ixz="-3.44E-05" iyy="0.0014193" iyz="0.000171" izz="0.0012812"/>
|
| 62 |
+
</inertial>
|
| 63 |
+
<visual>
|
| 64 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 65 |
+
<geometry>
|
| 66 |
+
<mesh filename="meshes/left_hip_pitch_link.STL"/>
|
| 67 |
+
</geometry>
|
| 68 |
+
<material name="dark">
|
| 69 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 70 |
+
</material>
|
| 71 |
+
</visual>
|
| 72 |
+
<collision>
|
| 73 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 74 |
+
<geometry>
|
| 75 |
+
<mesh filename="meshes/left_hip_pitch_link.STL"/>
|
| 76 |
+
</geometry>
|
| 77 |
+
</collision>
|
| 78 |
+
</link>
|
| 79 |
+
<joint name="left_hip_pitch_joint" type="revolute">
|
| 80 |
+
<origin xyz="0 0.064452 -0.1027" rpy="0 0 0"/>
|
| 81 |
+
<parent link="pelvis"/>
|
| 82 |
+
<child link="left_hip_pitch_link"/>
|
| 83 |
+
<axis xyz="0 1 0"/>
|
| 84 |
+
<limit lower="-2.5307" upper="2.8798" effort="88" velocity="32"/>
|
| 85 |
+
</joint>
|
| 86 |
+
<link name="left_hip_roll_link">
|
| 87 |
+
<inertial>
|
| 88 |
+
<origin xyz="0.029812 -0.001045 -0.087934" rpy="0 0 0"/>
|
| 89 |
+
<mass value="1.52"/>
|
| 90 |
+
<inertia ixx="0.0023773" ixy="-3.8E-06" ixz="-0.0003908" iyy="0.0024123" iyz="1.84E-05" izz="0.0016595"/>
|
| 91 |
+
</inertial>
|
| 92 |
+
<visual>
|
| 93 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 94 |
+
<geometry>
|
| 95 |
+
<mesh filename="meshes/left_hip_roll_link.STL"/>
|
| 96 |
+
</geometry>
|
| 97 |
+
<material name="white">
|
| 98 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 99 |
+
</material>
|
| 100 |
+
</visual>
|
| 101 |
+
<collision>
|
| 102 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 103 |
+
<geometry>
|
| 104 |
+
<mesh filename="meshes/left_hip_roll_link.STL"/>
|
| 105 |
+
</geometry>
|
| 106 |
+
</collision>
|
| 107 |
+
</link>
|
| 108 |
+
<joint name="left_hip_roll_joint" type="revolute">
|
| 109 |
+
<origin xyz="0 0.052 -0.030465" rpy="0 -0.1749 0"/>
|
| 110 |
+
<parent link="left_hip_pitch_link"/>
|
| 111 |
+
<child link="left_hip_roll_link"/>
|
| 112 |
+
<axis xyz="1 0 0"/>
|
| 113 |
+
<limit lower="-0.5236" upper="2.9671" effort="88" velocity="32"/>
|
| 114 |
+
</joint>
|
| 115 |
+
<link name="left_hip_yaw_link">
|
| 116 |
+
<inertial>
|
| 117 |
+
<origin xyz="-0.057709 -0.010981 -0.15078" rpy="0 0 0"/>
|
| 118 |
+
<mass value="1.702"/>
|
| 119 |
+
<inertia ixx="0.0057774" ixy="-0.0005411" ixz="-0.0023948" iyy="0.0076124" iyz="-0.0007072" izz="0.003149"/>
|
| 120 |
+
</inertial>
|
| 121 |
+
<visual>
|
| 122 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 123 |
+
<geometry>
|
| 124 |
+
<mesh filename="meshes/left_hip_yaw_link.STL"/>
|
| 125 |
+
</geometry>
|
| 126 |
+
<material name="white">
|
| 127 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 128 |
+
</material>
|
| 129 |
+
</visual>
|
| 130 |
+
<collision>
|
| 131 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 132 |
+
<geometry>
|
| 133 |
+
<mesh filename="meshes/left_hip_yaw_link.STL"/>
|
| 134 |
+
</geometry>
|
| 135 |
+
</collision>
|
| 136 |
+
</link>
|
| 137 |
+
<joint name="left_hip_yaw_joint" type="revolute">
|
| 138 |
+
<origin xyz="0.025001 0 -0.12412" rpy="0 0 0"/>
|
| 139 |
+
<parent link="left_hip_roll_link"/>
|
| 140 |
+
<child link="left_hip_yaw_link"/>
|
| 141 |
+
<axis xyz="0 0 1"/>
|
| 142 |
+
<limit lower="-2.7576" upper="2.7576" effort="88" velocity="32"/>
|
| 143 |
+
</joint>
|
| 144 |
+
<link name="left_knee_link">
|
| 145 |
+
<inertial>
|
| 146 |
+
<origin xyz="0.005457 0.003964 -0.12074" rpy="0 0 0"/>
|
| 147 |
+
<mass value="1.932"/>
|
| 148 |
+
<inertia ixx="0.011329" ixy="4.82E-05" ixz="-4.49E-05" iyy="0.011277" iyz="-0.0007146" izz="0.0015168"/>
|
| 149 |
+
</inertial>
|
| 150 |
+
<visual>
|
| 151 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 152 |
+
<geometry>
|
| 153 |
+
<mesh filename="meshes/left_knee_link.STL"/>
|
| 154 |
+
</geometry>
|
| 155 |
+
<material name="white">
|
| 156 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 157 |
+
</material>
|
| 158 |
+
</visual>
|
| 159 |
+
<collision>
|
| 160 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 161 |
+
<geometry>
|
| 162 |
+
<mesh filename="meshes/left_knee_link.STL"/>
|
| 163 |
+
</geometry>
|
| 164 |
+
</collision>
|
| 165 |
+
</link>
|
| 166 |
+
<joint name="left_knee_joint" type="revolute">
|
| 167 |
+
<origin xyz="-0.078273 0.0021489 -0.17734" rpy="0 0.1749 0"/>
|
| 168 |
+
<parent link="left_hip_yaw_link"/>
|
| 169 |
+
<child link="left_knee_link"/>
|
| 170 |
+
<axis xyz="0 1 0"/>
|
| 171 |
+
<limit lower="-0.087267" upper="2.8798" effort="139" velocity="20"/>
|
| 172 |
+
</joint>
|
| 173 |
+
<link name="left_ankle_pitch_link">
|
| 174 |
+
<inertial>
|
| 175 |
+
<origin xyz="-0.007269 0 0.011137" rpy="0 0 0"/>
|
| 176 |
+
<mass value="0.074"/>
|
| 177 |
+
<inertia ixx="8.4E-06" ixy="0" ixz="-2.9E-06" iyy="1.89E-05" iyz="0" izz="1.26E-05"/>
|
| 178 |
+
</inertial>
|
| 179 |
+
<visual>
|
| 180 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 181 |
+
<geometry>
|
| 182 |
+
<mesh filename="meshes/left_ankle_pitch_link.STL"/>
|
| 183 |
+
</geometry>
|
| 184 |
+
<material name="white">
|
| 185 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 186 |
+
</material>
|
| 187 |
+
</visual>
|
| 188 |
+
<collision>
|
| 189 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 190 |
+
<geometry>
|
| 191 |
+
<mesh filename="meshes/left_ankle_pitch_link.STL"/>
|
| 192 |
+
</geometry>
|
| 193 |
+
</collision>
|
| 194 |
+
</link>
|
| 195 |
+
<joint name="left_ankle_pitch_joint" type="revolute">
|
| 196 |
+
<origin xyz="0 -9.4445E-05 -0.30001" rpy="0 0 0"/>
|
| 197 |
+
<parent link="left_knee_link"/>
|
| 198 |
+
<child link="left_ankle_pitch_link"/>
|
| 199 |
+
<axis xyz="0 1 0"/>
|
| 200 |
+
<limit lower="-0.87267" upper="0.5236" effort="50" velocity="37"/>
|
| 201 |
+
</joint>
|
| 202 |
+
<link name="left_ankle_roll_link">
|
| 203 |
+
<inertial>
|
| 204 |
+
<origin xyz="0.026505 0 -0.016425" rpy="0 0 0"/>
|
| 205 |
+
<mass value="0.608"/>
|
| 206 |
+
<inertia ixx="0.0002231" ixy="2E-07" ixz="8.91E-05" iyy="0.0016161" iyz="-1E-07" izz="0.0016667"/>
|
| 207 |
+
</inertial>
|
| 208 |
+
<visual>
|
| 209 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 210 |
+
<geometry>
|
| 211 |
+
<mesh filename="meshes/left_ankle_roll_link.STL"/>
|
| 212 |
+
</geometry>
|
| 213 |
+
<material name="dark">
|
| 214 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 215 |
+
</material>
|
| 216 |
+
</visual>
|
| 217 |
+
<collision>
|
| 218 |
+
<origin xyz="-0.05 0.025 -0.03" rpy="0 0 0"/>
|
| 219 |
+
<geometry>
|
| 220 |
+
<sphere radius="0.005"/>
|
| 221 |
+
</geometry>
|
| 222 |
+
</collision>
|
| 223 |
+
<collision>
|
| 224 |
+
<origin xyz="-0.05 -0.025 -0.03" rpy="0 0 0"/>
|
| 225 |
+
<geometry>
|
| 226 |
+
<sphere radius="0.005"/>
|
| 227 |
+
</geometry>
|
| 228 |
+
</collision>
|
| 229 |
+
<collision>
|
| 230 |
+
<origin xyz="0.12 0.03 -0.03" rpy="0 0 0"/>
|
| 231 |
+
<geometry>
|
| 232 |
+
<sphere radius="0.005"/>
|
| 233 |
+
</geometry>
|
| 234 |
+
</collision>
|
| 235 |
+
<collision>
|
| 236 |
+
<origin xyz="0.12 -0.03 -0.03" rpy="0 0 0"/>
|
| 237 |
+
<geometry>
|
| 238 |
+
<sphere radius="0.005"/>
|
| 239 |
+
</geometry>
|
| 240 |
+
</collision>
|
| 241 |
+
</link>
|
| 242 |
+
<joint name="left_ankle_roll_joint" type="revolute">
|
| 243 |
+
<origin xyz="0 0 -0.017558" rpy="0 0 0"/>
|
| 244 |
+
<parent link="left_ankle_pitch_link"/>
|
| 245 |
+
<child link="left_ankle_roll_link"/>
|
| 246 |
+
<axis xyz="1 0 0"/>
|
| 247 |
+
<limit lower="-0.2618" upper="0.2618" effort="50" velocity="37"/>
|
| 248 |
+
</joint>
|
| 249 |
+
<link name="right_hip_pitch_link">
|
| 250 |
+
<inertial>
|
| 251 |
+
<origin xyz="0.002741 -0.047791 -0.02606" rpy="0 0 0"/>
|
| 252 |
+
<mass value="1.35"/>
|
| 253 |
+
<inertia ixx="0.001811" ixy="-3.68E-05" ixz="-3.44E-05" iyy="0.0014193" iyz="-0.000171" izz="0.0012812"/>
|
| 254 |
+
</inertial>
|
| 255 |
+
<visual>
|
| 256 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 257 |
+
<geometry>
|
| 258 |
+
<mesh filename="meshes/right_hip_pitch_link.STL"/>
|
| 259 |
+
</geometry>
|
| 260 |
+
<material name="dark">
|
| 261 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 262 |
+
</material>
|
| 263 |
+
</visual>
|
| 264 |
+
<collision>
|
| 265 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 266 |
+
<geometry>
|
| 267 |
+
<mesh filename="meshes/right_hip_pitch_link.STL"/>
|
| 268 |
+
</geometry>
|
| 269 |
+
</collision>
|
| 270 |
+
</link>
|
| 271 |
+
<joint name="right_hip_pitch_joint" type="revolute">
|
| 272 |
+
<origin xyz="0 -0.064452 -0.1027" rpy="0 0 0"/>
|
| 273 |
+
<parent link="pelvis"/>
|
| 274 |
+
<child link="right_hip_pitch_link"/>
|
| 275 |
+
<axis xyz="0 1 0"/>
|
| 276 |
+
<limit lower="-2.5307" upper="2.8798" effort="88" velocity="32"/>
|
| 277 |
+
</joint>
|
| 278 |
+
<link name="right_hip_roll_link">
|
| 279 |
+
<inertial>
|
| 280 |
+
<origin xyz="0.029812 0.001045 -0.087934" rpy="0 0 0"/>
|
| 281 |
+
<mass value="1.52"/>
|
| 282 |
+
<inertia ixx="0.0023773" ixy="3.8E-06" ixz="-0.0003908" iyy="0.0024123" iyz="-1.84E-05" izz="0.0016595"/>
|
| 283 |
+
</inertial>
|
| 284 |
+
<visual>
|
| 285 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 286 |
+
<geometry>
|
| 287 |
+
<mesh filename="meshes/right_hip_roll_link.STL"/>
|
| 288 |
+
</geometry>
|
| 289 |
+
<material name="white">
|
| 290 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 291 |
+
</material>
|
| 292 |
+
</visual>
|
| 293 |
+
<collision>
|
| 294 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 295 |
+
<geometry>
|
| 296 |
+
<mesh filename="meshes/right_hip_roll_link.STL"/>
|
| 297 |
+
</geometry>
|
| 298 |
+
</collision>
|
| 299 |
+
</link>
|
| 300 |
+
<joint name="right_hip_roll_joint" type="revolute">
|
| 301 |
+
<origin xyz="0 -0.052 -0.030465" rpy="0 -0.1749 0"/>
|
| 302 |
+
<parent link="right_hip_pitch_link"/>
|
| 303 |
+
<child link="right_hip_roll_link"/>
|
| 304 |
+
<axis xyz="1 0 0"/>
|
| 305 |
+
<limit lower="-2.9671" upper="0.5236" effort="88" velocity="32"/>
|
| 306 |
+
</joint>
|
| 307 |
+
<link name="right_hip_yaw_link">
|
| 308 |
+
<inertial>
|
| 309 |
+
<origin xyz="-0.057709 0.010981 -0.15078" rpy="0 0 0"/>
|
| 310 |
+
<mass value="1.702"/>
|
| 311 |
+
<inertia ixx="0.0057774" ixy="0.0005411" ixz="-0.0023948" iyy="0.0076124" iyz="0.0007072" izz="0.003149"/>
|
| 312 |
+
</inertial>
|
| 313 |
+
<visual>
|
| 314 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 315 |
+
<geometry>
|
| 316 |
+
<mesh filename="meshes/right_hip_yaw_link.STL"/>
|
| 317 |
+
</geometry>
|
| 318 |
+
<material name="white">
|
| 319 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 320 |
+
</material>
|
| 321 |
+
</visual>
|
| 322 |
+
<collision>
|
| 323 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 324 |
+
<geometry>
|
| 325 |
+
<mesh filename="meshes/right_hip_yaw_link.STL"/>
|
| 326 |
+
</geometry>
|
| 327 |
+
</collision>
|
| 328 |
+
</link>
|
| 329 |
+
<joint name="right_hip_yaw_joint" type="revolute">
|
| 330 |
+
<origin xyz="0.025001 0 -0.12412" rpy="0 0 0"/>
|
| 331 |
+
<parent link="right_hip_roll_link"/>
|
| 332 |
+
<child link="right_hip_yaw_link"/>
|
| 333 |
+
<axis xyz="0 0 1"/>
|
| 334 |
+
<limit lower="-2.7576" upper="2.7576" effort="88" velocity="32"/>
|
| 335 |
+
</joint>
|
| 336 |
+
<link name="right_knee_link">
|
| 337 |
+
<inertial>
|
| 338 |
+
<origin xyz="0.005457 -0.003964 -0.12074" rpy="0 0 0"/>
|
| 339 |
+
<mass value="1.932"/>
|
| 340 |
+
<inertia ixx="0.011329" ixy="-4.82E-05" ixz="4.49E-05" iyy="0.011277" iyz="0.0007146" izz="0.0015168"/>
|
| 341 |
+
</inertial>
|
| 342 |
+
<visual>
|
| 343 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 344 |
+
<geometry>
|
| 345 |
+
<mesh filename="meshes/right_knee_link.STL"/>
|
| 346 |
+
</geometry>
|
| 347 |
+
<material name="white">
|
| 348 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 349 |
+
</material>
|
| 350 |
+
</visual>
|
| 351 |
+
<collision>
|
| 352 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 353 |
+
<geometry>
|
| 354 |
+
<mesh filename="meshes/right_knee_link.STL"/>
|
| 355 |
+
</geometry>
|
| 356 |
+
</collision>
|
| 357 |
+
</link>
|
| 358 |
+
<joint name="right_knee_joint" type="revolute">
|
| 359 |
+
<origin xyz="-0.078273 -0.0021489 -0.17734" rpy="0 0.1749 0"/>
|
| 360 |
+
<parent link="right_hip_yaw_link"/>
|
| 361 |
+
<child link="right_knee_link"/>
|
| 362 |
+
<axis xyz="0 1 0"/>
|
| 363 |
+
<limit lower="-0.087267" upper="2.8798" effort="139" velocity="20"/>
|
| 364 |
+
</joint>
|
| 365 |
+
<link name="right_ankle_pitch_link">
|
| 366 |
+
<inertial>
|
| 367 |
+
<origin xyz="-0.007269 0 0.011137" rpy="0 0 0"/>
|
| 368 |
+
<mass value="0.074"/>
|
| 369 |
+
<inertia ixx="8.4E-06" ixy="0" ixz="-2.9E-06" iyy="1.89E-05" iyz="0" izz="1.26E-05"/>
|
| 370 |
+
</inertial>
|
| 371 |
+
<visual>
|
| 372 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 373 |
+
<geometry>
|
| 374 |
+
<mesh filename="meshes/right_ankle_pitch_link.STL"/>
|
| 375 |
+
</geometry>
|
| 376 |
+
<material name="white">
|
| 377 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 378 |
+
</material>
|
| 379 |
+
</visual>
|
| 380 |
+
<collision>
|
| 381 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 382 |
+
<geometry>
|
| 383 |
+
<mesh filename="meshes/right_ankle_pitch_link.STL"/>
|
| 384 |
+
</geometry>
|
| 385 |
+
</collision>
|
| 386 |
+
</link>
|
| 387 |
+
<joint name="right_ankle_pitch_joint" type="revolute">
|
| 388 |
+
<origin xyz="0 9.4445E-05 -0.30001" rpy="0 0 0"/>
|
| 389 |
+
<parent link="right_knee_link"/>
|
| 390 |
+
<child link="right_ankle_pitch_link"/>
|
| 391 |
+
<axis xyz="0 1 0"/>
|
| 392 |
+
<limit lower="-0.87267" upper="0.5236" effort="50" velocity="37"/>
|
| 393 |
+
</joint>
|
| 394 |
+
<link name="right_ankle_roll_link">
|
| 395 |
+
<inertial>
|
| 396 |
+
<origin xyz="0.026505 0 -0.016425" rpy="0 0 0"/>
|
| 397 |
+
<mass value="0.608"/>
|
| 398 |
+
<inertia ixx="0.0002231" ixy="-2E-07" ixz="8.91E-05" iyy="0.0016161" iyz="1E-07" izz="0.0016667"/>
|
| 399 |
+
</inertial>
|
| 400 |
+
<visual>
|
| 401 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 402 |
+
<geometry>
|
| 403 |
+
<mesh filename="meshes/right_ankle_roll_link.STL"/>
|
| 404 |
+
</geometry>
|
| 405 |
+
<material name="dark">
|
| 406 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 407 |
+
</material>
|
| 408 |
+
</visual>
|
| 409 |
+
<collision>
|
| 410 |
+
<origin xyz="-0.05 0.025 -0.03" rpy="0 0 0"/>
|
| 411 |
+
<geometry>
|
| 412 |
+
<sphere radius="0.005"/>
|
| 413 |
+
</geometry>
|
| 414 |
+
</collision>
|
| 415 |
+
<collision>
|
| 416 |
+
<origin xyz="-0.05 -0.025 -0.03" rpy="0 0 0"/>
|
| 417 |
+
<geometry>
|
| 418 |
+
<sphere radius="0.005"/>
|
| 419 |
+
</geometry>
|
| 420 |
+
</collision>
|
| 421 |
+
<collision>
|
| 422 |
+
<origin xyz="0.12 0.03 -0.03" rpy="0 0 0"/>
|
| 423 |
+
<geometry>
|
| 424 |
+
<sphere radius="0.005"/>
|
| 425 |
+
</geometry>
|
| 426 |
+
</collision>
|
| 427 |
+
<collision>
|
| 428 |
+
<origin xyz="0.12 -0.03 -0.03" rpy="0 0 0"/>
|
| 429 |
+
<geometry>
|
| 430 |
+
<sphere radius="0.005"/>
|
| 431 |
+
</geometry>
|
| 432 |
+
</collision>
|
| 433 |
+
</link>
|
| 434 |
+
<joint name="right_ankle_roll_joint" type="revolute">
|
| 435 |
+
<origin xyz="0 0 -0.017558" rpy="0 0 0"/>
|
| 436 |
+
<parent link="right_ankle_pitch_link"/>
|
| 437 |
+
<child link="right_ankle_roll_link"/>
|
| 438 |
+
<axis xyz="1 0 0"/>
|
| 439 |
+
<limit lower="-0.2618" upper="0.2618" effort="50" velocity="37"/>
|
| 440 |
+
</joint>
|
| 441 |
+
|
| 442 |
+
<!-- Torso -->
|
| 443 |
+
<link name="waist_yaw_link">
|
| 444 |
+
<inertial>
|
| 445 |
+
<origin xyz="0.003964 0 0.018769" rpy="0 0 0"/>
|
| 446 |
+
<mass value="0.244"/>
|
| 447 |
+
<inertia ixx="9.9587E-05" ixy="-1.833E-06" ixz="-1.2617E-05" iyy="0.00012411" iyz="-1.18E-07" izz="0.00015586"/>
|
| 448 |
+
</inertial>
|
| 449 |
+
<visual>
|
| 450 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 451 |
+
<geometry>
|
| 452 |
+
<mesh filename="meshes/waist_yaw_link.STL"/>
|
| 453 |
+
</geometry>
|
| 454 |
+
<material name="white">
|
| 455 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 456 |
+
</material>
|
| 457 |
+
</visual>
|
| 458 |
+
</link>
|
| 459 |
+
<joint name="waist_yaw_joint" type="revolute">
|
| 460 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 461 |
+
<parent link="pelvis"/>
|
| 462 |
+
<child link="waist_yaw_link"/>
|
| 463 |
+
<axis xyz="0 0 1"/>
|
| 464 |
+
<limit lower="-2.618" upper="2.618" effort="88" velocity="32"/>
|
| 465 |
+
</joint>
|
| 466 |
+
<link name="waist_roll_link">
|
| 467 |
+
<inertial>
|
| 468 |
+
<origin xyz="0 -0.000236 0.010111" rpy="0 0 0"/>
|
| 469 |
+
<mass value="0.047"/>
|
| 470 |
+
<inertia ixx="7.515E-06" ixy="0" ixz="0" iyy="6.398E-06" iyz="9.9E-08" izz="3.988E-06"/>
|
| 471 |
+
</inertial>
|
| 472 |
+
<visual>
|
| 473 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 474 |
+
<geometry>
|
| 475 |
+
<mesh filename="meshes/waist_roll_link.STL"/>
|
| 476 |
+
</geometry>
|
| 477 |
+
<material name="white">
|
| 478 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 479 |
+
</material>
|
| 480 |
+
</visual>
|
| 481 |
+
</link>
|
| 482 |
+
<joint name="waist_roll_joint" type="revolute">
|
| 483 |
+
<origin xyz="-0.0039635 0 0.035" rpy="0 0 0"/>
|
| 484 |
+
<parent link="waist_yaw_link"/>
|
| 485 |
+
<child link="waist_roll_link"/>
|
| 486 |
+
<axis xyz="1 0 0"/>
|
| 487 |
+
<limit lower="-0.52" upper="0.52" effort="50" velocity="37"/>
|
| 488 |
+
</joint>
|
| 489 |
+
<link name="torso_link">
|
| 490 |
+
<inertial>
|
| 491 |
+
<origin xyz="0.002601 0.000257 0.153719" rpy="0 0 0"/>
|
| 492 |
+
<mass value="8.562"/>
|
| 493 |
+
<inertia ixx="0.065674966" ixy="-8.597E-05" ixz="-0.001737252" iyy="0.053535188" iyz="8.6899E-05" izz="0.030808125"/>
|
| 494 |
+
</inertial>
|
| 495 |
+
<visual>
|
| 496 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 497 |
+
<geometry>
|
| 498 |
+
<mesh filename="meshes/torso_link.STL"/>
|
| 499 |
+
</geometry>
|
| 500 |
+
<material name="white">
|
| 501 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 502 |
+
</material>
|
| 503 |
+
</visual>
|
| 504 |
+
<collision>
|
| 505 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 506 |
+
<geometry>
|
| 507 |
+
<mesh filename="meshes/torso_link.STL"/>
|
| 508 |
+
</geometry>
|
| 509 |
+
</collision>
|
| 510 |
+
</link>
|
| 511 |
+
<joint name="waist_pitch_joint" type="revolute">
|
| 512 |
+
<origin xyz="0 0 0.019" rpy="0 0 0"/>
|
| 513 |
+
<parent link="waist_roll_link"/>
|
| 514 |
+
<child link="torso_link"/>
|
| 515 |
+
<axis xyz="0 1 0"/>
|
| 516 |
+
<limit lower="-0.52" upper="0.52" effort="50" velocity="37"/>
|
| 517 |
+
</joint>
|
| 518 |
+
|
| 519 |
+
<!-- LOGO -->
|
| 520 |
+
<joint name="logo_joint" type="fixed">
|
| 521 |
+
<origin xyz="0.0039635 0 -0.054" rpy="0 0 0"/>
|
| 522 |
+
<parent link="torso_link"/>
|
| 523 |
+
<child link="logo_link"/>
|
| 524 |
+
</joint>
|
| 525 |
+
<link name="logo_link">
|
| 526 |
+
<inertial>
|
| 527 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 528 |
+
<mass value="0.001"/>
|
| 529 |
+
<inertia ixx="1e-7" ixy="0" ixz="0" iyy="1e-7" iyz="0" izz="1e-7"/>
|
| 530 |
+
</inertial>
|
| 531 |
+
<visual>
|
| 532 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 533 |
+
<geometry>
|
| 534 |
+
<mesh filename="meshes/logo_link.STL"/>
|
| 535 |
+
</geometry>
|
| 536 |
+
<material name="dark">
|
| 537 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 538 |
+
</material>
|
| 539 |
+
</visual>
|
| 540 |
+
<collision>
|
| 541 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 542 |
+
<geometry>
|
| 543 |
+
<mesh filename="meshes/logo_link.STL"/>
|
| 544 |
+
</geometry>
|
| 545 |
+
</collision>
|
| 546 |
+
</link>
|
| 547 |
+
|
| 548 |
+
<!-- Head -->
|
| 549 |
+
<link name="head_link">
|
| 550 |
+
<inertial>
|
| 551 |
+
<origin xyz="0.005267 0.000299 0.449869" rpy="0 0 0"/>
|
| 552 |
+
<mass value="1.036"/>
|
| 553 |
+
<inertia ixx="0.004085051" ixy="-2.543E-06" ixz="-6.9455E-05" iyy="0.004185212" iyz="-3.726E-06" izz="0.001807911"/>
|
| 554 |
+
</inertial>
|
| 555 |
+
<visual>
|
| 556 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 557 |
+
<geometry>
|
| 558 |
+
<mesh filename="meshes/head_link.STL"/>
|
| 559 |
+
</geometry>
|
| 560 |
+
<material name="dark">
|
| 561 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 562 |
+
</material>
|
| 563 |
+
</visual>
|
| 564 |
+
<collision>
|
| 565 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 566 |
+
<geometry>
|
| 567 |
+
<mesh filename="meshes/head_link.STL"/>
|
| 568 |
+
</geometry>
|
| 569 |
+
</collision>
|
| 570 |
+
</link>
|
| 571 |
+
<joint name="head_joint" type="fixed">
|
| 572 |
+
<origin xyz="0.0039635 0 -0.054" rpy="0 0 0"/>
|
| 573 |
+
<parent link="torso_link"/>
|
| 574 |
+
<child link="head_link"/>
|
| 575 |
+
</joint>
|
| 576 |
+
|
| 577 |
+
<!-- Waist Support -->
|
| 578 |
+
<link name="waist_support_link">
|
| 579 |
+
<inertial>
|
| 580 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 581 |
+
<mass value="0.001"/>
|
| 582 |
+
<inertia ixx="1e-7" ixy="0" ixz="0" iyy="1e-7" iyz="0" izz="1e-7"/>
|
| 583 |
+
</inertial>
|
| 584 |
+
<visual>
|
| 585 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 586 |
+
<geometry>
|
| 587 |
+
<mesh filename="meshes/waist_support_link.STL"/>
|
| 588 |
+
</geometry>
|
| 589 |
+
<material name="white">
|
| 590 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 591 |
+
</material>
|
| 592 |
+
</visual>
|
| 593 |
+
<collision>
|
| 594 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 595 |
+
<geometry>
|
| 596 |
+
<mesh filename="meshes/waist_support_link.STL"/>
|
| 597 |
+
</geometry>
|
| 598 |
+
</collision>
|
| 599 |
+
</link>
|
| 600 |
+
<joint name="waist_support_joint" type="fixed">
|
| 601 |
+
<origin xyz="0.0039635 0 -0.054" rpy="0 0 0"/>
|
| 602 |
+
<parent link="torso_link"/>
|
| 603 |
+
<child link="waist_support_link"/>
|
| 604 |
+
</joint>
|
| 605 |
+
|
| 606 |
+
<!-- IMU -->
|
| 607 |
+
<link name="imu_link"></link>
|
| 608 |
+
<joint name="imu_joint" type="fixed">
|
| 609 |
+
<origin xyz="-0.03959 -0.00224 0.13792" rpy="0 0 0"/>
|
| 610 |
+
<parent link="torso_link"/>
|
| 611 |
+
<child link="imu_link"/>
|
| 612 |
+
</joint>
|
| 613 |
+
|
| 614 |
+
<!-- d435 -->
|
| 615 |
+
<link name="d435_link"></link>
|
| 616 |
+
<joint name="d435_joint" type="fixed">
|
| 617 |
+
<origin xyz="0.0576235 0.01753 0.41987" rpy="0 0.8307767239493009 0"/>
|
| 618 |
+
<parent link="torso_link"/>
|
| 619 |
+
<child link="d435_link"/>
|
| 620 |
+
</joint>
|
| 621 |
+
|
| 622 |
+
<!-- mid360 -->
|
| 623 |
+
<link name="mid360_link"></link>
|
| 624 |
+
<joint name="mid360_joint" type="fixed">
|
| 625 |
+
<origin xyz="0.0002835 0.00003 0.40618" rpy="0 0.04014257279586953 0"/>
|
| 626 |
+
<parent link="torso_link"/>
|
| 627 |
+
<child link="mid360_link"/>
|
| 628 |
+
</joint>
|
| 629 |
+
|
| 630 |
+
<!-- Arm -->
|
| 631 |
+
<link name="left_shoulder_pitch_link">
|
| 632 |
+
<inertial>
|
| 633 |
+
<origin xyz="0 0.035892 -0.011628" rpy="0 0 0"/>
|
| 634 |
+
<mass value="0.718"/>
|
| 635 |
+
<inertia ixx="0.0004291" ixy="-9.2E-06" ixz="6.4E-06" iyy="0.000453" iyz="2.26E-05" izz="0.000423"/>
|
| 636 |
+
</inertial>
|
| 637 |
+
<visual>
|
| 638 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 639 |
+
<geometry>
|
| 640 |
+
<mesh filename="meshes/left_shoulder_pitch_link.STL"/>
|
| 641 |
+
</geometry>
|
| 642 |
+
<material name="white">
|
| 643 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 644 |
+
</material>
|
| 645 |
+
</visual>
|
| 646 |
+
<collision>
|
| 647 |
+
<origin xyz="0 0.04 -0.01" rpy="0 1.5707963267948966 0"/>
|
| 648 |
+
<geometry>
|
| 649 |
+
<cylinder radius="0.03" length="0.05"/>
|
| 650 |
+
</geometry>
|
| 651 |
+
</collision>
|
| 652 |
+
</link>
|
| 653 |
+
<joint name="left_shoulder_pitch_joint" type="revolute">
|
| 654 |
+
<origin xyz="0.0039563 0.10022 0.23778" rpy="0.27931 5.4949E-05 -0.00019159"/>
|
| 655 |
+
<parent link="torso_link"/>
|
| 656 |
+
<child link="left_shoulder_pitch_link"/>
|
| 657 |
+
<axis xyz="0 1 0"/>
|
| 658 |
+
<limit lower="-3.0892" upper="2.6704" effort="25" velocity="37"/>
|
| 659 |
+
</joint>
|
| 660 |
+
<link name="left_shoulder_roll_link">
|
| 661 |
+
<inertial>
|
| 662 |
+
<origin xyz="-0.000227 0.00727 -0.063243" rpy="0 0 0"/>
|
| 663 |
+
<mass value="0.643"/>
|
| 664 |
+
<inertia ixx="0.0006177" ixy="-1E-06" ixz="8.7E-06" iyy="0.0006912" iyz="-5.3E-06" izz="0.0003894"/>
|
| 665 |
+
</inertial>
|
| 666 |
+
<visual>
|
| 667 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 668 |
+
<geometry>
|
| 669 |
+
<mesh filename="meshes/left_shoulder_roll_link.STL"/>
|
| 670 |
+
</geometry>
|
| 671 |
+
<material name="white">
|
| 672 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 673 |
+
</material>
|
| 674 |
+
</visual>
|
| 675 |
+
<collision>
|
| 676 |
+
<origin xyz="-0.004 0.006 -0.053" rpy="0 0 0"/>
|
| 677 |
+
<geometry>
|
| 678 |
+
<cylinder radius="0.03" length="0.03"/>
|
| 679 |
+
</geometry>
|
| 680 |
+
</collision>
|
| 681 |
+
</link>
|
| 682 |
+
<joint name="left_shoulder_roll_joint" type="revolute">
|
| 683 |
+
<origin xyz="0 0.038 -0.013831" rpy="-0.27925 0 0"/>
|
| 684 |
+
<parent link="left_shoulder_pitch_link"/>
|
| 685 |
+
<child link="left_shoulder_roll_link"/>
|
| 686 |
+
<axis xyz="1 0 0"/>
|
| 687 |
+
<limit lower="-1.5882" upper="2.2515" effort="25" velocity="37"/>
|
| 688 |
+
</joint>
|
| 689 |
+
<link name="left_shoulder_yaw_link">
|
| 690 |
+
<inertial>
|
| 691 |
+
<origin xyz="0.010773 -0.002949 -0.072009" rpy="0 0 0"/>
|
| 692 |
+
<mass value="0.734"/>
|
| 693 |
+
<inertia ixx="0.0009988" ixy="7.9E-06" ixz="0.0001412" iyy="0.0010605" iyz="-2.86E-05" izz="0.0004354"/>
|
| 694 |
+
</inertial>
|
| 695 |
+
<visual>
|
| 696 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 697 |
+
<geometry>
|
| 698 |
+
<mesh filename="meshes/left_shoulder_yaw_link.STL"/>
|
| 699 |
+
</geometry>
|
| 700 |
+
<material name="white">
|
| 701 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 702 |
+
</material>
|
| 703 |
+
</visual>
|
| 704 |
+
<collision>
|
| 705 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 706 |
+
<geometry>
|
| 707 |
+
<mesh filename="meshes/left_shoulder_yaw_link.STL"/>
|
| 708 |
+
</geometry>
|
| 709 |
+
</collision>
|
| 710 |
+
</link>
|
| 711 |
+
<joint name="left_shoulder_yaw_joint" type="revolute">
|
| 712 |
+
<origin xyz="0 0.00624 -0.1032" rpy="0 0 0"/>
|
| 713 |
+
<parent link="left_shoulder_roll_link"/>
|
| 714 |
+
<child link="left_shoulder_yaw_link"/>
|
| 715 |
+
<axis xyz="0 0 1"/>
|
| 716 |
+
<limit lower="-2.618" upper="2.618" effort="25" velocity="37"/>
|
| 717 |
+
</joint>
|
| 718 |
+
<link name="left_elbow_link">
|
| 719 |
+
<inertial>
|
| 720 |
+
<origin xyz="0.064956 0.004454 -0.010062" rpy="0 0 0"/>
|
| 721 |
+
<mass value="0.6"/>
|
| 722 |
+
<inertia ixx="0.0002891" ixy="6.53E-05" ixz="1.72E-05" iyy="0.0004152" iyz="-5.6E-06" izz="0.0004197"/>
|
| 723 |
+
</inertial>
|
| 724 |
+
<visual>
|
| 725 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 726 |
+
<geometry>
|
| 727 |
+
<mesh filename="meshes/left_elbow_link.STL"/>
|
| 728 |
+
</geometry>
|
| 729 |
+
<material name="white">
|
| 730 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 731 |
+
</material>
|
| 732 |
+
</visual>
|
| 733 |
+
<collision>
|
| 734 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 735 |
+
<geometry>
|
| 736 |
+
<mesh filename="meshes/left_elbow_link.STL"/>
|
| 737 |
+
</geometry>
|
| 738 |
+
</collision>
|
| 739 |
+
</link>
|
| 740 |
+
<joint name="left_elbow_joint" type="revolute">
|
| 741 |
+
<origin xyz="0.015783 0 -0.080518" rpy="0 0 0"/>
|
| 742 |
+
<parent link="left_shoulder_yaw_link"/>
|
| 743 |
+
<child link="left_elbow_link"/>
|
| 744 |
+
<axis xyz="0 1 0"/>
|
| 745 |
+
<limit lower="-1.0472" upper="2.0944" effort="25" velocity="37"/>
|
| 746 |
+
</joint>
|
| 747 |
+
<joint name="left_wrist_roll_joint" type="revolute">
|
| 748 |
+
<origin xyz="0.100 0.00188791 -0.010" rpy="0 0 0"/>
|
| 749 |
+
<axis xyz="1 0 0"/>
|
| 750 |
+
<parent link="left_elbow_link"/>
|
| 751 |
+
<child link="left_wrist_roll_link"/>
|
| 752 |
+
<limit effort="25" velocity="37" lower="-1.972222054" upper="1.972222054"/>
|
| 753 |
+
</joint>
|
| 754 |
+
<link name="left_wrist_roll_link">
|
| 755 |
+
<inertial>
|
| 756 |
+
<origin xyz="0.01713944778 0.00053759094 0.00000048864" rpy="0 0 0"/>
|
| 757 |
+
<mass value="0.08544498"/>
|
| 758 |
+
<inertia ixx="0.00004821544023" ixy="-0.00000424511021" ixz="0.00000000510599" iyy="0.00003722899093" iyz="-0.00000000123525" izz="0.00005482106541"/>
|
| 759 |
+
</inertial>
|
| 760 |
+
<visual>
|
| 761 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 762 |
+
<geometry>
|
| 763 |
+
<mesh filename="meshes/left_wrist_roll_link.STL"/>
|
| 764 |
+
</geometry>
|
| 765 |
+
<material name="white">
|
| 766 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 767 |
+
</material>
|
| 768 |
+
</visual>
|
| 769 |
+
<collision>
|
| 770 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 771 |
+
<geometry>
|
| 772 |
+
<mesh filename="meshes/left_wrist_roll_link.STL"/>
|
| 773 |
+
</geometry>
|
| 774 |
+
</collision>
|
| 775 |
+
</link>
|
| 776 |
+
<joint name="left_wrist_pitch_joint" type="revolute">
|
| 777 |
+
<origin xyz="0.038 0 0" rpy="0 0 0"/>
|
| 778 |
+
<axis xyz="0 1 0"/>
|
| 779 |
+
<parent link="left_wrist_roll_link"/>
|
| 780 |
+
<child link="left_wrist_pitch_link"/>
|
| 781 |
+
<limit effort="5" velocity="22" lower="-1.614429558" upper="1.614429558"/>
|
| 782 |
+
</joint>
|
| 783 |
+
<link name="left_wrist_pitch_link">
|
| 784 |
+
<inertial>
|
| 785 |
+
<origin xyz="0.02299989837 -0.00111685314 -0.00111658096" rpy="0 0 0"/>
|
| 786 |
+
<mass value="0.48404956"/>
|
| 787 |
+
<inertia ixx="0.00016579646273" ixy="-0.00001231206746" ixz="0.00001231699194" iyy="0.00042954057410" iyz="0.00000081417712" izz="0.00042953697654"/>
|
| 788 |
+
</inertial>
|
| 789 |
+
<visual>
|
| 790 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 791 |
+
<geometry>
|
| 792 |
+
<mesh filename="meshes/left_wrist_pitch_link.STL"/>
|
| 793 |
+
</geometry>
|
| 794 |
+
<material name="white">
|
| 795 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 796 |
+
</material>
|
| 797 |
+
</visual>
|
| 798 |
+
<collision>
|
| 799 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 800 |
+
<geometry>
|
| 801 |
+
<mesh filename="meshes/left_wrist_pitch_link.STL"/>
|
| 802 |
+
</geometry>
|
| 803 |
+
</collision>
|
| 804 |
+
</link>
|
| 805 |
+
<joint name="left_wrist_yaw_joint" type="revolute">
|
| 806 |
+
<origin xyz="0.046 0 0" rpy="0 0 0"/>
|
| 807 |
+
<axis xyz="0 0 1"/>
|
| 808 |
+
<parent link="left_wrist_pitch_link"/>
|
| 809 |
+
<child link="left_wrist_yaw_link"/>
|
| 810 |
+
<limit effort="5" velocity="22" lower="-1.614429558" upper="1.614429558"/>
|
| 811 |
+
</joint>
|
| 812 |
+
<link name="left_wrist_yaw_link">
|
| 813 |
+
<inertial>
|
| 814 |
+
<origin xyz="0.02200381568 0.00049485096 0.00053861123" rpy="0 0 0"/>
|
| 815 |
+
<mass value="0.08457647"/>
|
| 816 |
+
<inertia ixx="0.00004929128828" ixy="-0.00000045735494" ixz="0.00000445867591" iyy="0.00005973338134" iyz="0.00000043217198" izz="0.00003928083826"/>
|
| 817 |
+
</inertial>
|
| 818 |
+
<visual>
|
| 819 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 820 |
+
<geometry>
|
| 821 |
+
<mesh filename="meshes/left_wrist_yaw_link.STL"/>
|
| 822 |
+
</geometry>
|
| 823 |
+
<material name="white">
|
| 824 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 825 |
+
</material>
|
| 826 |
+
</visual>
|
| 827 |
+
<collision>
|
| 828 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 829 |
+
<geometry>
|
| 830 |
+
<mesh filename="meshes/left_wrist_yaw_link.STL"/>
|
| 831 |
+
</geometry>
|
| 832 |
+
</collision>
|
| 833 |
+
</link>
|
| 834 |
+
<joint name="left_hand_palm_joint" type="fixed">
|
| 835 |
+
<origin xyz="0.0415 0.003 0" rpy="0 0 0"/>
|
| 836 |
+
<parent link="left_wrist_yaw_link"/>
|
| 837 |
+
<child link="left_rubber_hand"/>
|
| 838 |
+
</joint>
|
| 839 |
+
<link name="left_rubber_hand">
|
| 840 |
+
<inertial>
|
| 841 |
+
<origin xyz="0.05361310808 -0.00295905240 0.00215413091" rpy="0 0 0"/>
|
| 842 |
+
<mass value="0.170"/>
|
| 843 |
+
<inertia ixx="0.00010099485234748" ixy="0.00003618590790516" ixz="-0.00000074301518642" iyy="0.00028135871571621" iyz="0.00000330189743286" izz="0.00021894770413514"/>
|
| 844 |
+
</inertial>
|
| 845 |
+
<visual>
|
| 846 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 847 |
+
<geometry>
|
| 848 |
+
<mesh filename="meshes/left_rubber_hand.STL"/>
|
| 849 |
+
</geometry>
|
| 850 |
+
<material name="white">
|
| 851 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 852 |
+
</material>
|
| 853 |
+
</visual>
|
| 854 |
+
<collision>
|
| 855 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 856 |
+
<geometry>
|
| 857 |
+
<mesh filename="meshes/left_rubber_hand.STL"/>
|
| 858 |
+
</geometry>
|
| 859 |
+
</collision>
|
| 860 |
+
</link>
|
| 861 |
+
<link name="right_shoulder_pitch_link">
|
| 862 |
+
<inertial>
|
| 863 |
+
<origin xyz="0 -0.035892 -0.011628" rpy="0 0 0"/>
|
| 864 |
+
<mass value="0.718"/>
|
| 865 |
+
<inertia ixx="0.0004291" ixy="9.2E-06" ixz="6.4E-06" iyy="0.000453" iyz="-2.26E-05" izz="0.000423"/>
|
| 866 |
+
</inertial>
|
| 867 |
+
<visual>
|
| 868 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 869 |
+
<geometry>
|
| 870 |
+
<mesh filename="meshes/right_shoulder_pitch_link.STL"/>
|
| 871 |
+
</geometry>
|
| 872 |
+
<material name="white">
|
| 873 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 874 |
+
</material>
|
| 875 |
+
</visual>
|
| 876 |
+
<collision>
|
| 877 |
+
<origin xyz="0 -0.04 -0.01" rpy="0 1.5707963267948966 0"/>
|
| 878 |
+
<geometry>
|
| 879 |
+
<cylinder radius="0.03" length="0.05"/>
|
| 880 |
+
</geometry>
|
| 881 |
+
</collision>
|
| 882 |
+
</link>
|
| 883 |
+
<joint name="right_shoulder_pitch_joint" type="revolute">
|
| 884 |
+
<origin xyz="0.0039563 -0.10021 0.23778" rpy="-0.27931 5.4949E-05 0.00019159"/>
|
| 885 |
+
<parent link="torso_link"/>
|
| 886 |
+
<child link="right_shoulder_pitch_link"/>
|
| 887 |
+
<axis xyz="0 1 0"/>
|
| 888 |
+
<limit lower="-3.0892" upper="2.6704" effort="25" velocity="37"/>
|
| 889 |
+
</joint>
|
| 890 |
+
<link name="right_shoulder_roll_link">
|
| 891 |
+
<inertial>
|
| 892 |
+
<origin xyz="-0.000227 -0.00727 -0.063243" rpy="0 0 0"/>
|
| 893 |
+
<mass value="0.643"/>
|
| 894 |
+
<inertia ixx="0.0006177" ixy="1E-06" ixz="8.7E-06" iyy="0.0006912" iyz="5.3E-06" izz="0.0003894"/>
|
| 895 |
+
</inertial>
|
| 896 |
+
<visual>
|
| 897 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 898 |
+
<geometry>
|
| 899 |
+
<mesh filename="meshes/right_shoulder_roll_link.STL"/>
|
| 900 |
+
</geometry>
|
| 901 |
+
<material name="white">
|
| 902 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 903 |
+
</material>
|
| 904 |
+
</visual>
|
| 905 |
+
<collision>
|
| 906 |
+
<origin xyz="-0.004 -0.006 -0.053" rpy="0 0 0"/>
|
| 907 |
+
<geometry>
|
| 908 |
+
<cylinder radius="0.03" length="0.03"/>
|
| 909 |
+
</geometry>
|
| 910 |
+
</collision>
|
| 911 |
+
</link>
|
| 912 |
+
<joint name="right_shoulder_roll_joint" type="revolute">
|
| 913 |
+
<origin xyz="0 -0.038 -0.013831" rpy="0.27925 0 0"/>
|
| 914 |
+
<parent link="right_shoulder_pitch_link"/>
|
| 915 |
+
<child link="right_shoulder_roll_link"/>
|
| 916 |
+
<axis xyz="1 0 0"/>
|
| 917 |
+
<limit lower="-2.2515" upper="1.5882" effort="25" velocity="37"/>
|
| 918 |
+
</joint>
|
| 919 |
+
<link name="right_shoulder_yaw_link">
|
| 920 |
+
<inertial>
|
| 921 |
+
<origin xyz="0.010773 0.002949 -0.072009" rpy="0 0 0"/>
|
| 922 |
+
<mass value="0.734"/>
|
| 923 |
+
<inertia ixx="0.0009988" ixy="-7.9E-06" ixz="0.0001412" iyy="0.0010605" iyz="2.86E-05" izz="0.0004354"/>
|
| 924 |
+
</inertial>
|
| 925 |
+
<visual>
|
| 926 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 927 |
+
<geometry>
|
| 928 |
+
<mesh filename="meshes/right_shoulder_yaw_link.STL"/>
|
| 929 |
+
</geometry>
|
| 930 |
+
<material name="white">
|
| 931 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 932 |
+
</material>
|
| 933 |
+
</visual>
|
| 934 |
+
<collision>
|
| 935 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 936 |
+
<geometry>
|
| 937 |
+
<mesh filename="meshes/right_shoulder_yaw_link.STL"/>
|
| 938 |
+
</geometry>
|
| 939 |
+
</collision>
|
| 940 |
+
</link>
|
| 941 |
+
<joint name="right_shoulder_yaw_joint" type="revolute">
|
| 942 |
+
<origin xyz="0 -0.00624 -0.1032" rpy="0 0 0"/>
|
| 943 |
+
<parent link="right_shoulder_roll_link"/>
|
| 944 |
+
<child link="right_shoulder_yaw_link"/>
|
| 945 |
+
<axis xyz="0 0 1"/>
|
| 946 |
+
<limit lower="-2.618" upper="2.618" effort="25" velocity="37"/>
|
| 947 |
+
</joint>
|
| 948 |
+
<link name="right_elbow_link">
|
| 949 |
+
<inertial>
|
| 950 |
+
<origin xyz="0.064956 -0.004454 -0.010062" rpy="0 0 0"/>
|
| 951 |
+
<mass value="0.6"/>
|
| 952 |
+
<inertia ixx="0.0002891" ixy="-6.53E-05" ixz="1.72E-05" iyy="0.0004152" iyz="5.6E-06" izz="0.0004197"/>
|
| 953 |
+
</inertial>
|
| 954 |
+
<visual>
|
| 955 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 956 |
+
<geometry>
|
| 957 |
+
<mesh filename="meshes/right_elbow_link.STL"/>
|
| 958 |
+
</geometry>
|
| 959 |
+
<material name="white">
|
| 960 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 961 |
+
</material>
|
| 962 |
+
</visual>
|
| 963 |
+
<collision>
|
| 964 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 965 |
+
<geometry>
|
| 966 |
+
<mesh filename="meshes/right_elbow_link.STL"/>
|
| 967 |
+
</geometry>
|
| 968 |
+
</collision>
|
| 969 |
+
</link>
|
| 970 |
+
<joint name="right_elbow_joint" type="revolute">
|
| 971 |
+
<origin xyz="0.015783 0 -0.080518" rpy="0 0 0"/>
|
| 972 |
+
<parent link="right_shoulder_yaw_link"/>
|
| 973 |
+
<child link="right_elbow_link"/>
|
| 974 |
+
<axis xyz="0 1 0"/>
|
| 975 |
+
<limit lower="-1.0472" upper="2.0944" effort="25" velocity="37"/>
|
| 976 |
+
</joint>
|
| 977 |
+
<joint name="right_wrist_roll_joint" type="revolute">
|
| 978 |
+
<origin xyz="0.100 -0.00188791 -0.010" rpy="0 0 0"/>
|
| 979 |
+
<axis xyz="1 0 0"/>
|
| 980 |
+
<parent link="right_elbow_link"/>
|
| 981 |
+
<child link="right_wrist_roll_link"/>
|
| 982 |
+
<limit effort="25" velocity="37" lower="-1.972222054" upper="1.972222054"/>
|
| 983 |
+
</joint>
|
| 984 |
+
<link name="right_wrist_roll_link">
|
| 985 |
+
<inertial>
|
| 986 |
+
<origin xyz="0.01713944778 -0.00053759094 0.00000048864" rpy="0 0 0"/>
|
| 987 |
+
<mass value="0.08544498"/>
|
| 988 |
+
<inertia ixx="0.00004821544023" ixy="0.00000424511021" ixz="0.00000000510599" iyy="0.00003722899093" iyz="0.00000000123525" izz="0.00005482106541"/>
|
| 989 |
+
</inertial>
|
| 990 |
+
<visual>
|
| 991 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 992 |
+
<geometry>
|
| 993 |
+
<mesh filename="meshes/right_wrist_roll_link.STL"/>
|
| 994 |
+
</geometry>
|
| 995 |
+
<material name="white">
|
| 996 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 997 |
+
</material>
|
| 998 |
+
</visual>
|
| 999 |
+
<collision>
|
| 1000 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1001 |
+
<geometry>
|
| 1002 |
+
<mesh filename="meshes/right_wrist_roll_link.STL"/>
|
| 1003 |
+
</geometry>
|
| 1004 |
+
</collision>
|
| 1005 |
+
</link>
|
| 1006 |
+
<joint name="right_wrist_pitch_joint" type="revolute">
|
| 1007 |
+
<origin xyz="0.038 0 0" rpy="0 0 0"/>
|
| 1008 |
+
<axis xyz="0 1 0"/>
|
| 1009 |
+
<parent link="right_wrist_roll_link"/>
|
| 1010 |
+
<child link="right_wrist_pitch_link"/>
|
| 1011 |
+
<limit effort="5" velocity="22" lower="-1.614429558" upper="1.614429558"/>
|
| 1012 |
+
</joint>
|
| 1013 |
+
<link name="right_wrist_pitch_link">
|
| 1014 |
+
<inertial>
|
| 1015 |
+
<origin xyz="0.02299989837 0.00111685314 -0.00111658096" rpy="0 0 0"/>
|
| 1016 |
+
<mass value="0.48404956"/>
|
| 1017 |
+
<inertia ixx="0.00016579646273" ixy="0.00001231206746" ixz="0.00001231699194" iyy="0.00042954057410" iyz="-0.00000081417712" izz="0.00042953697654"/>
|
| 1018 |
+
</inertial>
|
| 1019 |
+
<visual>
|
| 1020 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1021 |
+
<geometry>
|
| 1022 |
+
<mesh filename="meshes/right_wrist_pitch_link.STL"/>
|
| 1023 |
+
</geometry>
|
| 1024 |
+
<material name="white">
|
| 1025 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1026 |
+
</material>
|
| 1027 |
+
</visual>
|
| 1028 |
+
<collision>
|
| 1029 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1030 |
+
<geometry>
|
| 1031 |
+
<mesh filename="meshes/right_wrist_pitch_link.STL"/>
|
| 1032 |
+
</geometry>
|
| 1033 |
+
</collision>
|
| 1034 |
+
</link>
|
| 1035 |
+
<joint name="right_wrist_yaw_joint" type="revolute">
|
| 1036 |
+
<origin xyz="0.046 0 0" rpy="0 0 0"/>
|
| 1037 |
+
<axis xyz="0 0 1"/>
|
| 1038 |
+
<parent link="right_wrist_pitch_link"/>
|
| 1039 |
+
<child link="right_wrist_yaw_link"/>
|
| 1040 |
+
<limit effort="5" velocity="22" lower="-1.614429558" upper="1.614429558"/>
|
| 1041 |
+
</joint>
|
| 1042 |
+
<link name="right_wrist_yaw_link">
|
| 1043 |
+
<inertial>
|
| 1044 |
+
<origin xyz="0.02200381568 -0.00049485096 0.00053861123" rpy="0 0 0"/>
|
| 1045 |
+
<mass value="0.08457647"/>
|
| 1046 |
+
<inertia ixx="0.00004929128828" ixy="0.00000045735494" ixz="0.00000445867591" iyy="0.00005973338134" iyz="-0.00000043217198" izz="0.00003928083826"/>
|
| 1047 |
+
</inertial>
|
| 1048 |
+
<visual>
|
| 1049 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1050 |
+
<geometry>
|
| 1051 |
+
<mesh filename="meshes/right_wrist_yaw_link.STL"/>
|
| 1052 |
+
</geometry>
|
| 1053 |
+
<material name="white">
|
| 1054 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1055 |
+
</material>
|
| 1056 |
+
</visual>
|
| 1057 |
+
<collision>
|
| 1058 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1059 |
+
<geometry>
|
| 1060 |
+
<mesh filename="meshes/right_wrist_yaw_link.STL"/>
|
| 1061 |
+
</geometry>
|
| 1062 |
+
</collision>
|
| 1063 |
+
</link>
|
| 1064 |
+
<joint name="right_hand_palm_joint" type="fixed">
|
| 1065 |
+
<origin xyz="0.0415 -0.003 0" rpy="0 0 0"/>
|
| 1066 |
+
<parent link="right_wrist_yaw_link"/>
|
| 1067 |
+
<child link="right_rubber_hand"/>
|
| 1068 |
+
</joint>
|
| 1069 |
+
<link name="right_rubber_hand">
|
| 1070 |
+
<inertial>
|
| 1071 |
+
<origin xyz="0.05361310808 0.00295905240 0.00215413091" rpy="0 0 0"/>
|
| 1072 |
+
<mass value="0.170"/>
|
| 1073 |
+
<inertia ixx="0.00010099485234748" ixy="-0.00003618590790516" ixz="-0.00000074301518642" iyy="0.00028135871571621" iyz="-0.00000330189743286" izz="0.00021894770413514"/>
|
| 1074 |
+
</inertial>
|
| 1075 |
+
<visual>
|
| 1076 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1077 |
+
<geometry>
|
| 1078 |
+
<mesh filename="meshes/right_rubber_hand.STL"/>
|
| 1079 |
+
</geometry>
|
| 1080 |
+
<material name="white">
|
| 1081 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1082 |
+
</material>
|
| 1083 |
+
</visual>
|
| 1084 |
+
<collision>
|
| 1085 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1086 |
+
<geometry>
|
| 1087 |
+
<mesh filename="meshes/right_rubber_hand.STL"/>
|
| 1088 |
+
</geometry>
|
| 1089 |
+
</collision>
|
| 1090 |
+
</link>
|
| 1091 |
+
</robot>
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_old.xml
ADDED
|
@@ -0,0 +1,568 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<mujoco model="g1_29dof">
|
| 2 |
+
<compiler angle="radian" meshdir="meshes" />
|
| 3 |
+
|
| 4 |
+
<default>
|
| 5 |
+
<default class="torso_motor">
|
| 6 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2"/>
|
| 7 |
+
</default>
|
| 8 |
+
<default class="leg_motor">
|
| 9 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2"/>
|
| 10 |
+
</default>
|
| 11 |
+
<default class="ankle_motor">
|
| 12 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2"/>
|
| 13 |
+
</default>
|
| 14 |
+
<default class="arm_motor">
|
| 15 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2"/>
|
| 16 |
+
</default>
|
| 17 |
+
<default class="wrist_motor">
|
| 18 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.1"/>
|
| 19 |
+
</default>
|
| 20 |
+
|
| 21 |
+
</default>
|
| 22 |
+
|
| 23 |
+
<asset>
|
| 24 |
+
<mesh name="pelvis" file="pelvis.STL" />
|
| 25 |
+
<mesh name="pelvis_contour_link" file="pelvis_contour_link.STL" />
|
| 26 |
+
<mesh name="left_hip_pitch_link" file="left_hip_pitch_link.STL" />
|
| 27 |
+
<mesh name="left_hip_roll_link" file="left_hip_roll_link.STL" />
|
| 28 |
+
<mesh name="left_hip_yaw_link" file="left_hip_yaw_link.STL" />
|
| 29 |
+
<mesh name="left_knee_link" file="left_knee_link.STL" />
|
| 30 |
+
<mesh name="left_ankle_pitch_link" file="left_ankle_pitch_link.STL" />
|
| 31 |
+
<mesh name="left_ankle_roll_link" file="left_ankle_roll_link.STL" />
|
| 32 |
+
<mesh name="right_hip_pitch_link" file="right_hip_pitch_link.STL" />
|
| 33 |
+
<mesh name="right_hip_roll_link" file="right_hip_roll_link.STL" />
|
| 34 |
+
<mesh name="right_hip_yaw_link" file="right_hip_yaw_link.STL" />
|
| 35 |
+
<mesh name="right_knee_link" file="right_knee_link.STL" />
|
| 36 |
+
<mesh name="right_ankle_pitch_link" file="right_ankle_pitch_link.STL" />
|
| 37 |
+
<mesh name="right_ankle_roll_link" file="right_ankle_roll_link.STL" />
|
| 38 |
+
<mesh name="waist_yaw_link" file="waist_yaw_link.STL" />
|
| 39 |
+
<mesh name="waist_roll_link" file="waist_roll_link.STL" />
|
| 40 |
+
<mesh name="torso_link" file="torso_link.STL" />
|
| 41 |
+
<mesh name="logo_link" file="logo_link.STL" />
|
| 42 |
+
<mesh name="head_link" file="head_link.STL" />
|
| 43 |
+
<mesh name="waist_support_link" file="waist_support_link.STL" />
|
| 44 |
+
<mesh name="left_shoulder_pitch_link" file="left_shoulder_pitch_link.STL" />
|
| 45 |
+
<mesh name="left_shoulder_roll_link" file="left_shoulder_roll_link.STL" />
|
| 46 |
+
<mesh name="left_shoulder_yaw_link" file="left_shoulder_yaw_link.STL" />
|
| 47 |
+
<mesh name="left_elbow_link" file="left_elbow_link.STL" />
|
| 48 |
+
<mesh name="left_wrist_roll_link" file="left_wrist_roll_link.STL" />
|
| 49 |
+
<mesh name="left_wrist_pitch_link" file="left_wrist_pitch_link.STL" />
|
| 50 |
+
<mesh name="left_wrist_yaw_link" file="left_wrist_yaw_link.STL" />
|
| 51 |
+
<mesh name="left_rubber_hand" file="left_rubber_hand.STL" />
|
| 52 |
+
<mesh name="right_shoulder_pitch_link" file="right_shoulder_pitch_link.STL" />
|
| 53 |
+
<mesh name="right_shoulder_roll_link" file="right_shoulder_roll_link.STL" />
|
| 54 |
+
<mesh name="right_shoulder_yaw_link" file="right_shoulder_yaw_link.STL" />
|
| 55 |
+
<mesh name="right_elbow_link" file="right_elbow_link.STL" />
|
| 56 |
+
<mesh name="right_wrist_roll_link" file="right_wrist_roll_link.STL" />
|
| 57 |
+
<mesh name="right_wrist_pitch_link" file="right_wrist_pitch_link.STL" />
|
| 58 |
+
<mesh name="right_wrist_yaw_link" file="right_wrist_yaw_link.STL" />
|
| 59 |
+
<mesh name="right_rubber_hand" file="right_rubber_hand.STL" />
|
| 60 |
+
</asset>
|
| 61 |
+
|
| 62 |
+
<worldbody>
|
| 63 |
+
<body name="pelvis" pos="0 0 0.793" quat="1 0 0 0">
|
| 64 |
+
<inertial pos="0 0 -0.07605" quat="1 0 -0.000399148 0" mass="3.813"
|
| 65 |
+
diaginertia="0.010549 0.0093089 0.0079184" />
|
| 66 |
+
<joint name="floating_base_joint" type="free" limited="false" actuatorfrclimited="false" />
|
| 67 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.2 0.2 0.2 1"
|
| 68 |
+
mesh="pelvis" />
|
| 69 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 70 |
+
mesh="pelvis_contour_link" />
|
| 71 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="pelvis_contour_link" />
|
| 72 |
+
<body name="left_hip_pitch_link" pos="0 0.064452 -0.1027">
|
| 73 |
+
<inertial pos="0.002741 0.047791 -0.02606" quat="0.954862 0.293964 0.0302556 0.030122"
|
| 74 |
+
mass="1.35" diaginertia="0.00181517 0.00153422 0.00116212" />
|
| 75 |
+
<joint name="left_hip_pitch_joint" pos="0 0 0" axis="0 1 0" range="-2.5307 2.8798"
|
| 76 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 77 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.2 0.2 0.2 1"
|
| 78 |
+
mesh="left_hip_pitch_link" />
|
| 79 |
+
<geom type="mesh" rgba="0.2 0.2 0.2 1" mesh="left_hip_pitch_link" />
|
| 80 |
+
<body name="left_hip_roll_link" pos="0 0.052 -0.030465" quat="0.996179 0 -0.0873386 0">
|
| 81 |
+
<inertial pos="0.029812 -0.001045 -0.087934"
|
| 82 |
+
quat="0.977808 -1.97119e-05 0.205576 -0.0403793" mass="1.52"
|
| 83 |
+
diaginertia="0.00254986 0.00241169 0.00148755" />
|
| 84 |
+
<joint name="left_hip_roll_joint" pos="0 0 0" axis="1 0 0" range="-0.5236 2.9671"
|
| 85 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 86 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 87 |
+
mesh="left_hip_roll_link" />
|
| 88 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hip_roll_link" />
|
| 89 |
+
<body name="left_hip_yaw_link" pos="0.025001 0 -0.12412">
|
| 90 |
+
<inertial pos="-0.057709 -0.010981 -0.15078" quat="0.600598 0.15832 0.223482 0.751181"
|
| 91 |
+
mass="1.702" diaginertia="0.00776166 0.00717575 0.00160139" />
|
| 92 |
+
<joint name="left_hip_yaw_joint" pos="0 0 0" axis="0 0 1" range="-2.7576 2.7576"
|
| 93 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 94 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 95 |
+
mesh="left_hip_yaw_link" />
|
| 96 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hip_yaw_link" />
|
| 97 |
+
<body name="left_knee_link" pos="-0.078273 0.0021489 -0.17734"
|
| 98 |
+
quat="0.996179 0 0.0873386 0">
|
| 99 |
+
<inertial pos="0.005457 0.003964 -0.12074"
|
| 100 |
+
quat="0.923418 -0.0327699 0.0158246 0.382067" mass="1.932"
|
| 101 |
+
diaginertia="0.0113804 0.0112778 0.00146458" />
|
| 102 |
+
<joint name="left_knee_joint" pos="0 0 0" axis="0 1 0" range="-0.087267 2.8798"
|
| 103 |
+
actuatorfrcrange="-139 139" class="leg_motor" />
|
| 104 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 105 |
+
rgba="0.7 0.7 0.7 1" mesh="left_knee_link" />
|
| 106 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_knee_link" />
|
| 107 |
+
<body name="left_ankle_pitch_link" pos="0 -9.4445e-05 -0.30001">
|
| 108 |
+
<inertial pos="-0.007269 0 0.011137" quat="0.603053 0.369225 0.369225 0.603053"
|
| 109 |
+
mass="0.074" diaginertia="1.89e-05 1.40805e-05 6.9195e-06" />
|
| 110 |
+
<joint name="left_ankle_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 111 |
+
range="-0.87267 0.5236" actuatorfrcrange="-50 50" class="ankle_motor"/>
|
| 112 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 113 |
+
rgba="0.7 0.7 0.7 1" mesh="left_ankle_pitch_link" />
|
| 114 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_ankle_pitch_link" />
|
| 115 |
+
<body name="left_ankle_roll_link" pos="0 0 -0.017558">
|
| 116 |
+
<inertial pos="0.026505 0 -0.016425"
|
| 117 |
+
quat="-0.000481092 0.728482 -0.000618967 0.685065" mass="0.608"
|
| 118 |
+
diaginertia="0.00167218 0.0016161 0.000217621" />
|
| 119 |
+
<joint name="left_ankle_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 120 |
+
range="-0.2618 0.2618" actuatorfrcrange="-50 50" class="ankle_motor"/>
|
| 121 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 122 |
+
rgba="0.2 0.2 0.2 1" mesh="left_ankle_roll_link" />
|
| 123 |
+
<body name="dummy_lf_1" >
|
| 124 |
+
<inertial pos="0 0 0" mass="0.0001" diaginertia="0 0 0" />
|
| 125 |
+
<geom size="0.005" pos="-0.05 0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 126 |
+
<site name="left_foot_contact_1" pos="-0.05 0.025 -0.03" size="0.005" />
|
| 127 |
+
</body>
|
| 128 |
+
<body name="dummy_lf_2" >
|
| 129 |
+
<inertial pos="0 0 0" mass="0.0001" diaginertia="0 0 0" />
|
| 130 |
+
<geom size="0.005" pos="-0.05 -0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 131 |
+
<site name="left_foot_contact_2" pos="-0.05 -0.025 -0.03" size="0.005" />
|
| 132 |
+
</body>
|
| 133 |
+
<body name="dummy_lf_3" >
|
| 134 |
+
<inertial pos="0 0 0" mass="0.0001" diaginertia="0 0 0" />
|
| 135 |
+
<geom size="0.005" pos="0.12 0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 136 |
+
<site name="left_foot_contact_3" pos="0.12 0.03 -0.03" size="0.005" />
|
| 137 |
+
</body>
|
| 138 |
+
<body name="dummy_lf_4" >
|
| 139 |
+
<inertial pos="0 0 0" mass="0.0001" diaginertia="0 0 0" />
|
| 140 |
+
<geom size="0.005" pos="0.12 -0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 141 |
+
<site name="left_foot_contact_4" pos="0.12 -0.03 -0.03" size="0.005" />
|
| 142 |
+
</body>
|
| 143 |
+
</body>
|
| 144 |
+
</body>
|
| 145 |
+
</body>
|
| 146 |
+
</body>
|
| 147 |
+
</body>
|
| 148 |
+
</body>
|
| 149 |
+
<body name="right_hip_pitch_link" pos="0 -0.064452 -0.1027">
|
| 150 |
+
<inertial pos="0.002741 -0.047791 -0.02606" quat="0.954862 -0.293964 0.0302556 -0.030122"
|
| 151 |
+
mass="1.35" diaginertia="0.00181517 0.00153422 0.00116212" />
|
| 152 |
+
<joint name="right_hip_pitch_joint" pos="0 0 0" axis="0 1 0" range="-2.5307 2.8798"
|
| 153 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 154 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.2 0.2 0.2 1"
|
| 155 |
+
mesh="right_hip_pitch_link" />
|
| 156 |
+
<geom type="mesh" rgba="0.2 0.2 0.2 1" mesh="right_hip_pitch_link" />
|
| 157 |
+
<body name="right_hip_roll_link" pos="0 -0.052 -0.030465" quat="0.996179 0 -0.0873386 0">
|
| 158 |
+
<inertial pos="0.029812 0.001045 -0.087934" quat="0.977808 1.97119e-05 0.205576 0.0403793"
|
| 159 |
+
mass="1.52" diaginertia="0.00254986 0.00241169 0.00148755" />
|
| 160 |
+
<joint name="right_hip_roll_joint" pos="0 0 0" axis="1 0 0" range="-2.9671 0.5236"
|
| 161 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 162 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 163 |
+
mesh="right_hip_roll_link" />
|
| 164 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hip_roll_link" />
|
| 165 |
+
<body name="right_hip_yaw_link" pos="0.025001 0 -0.12412">
|
| 166 |
+
<inertial pos="-0.057709 0.010981 -0.15078" quat="0.751181 0.223482 0.15832 0.600598"
|
| 167 |
+
mass="1.702" diaginertia="0.00776166 0.00717575 0.00160139" />
|
| 168 |
+
<joint name="right_hip_yaw_joint" pos="0 0 0" axis="0 0 1" range="-2.7576 2.7576"
|
| 169 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 170 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 171 |
+
mesh="right_hip_yaw_link" />
|
| 172 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hip_yaw_link" />
|
| 173 |
+
<body name="right_knee_link" pos="-0.078273 -0.0021489 -0.17734"
|
| 174 |
+
quat="0.996179 0 0.0873386 0">
|
| 175 |
+
<inertial pos="0.005457 -0.003964 -0.12074"
|
| 176 |
+
quat="0.923439 0.0345276 0.0116333 -0.382012" mass="1.932"
|
| 177 |
+
diaginertia="0.011374 0.0112843 0.00146452" />
|
| 178 |
+
<joint name="right_knee_joint" pos="0 0 0" axis="0 1 0" range="-0.087267 2.8798"
|
| 179 |
+
actuatorfrcrange="-139 139" class="leg_motor" />
|
| 180 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 181 |
+
rgba="0.7 0.7 0.7 1" mesh="right_knee_link" />
|
| 182 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_knee_link" />
|
| 183 |
+
<body name="right_ankle_pitch_link" pos="0 9.4445e-05 -0.30001">
|
| 184 |
+
<inertial pos="-0.007269 0 0.011137" quat="0.603053 0.369225 0.369225 0.603053"
|
| 185 |
+
mass="0.074" diaginertia="1.89e-05 1.40805e-05 6.9195e-06" />
|
| 186 |
+
<joint name="right_ankle_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 187 |
+
range="-0.87267 0.5236" actuatorfrcrange="-50 50" class="ankle_motor" />
|
| 188 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 189 |
+
rgba="0.7 0.7 0.7 1" mesh="right_ankle_pitch_link" />
|
| 190 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_ankle_pitch_link" />
|
| 191 |
+
<body name="right_ankle_roll_link" pos="0 0 -0.017558">
|
| 192 |
+
<inertial pos="0.026505 0 -0.016425"
|
| 193 |
+
quat="0.000481092 0.728482 0.000618967 0.685065" mass="0.608"
|
| 194 |
+
diaginertia="0.00167218 0.0016161 0.000217621" />
|
| 195 |
+
<joint name="right_ankle_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 196 |
+
range="-0.2618 0.2618" actuatorfrcrange="-50 50" class="ankle_motor" />
|
| 197 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 198 |
+
rgba="0.2 0.2 0.2 1" mesh="right_ankle_roll_link" />
|
| 199 |
+
<geom size="0.005" pos="-0.05 0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 200 |
+
<geom size="0.005" pos="-0.05 -0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 201 |
+
<geom size="0.005" pos="0.12 0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 202 |
+
<geom size="0.005" pos="0.12 -0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 203 |
+
<body name="dummy_rf_1" >
|
| 204 |
+
<inertial pos="0 0 0" mass="0.0001" diaginertia="0 0 0" />
|
| 205 |
+
<site name="right_foot_contact_1" pos="-0.05 0.025 -0.03" size="0.005" />
|
| 206 |
+
</body>
|
| 207 |
+
<body name="dummy_rf_2" >
|
| 208 |
+
<inertial pos="0 0 0" mass="0.0001" diaginertia="0 0 0" />
|
| 209 |
+
<site name="right_foot_contact_2" pos="-0.05 -0.025 -0.03" size="0.005" />
|
| 210 |
+
</body>
|
| 211 |
+
<body name="dummy_rf_3" >
|
| 212 |
+
<inertial pos="0 0 0" mass="0.0001" diaginertia="0 0 0" />
|
| 213 |
+
<site name="right_foot_contact_3" pos="0.12 0.03 -0.03" size="0.005" />
|
| 214 |
+
</body>
|
| 215 |
+
<body name="dummy_rf_4" >
|
| 216 |
+
<inertial pos="0 0 0" mass="0.0001" diaginertia="0 0 0" />
|
| 217 |
+
<site name="right_foot_contact_4" pos="0.12 -0.03 -0.03" size="0.005" />
|
| 218 |
+
</body>
|
| 219 |
+
</body>
|
| 220 |
+
</body>
|
| 221 |
+
</body>
|
| 222 |
+
</body>
|
| 223 |
+
</body>
|
| 224 |
+
</body>
|
| 225 |
+
<body name="waist_yaw_link">
|
| 226 |
+
<inertial pos="0.003964 0 0.018769" quat="-0.0178291 0.628464 0.0282471 0.777121"
|
| 227 |
+
mass="0.244" diaginertia="0.000158561 0.000124229 9.67669e-05" />
|
| 228 |
+
<joint name="waist_yaw_joint" pos="0 0 0" axis="0 0 1" range="-2.618 2.618"
|
| 229 |
+
actuatorfrcrange="-88 88" class="torso_motor"/>
|
| 230 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 231 |
+
mesh="waist_yaw_link" />
|
| 232 |
+
<body name="waist_roll_link" pos="-0.0039635 0 0.035">
|
| 233 |
+
<inertial pos="0 -0.000236 0.010111" quat="0.99979 0.020492 0 0" mass="0.047"
|
| 234 |
+
diaginertia="7.515e-06 6.40206e-06 3.98394e-06" />
|
| 235 |
+
<joint name="waist_roll_joint" pos="0 0 0" axis="1 0 0" range="-0.52 0.52"
|
| 236 |
+
actuatorfrcrange="-50 50" class="torso_motor"/>
|
| 237 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 238 |
+
mesh="waist_roll_link" />
|
| 239 |
+
<body name="torso_link" pos="0 0 0.019">
|
| 240 |
+
<camera name="head_camera" pos="0.06 0.0 0.45" euler="0 -0.8 -1.57"/>
|
| 241 |
+
<inertial pos="0.00331658 0.000261533 0.179856"
|
| 242 |
+
quat="0.999831 0.000376204 0.0179895 -0.00377704" mass="9.598"
|
| 243 |
+
diaginertia="0.12407 0.111951 0.0325382" />
|
| 244 |
+
<joint name="waist_pitch_joint" pos="0 0 0" axis="0 1 0" range="-0.52 0.52"
|
| 245 |
+
actuatorfrcrange="-50 50" class="torso_motor"/>
|
| 246 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 247 |
+
mesh="torso_link" />
|
| 248 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="torso_link" />
|
| 249 |
+
<geom pos="0.0039635 0 -0.054" quat="1 0 0 0" type="mesh" contype="0" conaffinity="0"
|
| 250 |
+
group="1" density="0" rgba="0.2 0.2 0.2 1" mesh="logo_link" />
|
| 251 |
+
<geom pos="0.0039635 0 -0.054" quat="1 0 0 0" type="mesh" rgba="0.2 0.2 0.2 1"
|
| 252 |
+
mesh="logo_link" />
|
| 253 |
+
<geom pos="0.0039635 0 -0.054" type="mesh" contype="0" conaffinity="0" group="1"
|
| 254 |
+
density="0" rgba="0.2 0.2 0.2 1" mesh="head_link" />
|
| 255 |
+
<geom pos="0.0039635 0 -0.054" type="mesh" rgba="0.2 0.2 0.2 1" mesh="head_link" />
|
| 256 |
+
<geom pos="0.0039635 0 -0.054" quat="1 0 0 0" type="mesh" contype="0" conaffinity="0"
|
| 257 |
+
group="1" density="0" rgba="0.7 0.7 0.7 1" mesh="waist_support_link" />
|
| 258 |
+
<geom pos="0.0039635 0 -0.054" quat="1 0 0 0" type="mesh" rgba="0.7 0.7 0.7 1"
|
| 259 |
+
mesh="waist_support_link" />
|
| 260 |
+
<site name="imu" size="0.01" pos="-0.03959 -0.00224 0.13792" />
|
| 261 |
+
<body name="left_shoulder_pitch_link" pos="0.0039563 0.10022 0.23778"
|
| 262 |
+
quat="0.990264 0.139201 1.38722e-05 -9.86868e-05">
|
| 263 |
+
<inertial pos="0 0.035892 -0.011628" quat="0.654152 0.0130458 -0.326267 0.68225"
|
| 264 |
+
mass="0.718" diaginertia="0.000465864 0.000432842 0.000406394" />
|
| 265 |
+
<joint name="left_shoulder_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 266 |
+
range="-3.0892 2.6704" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 267 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 268 |
+
rgba="0.7 0.7 0.7 1" mesh="left_shoulder_pitch_link" />
|
| 269 |
+
<geom size="0.03 0.025" pos="0 0.04 -0.01" quat="0.707107 0 0.707107 0"
|
| 270 |
+
type="cylinder" rgba="0.7 0.7 0.7 1" />
|
| 271 |
+
<body name="left_shoulder_roll_link" pos="0 0.038 -0.013831"
|
| 272 |
+
quat="0.990268 -0.139172 0 0">
|
| 273 |
+
<inertial pos="-0.000227 0.00727 -0.063243"
|
| 274 |
+
quat="0.701256 -0.0196223 -0.00710317 0.712604" mass="0.643"
|
| 275 |
+
diaginertia="0.000691311 0.000618011 0.000388977" />
|
| 276 |
+
<joint name="left_shoulder_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 277 |
+
range="-1.5882 2.2515" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 278 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 279 |
+
rgba="0.7 0.7 0.7 1" mesh="left_shoulder_roll_link" />
|
| 280 |
+
<geom size="0.03 0.015" pos="-0.004 0.006 -0.053" type="cylinder"
|
| 281 |
+
rgba="0.7 0.7 0.7 1" />
|
| 282 |
+
<body name="left_shoulder_yaw_link" pos="0 0.00624 -0.1032">
|
| 283 |
+
<inertial pos="0.010773 -0.002949 -0.072009"
|
| 284 |
+
quat="0.716879 -0.0964829 -0.0679942 0.687134" mass="0.734"
|
| 285 |
+
diaginertia="0.00106187 0.00103217 0.000400661" />
|
| 286 |
+
<joint name="left_shoulder_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 287 |
+
range="-2.618 2.618" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 288 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 289 |
+
rgba="0.7 0.7 0.7 1" mesh="left_shoulder_yaw_link" />
|
| 290 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_shoulder_yaw_link" />
|
| 291 |
+
<body name="left_elbow_link" pos="0.015783 0 -0.080518">
|
| 292 |
+
<inertial pos="0.064956 0.004454 -0.010062"
|
| 293 |
+
quat="0.541765 0.636132 0.388821 0.388129" mass="0.6"
|
| 294 |
+
diaginertia="0.000443035 0.000421612 0.000259353" />
|
| 295 |
+
<joint name="left_elbow_joint" pos="0 0 0" axis="0 1 0" range="-1.0472 2.0944"
|
| 296 |
+
actuatorfrcrange="-25 25" class="arm_motor" />
|
| 297 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 298 |
+
rgba="0.7 0.7 0.7 1" mesh="left_elbow_link" />
|
| 299 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_elbow_link" />
|
| 300 |
+
<body name="left_wrist_roll_link" pos="0.1 0.00188791 -0.01">
|
| 301 |
+
<inertial pos="0.0171394 0.000537591 4.8864e-07"
|
| 302 |
+
quat="0.575338 0.411667 -0.574906 0.411094" mass="0.085445"
|
| 303 |
+
diaginertia="5.48211e-05 4.96646e-05 3.57798e-05" />
|
| 304 |
+
<joint name="left_wrist_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 305 |
+
range="-1.97222 1.97222" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 306 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 307 |
+
rgba="0.7 0.7 0.7 1" mesh="left_wrist_roll_link" />
|
| 308 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_wrist_roll_link" />
|
| 309 |
+
<body name="left_wrist_pitch_link" pos="0.038 0 0">
|
| 310 |
+
<inertial pos="0.0229999 -0.00111685 -0.00111658"
|
| 311 |
+
quat="0.249998 0.661363 0.293036 0.643608" mass="0.48405"
|
| 312 |
+
diaginertia="0.000430353 0.000429873 0.000164648" />
|
| 313 |
+
<joint name="left_wrist_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 314 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 315 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 316 |
+
rgba="0.7 0.7 0.7 1" mesh="left_wrist_pitch_link" />
|
| 317 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_wrist_pitch_link" />
|
| 318 |
+
<body name="left_wrist_yaw_link" pos="0.046 0 0">
|
| 319 |
+
<inertial pos="0.0708244 0.000191745 0.00161742"
|
| 320 |
+
quat="0.510571 0.526295 0.468078 0.493188" mass="0.254576"
|
| 321 |
+
diaginertia="0.000646113 0.000559993 0.000147566" />
|
| 322 |
+
<joint name="left_wrist_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 323 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 324 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 325 |
+
rgba="0.7 0.7 0.7 1" mesh="left_wrist_yaw_link" />
|
| 326 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_wrist_yaw_link" />
|
| 327 |
+
<body name="left_rubber_hand" >
|
| 328 |
+
<inertial pos="0.0001 0.0001 0.0001" mass="0.0001" diaginertia="0 0 0" />
|
| 329 |
+
<geom pos="0.0415 0.003 0" quat="1 0 0 0" type="mesh" density="0" rgba="0.7 0.7 0.7 1"
|
| 330 |
+
mesh="left_rubber_hand" />
|
| 331 |
+
</body>
|
| 332 |
+
</body>
|
| 333 |
+
</body>
|
| 334 |
+
</body>
|
| 335 |
+
</body>
|
| 336 |
+
</body>
|
| 337 |
+
</body>
|
| 338 |
+
</body>
|
| 339 |
+
<body name="right_shoulder_pitch_link" pos="0.0039563 -0.10021 0.23778"
|
| 340 |
+
quat="0.990264 -0.139201 1.38722e-05 9.86868e-05">
|
| 341 |
+
<inertial pos="0 -0.035892 -0.011628" quat="0.68225 -0.326267 0.0130458 0.654152"
|
| 342 |
+
mass="0.718" diaginertia="0.000465864 0.000432842 0.000406394" />
|
| 343 |
+
<joint name="right_shoulder_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 344 |
+
range="-3.0892 2.6704" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 345 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 346 |
+
rgba="0.7 0.7 0.7 1" mesh="right_shoulder_pitch_link" />
|
| 347 |
+
<geom size="0.03 0.025" pos="0 -0.04 -0.01" quat="0.707107 0 0.707107 0"
|
| 348 |
+
type="cylinder" rgba="0.7 0.7 0.7 1" />
|
| 349 |
+
<body name="right_shoulder_roll_link" pos="0 -0.038 -0.013831"
|
| 350 |
+
quat="0.990268 0.139172 0 0">
|
| 351 |
+
<inertial pos="-0.000227 -0.00727 -0.063243"
|
| 352 |
+
quat="0.712604 -0.00710317 -0.0196223 0.701256" mass="0.643"
|
| 353 |
+
diaginertia="0.000691311 0.000618011 0.000388977" />
|
| 354 |
+
<joint name="right_shoulder_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 355 |
+
range="-2.2515 1.5882" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 356 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 357 |
+
rgba="0.7 0.7 0.7 1" mesh="right_shoulder_roll_link" />
|
| 358 |
+
<geom size="0.03 0.015" pos="-0.004 -0.006 -0.053" type="cylinder"
|
| 359 |
+
rgba="0.7 0.7 0.7 1" />
|
| 360 |
+
<body name="right_shoulder_yaw_link" pos="0 -0.00624 -0.1032">
|
| 361 |
+
<inertial pos="0.010773 0.002949 -0.072009"
|
| 362 |
+
quat="0.687134 -0.0679942 -0.0964829 0.716879" mass="0.734"
|
| 363 |
+
diaginertia="0.00106187 0.00103217 0.000400661" />
|
| 364 |
+
<joint name="right_shoulder_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 365 |
+
range="-2.618 2.618" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 366 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 367 |
+
rgba="0.7 0.7 0.7 1" mesh="right_shoulder_yaw_link" />
|
| 368 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_shoulder_yaw_link" />
|
| 369 |
+
<body name="right_elbow_link" pos="0.015783 0 -0.080518">
|
| 370 |
+
<inertial pos="0.064956 -0.004454 -0.010062"
|
| 371 |
+
quat="0.388129 0.388821 0.636132 0.541765" mass="0.6"
|
| 372 |
+
diaginertia="0.000443035 0.000421612 0.000259353" />
|
| 373 |
+
<joint name="right_elbow_joint" pos="0 0 0" axis="0 1 0" range="-1.0472 2.0944"
|
| 374 |
+
actuatorfrcrange="-25 25" class="arm_motor" />
|
| 375 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 376 |
+
rgba="0.7 0.7 0.7 1" mesh="right_elbow_link" />
|
| 377 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_elbow_link" />
|
| 378 |
+
<body name="right_wrist_roll_link" pos="0.1 -0.00188791 -0.01">
|
| 379 |
+
<inertial pos="0.0171394 -0.000537591 4.8864e-07"
|
| 380 |
+
quat="0.411667 0.575338 -0.411094 0.574906" mass="0.085445"
|
| 381 |
+
diaginertia="5.48211e-05 4.96646e-05 3.57798e-05" />
|
| 382 |
+
<joint name="right_wrist_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 383 |
+
range="-1.97222 1.97222" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 384 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 385 |
+
rgba="0.7 0.7 0.7 1" mesh="right_wrist_roll_link" />
|
| 386 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_wrist_roll_link" />
|
| 387 |
+
<body name="right_wrist_pitch_link" pos="0.038 0 0">
|
| 388 |
+
<inertial pos="0.0229999 0.00111685 -0.00111658"
|
| 389 |
+
quat="0.643608 0.293036 0.661363 0.249998" mass="0.48405"
|
| 390 |
+
diaginertia="0.000430353 0.000429873 0.000164648" />
|
| 391 |
+
<joint name="right_wrist_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 392 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 393 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 394 |
+
rgba="0.7 0.7 0.7 1" mesh="right_wrist_pitch_link" />
|
| 395 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_wrist_pitch_link" />
|
| 396 |
+
<body name="right_wrist_yaw_link" pos="0.046 0 0">
|
| 397 |
+
<inertial pos="0.0708244 -0.000191745 0.00161742"
|
| 398 |
+
quat="0.493188 0.468078 0.526295 0.510571" mass="0.254576"
|
| 399 |
+
diaginertia="0.000646113 0.000559993 0.000147566" />
|
| 400 |
+
<joint name="right_wrist_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 401 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 402 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 403 |
+
rgba="0.7 0.7 0.7 1" mesh="right_wrist_yaw_link" />
|
| 404 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_wrist_yaw_link" />
|
| 405 |
+
<body name="right_rubber_hand" >
|
| 406 |
+
<inertial pos="0.0001 0.0001 0.0001" mass="0.0001" diaginertia="0 0 0" />
|
| 407 |
+
<geom pos="0.0415 -0.003 0" quat="1 0 0 0" type="mesh" density="0" rgba="0.7 0.7 0.7 1"
|
| 408 |
+
mesh="right_rubber_hand" />
|
| 409 |
+
</body>
|
| 410 |
+
</body>
|
| 411 |
+
</body>
|
| 412 |
+
</body>
|
| 413 |
+
</body>
|
| 414 |
+
</body>
|
| 415 |
+
</body>
|
| 416 |
+
</body>
|
| 417 |
+
</body>
|
| 418 |
+
</body>
|
| 419 |
+
</body>
|
| 420 |
+
</body>
|
| 421 |
+
</worldbody>
|
| 422 |
+
|
| 423 |
+
<actuator>
|
| 424 |
+
<motor name="left_hip_pitch" joint="left_hip_pitch_joint" ctrlrange="-88 88" />
|
| 425 |
+
<motor name="left_hip_roll" joint="left_hip_roll_joint" ctrlrange="-88 88" />
|
| 426 |
+
<motor name="left_hip_yaw" joint="left_hip_yaw_joint" ctrlrange="-88 88" />
|
| 427 |
+
<motor name="left_knee" joint="left_knee_joint" ctrlrange="-139 139" />
|
| 428 |
+
<motor name="left_ankle_pitch" joint="left_ankle_pitch_joint" ctrlrange="-50 50" />
|
| 429 |
+
<motor name="left_ankle_roll" joint="left_ankle_roll_joint" ctrlrange="-50 50" />
|
| 430 |
+
|
| 431 |
+
<motor name="right_hip_pitch" joint="right_hip_pitch_joint" ctrlrange="-88 88" />
|
| 432 |
+
<motor name="right_hip_roll" joint="right_hip_roll_joint" ctrlrange="-88 88" />
|
| 433 |
+
<motor name="right_hip_yaw" joint="right_hip_yaw_joint" ctrlrange="-88 88" />
|
| 434 |
+
<motor name="right_knee" joint="right_knee_joint" ctrlrange="-139 139" />
|
| 435 |
+
<motor name="right_ankle_pitch" joint="right_ankle_pitch_joint" ctrlrange="-50 50" />
|
| 436 |
+
<motor name="right_ankle_roll" joint="right_ankle_roll_joint" ctrlrange="-50 50" />
|
| 437 |
+
|
| 438 |
+
<motor name="waist_yaw" joint="waist_yaw_joint" ctrlrange="-88 88" />
|
| 439 |
+
<motor name="waist_roll" joint="waist_roll_joint" ctrlrange="-50 50" />
|
| 440 |
+
<motor name="waist_pitch" joint="waist_pitch_joint" ctrlrange="-50 50" />
|
| 441 |
+
|
| 442 |
+
<motor name="left_shoulder_pitch" joint="left_shoulder_pitch_joint" ctrlrange="-25 25" />
|
| 443 |
+
<motor name="left_shoulder_roll" joint="left_shoulder_roll_joint" ctrlrange="-25 25" />
|
| 444 |
+
<motor name="left_shoulder_yaw" joint="left_shoulder_yaw_joint" ctrlrange="-25 25" />
|
| 445 |
+
<motor name="left_elbow" joint="left_elbow_joint" ctrlrange="-25 25" />
|
| 446 |
+
<motor name="left_wrist_roll" joint="left_wrist_roll_joint" ctrlrange="-25 25" />
|
| 447 |
+
<motor name="left_wrist_pitch" joint="left_wrist_pitch_joint" ctrlrange="-5 5" />
|
| 448 |
+
<motor name="left_wrist_yaw" joint="left_wrist_yaw_joint" ctrlrange="-5 5" />
|
| 449 |
+
|
| 450 |
+
<motor name="right_shoulder_pitch" joint="right_shoulder_pitch_joint" ctrlrange="-25 25" />
|
| 451 |
+
<motor name="right_shoulder_roll" joint="right_shoulder_roll_joint" ctrlrange="-25 25" />
|
| 452 |
+
<motor name="right_shoulder_yaw" joint="right_shoulder_yaw_joint" ctrlrange="-25 25" />
|
| 453 |
+
<motor name="right_elbow" joint="right_elbow_joint" ctrlrange="-25 25" />
|
| 454 |
+
<motor name="right_wrist_roll" joint="right_wrist_roll_joint" ctrlrange="-25 25" />
|
| 455 |
+
<motor name="right_wrist_pitch" joint="right_wrist_pitch_joint" ctrlrange="-5 5" />
|
| 456 |
+
<motor name="right_wrist_yaw" joint="right_wrist_yaw_joint" ctrlrange="-5 5" />
|
| 457 |
+
</actuator>
|
| 458 |
+
|
| 459 |
+
<sensor>
|
| 460 |
+
<jointpos name="left_hip_pitch_pos" joint="left_hip_pitch_joint" />
|
| 461 |
+
<jointpos name="left_hip_roll_pos" joint="left_hip_roll_joint" />
|
| 462 |
+
<jointpos name="left_hip_yaw_pos" joint="left_hip_yaw_joint" />
|
| 463 |
+
<jointpos name="left_knee_pos" joint="left_knee_joint" />
|
| 464 |
+
<jointpos name="left_ankle_pitch_pos" joint="left_ankle_pitch_joint" />
|
| 465 |
+
<jointpos name="left_ankle_roll_pos" joint="left_ankle_roll_joint" />
|
| 466 |
+
<jointpos name="right_hip_pitch_pos" joint="right_hip_pitch_joint" />
|
| 467 |
+
<jointpos name="right_hip_roll_pos" joint="right_hip_roll_joint" />
|
| 468 |
+
<jointpos name="right_hip_yaw_pos" joint="right_hip_yaw_joint" />
|
| 469 |
+
<jointpos name="right_knee_pos" joint="right_knee_joint" />
|
| 470 |
+
<jointpos name="right_ankle_pitch_pos" joint="right_ankle_pitch_joint" />
|
| 471 |
+
<jointpos name="right_ankle_roll_pos" joint="right_ankle_roll_joint" />
|
| 472 |
+
<jointpos name="waist_yaw_pos" joint="waist_yaw_joint" />
|
| 473 |
+
<jointpos name="waist_roll_pos" joint="waist_roll_joint" />
|
| 474 |
+
<jointpos name="waist_pitch_pos" joint="waist_pitch_joint" />
|
| 475 |
+
<jointpos name="left_shoulder_pitch_pos" joint="left_shoulder_pitch_joint" />
|
| 476 |
+
<jointpos name="left_shoulder_roll_pos" joint="left_shoulder_roll_joint" />
|
| 477 |
+
<jointpos name="left_shoulder_yaw_pos" joint="left_shoulder_yaw_joint" />
|
| 478 |
+
<jointpos name="left_elbow_pos" joint="left_elbow_joint" />
|
| 479 |
+
<jointpos name="left_wrist_roll_pos" joint="left_wrist_roll_joint" />
|
| 480 |
+
<jointpos name="left_wrist_pitch_pos" joint="left_wrist_pitch_joint" />
|
| 481 |
+
<jointpos name="left_wrist_yaw_pos" joint="left_wrist_yaw_joint" />
|
| 482 |
+
<jointpos name="right_shoulder_pitch_pos" joint="right_shoulder_pitch_joint" />
|
| 483 |
+
<jointpos name="right_shoulder_roll_pos" joint="right_shoulder_roll_joint" />
|
| 484 |
+
<jointpos name="right_shoulder_yaw_pos" joint="right_shoulder_yaw_joint" />
|
| 485 |
+
<jointpos name="right_elbow_pos" joint="right_elbow_joint" />
|
| 486 |
+
<jointpos name="right_wrist_roll_pos" joint="right_wrist_roll_joint" />
|
| 487 |
+
<jointpos name="right_wrist_pitch_pos" joint="right_wrist_pitch_joint" />
|
| 488 |
+
<jointpos name="right_wrist_yaw_pos" joint="right_wrist_yaw_joint" />
|
| 489 |
+
|
| 490 |
+
<jointvel name="left_hip_pitch_vel" joint="left_hip_pitch_joint" />
|
| 491 |
+
<jointvel name="left_hip_roll_vel" joint="left_hip_roll_joint" />
|
| 492 |
+
<jointvel name="left_hip_yaw_vel" joint="left_hip_yaw_joint" />
|
| 493 |
+
<jointvel name="left_knee_vel" joint="left_knee_joint" />
|
| 494 |
+
<jointvel name="left_ankle_pitch_vel" joint="left_ankle_pitch_joint" />
|
| 495 |
+
<jointvel name="left_ankle_roll_vel" joint="left_ankle_roll_joint" />
|
| 496 |
+
<jointvel name="right_hip_pitch_vel" joint="right_hip_pitch_joint" />
|
| 497 |
+
<jointvel name="right_hip_roll_vel" joint="right_hip_roll_joint" />
|
| 498 |
+
<jointvel name="right_hip_yaw_vel" joint="right_hip_yaw_joint" />
|
| 499 |
+
<jointvel name="right_knee_vel" joint="right_knee_joint" />
|
| 500 |
+
<jointvel name="right_ankle_pitch_vel" joint="right_ankle_pitch_joint" />
|
| 501 |
+
<jointvel name="right_ankle_roll_vel" joint="right_ankle_roll_joint" />
|
| 502 |
+
<jointvel name="waist_yaw_vel" joint="waist_yaw_joint" />
|
| 503 |
+
<jointvel name="waist_roll_vel" joint="waist_roll_joint" />
|
| 504 |
+
<jointvel name="waist_pitch_vel" joint="waist_pitch_joint" />
|
| 505 |
+
<jointvel name="left_shoulder_pitch_vel" joint="left_shoulder_pitch_joint" />
|
| 506 |
+
<jointvel name="left_shoulder_roll_vel" joint="left_shoulder_roll_joint" />
|
| 507 |
+
<jointvel name="left_shoulder_yaw_vel" joint="left_shoulder_yaw_joint" />
|
| 508 |
+
<jointvel name="left_elbow_vel" joint="left_elbow_joint" />
|
| 509 |
+
<jointvel name="left_wrist_roll_vel" joint="left_wrist_roll_joint" />
|
| 510 |
+
<jointvel name="left_wrist_pitch_vel" joint="left_wrist_pitch_joint" />
|
| 511 |
+
<jointvel name="left_wrist_yaw_vel" joint="left_wrist_yaw_joint" />
|
| 512 |
+
<jointvel name="right_shoulder_pitch_vel" joint="right_shoulder_pitch_joint" />
|
| 513 |
+
<jointvel name="right_shoulder_roll_vel" joint="right_shoulder_roll_joint" />
|
| 514 |
+
<jointvel name="right_shoulder_yaw_vel" joint="right_shoulder_yaw_joint" />
|
| 515 |
+
<jointvel name="right_elbow_vel" joint="right_elbow_joint" />
|
| 516 |
+
<jointvel name="right_wrist_roll_vel" joint="right_wrist_roll_joint" />
|
| 517 |
+
<jointvel name="right_wrist_pitch_vel" joint="right_wrist_pitch_joint" />
|
| 518 |
+
<jointvel name="right_wrist_yaw_vel" joint="right_wrist_yaw_joint" />
|
| 519 |
+
|
| 520 |
+
<jointactuatorfrc name="left_hip_pitch_torque" joint="left_hip_pitch_joint" />
|
| 521 |
+
<jointactuatorfrc name="left_hip_roll_torque" joint="left_hip_roll_joint" />
|
| 522 |
+
<jointactuatorfrc name="left_hip_yaw_torque" joint="left_hip_yaw_joint" />
|
| 523 |
+
<jointactuatorfrc name="left_knee_torque" joint="left_knee_joint" />
|
| 524 |
+
<jointactuatorfrc name="left_ankle_pitch_torque" joint="left_ankle_pitch_joint" />
|
| 525 |
+
<jointactuatorfrc name="left_ankle_roll_torque" joint="left_ankle_roll_joint" />
|
| 526 |
+
<jointactuatorfrc name="right_hip_pitch_torque" joint="right_hip_pitch_joint" />
|
| 527 |
+
<jointactuatorfrc name="right_hip_roll_torque" joint="right_hip_roll_joint" />
|
| 528 |
+
<jointactuatorfrc name="right_hip_yaw_torque" joint="right_hip_yaw_joint" />
|
| 529 |
+
<jointactuatorfrc name="right_knee_torque" joint="right_knee_joint" />
|
| 530 |
+
<jointactuatorfrc name="right_ankle_pitch_torque" joint="right_ankle_pitch_joint" />
|
| 531 |
+
<jointactuatorfrc name="right_ankle_roll_torque" joint="right_ankle_roll_joint" />
|
| 532 |
+
<jointactuatorfrc name="waist_yaw_torque" joint="waist_yaw_joint" />
|
| 533 |
+
<jointactuatorfrc name="waist_roll_torque" joint="waist_roll_joint" />
|
| 534 |
+
<jointactuatorfrc name="waist_pitch_torque" joint="waist_pitch_joint" />
|
| 535 |
+
<jointactuatorfrc name="left_shoulder_pitch_torque" joint="left_shoulder_pitch_joint" />
|
| 536 |
+
<jointactuatorfrc name="left_shoulder_roll_torque" joint="left_shoulder_roll_joint" />
|
| 537 |
+
<jointactuatorfrc name="left_shoulder_yaw_torque" joint="left_shoulder_yaw_joint" />
|
| 538 |
+
<jointactuatorfrc name="left_elbow_torque" joint="left_elbow_joint" />
|
| 539 |
+
<jointactuatorfrc name="left_wrist_roll_torque" joint="left_wrist_roll_joint" />
|
| 540 |
+
<jointactuatorfrc name="left_wrist_pitch_torque" joint="left_wrist_pitch_joint" />
|
| 541 |
+
<jointactuatorfrc name="left_wrist_yaw_torque" joint="left_wrist_yaw_joint" />
|
| 542 |
+
<jointactuatorfrc name="right_shoulder_pitch_torque" joint="right_shoulder_pitch_joint" />
|
| 543 |
+
<jointactuatorfrc name="right_shoulder_roll_torque" joint="right_shoulder_roll_joint" />
|
| 544 |
+
<jointactuatorfrc name="right_shoulder_yaw_torque" joint="right_shoulder_yaw_joint" />
|
| 545 |
+
<jointactuatorfrc name="right_elbow_torque" joint="right_elbow_joint" />
|
| 546 |
+
<jointactuatorfrc name="right_wrist_roll_torque" joint="right_wrist_roll_joint" />
|
| 547 |
+
<jointactuatorfrc name="right_wrist_pitch_torque" joint="right_wrist_pitch_joint" />
|
| 548 |
+
<jointactuatorfrc name="right_wrist_yaw_torque" joint="right_wrist_yaw_joint" />
|
| 549 |
+
|
| 550 |
+
<framequat name="imu_quat" objtype="site" objname="imu" />
|
| 551 |
+
<gyro name="imu_gyro" site="imu" />
|
| 552 |
+
<accelerometer name="imu_acc" site="imu" />
|
| 553 |
+
|
| 554 |
+
<framepos name="frame_pos" objtype="site" objname="imu" />
|
| 555 |
+
<framelinvel name="frame_vel" objtype="site" objname="imu" />
|
| 556 |
+
</sensor>
|
| 557 |
+
<sensor>
|
| 558 |
+
<force site="left_foot_contact_1" />
|
| 559 |
+
<force site="left_foot_contact_2" />
|
| 560 |
+
<force site="left_foot_contact_3" />
|
| 561 |
+
<force site="left_foot_contact_4" />
|
| 562 |
+
<force site="right_foot_contact_1" />
|
| 563 |
+
<force site="right_foot_contact_2" />
|
| 564 |
+
<force site="right_foot_contact_3" />
|
| 565 |
+
<force site="right_foot_contact_4" />
|
| 566 |
+
</sensor>
|
| 567 |
+
|
| 568 |
+
</mujoco>
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_with_hand.urdf
ADDED
|
@@ -0,0 +1,1497 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<robot name="g1_29dof_with_hand">
|
| 2 |
+
<mujoco>
|
| 3 |
+
<compiler meshdir="meshes" discardvisual="false"/>
|
| 4 |
+
</mujoco>
|
| 5 |
+
|
| 6 |
+
<!-- [CAUTION] uncomment when convert to mujoco -->
|
| 7 |
+
<!-- <link name="world"></link>
|
| 8 |
+
<joint name="floating_base_joint" type="floating">
|
| 9 |
+
<parent link="world"/>
|
| 10 |
+
<child link="pelvis"/>
|
| 11 |
+
</joint> -->
|
| 12 |
+
|
| 13 |
+
<link name="pelvis">
|
| 14 |
+
<inertial>
|
| 15 |
+
<origin xyz="0 0 -0.07605" rpy="0 0 0"/>
|
| 16 |
+
<mass value="3.813"/>
|
| 17 |
+
<inertia ixx="0.010549" ixy="0" ixz="2.1E-06" iyy="0.0093089" iyz="0" izz="0.0079184"/>
|
| 18 |
+
</inertial>
|
| 19 |
+
<visual>
|
| 20 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 21 |
+
<geometry>
|
| 22 |
+
<mesh filename="meshes/pelvis.STL"/>
|
| 23 |
+
</geometry>
|
| 24 |
+
<material name="dark">
|
| 25 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 26 |
+
</material>
|
| 27 |
+
</visual>
|
| 28 |
+
</link>
|
| 29 |
+
<link name="pelvis_contour_link">
|
| 30 |
+
<inertial>
|
| 31 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 32 |
+
<mass value="0.001"/>
|
| 33 |
+
<inertia ixx="1e-7" ixy="0" ixz="0" iyy="1e-7" iyz="0" izz="1e-7"/>
|
| 34 |
+
</inertial>
|
| 35 |
+
<visual>
|
| 36 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 37 |
+
<geometry>
|
| 38 |
+
<mesh filename="meshes/pelvis_contour_link.STL"/>
|
| 39 |
+
</geometry>
|
| 40 |
+
<material name="white">
|
| 41 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 42 |
+
</material>
|
| 43 |
+
</visual>
|
| 44 |
+
<collision>
|
| 45 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 46 |
+
<geometry>
|
| 47 |
+
<mesh filename="meshes/pelvis_contour_link.STL"/>
|
| 48 |
+
</geometry>
|
| 49 |
+
</collision>
|
| 50 |
+
</link>
|
| 51 |
+
<joint name="pelvis_contour_joint" type="fixed">
|
| 52 |
+
<parent link="pelvis"/>
|
| 53 |
+
<child link="pelvis_contour_link"/>
|
| 54 |
+
</joint>
|
| 55 |
+
|
| 56 |
+
<!-- Legs -->
|
| 57 |
+
<link name="left_hip_pitch_link">
|
| 58 |
+
<inertial>
|
| 59 |
+
<origin xyz="0.002741 0.047791 -0.02606" rpy="0 0 0"/>
|
| 60 |
+
<mass value="1.35"/>
|
| 61 |
+
<inertia ixx="0.001811" ixy="3.68E-05" ixz="-3.44E-05" iyy="0.0014193" iyz="0.000171" izz="0.0012812"/>
|
| 62 |
+
</inertial>
|
| 63 |
+
<visual>
|
| 64 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 65 |
+
<geometry>
|
| 66 |
+
<mesh filename="meshes/left_hip_pitch_link.STL"/>
|
| 67 |
+
</geometry>
|
| 68 |
+
<material name="dark">
|
| 69 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 70 |
+
</material>
|
| 71 |
+
</visual>
|
| 72 |
+
<collision>
|
| 73 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 74 |
+
<geometry>
|
| 75 |
+
<mesh filename="meshes/left_hip_pitch_link.STL"/>
|
| 76 |
+
</geometry>
|
| 77 |
+
</collision>
|
| 78 |
+
</link>
|
| 79 |
+
<joint name="left_hip_pitch_joint" type="revolute">
|
| 80 |
+
<origin xyz="0 0.064452 -0.1027" rpy="0 0 0"/>
|
| 81 |
+
<parent link="pelvis"/>
|
| 82 |
+
<child link="left_hip_pitch_link"/>
|
| 83 |
+
<axis xyz="0 1 0"/>
|
| 84 |
+
<limit lower="-2.5307" upper="2.8798" effort="88" velocity="32"/>
|
| 85 |
+
</joint>
|
| 86 |
+
<link name="left_hip_roll_link">
|
| 87 |
+
<inertial>
|
| 88 |
+
<origin xyz="0.029812 -0.001045 -0.087934" rpy="0 0 0"/>
|
| 89 |
+
<mass value="1.52"/>
|
| 90 |
+
<inertia ixx="0.0023773" ixy="-3.8E-06" ixz="-0.0003908" iyy="0.0024123" iyz="1.84E-05" izz="0.0016595"/>
|
| 91 |
+
</inertial>
|
| 92 |
+
<visual>
|
| 93 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 94 |
+
<geometry>
|
| 95 |
+
<mesh filename="meshes/left_hip_roll_link.STL"/>
|
| 96 |
+
</geometry>
|
| 97 |
+
<material name="white">
|
| 98 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 99 |
+
</material>
|
| 100 |
+
</visual>
|
| 101 |
+
<collision>
|
| 102 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 103 |
+
<geometry>
|
| 104 |
+
<mesh filename="meshes/left_hip_roll_link.STL"/>
|
| 105 |
+
</geometry>
|
| 106 |
+
</collision>
|
| 107 |
+
</link>
|
| 108 |
+
<joint name="left_hip_roll_joint" type="revolute">
|
| 109 |
+
<origin xyz="0 0.052 -0.030465" rpy="0 -0.1749 0"/>
|
| 110 |
+
<parent link="left_hip_pitch_link"/>
|
| 111 |
+
<child link="left_hip_roll_link"/>
|
| 112 |
+
<axis xyz="1 0 0"/>
|
| 113 |
+
<limit lower="-0.5236" upper="2.9671" effort="88" velocity="32"/>
|
| 114 |
+
</joint>
|
| 115 |
+
<link name="left_hip_yaw_link">
|
| 116 |
+
<inertial>
|
| 117 |
+
<origin xyz="-0.057709 -0.010981 -0.15078" rpy="0 0 0"/>
|
| 118 |
+
<mass value="1.702"/>
|
| 119 |
+
<inertia ixx="0.0057774" ixy="-0.0005411" ixz="-0.0023948" iyy="0.0076124" iyz="-0.0007072" izz="0.003149"/>
|
| 120 |
+
</inertial>
|
| 121 |
+
<visual>
|
| 122 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 123 |
+
<geometry>
|
| 124 |
+
<mesh filename="meshes/left_hip_yaw_link.STL"/>
|
| 125 |
+
</geometry>
|
| 126 |
+
<material name="white">
|
| 127 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 128 |
+
</material>
|
| 129 |
+
</visual>
|
| 130 |
+
<collision>
|
| 131 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 132 |
+
<geometry>
|
| 133 |
+
<mesh filename="meshes/left_hip_yaw_link.STL"/>
|
| 134 |
+
</geometry>
|
| 135 |
+
</collision>
|
| 136 |
+
</link>
|
| 137 |
+
<joint name="left_hip_yaw_joint" type="revolute">
|
| 138 |
+
<origin xyz="0.025001 0 -0.12412" rpy="0 0 0"/>
|
| 139 |
+
<parent link="left_hip_roll_link"/>
|
| 140 |
+
<child link="left_hip_yaw_link"/>
|
| 141 |
+
<axis xyz="0 0 1"/>
|
| 142 |
+
<limit lower="-2.7576" upper="2.7576" effort="88" velocity="32"/>
|
| 143 |
+
</joint>
|
| 144 |
+
<link name="left_knee_link">
|
| 145 |
+
<inertial>
|
| 146 |
+
<origin xyz="0.005457 0.003964 -0.12074" rpy="0 0 0"/>
|
| 147 |
+
<mass value="1.932"/>
|
| 148 |
+
<inertia ixx="0.011329" ixy="4.82E-05" ixz="-4.49E-05" iyy="0.011277" iyz="-0.0007146" izz="0.0015168"/>
|
| 149 |
+
</inertial>
|
| 150 |
+
<visual>
|
| 151 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 152 |
+
<geometry>
|
| 153 |
+
<mesh filename="meshes/left_knee_link.STL"/>
|
| 154 |
+
</geometry>
|
| 155 |
+
<material name="white">
|
| 156 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 157 |
+
</material>
|
| 158 |
+
</visual>
|
| 159 |
+
<collision>
|
| 160 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 161 |
+
<geometry>
|
| 162 |
+
<mesh filename="meshes/left_knee_link.STL"/>
|
| 163 |
+
</geometry>
|
| 164 |
+
</collision>
|
| 165 |
+
</link>
|
| 166 |
+
<joint name="left_knee_joint" type="revolute">
|
| 167 |
+
<origin xyz="-0.078273 0.0021489 -0.17734" rpy="0 0.1749 0"/>
|
| 168 |
+
<parent link="left_hip_yaw_link"/>
|
| 169 |
+
<child link="left_knee_link"/>
|
| 170 |
+
<axis xyz="0 1 0"/>
|
| 171 |
+
<limit lower="-0.087267" upper="2.8798" effort="139" velocity="20"/>
|
| 172 |
+
</joint>
|
| 173 |
+
<link name="left_ankle_pitch_link">
|
| 174 |
+
<inertial>
|
| 175 |
+
<origin xyz="-0.007269 0 0.011137" rpy="0 0 0"/>
|
| 176 |
+
<mass value="0.074"/>
|
| 177 |
+
<inertia ixx="8.4E-06" ixy="0" ixz="-2.9E-06" iyy="1.89E-05" iyz="0" izz="1.26E-05"/>
|
| 178 |
+
</inertial>
|
| 179 |
+
<visual>
|
| 180 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 181 |
+
<geometry>
|
| 182 |
+
<mesh filename="meshes/left_ankle_pitch_link.STL"/>
|
| 183 |
+
</geometry>
|
| 184 |
+
<material name="white">
|
| 185 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 186 |
+
</material>
|
| 187 |
+
</visual>
|
| 188 |
+
<collision>
|
| 189 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 190 |
+
<geometry>
|
| 191 |
+
<mesh filename="meshes/left_ankle_pitch_link.STL"/>
|
| 192 |
+
</geometry>
|
| 193 |
+
</collision>
|
| 194 |
+
</link>
|
| 195 |
+
<joint name="left_ankle_pitch_joint" type="revolute">
|
| 196 |
+
<origin xyz="0 -9.4445E-05 -0.30001" rpy="0 0 0"/>
|
| 197 |
+
<parent link="left_knee_link"/>
|
| 198 |
+
<child link="left_ankle_pitch_link"/>
|
| 199 |
+
<axis xyz="0 1 0"/>
|
| 200 |
+
<limit lower="-0.87267" upper="0.5236" effort="50" velocity="37"/>
|
| 201 |
+
</joint>
|
| 202 |
+
<link name="left_ankle_roll_link">
|
| 203 |
+
<inertial>
|
| 204 |
+
<origin xyz="0.026505 0 -0.016425" rpy="0 0 0"/>
|
| 205 |
+
<mass value="0.608"/>
|
| 206 |
+
<inertia ixx="0.0002231" ixy="2E-07" ixz="8.91E-05" iyy="0.0016161" iyz="-1E-07" izz="0.0016667"/>
|
| 207 |
+
</inertial>
|
| 208 |
+
<visual>
|
| 209 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 210 |
+
<geometry>
|
| 211 |
+
<mesh filename="meshes/left_ankle_roll_link.STL"/>
|
| 212 |
+
</geometry>
|
| 213 |
+
<material name="dark">
|
| 214 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 215 |
+
</material>
|
| 216 |
+
</visual>
|
| 217 |
+
<collision>
|
| 218 |
+
<origin xyz="-0.05 0.025 -0.03" rpy="0 0 0"/>
|
| 219 |
+
<geometry>
|
| 220 |
+
<sphere radius="0.005"/>
|
| 221 |
+
</geometry>
|
| 222 |
+
</collision>
|
| 223 |
+
<collision>
|
| 224 |
+
<origin xyz="-0.05 -0.025 -0.03" rpy="0 0 0"/>
|
| 225 |
+
<geometry>
|
| 226 |
+
<sphere radius="0.005"/>
|
| 227 |
+
</geometry>
|
| 228 |
+
</collision>
|
| 229 |
+
<collision>
|
| 230 |
+
<origin xyz="0.12 0.03 -0.03" rpy="0 0 0"/>
|
| 231 |
+
<geometry>
|
| 232 |
+
<sphere radius="0.005"/>
|
| 233 |
+
</geometry>
|
| 234 |
+
</collision>
|
| 235 |
+
<collision>
|
| 236 |
+
<origin xyz="0.12 -0.03 -0.03" rpy="0 0 0"/>
|
| 237 |
+
<geometry>
|
| 238 |
+
<sphere radius="0.005"/>
|
| 239 |
+
</geometry>
|
| 240 |
+
</collision>
|
| 241 |
+
</link>
|
| 242 |
+
<joint name="left_ankle_roll_joint" type="revolute">
|
| 243 |
+
<origin xyz="0 0 -0.017558" rpy="0 0 0"/>
|
| 244 |
+
<parent link="left_ankle_pitch_link"/>
|
| 245 |
+
<child link="left_ankle_roll_link"/>
|
| 246 |
+
<axis xyz="1 0 0"/>
|
| 247 |
+
<limit lower="-0.2618" upper="0.2618" effort="50" velocity="37"/>
|
| 248 |
+
</joint>
|
| 249 |
+
<link name="right_hip_pitch_link">
|
| 250 |
+
<inertial>
|
| 251 |
+
<origin xyz="0.002741 -0.047791 -0.02606" rpy="0 0 0"/>
|
| 252 |
+
<mass value="1.35"/>
|
| 253 |
+
<inertia ixx="0.001811" ixy="-3.68E-05" ixz="-3.44E-05" iyy="0.0014193" iyz="-0.000171" izz="0.0012812"/>
|
| 254 |
+
</inertial>
|
| 255 |
+
<visual>
|
| 256 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 257 |
+
<geometry>
|
| 258 |
+
<mesh filename="meshes/right_hip_pitch_link.STL"/>
|
| 259 |
+
</geometry>
|
| 260 |
+
<material name="dark">
|
| 261 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 262 |
+
</material>
|
| 263 |
+
</visual>
|
| 264 |
+
<collision>
|
| 265 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 266 |
+
<geometry>
|
| 267 |
+
<mesh filename="meshes/right_hip_pitch_link.STL"/>
|
| 268 |
+
</geometry>
|
| 269 |
+
</collision>
|
| 270 |
+
</link>
|
| 271 |
+
<joint name="right_hip_pitch_joint" type="revolute">
|
| 272 |
+
<origin xyz="0 -0.064452 -0.1027" rpy="0 0 0"/>
|
| 273 |
+
<parent link="pelvis"/>
|
| 274 |
+
<child link="right_hip_pitch_link"/>
|
| 275 |
+
<axis xyz="0 1 0"/>
|
| 276 |
+
<limit lower="-2.5307" upper="2.8798" effort="88" velocity="32"/>
|
| 277 |
+
</joint>
|
| 278 |
+
<link name="right_hip_roll_link">
|
| 279 |
+
<inertial>
|
| 280 |
+
<origin xyz="0.029812 0.001045 -0.087934" rpy="0 0 0"/>
|
| 281 |
+
<mass value="1.52"/>
|
| 282 |
+
<inertia ixx="0.0023773" ixy="3.8E-06" ixz="-0.0003908" iyy="0.0024123" iyz="-1.84E-05" izz="0.0016595"/>
|
| 283 |
+
</inertial>
|
| 284 |
+
<visual>
|
| 285 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 286 |
+
<geometry>
|
| 287 |
+
<mesh filename="meshes/right_hip_roll_link.STL"/>
|
| 288 |
+
</geometry>
|
| 289 |
+
<material name="white">
|
| 290 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 291 |
+
</material>
|
| 292 |
+
</visual>
|
| 293 |
+
<collision>
|
| 294 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 295 |
+
<geometry>
|
| 296 |
+
<mesh filename="meshes/right_hip_roll_link.STL"/>
|
| 297 |
+
</geometry>
|
| 298 |
+
</collision>
|
| 299 |
+
</link>
|
| 300 |
+
<joint name="right_hip_roll_joint" type="revolute">
|
| 301 |
+
<origin xyz="0 -0.052 -0.030465" rpy="0 -0.1749 0"/>
|
| 302 |
+
<parent link="right_hip_pitch_link"/>
|
| 303 |
+
<child link="right_hip_roll_link"/>
|
| 304 |
+
<axis xyz="1 0 0"/>
|
| 305 |
+
<limit lower="-2.9671" upper="0.5236" effort="88" velocity="32"/>
|
| 306 |
+
</joint>
|
| 307 |
+
<link name="right_hip_yaw_link">
|
| 308 |
+
<inertial>
|
| 309 |
+
<origin xyz="-0.057709 0.010981 -0.15078" rpy="0 0 0"/>
|
| 310 |
+
<mass value="1.702"/>
|
| 311 |
+
<inertia ixx="0.0057774" ixy="0.0005411" ixz="-0.0023948" iyy="0.0076124" iyz="0.0007072" izz="0.003149"/>
|
| 312 |
+
</inertial>
|
| 313 |
+
<visual>
|
| 314 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 315 |
+
<geometry>
|
| 316 |
+
<mesh filename="meshes/right_hip_yaw_link.STL"/>
|
| 317 |
+
</geometry>
|
| 318 |
+
<material name="white">
|
| 319 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 320 |
+
</material>
|
| 321 |
+
</visual>
|
| 322 |
+
<collision>
|
| 323 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 324 |
+
<geometry>
|
| 325 |
+
<mesh filename="meshes/right_hip_yaw_link.STL"/>
|
| 326 |
+
</geometry>
|
| 327 |
+
</collision>
|
| 328 |
+
</link>
|
| 329 |
+
<joint name="right_hip_yaw_joint" type="revolute">
|
| 330 |
+
<origin xyz="0.025001 0 -0.12412" rpy="0 0 0"/>
|
| 331 |
+
<parent link="right_hip_roll_link"/>
|
| 332 |
+
<child link="right_hip_yaw_link"/>
|
| 333 |
+
<axis xyz="0 0 1"/>
|
| 334 |
+
<limit lower="-2.7576" upper="2.7576" effort="88" velocity="32"/>
|
| 335 |
+
</joint>
|
| 336 |
+
<link name="right_knee_link">
|
| 337 |
+
<inertial>
|
| 338 |
+
<origin xyz="0.005457 -0.003964 -0.12074" rpy="0 0 0"/>
|
| 339 |
+
<mass value="1.932"/>
|
| 340 |
+
<inertia ixx="0.011329" ixy="-4.82E-05" ixz="4.49E-05" iyy="0.011277" iyz="0.0007146" izz="0.0015168"/>
|
| 341 |
+
</inertial>
|
| 342 |
+
<visual>
|
| 343 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 344 |
+
<geometry>
|
| 345 |
+
<mesh filename="meshes/right_knee_link.STL"/>
|
| 346 |
+
</geometry>
|
| 347 |
+
<material name="white">
|
| 348 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 349 |
+
</material>
|
| 350 |
+
</visual>
|
| 351 |
+
<collision>
|
| 352 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 353 |
+
<geometry>
|
| 354 |
+
<mesh filename="meshes/right_knee_link.STL"/>
|
| 355 |
+
</geometry>
|
| 356 |
+
</collision>
|
| 357 |
+
</link>
|
| 358 |
+
<joint name="right_knee_joint" type="revolute">
|
| 359 |
+
<origin xyz="-0.078273 -0.0021489 -0.17734" rpy="0 0.1749 0"/>
|
| 360 |
+
<parent link="right_hip_yaw_link"/>
|
| 361 |
+
<child link="right_knee_link"/>
|
| 362 |
+
<axis xyz="0 1 0"/>
|
| 363 |
+
<limit lower="-0.087267" upper="2.8798" effort="139" velocity="20"/>
|
| 364 |
+
</joint>
|
| 365 |
+
<link name="right_ankle_pitch_link">
|
| 366 |
+
<inertial>
|
| 367 |
+
<origin xyz="-0.007269 0 0.011137" rpy="0 0 0"/>
|
| 368 |
+
<mass value="0.074"/>
|
| 369 |
+
<inertia ixx="8.4E-06" ixy="0" ixz="-2.9E-06" iyy="1.89E-05" iyz="0" izz="1.26E-05"/>
|
| 370 |
+
</inertial>
|
| 371 |
+
<visual>
|
| 372 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 373 |
+
<geometry>
|
| 374 |
+
<mesh filename="meshes/right_ankle_pitch_link.STL"/>
|
| 375 |
+
</geometry>
|
| 376 |
+
<material name="white">
|
| 377 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 378 |
+
</material>
|
| 379 |
+
</visual>
|
| 380 |
+
<collision>
|
| 381 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 382 |
+
<geometry>
|
| 383 |
+
<mesh filename="meshes/right_ankle_pitch_link.STL"/>
|
| 384 |
+
</geometry>
|
| 385 |
+
</collision>
|
| 386 |
+
</link>
|
| 387 |
+
<joint name="right_ankle_pitch_joint" type="revolute">
|
| 388 |
+
<origin xyz="0 9.4445E-05 -0.30001" rpy="0 0 0"/>
|
| 389 |
+
<parent link="right_knee_link"/>
|
| 390 |
+
<child link="right_ankle_pitch_link"/>
|
| 391 |
+
<axis xyz="0 1 0"/>
|
| 392 |
+
<limit lower="-0.87267" upper="0.5236" effort="50" velocity="37"/>
|
| 393 |
+
</joint>
|
| 394 |
+
<link name="right_ankle_roll_link">
|
| 395 |
+
<inertial>
|
| 396 |
+
<origin xyz="0.026505 0 -0.016425" rpy="0 0 0"/>
|
| 397 |
+
<mass value="0.608"/>
|
| 398 |
+
<inertia ixx="0.0002231" ixy="-2E-07" ixz="8.91E-05" iyy="0.0016161" iyz="1E-07" izz="0.0016667"/>
|
| 399 |
+
</inertial>
|
| 400 |
+
<visual>
|
| 401 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 402 |
+
<geometry>
|
| 403 |
+
<mesh filename="meshes/right_ankle_roll_link.STL"/>
|
| 404 |
+
</geometry>
|
| 405 |
+
<material name="dark">
|
| 406 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 407 |
+
</material>
|
| 408 |
+
</visual>
|
| 409 |
+
<collision>
|
| 410 |
+
<origin xyz="-0.05 0.025 -0.03" rpy="0 0 0"/>
|
| 411 |
+
<geometry>
|
| 412 |
+
<sphere radius="0.005"/>
|
| 413 |
+
</geometry>
|
| 414 |
+
</collision>
|
| 415 |
+
<collision>
|
| 416 |
+
<origin xyz="-0.05 -0.025 -0.03" rpy="0 0 0"/>
|
| 417 |
+
<geometry>
|
| 418 |
+
<sphere radius="0.005"/>
|
| 419 |
+
</geometry>
|
| 420 |
+
</collision>
|
| 421 |
+
<collision>
|
| 422 |
+
<origin xyz="0.12 0.03 -0.03" rpy="0 0 0"/>
|
| 423 |
+
<geometry>
|
| 424 |
+
<sphere radius="0.005"/>
|
| 425 |
+
</geometry>
|
| 426 |
+
</collision>
|
| 427 |
+
<collision>
|
| 428 |
+
<origin xyz="0.12 -0.03 -0.03" rpy="0 0 0"/>
|
| 429 |
+
<geometry>
|
| 430 |
+
<sphere radius="0.005"/>
|
| 431 |
+
</geometry>
|
| 432 |
+
</collision>
|
| 433 |
+
</link>
|
| 434 |
+
<joint name="right_ankle_roll_joint" type="revolute">
|
| 435 |
+
<origin xyz="0 0 -0.017558" rpy="0 0 0"/>
|
| 436 |
+
<parent link="right_ankle_pitch_link"/>
|
| 437 |
+
<child link="right_ankle_roll_link"/>
|
| 438 |
+
<axis xyz="1 0 0"/>
|
| 439 |
+
<limit lower="-0.2618" upper="0.2618" effort="50" velocity="37"/>
|
| 440 |
+
</joint>
|
| 441 |
+
|
| 442 |
+
<!-- Torso -->
|
| 443 |
+
<link name="waist_yaw_link">
|
| 444 |
+
<inertial>
|
| 445 |
+
<origin xyz="0.003964 0 0.018769" rpy="0 0 0"/>
|
| 446 |
+
<mass value="0.244"/>
|
| 447 |
+
<inertia ixx="9.9587E-05" ixy="-1.833E-06" ixz="-1.2617E-05" iyy="0.00012411" iyz="-1.18E-07" izz="0.00015586"/>
|
| 448 |
+
</inertial>
|
| 449 |
+
<visual>
|
| 450 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 451 |
+
<geometry>
|
| 452 |
+
<mesh filename="meshes/waist_yaw_link.STL"/>
|
| 453 |
+
</geometry>
|
| 454 |
+
<material name="white">
|
| 455 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 456 |
+
</material>
|
| 457 |
+
</visual>
|
| 458 |
+
</link>
|
| 459 |
+
<joint name="waist_yaw_joint" type="revolute">
|
| 460 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 461 |
+
<parent link="pelvis"/>
|
| 462 |
+
<child link="waist_yaw_link"/>
|
| 463 |
+
<axis xyz="0 0 1"/>
|
| 464 |
+
<limit lower="-2.618" upper="2.618" effort="88" velocity="32"/>
|
| 465 |
+
</joint>
|
| 466 |
+
<link name="waist_roll_link">
|
| 467 |
+
<inertial>
|
| 468 |
+
<origin xyz="0 -0.000236 0.010111" rpy="0 0 0"/>
|
| 469 |
+
<mass value="0.047"/>
|
| 470 |
+
<inertia ixx="7.515E-06" ixy="0" ixz="0" iyy="6.398E-06" iyz="9.9E-08" izz="3.988E-06"/>
|
| 471 |
+
</inertial>
|
| 472 |
+
<visual>
|
| 473 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 474 |
+
<geometry>
|
| 475 |
+
<mesh filename="meshes/waist_roll_link.STL"/>
|
| 476 |
+
</geometry>
|
| 477 |
+
<material name="white">
|
| 478 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 479 |
+
</material>
|
| 480 |
+
</visual>
|
| 481 |
+
</link>
|
| 482 |
+
<joint name="waist_roll_joint" type="revolute">
|
| 483 |
+
<origin xyz="-0.0039635 0 0.035" rpy="0 0 0"/>
|
| 484 |
+
<parent link="waist_yaw_link"/>
|
| 485 |
+
<child link="waist_roll_link"/>
|
| 486 |
+
<axis xyz="1 0 0"/>
|
| 487 |
+
<limit lower="-0.52" upper="0.52" effort="50" velocity="37"/>
|
| 488 |
+
</joint>
|
| 489 |
+
<link name="torso_link">
|
| 490 |
+
<inertial>
|
| 491 |
+
<origin xyz="0.002601 0.000257 0.153719" rpy="0 0 0"/>
|
| 492 |
+
<mass value="8.562"/>
|
| 493 |
+
<inertia ixx="0.065674966" ixy="-8.597E-05" ixz="-0.001737252" iyy="0.053535188" iyz="8.6899E-05" izz="0.030808125"/>
|
| 494 |
+
</inertial>
|
| 495 |
+
<visual>
|
| 496 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 497 |
+
<geometry>
|
| 498 |
+
<mesh filename="meshes/torso_link.STL"/>
|
| 499 |
+
</geometry>
|
| 500 |
+
<material name="white">
|
| 501 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 502 |
+
</material>
|
| 503 |
+
</visual>
|
| 504 |
+
<collision>
|
| 505 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 506 |
+
<geometry>
|
| 507 |
+
<mesh filename="meshes/torso_link.STL"/>
|
| 508 |
+
</geometry>
|
| 509 |
+
</collision>
|
| 510 |
+
</link>
|
| 511 |
+
<joint name="waist_pitch_joint" type="revolute">
|
| 512 |
+
<origin xyz="0 0 0.019" rpy="0 0 0"/>
|
| 513 |
+
<parent link="waist_roll_link"/>
|
| 514 |
+
<child link="torso_link"/>
|
| 515 |
+
<axis xyz="0 1 0"/>
|
| 516 |
+
<limit lower="-0.52" upper="0.52" effort="50" velocity="37"/>
|
| 517 |
+
</joint>
|
| 518 |
+
|
| 519 |
+
<!-- LOGO -->
|
| 520 |
+
<joint name="logo_joint" type="fixed">
|
| 521 |
+
<origin xyz="0.0039635 0 -0.054" rpy="0 0 0"/>
|
| 522 |
+
<parent link="torso_link"/>
|
| 523 |
+
<child link="logo_link"/>
|
| 524 |
+
</joint>
|
| 525 |
+
<link name="logo_link">
|
| 526 |
+
<inertial>
|
| 527 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 528 |
+
<mass value="0.001"/>
|
| 529 |
+
<inertia ixx="1e-7" ixy="0" ixz="0" iyy="1e-7" iyz="0" izz="1e-7"/>
|
| 530 |
+
</inertial>
|
| 531 |
+
<visual>
|
| 532 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 533 |
+
<geometry>
|
| 534 |
+
<mesh filename="meshes/logo_link.STL"/>
|
| 535 |
+
</geometry>
|
| 536 |
+
<material name="dark">
|
| 537 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 538 |
+
</material>
|
| 539 |
+
</visual>
|
| 540 |
+
<collision>
|
| 541 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 542 |
+
<geometry>
|
| 543 |
+
<mesh filename="meshes/logo_link.STL"/>
|
| 544 |
+
</geometry>
|
| 545 |
+
</collision>
|
| 546 |
+
</link>
|
| 547 |
+
|
| 548 |
+
<!-- Head -->
|
| 549 |
+
<link name="head_link">
|
| 550 |
+
<inertial>
|
| 551 |
+
<origin xyz="0.005267 0.000299 0.449869" rpy="0 0 0"/>
|
| 552 |
+
<mass value="1.036"/>
|
| 553 |
+
<inertia ixx="0.004085051" ixy="-2.543E-06" ixz="-6.9455E-05" iyy="0.004185212" iyz="-3.726E-06" izz="0.001807911"/>
|
| 554 |
+
</inertial>
|
| 555 |
+
<visual>
|
| 556 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 557 |
+
<geometry>
|
| 558 |
+
<mesh filename="meshes/head_link.STL"/>
|
| 559 |
+
</geometry>
|
| 560 |
+
<material name="dark">
|
| 561 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 562 |
+
</material>
|
| 563 |
+
</visual>
|
| 564 |
+
<collision>
|
| 565 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 566 |
+
<geometry>
|
| 567 |
+
<mesh filename="meshes/head_link.STL"/>
|
| 568 |
+
</geometry>
|
| 569 |
+
</collision>
|
| 570 |
+
</link>
|
| 571 |
+
<joint name="head_joint" type="fixed">
|
| 572 |
+
<origin xyz="0.0039635 0 -0.054" rpy="0 0 0"/>
|
| 573 |
+
<parent link="torso_link"/>
|
| 574 |
+
<child link="head_link"/>
|
| 575 |
+
</joint>
|
| 576 |
+
|
| 577 |
+
<!-- Waist Support -->
|
| 578 |
+
<link name="waist_support_link">
|
| 579 |
+
<inertial>
|
| 580 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 581 |
+
<mass value="0.001"/>
|
| 582 |
+
<inertia ixx="1e-7" ixy="0" ixz="0" iyy="1e-7" iyz="0" izz="1e-7"/>
|
| 583 |
+
</inertial>
|
| 584 |
+
<visual>
|
| 585 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 586 |
+
<geometry>
|
| 587 |
+
<mesh filename="meshes/waist_support_link.STL"/>
|
| 588 |
+
</geometry>
|
| 589 |
+
<material name="white">
|
| 590 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 591 |
+
</material>
|
| 592 |
+
</visual>
|
| 593 |
+
<collision>
|
| 594 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 595 |
+
<geometry>
|
| 596 |
+
<mesh filename="meshes/waist_support_link.STL"/>
|
| 597 |
+
</geometry>
|
| 598 |
+
</collision>
|
| 599 |
+
</link>
|
| 600 |
+
<joint name="waist_support_joint" type="fixed">
|
| 601 |
+
<origin xyz="0.0039635 0 -0.054" rpy="0 0 0"/>
|
| 602 |
+
<parent link="torso_link"/>
|
| 603 |
+
<child link="waist_support_link"/>
|
| 604 |
+
</joint>
|
| 605 |
+
|
| 606 |
+
<!-- IMU -->
|
| 607 |
+
<link name="imu_link"></link>
|
| 608 |
+
<joint name="imu_joint" type="fixed">
|
| 609 |
+
<origin xyz="-0.03959 -0.00224 0.13792" rpy="0 0 0"/>
|
| 610 |
+
<parent link="torso_link"/>
|
| 611 |
+
<child link="imu_link"/>
|
| 612 |
+
</joint>
|
| 613 |
+
|
| 614 |
+
<!-- d435 -->
|
| 615 |
+
<link name="d435_link"></link>
|
| 616 |
+
<joint name="d435_joint" type="fixed">
|
| 617 |
+
<origin xyz="0.0576235 0.01753 0.41987" rpy="0 0.8307767239493009 0"/>
|
| 618 |
+
<parent link="torso_link"/>
|
| 619 |
+
<child link="d435_link"/>
|
| 620 |
+
</joint>
|
| 621 |
+
|
| 622 |
+
<!-- mid360 -->
|
| 623 |
+
<link name="mid360_link"></link>
|
| 624 |
+
<joint name="mid360_joint" type="fixed">
|
| 625 |
+
<origin xyz="0.0002835 0.00003 0.40618" rpy="0 0.04014257279586953 0"/>
|
| 626 |
+
<parent link="torso_link"/>
|
| 627 |
+
<child link="mid360_link"/>
|
| 628 |
+
</joint>
|
| 629 |
+
|
| 630 |
+
<!-- Arm -->
|
| 631 |
+
<link name="left_shoulder_pitch_link">
|
| 632 |
+
<inertial>
|
| 633 |
+
<origin xyz="0 0.035892 -0.011628" rpy="0 0 0"/>
|
| 634 |
+
<mass value="0.718"/>
|
| 635 |
+
<inertia ixx="0.0004291" ixy="-9.2E-06" ixz="6.4E-06" iyy="0.000453" iyz="2.26E-05" izz="0.000423"/>
|
| 636 |
+
</inertial>
|
| 637 |
+
<visual>
|
| 638 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 639 |
+
<geometry>
|
| 640 |
+
<mesh filename="meshes/left_shoulder_pitch_link.STL"/>
|
| 641 |
+
</geometry>
|
| 642 |
+
<material name="white">
|
| 643 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 644 |
+
</material>
|
| 645 |
+
</visual>
|
| 646 |
+
<collision>
|
| 647 |
+
<origin xyz="0 0.04 -0.01" rpy="0 1.5707963267948966 0"/>
|
| 648 |
+
<geometry>
|
| 649 |
+
<cylinder radius="0.03" length="0.05"/>
|
| 650 |
+
</geometry>
|
| 651 |
+
</collision>
|
| 652 |
+
</link>
|
| 653 |
+
<joint name="left_shoulder_pitch_joint" type="revolute">
|
| 654 |
+
<origin xyz="0.0039563 0.10022 0.23778" rpy="0.27931 5.4949E-05 -0.00019159"/>
|
| 655 |
+
<parent link="torso_link"/>
|
| 656 |
+
<child link="left_shoulder_pitch_link"/>
|
| 657 |
+
<axis xyz="0 1 0"/>
|
| 658 |
+
<limit lower="-3.0892" upper="2.6704" effort="25" velocity="37"/>
|
| 659 |
+
</joint>
|
| 660 |
+
<link name="left_shoulder_roll_link">
|
| 661 |
+
<inertial>
|
| 662 |
+
<origin xyz="-0.000227 0.00727 -0.063243" rpy="0 0 0"/>
|
| 663 |
+
<mass value="0.643"/>
|
| 664 |
+
<inertia ixx="0.0006177" ixy="-1E-06" ixz="8.7E-06" iyy="0.0006912" iyz="-5.3E-06" izz="0.0003894"/>
|
| 665 |
+
</inertial>
|
| 666 |
+
<visual>
|
| 667 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 668 |
+
<geometry>
|
| 669 |
+
<mesh filename="meshes/left_shoulder_roll_link.STL"/>
|
| 670 |
+
</geometry>
|
| 671 |
+
<material name="white">
|
| 672 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 673 |
+
</material>
|
| 674 |
+
</visual>
|
| 675 |
+
<collision>
|
| 676 |
+
<origin xyz="-0.004 0.006 -0.053" rpy="0 0 0"/>
|
| 677 |
+
<geometry>
|
| 678 |
+
<cylinder radius="0.03" length="0.03"/>
|
| 679 |
+
</geometry>
|
| 680 |
+
</collision>
|
| 681 |
+
</link>
|
| 682 |
+
<joint name="left_shoulder_roll_joint" type="revolute">
|
| 683 |
+
<origin xyz="0 0.038 -0.013831" rpy="-0.27925 0 0"/>
|
| 684 |
+
<parent link="left_shoulder_pitch_link"/>
|
| 685 |
+
<child link="left_shoulder_roll_link"/>
|
| 686 |
+
<axis xyz="1 0 0"/>
|
| 687 |
+
<limit lower="-1.5882" upper="2.2515" effort="25" velocity="37"/>
|
| 688 |
+
</joint>
|
| 689 |
+
<link name="left_shoulder_yaw_link">
|
| 690 |
+
<inertial>
|
| 691 |
+
<origin xyz="0.010773 -0.002949 -0.072009" rpy="0 0 0"/>
|
| 692 |
+
<mass value="0.734"/>
|
| 693 |
+
<inertia ixx="0.0009988" ixy="7.9E-06" ixz="0.0001412" iyy="0.0010605" iyz="-2.86E-05" izz="0.0004354"/>
|
| 694 |
+
</inertial>
|
| 695 |
+
<visual>
|
| 696 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 697 |
+
<geometry>
|
| 698 |
+
<mesh filename="meshes/left_shoulder_yaw_link.STL"/>
|
| 699 |
+
</geometry>
|
| 700 |
+
<material name="white">
|
| 701 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 702 |
+
</material>
|
| 703 |
+
</visual>
|
| 704 |
+
<collision>
|
| 705 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 706 |
+
<geometry>
|
| 707 |
+
<mesh filename="meshes/left_shoulder_yaw_link.STL"/>
|
| 708 |
+
</geometry>
|
| 709 |
+
</collision>
|
| 710 |
+
</link>
|
| 711 |
+
<joint name="left_shoulder_yaw_joint" type="revolute">
|
| 712 |
+
<origin xyz="0 0.00624 -0.1032" rpy="0 0 0"/>
|
| 713 |
+
<parent link="left_shoulder_roll_link"/>
|
| 714 |
+
<child link="left_shoulder_yaw_link"/>
|
| 715 |
+
<axis xyz="0 0 1"/>
|
| 716 |
+
<limit lower="-2.618" upper="2.618" effort="25" velocity="37"/>
|
| 717 |
+
</joint>
|
| 718 |
+
<link name="left_elbow_link">
|
| 719 |
+
<inertial>
|
| 720 |
+
<origin xyz="0.064956 0.004454 -0.010062" rpy="0 0 0"/>
|
| 721 |
+
<mass value="0.6"/>
|
| 722 |
+
<inertia ixx="0.0002891" ixy="6.53E-05" ixz="1.72E-05" iyy="0.0004152" iyz="-5.6E-06" izz="0.0004197"/>
|
| 723 |
+
</inertial>
|
| 724 |
+
<visual>
|
| 725 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 726 |
+
<geometry>
|
| 727 |
+
<mesh filename="meshes/left_elbow_link.STL"/>
|
| 728 |
+
</geometry>
|
| 729 |
+
<material name="white">
|
| 730 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 731 |
+
</material>
|
| 732 |
+
</visual>
|
| 733 |
+
<collision>
|
| 734 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 735 |
+
<geometry>
|
| 736 |
+
<mesh filename="meshes/left_elbow_link.STL"/>
|
| 737 |
+
</geometry>
|
| 738 |
+
</collision>
|
| 739 |
+
</link>
|
| 740 |
+
<joint name="left_elbow_joint" type="revolute">
|
| 741 |
+
<origin xyz="0.015783 0 -0.080518" rpy="0 0 0"/>
|
| 742 |
+
<parent link="left_shoulder_yaw_link"/>
|
| 743 |
+
<child link="left_elbow_link"/>
|
| 744 |
+
<axis xyz="0 1 0"/>
|
| 745 |
+
<limit lower="-1.0472" upper="2.0944" effort="25" velocity="37"/>
|
| 746 |
+
</joint>
|
| 747 |
+
<joint name="left_wrist_roll_joint" type="revolute">
|
| 748 |
+
<origin xyz="0.100 0.00188791 -0.010" rpy="0 0 0"/>
|
| 749 |
+
<axis xyz="1 0 0"/>
|
| 750 |
+
<parent link="left_elbow_link"/>
|
| 751 |
+
<child link="left_wrist_roll_link"/>
|
| 752 |
+
<limit effort="25" velocity="37" lower="-1.972222054" upper="1.972222054"/>
|
| 753 |
+
</joint>
|
| 754 |
+
<link name="left_wrist_roll_link">
|
| 755 |
+
<inertial>
|
| 756 |
+
<origin xyz="0.01713944778 0.00053759094 0.00000048864" rpy="0 0 0"/>
|
| 757 |
+
<mass value="0.08544498"/>
|
| 758 |
+
<inertia ixx="0.00004821544023" ixy="-0.00000424511021" ixz="0.00000000510599" iyy="0.00003722899093" iyz="-0.00000000123525" izz="0.00005482106541"/>
|
| 759 |
+
</inertial>
|
| 760 |
+
<visual>
|
| 761 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 762 |
+
<geometry>
|
| 763 |
+
<mesh filename="meshes/left_wrist_roll_link.STL"/>
|
| 764 |
+
</geometry>
|
| 765 |
+
<material name="white">
|
| 766 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 767 |
+
</material>
|
| 768 |
+
</visual>
|
| 769 |
+
<collision>
|
| 770 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 771 |
+
<geometry>
|
| 772 |
+
<mesh filename="meshes/left_wrist_roll_link.STL"/>
|
| 773 |
+
</geometry>
|
| 774 |
+
</collision>
|
| 775 |
+
</link>
|
| 776 |
+
<joint name="left_wrist_pitch_joint" type="revolute">
|
| 777 |
+
<origin xyz="0.038 0 0" rpy="0 0 0"/>
|
| 778 |
+
<axis xyz="0 1 0"/>
|
| 779 |
+
<parent link="left_wrist_roll_link"/>
|
| 780 |
+
<child link="left_wrist_pitch_link"/>
|
| 781 |
+
<limit effort="5" velocity="22" lower="-1.614429558" upper="1.614429558"/>
|
| 782 |
+
</joint>
|
| 783 |
+
<link name="left_wrist_pitch_link">
|
| 784 |
+
<inertial>
|
| 785 |
+
<origin xyz="0.02299989837 -0.00111685314 -0.00111658096" rpy="0 0 0"/>
|
| 786 |
+
<mass value="0.48404956"/>
|
| 787 |
+
<inertia ixx="0.00016579646273" ixy="-0.00001231206746" ixz="0.00001231699194" iyy="0.00042954057410" iyz="0.00000081417712" izz="0.00042953697654"/>
|
| 788 |
+
</inertial>
|
| 789 |
+
<visual>
|
| 790 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 791 |
+
<geometry>
|
| 792 |
+
<mesh filename="meshes/left_wrist_pitch_link.STL"/>
|
| 793 |
+
</geometry>
|
| 794 |
+
<material name="white">
|
| 795 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 796 |
+
</material>
|
| 797 |
+
</visual>
|
| 798 |
+
<collision>
|
| 799 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 800 |
+
<geometry>
|
| 801 |
+
<mesh filename="meshes/left_wrist_pitch_link.STL"/>
|
| 802 |
+
</geometry>
|
| 803 |
+
</collision>
|
| 804 |
+
</link>
|
| 805 |
+
<joint name="left_wrist_yaw_joint" type="revolute">
|
| 806 |
+
<origin xyz="0.046 0 0" rpy="0 0 0"/>
|
| 807 |
+
<axis xyz="0 0 1"/>
|
| 808 |
+
<parent link="left_wrist_pitch_link"/>
|
| 809 |
+
<child link="left_wrist_yaw_link"/>
|
| 810 |
+
<limit effort="5" velocity="22" lower="-1.614429558" upper="1.614429558"/>
|
| 811 |
+
</joint>
|
| 812 |
+
<link name="left_wrist_yaw_link">
|
| 813 |
+
<inertial>
|
| 814 |
+
<origin xyz="0.02200381568 0.00049485096 0.00053861123" rpy="0 0 0"/>
|
| 815 |
+
<mass value="0.08457647"/>
|
| 816 |
+
<inertia ixx="0.00004929128828" ixy="-0.00000045735494" ixz="0.00000445867591" iyy="0.00005973338134" iyz="0.00000043217198" izz="0.00003928083826"/>
|
| 817 |
+
</inertial>
|
| 818 |
+
<visual>
|
| 819 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 820 |
+
<geometry>
|
| 821 |
+
<mesh filename="meshes/left_wrist_yaw_link.STL"/>
|
| 822 |
+
</geometry>
|
| 823 |
+
<material name="white">
|
| 824 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 825 |
+
</material>
|
| 826 |
+
</visual>
|
| 827 |
+
<collision>
|
| 828 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 829 |
+
<geometry>
|
| 830 |
+
<mesh filename="meshes/left_wrist_yaw_link.STL"/>
|
| 831 |
+
</geometry>
|
| 832 |
+
</collision>
|
| 833 |
+
</link>
|
| 834 |
+
<joint name="left_hand_palm_joint" type="fixed">
|
| 835 |
+
<origin xyz="0.0415 0.003 0" rpy="0 0 0"/>
|
| 836 |
+
<parent link="left_wrist_yaw_link"/>
|
| 837 |
+
<child link="left_hand_palm_link"/>
|
| 838 |
+
</joint>
|
| 839 |
+
<link name="left_hand_palm_link">
|
| 840 |
+
<inertial>
|
| 841 |
+
<origin xyz="0.06214634836 -0.00050869656 -0.00058171093" rpy="0 0 0"/>
|
| 842 |
+
<mass value="0.37283854"/>
|
| 843 |
+
<inertia ixx="0.00027535181027" ixy="-0.00001595519465" ixz="-0.00000242161890" iyy="0.00053951827219" iyz="-0.00000042279435" izz="0.00039623390907"/>
|
| 844 |
+
</inertial>
|
| 845 |
+
<visual>
|
| 846 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 847 |
+
<geometry>
|
| 848 |
+
<mesh filename="meshes/left_hand_palm_link.STL"/>
|
| 849 |
+
</geometry>
|
| 850 |
+
<material name="white">
|
| 851 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 852 |
+
</material>
|
| 853 |
+
</visual>
|
| 854 |
+
<collision>
|
| 855 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 856 |
+
<geometry>
|
| 857 |
+
<mesh filename="meshes/left_hand_palm_link.STL"/>
|
| 858 |
+
</geometry>
|
| 859 |
+
</collision>
|
| 860 |
+
</link>
|
| 861 |
+
<joint name="left_hand_thumb_0_joint" type="revolute">
|
| 862 |
+
<origin xyz="0.0255 0 0" rpy="0 0 0"/>
|
| 863 |
+
<axis xyz="0 1 0"/>
|
| 864 |
+
<parent link="left_hand_palm_link"/>
|
| 865 |
+
<child link="left_hand_thumb_0_link"/>
|
| 866 |
+
<limit effort="2.45" velocity="6.857" lower="-1.04719755" upper="1.04719755"/>
|
| 867 |
+
</joint>
|
| 868 |
+
<link name="left_hand_thumb_0_link">
|
| 869 |
+
<inertial>
|
| 870 |
+
<origin xyz="-0.00088424580 -0.00863407079 0.00094429336" rpy="0 0 0"/>
|
| 871 |
+
<mass value="0.08623657"/>
|
| 872 |
+
<inertia ixx="0.00001602919238" ixy="0.00000010683177" ixz="0.00000016728875" iyy="0.00001451795012" iyz="-0.00000051094752" izz="0.00001637877663"/>
|
| 873 |
+
</inertial>
|
| 874 |
+
<visual>
|
| 875 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 876 |
+
<geometry>
|
| 877 |
+
<mesh filename="meshes/left_hand_thumb_0_link.STL"/>
|
| 878 |
+
</geometry>
|
| 879 |
+
<material name="white">
|
| 880 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 881 |
+
</material>
|
| 882 |
+
</visual>
|
| 883 |
+
<collision>
|
| 884 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 885 |
+
<geometry>
|
| 886 |
+
<mesh filename="meshes/left_hand_thumb_0_link.STL"/>
|
| 887 |
+
</geometry>
|
| 888 |
+
</collision>
|
| 889 |
+
</link>
|
| 890 |
+
<joint name="left_hand_thumb_1_joint" type="revolute">
|
| 891 |
+
<origin xyz="-0.0025 -0.0193 0" rpy="0 0 0"/>
|
| 892 |
+
<axis xyz="0 0 1"/>
|
| 893 |
+
<parent link="left_hand_thumb_0_link"/>
|
| 894 |
+
<child link="left_hand_thumb_1_link"/>
|
| 895 |
+
<limit effort="1.4" velocity="12" lower="-0.72431163" upper="1.04719755"/>
|
| 896 |
+
</joint>
|
| 897 |
+
<link name="left_hand_thumb_1_link">
|
| 898 |
+
<inertial>
|
| 899 |
+
<origin xyz="-0.00082788768 -0.03547435774 -0.00038089960" rpy="0 0 0"/>
|
| 900 |
+
<mass value="0.05885070"/>
|
| 901 |
+
<inertia ixx="0.00001274699945" ixy="-0.00000050770784" ixz="0.00000016088850" iyy="0.00000601573947" iyz="-0.00000027839003" izz="0.00001234543582"/>
|
| 902 |
+
</inertial>
|
| 903 |
+
<visual>
|
| 904 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 905 |
+
<geometry>
|
| 906 |
+
<mesh filename="meshes/left_hand_thumb_1_link.STL"/>
|
| 907 |
+
</geometry>
|
| 908 |
+
<material name="white">
|
| 909 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 910 |
+
</material>
|
| 911 |
+
</visual>
|
| 912 |
+
<collision>
|
| 913 |
+
<origin xyz="-0.001 -0.032 0" rpy="0 0 0"/>
|
| 914 |
+
<geometry>
|
| 915 |
+
<box size="0.02 0.03 0.02"/>
|
| 916 |
+
</geometry>
|
| 917 |
+
</collision>
|
| 918 |
+
</link>
|
| 919 |
+
<joint name="left_hand_thumb_2_joint" type="revolute">
|
| 920 |
+
<origin xyz="0 -0.0458 0" rpy="0 0 0"/>
|
| 921 |
+
<axis xyz="0 0 1"/>
|
| 922 |
+
<parent link="left_hand_thumb_1_link"/>
|
| 923 |
+
<child link="left_hand_thumb_2_link"/>
|
| 924 |
+
<limit effort="1.4" velocity="12" lower="0" upper="1.74532925"/>
|
| 925 |
+
</joint>
|
| 926 |
+
<link name="left_hand_thumb_2_link">
|
| 927 |
+
<inertial>
|
| 928 |
+
<origin xyz="-0.00171735242 -0.02628192939 0.00010778879" rpy="0 0 0"/>
|
| 929 |
+
<mass value="0.02030626"/>
|
| 930 |
+
<inertia ixx="0.00000461267817" ixy="-0.00000003422130" ixz="-0.00000000823881" iyy="0.00000153561368" iyz="-0.00000002549885" izz="0.00000386625776"/>
|
| 931 |
+
</inertial>
|
| 932 |
+
<visual>
|
| 933 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 934 |
+
<geometry>
|
| 935 |
+
<mesh filename="meshes/left_hand_thumb_2_link.STL"/>
|
| 936 |
+
</geometry>
|
| 937 |
+
<material name="white">
|
| 938 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 939 |
+
</material>
|
| 940 |
+
</visual>
|
| 941 |
+
<collision>
|
| 942 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 943 |
+
<geometry>
|
| 944 |
+
<mesh filename="meshes/left_hand_thumb_2_link.STL"/>
|
| 945 |
+
</geometry>
|
| 946 |
+
</collision>
|
| 947 |
+
</link>
|
| 948 |
+
<joint name="left_hand_middle_0_joint" type="revolute">
|
| 949 |
+
<origin xyz="0.0777 0.0016 -0.0285" rpy="0 0 0"/>
|
| 950 |
+
<axis xyz="0 0 1"/>
|
| 951 |
+
<parent link="left_hand_palm_link"/>
|
| 952 |
+
<child link="left_hand_middle_0_link"/>
|
| 953 |
+
<limit effort="1.4" velocity="12" lower="-1.57079632" upper="0"/>
|
| 954 |
+
</joint>
|
| 955 |
+
<link name="left_hand_middle_0_link">
|
| 956 |
+
<inertial>
|
| 957 |
+
<origin xyz="0.03547435774 0.00082788768 0.00038089960" rpy="0 0 0"/>
|
| 958 |
+
<mass value="0.05885070"/>
|
| 959 |
+
<inertia ixx="0.00000601573947" ixy="-0.00000050770784" ixz="-0.00000027839003" iyy="0.00001274699945" iyz="0.00000016088850" izz="0.00001234543582"/>
|
| 960 |
+
</inertial>
|
| 961 |
+
<visual>
|
| 962 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 963 |
+
<geometry>
|
| 964 |
+
<mesh filename="meshes/left_hand_middle_0_link.STL"/>
|
| 965 |
+
</geometry>
|
| 966 |
+
<material name="white">
|
| 967 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 968 |
+
</material>
|
| 969 |
+
</visual>
|
| 970 |
+
<collision>
|
| 971 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 972 |
+
<geometry>
|
| 973 |
+
<mesh filename="meshes/left_hand_middle_0_link.STL"/>
|
| 974 |
+
</geometry>
|
| 975 |
+
</collision>
|
| 976 |
+
</link>
|
| 977 |
+
<joint name="left_hand_middle_1_joint" type="revolute">
|
| 978 |
+
<origin xyz="0.0458 0 0" rpy="0 0 0"/>
|
| 979 |
+
<axis xyz="0 0 1"/>
|
| 980 |
+
<parent link="left_hand_middle_0_link"/>
|
| 981 |
+
<child link="left_hand_middle_1_link"/>
|
| 982 |
+
<limit effort="1.4" velocity="12" lower="-1.74532925" upper="0"/>
|
| 983 |
+
</joint>
|
| 984 |
+
<link name="left_hand_middle_1_link">
|
| 985 |
+
<inertial>
|
| 986 |
+
<origin xyz="0.02628192939 0.00171735242 -0.00010778879" rpy="0 0 0"/>
|
| 987 |
+
<mass value="0.02030626"/>
|
| 988 |
+
<inertia ixx="0.00000153561368" ixy="-0.00000003422130" ixz="-0.00000002549885" iyy="0.00000461267817" iyz="-0.00000000823881" izz="0.00000386625776"/>
|
| 989 |
+
</inertial>
|
| 990 |
+
<visual>
|
| 991 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 992 |
+
<geometry>
|
| 993 |
+
<mesh filename="meshes/left_hand_middle_1_link.STL"/>
|
| 994 |
+
</geometry>
|
| 995 |
+
<material name="white">
|
| 996 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 997 |
+
</material>
|
| 998 |
+
</visual>
|
| 999 |
+
<collision>
|
| 1000 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1001 |
+
<geometry>
|
| 1002 |
+
<mesh filename="meshes/left_hand_middle_1_link.STL"/>
|
| 1003 |
+
</geometry>
|
| 1004 |
+
</collision>
|
| 1005 |
+
</link>
|
| 1006 |
+
<joint name="left_hand_index_0_joint" type="revolute">
|
| 1007 |
+
<origin xyz="0.0777 0.0016 0.0285" rpy="0 0 0"/>
|
| 1008 |
+
<axis xyz="0 0 1"/>
|
| 1009 |
+
<parent link="left_hand_palm_link"/>
|
| 1010 |
+
<child link="left_hand_index_0_link"/>
|
| 1011 |
+
<limit effort="1.4" velocity="12" lower="-1.57079632" upper="0"/>
|
| 1012 |
+
</joint>
|
| 1013 |
+
<link name="left_hand_index_0_link">
|
| 1014 |
+
<inertial>
|
| 1015 |
+
<origin xyz="0.03547435774 0.00082788768 0.00038089960" rpy="0 0 0"/>
|
| 1016 |
+
<mass value="0.05885070"/>
|
| 1017 |
+
<inertia ixx="0.00000601573947" ixy="-0.00000050770784" ixz="-0.00000027839003" iyy="0.00001274699945" iyz="0.00000016088850" izz="0.00001234543582"/>
|
| 1018 |
+
</inertial>
|
| 1019 |
+
<visual>
|
| 1020 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1021 |
+
<geometry>
|
| 1022 |
+
<mesh filename="meshes/left_hand_index_0_link.STL"/>
|
| 1023 |
+
</geometry>
|
| 1024 |
+
<material name="white">
|
| 1025 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1026 |
+
</material>
|
| 1027 |
+
</visual>
|
| 1028 |
+
<collision>
|
| 1029 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1030 |
+
<geometry>
|
| 1031 |
+
<mesh filename="meshes/left_hand_index_0_link.STL"/>
|
| 1032 |
+
</geometry>
|
| 1033 |
+
</collision>
|
| 1034 |
+
</link>
|
| 1035 |
+
<joint name="left_hand_index_1_joint" type="revolute">
|
| 1036 |
+
<origin xyz="0.0458 0 0" rpy="0 0 0"/>
|
| 1037 |
+
<axis xyz="0 0 1"/>
|
| 1038 |
+
<parent link="left_hand_index_0_link"/>
|
| 1039 |
+
<child link="left_hand_index_1_link"/>
|
| 1040 |
+
<limit effort="1.4" velocity="12" lower="-1.74532925" upper="0"/>
|
| 1041 |
+
</joint>
|
| 1042 |
+
<link name="left_hand_index_1_link">
|
| 1043 |
+
<inertial>
|
| 1044 |
+
<origin xyz="0.02628192939 0.00171735242 -0.00010778879" rpy="0 0 0"/>
|
| 1045 |
+
<mass value="0.02030626"/>
|
| 1046 |
+
<inertia ixx="0.00000153561368" ixy="-0.00000003422130" ixz="-0.00000002549885" iyy="0.00000461267817" iyz="-0.00000000823881" izz="0.00000386625776"/>
|
| 1047 |
+
</inertial>
|
| 1048 |
+
<visual>
|
| 1049 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1050 |
+
<geometry>
|
| 1051 |
+
<mesh filename="meshes/left_hand_index_1_link.STL"/>
|
| 1052 |
+
</geometry>
|
| 1053 |
+
<material name="white">
|
| 1054 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1055 |
+
</material>
|
| 1056 |
+
</visual>
|
| 1057 |
+
<collision>
|
| 1058 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1059 |
+
<geometry>
|
| 1060 |
+
<mesh filename="meshes/left_hand_index_1_link.STL"/>
|
| 1061 |
+
</geometry>
|
| 1062 |
+
</collision>
|
| 1063 |
+
</link>
|
| 1064 |
+
<link name="right_shoulder_pitch_link">
|
| 1065 |
+
<inertial>
|
| 1066 |
+
<origin xyz="0 -0.035892 -0.011628" rpy="0 0 0"/>
|
| 1067 |
+
<mass value="0.718"/>
|
| 1068 |
+
<inertia ixx="0.0004291" ixy="9.2E-06" ixz="6.4E-06" iyy="0.000453" iyz="-2.26E-05" izz="0.000423"/>
|
| 1069 |
+
</inertial>
|
| 1070 |
+
<visual>
|
| 1071 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1072 |
+
<geometry>
|
| 1073 |
+
<mesh filename="meshes/right_shoulder_pitch_link.STL"/>
|
| 1074 |
+
</geometry>
|
| 1075 |
+
<material name="white">
|
| 1076 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1077 |
+
</material>
|
| 1078 |
+
</visual>
|
| 1079 |
+
<collision>
|
| 1080 |
+
<origin xyz="0 -0.04 -0.01" rpy="0 1.5707963267948966 0"/>
|
| 1081 |
+
<geometry>
|
| 1082 |
+
<cylinder radius="0.03" length="0.05"/>
|
| 1083 |
+
</geometry>
|
| 1084 |
+
</collision>
|
| 1085 |
+
</link>
|
| 1086 |
+
<joint name="right_shoulder_pitch_joint" type="revolute">
|
| 1087 |
+
<origin xyz="0.0039563 -0.10021 0.23778" rpy="-0.27931 5.4949E-05 0.00019159"/>
|
| 1088 |
+
<parent link="torso_link"/>
|
| 1089 |
+
<child link="right_shoulder_pitch_link"/>
|
| 1090 |
+
<axis xyz="0 1 0"/>
|
| 1091 |
+
<limit lower="-3.0892" upper="2.6704" effort="25" velocity="37"/>
|
| 1092 |
+
</joint>
|
| 1093 |
+
<link name="right_shoulder_roll_link">
|
| 1094 |
+
<inertial>
|
| 1095 |
+
<origin xyz="-0.000227 -0.00727 -0.063243" rpy="0 0 0"/>
|
| 1096 |
+
<mass value="0.643"/>
|
| 1097 |
+
<inertia ixx="0.0006177" ixy="1E-06" ixz="8.7E-06" iyy="0.0006912" iyz="5.3E-06" izz="0.0003894"/>
|
| 1098 |
+
</inertial>
|
| 1099 |
+
<visual>
|
| 1100 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1101 |
+
<geometry>
|
| 1102 |
+
<mesh filename="meshes/right_shoulder_roll_link.STL"/>
|
| 1103 |
+
</geometry>
|
| 1104 |
+
<material name="white">
|
| 1105 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1106 |
+
</material>
|
| 1107 |
+
</visual>
|
| 1108 |
+
<collision>
|
| 1109 |
+
<origin xyz="-0.004 -0.006 -0.053" rpy="0 0 0"/>
|
| 1110 |
+
<geometry>
|
| 1111 |
+
<cylinder radius="0.03" length="0.03"/>
|
| 1112 |
+
</geometry>
|
| 1113 |
+
</collision>
|
| 1114 |
+
</link>
|
| 1115 |
+
<joint name="right_shoulder_roll_joint" type="revolute">
|
| 1116 |
+
<origin xyz="0 -0.038 -0.013831" rpy="0.27925 0 0"/>
|
| 1117 |
+
<parent link="right_shoulder_pitch_link"/>
|
| 1118 |
+
<child link="right_shoulder_roll_link"/>
|
| 1119 |
+
<axis xyz="1 0 0"/>
|
| 1120 |
+
<limit lower="-2.2515" upper="1.5882" effort="25" velocity="37"/>
|
| 1121 |
+
</joint>
|
| 1122 |
+
<link name="right_shoulder_yaw_link">
|
| 1123 |
+
<inertial>
|
| 1124 |
+
<origin xyz="0.010773 0.002949 -0.072009" rpy="0 0 0"/>
|
| 1125 |
+
<mass value="0.734"/>
|
| 1126 |
+
<inertia ixx="0.0009988" ixy="-7.9E-06" ixz="0.0001412" iyy="0.0010605" iyz="2.86E-05" izz="0.0004354"/>
|
| 1127 |
+
</inertial>
|
| 1128 |
+
<visual>
|
| 1129 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1130 |
+
<geometry>
|
| 1131 |
+
<mesh filename="meshes/right_shoulder_yaw_link.STL"/>
|
| 1132 |
+
</geometry>
|
| 1133 |
+
<material name="white">
|
| 1134 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1135 |
+
</material>
|
| 1136 |
+
</visual>
|
| 1137 |
+
<collision>
|
| 1138 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1139 |
+
<geometry>
|
| 1140 |
+
<mesh filename="meshes/right_shoulder_yaw_link.STL"/>
|
| 1141 |
+
</geometry>
|
| 1142 |
+
</collision>
|
| 1143 |
+
</link>
|
| 1144 |
+
<joint name="right_shoulder_yaw_joint" type="revolute">
|
| 1145 |
+
<origin xyz="0 -0.00624 -0.1032" rpy="0 0 0"/>
|
| 1146 |
+
<parent link="right_shoulder_roll_link"/>
|
| 1147 |
+
<child link="right_shoulder_yaw_link"/>
|
| 1148 |
+
<axis xyz="0 0 1"/>
|
| 1149 |
+
<limit lower="-2.618" upper="2.618" effort="25" velocity="37"/>
|
| 1150 |
+
</joint>
|
| 1151 |
+
<link name="right_elbow_link">
|
| 1152 |
+
<inertial>
|
| 1153 |
+
<origin xyz="0.064956 -0.004454 -0.010062" rpy="0 0 0"/>
|
| 1154 |
+
<mass value="0.6"/>
|
| 1155 |
+
<inertia ixx="0.0002891" ixy="-6.53E-05" ixz="1.72E-05" iyy="0.0004152" iyz="5.6E-06" izz="0.0004197"/>
|
| 1156 |
+
</inertial>
|
| 1157 |
+
<visual>
|
| 1158 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1159 |
+
<geometry>
|
| 1160 |
+
<mesh filename="meshes/right_elbow_link.STL"/>
|
| 1161 |
+
</geometry>
|
| 1162 |
+
<material name="white">
|
| 1163 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1164 |
+
</material>
|
| 1165 |
+
</visual>
|
| 1166 |
+
<collision>
|
| 1167 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1168 |
+
<geometry>
|
| 1169 |
+
<mesh filename="meshes/right_elbow_link.STL"/>
|
| 1170 |
+
</geometry>
|
| 1171 |
+
</collision>
|
| 1172 |
+
</link>
|
| 1173 |
+
<joint name="right_elbow_joint" type="revolute">
|
| 1174 |
+
<origin xyz="0.015783 0 -0.080518" rpy="0 0 0"/>
|
| 1175 |
+
<parent link="right_shoulder_yaw_link"/>
|
| 1176 |
+
<child link="right_elbow_link"/>
|
| 1177 |
+
<axis xyz="0 1 0"/>
|
| 1178 |
+
<limit lower="-1.0472" upper="2.0944" effort="25" velocity="37"/>
|
| 1179 |
+
</joint>
|
| 1180 |
+
<joint name="right_wrist_roll_joint" type="revolute">
|
| 1181 |
+
<origin xyz="0.100 -0.00188791 -0.010" rpy="0 0 0"/>
|
| 1182 |
+
<axis xyz="1 0 0"/>
|
| 1183 |
+
<parent link="right_elbow_link"/>
|
| 1184 |
+
<child link="right_wrist_roll_link"/>
|
| 1185 |
+
<limit effort="25" velocity="37" lower="-1.972222054" upper="1.972222054"/>
|
| 1186 |
+
</joint>
|
| 1187 |
+
<link name="right_wrist_roll_link">
|
| 1188 |
+
<inertial>
|
| 1189 |
+
<origin xyz="0.01713944778 -0.00053759094 0.00000048864" rpy="0 0 0"/>
|
| 1190 |
+
<mass value="0.08544498"/>
|
| 1191 |
+
<inertia ixx="0.00004821544023" ixy="0.00000424511021" ixz="0.00000000510599" iyy="0.00003722899093" iyz="0.00000000123525" izz="0.00005482106541"/>
|
| 1192 |
+
</inertial>
|
| 1193 |
+
<visual>
|
| 1194 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1195 |
+
<geometry>
|
| 1196 |
+
<mesh filename="meshes/right_wrist_roll_link.STL"/>
|
| 1197 |
+
</geometry>
|
| 1198 |
+
<material name="white">
|
| 1199 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1200 |
+
</material>
|
| 1201 |
+
</visual>
|
| 1202 |
+
<collision>
|
| 1203 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1204 |
+
<geometry>
|
| 1205 |
+
<mesh filename="meshes/right_wrist_roll_link.STL"/>
|
| 1206 |
+
</geometry>
|
| 1207 |
+
</collision>
|
| 1208 |
+
</link>
|
| 1209 |
+
<joint name="right_wrist_pitch_joint" type="revolute">
|
| 1210 |
+
<origin xyz="0.038 0 0" rpy="0 0 0"/>
|
| 1211 |
+
<axis xyz="0 1 0"/>
|
| 1212 |
+
<parent link="right_wrist_roll_link"/>
|
| 1213 |
+
<child link="right_wrist_pitch_link"/>
|
| 1214 |
+
<limit effort="5" velocity="22" lower="-1.614429558" upper="1.614429558"/>
|
| 1215 |
+
</joint>
|
| 1216 |
+
<link name="right_wrist_pitch_link">
|
| 1217 |
+
<inertial>
|
| 1218 |
+
<origin xyz="0.02299989837 0.00111685314 -0.00111658096" rpy="0 0 0"/>
|
| 1219 |
+
<mass value="0.48404956"/>
|
| 1220 |
+
<inertia ixx="0.00016579646273" ixy="0.00001231206746" ixz="0.00001231699194" iyy="0.00042954057410" iyz="-0.00000081417712" izz="0.00042953697654"/>
|
| 1221 |
+
</inertial>
|
| 1222 |
+
<visual>
|
| 1223 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1224 |
+
<geometry>
|
| 1225 |
+
<mesh filename="meshes/right_wrist_pitch_link.STL"/>
|
| 1226 |
+
</geometry>
|
| 1227 |
+
<material name="white">
|
| 1228 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1229 |
+
</material>
|
| 1230 |
+
</visual>
|
| 1231 |
+
<collision>
|
| 1232 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1233 |
+
<geometry>
|
| 1234 |
+
<mesh filename="meshes/right_wrist_pitch_link.STL"/>
|
| 1235 |
+
</geometry>
|
| 1236 |
+
</collision>
|
| 1237 |
+
</link>
|
| 1238 |
+
<joint name="right_wrist_yaw_joint" type="revolute">
|
| 1239 |
+
<origin xyz="0.046 0 0" rpy="0 0 0"/>
|
| 1240 |
+
<axis xyz="0 0 1"/>
|
| 1241 |
+
<parent link="right_wrist_pitch_link"/>
|
| 1242 |
+
<child link="right_wrist_yaw_link"/>
|
| 1243 |
+
<limit effort="5" velocity="22" lower="-1.614429558" upper="1.614429558"/>
|
| 1244 |
+
</joint>
|
| 1245 |
+
<link name="right_wrist_yaw_link">
|
| 1246 |
+
<inertial>
|
| 1247 |
+
<origin xyz="0.02200381568 -0.00049485096 0.00053861123" rpy="0 0 0"/>
|
| 1248 |
+
<mass value="0.08457647"/>
|
| 1249 |
+
<inertia ixx="0.00004929128828" ixy="0.00000045735494" ixz="0.00000445867591" iyy="0.00005973338134" iyz="-0.00000043217198" izz="0.00003928083826"/>
|
| 1250 |
+
</inertial>
|
| 1251 |
+
<visual>
|
| 1252 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1253 |
+
<geometry>
|
| 1254 |
+
<mesh filename="meshes/right_wrist_yaw_link.STL"/>
|
| 1255 |
+
</geometry>
|
| 1256 |
+
<material name="white">
|
| 1257 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1258 |
+
</material>
|
| 1259 |
+
</visual>
|
| 1260 |
+
<collision>
|
| 1261 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1262 |
+
<geometry>
|
| 1263 |
+
<mesh filename="meshes/right_wrist_yaw_link.STL"/>
|
| 1264 |
+
</geometry>
|
| 1265 |
+
</collision>
|
| 1266 |
+
</link>
|
| 1267 |
+
<joint name="right_hand_palm_joint" type="fixed">
|
| 1268 |
+
<origin xyz="0.0415 -0.003 0" rpy="0 0 0"/>
|
| 1269 |
+
<parent link="right_wrist_yaw_link"/>
|
| 1270 |
+
<child link="right_hand_palm_link"/>
|
| 1271 |
+
</joint>
|
| 1272 |
+
<link name="right_hand_palm_link">
|
| 1273 |
+
<inertial>
|
| 1274 |
+
<origin xyz="0.06214634836 0.00050869656 -0.00058171093" rpy="0 0 0"/>
|
| 1275 |
+
<mass value="0.37283854"/>
|
| 1276 |
+
<inertia ixx="0.00027535181027" ixy="0.00001595519465" ixz="-0.00000242161890" iyy="0.00053951827219" iyz="0.00000042279435" izz="0.00039623390907"/>
|
| 1277 |
+
</inertial>
|
| 1278 |
+
<visual>
|
| 1279 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1280 |
+
<geometry>
|
| 1281 |
+
<mesh filename="meshes/right_hand_palm_link.STL"/>
|
| 1282 |
+
</geometry>
|
| 1283 |
+
<material name="white">
|
| 1284 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1285 |
+
</material>
|
| 1286 |
+
</visual>
|
| 1287 |
+
<collision>
|
| 1288 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1289 |
+
<geometry>
|
| 1290 |
+
<mesh filename="meshes/right_hand_palm_link.STL"/>
|
| 1291 |
+
</geometry>
|
| 1292 |
+
</collision>
|
| 1293 |
+
</link>
|
| 1294 |
+
<joint name="right_hand_thumb_0_joint" type="revolute">
|
| 1295 |
+
<origin xyz="0.0255 0 0" rpy="0 0 0"/>
|
| 1296 |
+
<axis xyz="0 1 0"/>
|
| 1297 |
+
<parent link="right_hand_palm_link"/>
|
| 1298 |
+
<child link="right_hand_thumb_0_link"/>
|
| 1299 |
+
<limit effort="2.45" velocity="6.857" lower="-1.04719755" upper="1.04719755"/>
|
| 1300 |
+
</joint>
|
| 1301 |
+
<link name="right_hand_thumb_0_link">
|
| 1302 |
+
<inertial>
|
| 1303 |
+
<origin xyz="-0.00088424580 0.00863407079 0.00094429336" rpy="0 0 0"/>
|
| 1304 |
+
<mass value="0.08623657"/>
|
| 1305 |
+
<inertia ixx="0.00001602919238" ixy="-0.00000010683177" ixz="0.00000016728875" iyy="0.00001451795012" iyz="0.00000051094752" izz="0.00001637877663"/>
|
| 1306 |
+
</inertial>
|
| 1307 |
+
<visual>
|
| 1308 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1309 |
+
<geometry>
|
| 1310 |
+
<mesh filename="meshes/right_hand_thumb_0_link.STL"/>
|
| 1311 |
+
</geometry>
|
| 1312 |
+
<material name="white">
|
| 1313 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1314 |
+
</material>
|
| 1315 |
+
</visual>
|
| 1316 |
+
<collision>
|
| 1317 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1318 |
+
<geometry>
|
| 1319 |
+
<mesh filename="meshes/right_hand_thumb_0_link.STL"/>
|
| 1320 |
+
</geometry>
|
| 1321 |
+
</collision>
|
| 1322 |
+
</link>
|
| 1323 |
+
<joint name="right_hand_thumb_1_joint" type="revolute">
|
| 1324 |
+
<origin xyz="-0.0025 0.0193 0" rpy="0 0 0"/>
|
| 1325 |
+
<axis xyz="0 0 1"/>
|
| 1326 |
+
<parent link="right_hand_thumb_0_link"/>
|
| 1327 |
+
<child link="right_hand_thumb_1_link"/>
|
| 1328 |
+
<limit effort="1.4" velocity="12" lower="-1.04719755" upper="0.72431163"/>
|
| 1329 |
+
</joint>
|
| 1330 |
+
<link name="right_hand_thumb_1_link">
|
| 1331 |
+
<inertial>
|
| 1332 |
+
<origin xyz="-0.00082788768 0.03547435774 -0.00038089960" rpy="0 0 0"/>
|
| 1333 |
+
<mass value="0.05885070"/>
|
| 1334 |
+
<inertia ixx="0.00001274699945" ixy="0.00000050770784" ixz="0.00000016088850" iyy="0.00000601573947" iyz="0.00000027839003" izz="0.00001234543582"/>
|
| 1335 |
+
</inertial>
|
| 1336 |
+
<visual>
|
| 1337 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1338 |
+
<geometry>
|
| 1339 |
+
<mesh filename="meshes/right_hand_thumb_1_link.STL"/>
|
| 1340 |
+
</geometry>
|
| 1341 |
+
<material name="white">
|
| 1342 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1343 |
+
</material>
|
| 1344 |
+
</visual>
|
| 1345 |
+
<collision>
|
| 1346 |
+
<origin xyz="-0.001 0.032 0" rpy="0 0 0"/>
|
| 1347 |
+
<geometry>
|
| 1348 |
+
<box size="0.02 0.03 0.02"/>
|
| 1349 |
+
</geometry>
|
| 1350 |
+
</collision>
|
| 1351 |
+
</link>
|
| 1352 |
+
<joint name="right_hand_thumb_2_joint" type="revolute">
|
| 1353 |
+
<origin xyz="0 0.0458 0" rpy="0 0 0"/>
|
| 1354 |
+
<axis xyz="0 0 1"/>
|
| 1355 |
+
<parent link="right_hand_thumb_1_link"/>
|
| 1356 |
+
<child link="right_hand_thumb_2_link"/>
|
| 1357 |
+
<limit effort="1.4" velocity="12" lower="-1.74532925" upper="0"/>
|
| 1358 |
+
</joint>
|
| 1359 |
+
<link name="right_hand_thumb_2_link">
|
| 1360 |
+
<inertial>
|
| 1361 |
+
<origin xyz="-0.00171735242 0.02628192939 0.00010778879" rpy="0 0 0"/>
|
| 1362 |
+
<mass value="0.02030626"/>
|
| 1363 |
+
<inertia ixx="0.00000461267817" ixy="0.00000003422130" ixz="-0.00000000823881" iyy="0.00000153561368" iyz="0.00000002549885" izz="0.00000386625776"/>
|
| 1364 |
+
</inertial>
|
| 1365 |
+
<visual>
|
| 1366 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1367 |
+
<geometry>
|
| 1368 |
+
<mesh filename="meshes/right_hand_thumb_2_link.STL"/>
|
| 1369 |
+
</geometry>
|
| 1370 |
+
<material name="white">
|
| 1371 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1372 |
+
</material>
|
| 1373 |
+
</visual>
|
| 1374 |
+
<collision>
|
| 1375 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1376 |
+
<geometry>
|
| 1377 |
+
<mesh filename="meshes/right_hand_thumb_2_link.STL"/>
|
| 1378 |
+
</geometry>
|
| 1379 |
+
</collision>
|
| 1380 |
+
</link>
|
| 1381 |
+
<joint name="right_hand_middle_0_joint" type="revolute">
|
| 1382 |
+
<origin xyz="0.0777 -0.0016 -0.0285" rpy="0 0 0"/>
|
| 1383 |
+
<axis xyz="0 0 1"/>
|
| 1384 |
+
<parent link="right_hand_palm_link"/>
|
| 1385 |
+
<child link="right_hand_middle_0_link"/>
|
| 1386 |
+
<limit effort="1.4" velocity="12" lower="0" upper="1.57079632"/>
|
| 1387 |
+
</joint>
|
| 1388 |
+
<link name="right_hand_middle_0_link">
|
| 1389 |
+
<inertial>
|
| 1390 |
+
<origin xyz="0.03547435774 -0.00082788768 0.00038089960" rpy="0 0 0"/>
|
| 1391 |
+
<mass value="0.05885070"/>
|
| 1392 |
+
<inertia ixx="0.00000601573947" ixy="0.00000050770784" ixz="-0.00000027839003" iyy="0.00001274699945" iyz="-0.00000016088850" izz="0.00001234543582"/>
|
| 1393 |
+
</inertial>
|
| 1394 |
+
<visual>
|
| 1395 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1396 |
+
<geometry>
|
| 1397 |
+
<mesh filename="meshes/right_hand_middle_0_link.STL"/>
|
| 1398 |
+
</geometry>
|
| 1399 |
+
<material name="white">
|
| 1400 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1401 |
+
</material>
|
| 1402 |
+
</visual>
|
| 1403 |
+
<collision>
|
| 1404 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1405 |
+
<geometry>
|
| 1406 |
+
<mesh filename="meshes/right_hand_middle_0_link.STL"/>
|
| 1407 |
+
</geometry>
|
| 1408 |
+
</collision>
|
| 1409 |
+
</link>
|
| 1410 |
+
<joint name="right_hand_middle_1_joint" type="revolute">
|
| 1411 |
+
<origin xyz="0.0458 0 0" rpy="0 0 0"/>
|
| 1412 |
+
<axis xyz="0 0 1"/>
|
| 1413 |
+
<parent link="right_hand_middle_0_link"/>
|
| 1414 |
+
<child link="right_hand_middle_1_link"/>
|
| 1415 |
+
<limit effort="1.4" velocity="12" lower="0" upper="1.74532925"/>
|
| 1416 |
+
</joint>
|
| 1417 |
+
<link name="right_hand_middle_1_link">
|
| 1418 |
+
<inertial>
|
| 1419 |
+
<origin xyz="0.02628192939 -0.00171735242 -0.00010778879" rpy="0 0 0"/>
|
| 1420 |
+
<mass value="0.02030626"/>
|
| 1421 |
+
<inertia ixx="0.00000153561368" ixy="0.00000003422130" ixz="-0.00000002549885" iyy="0.00000461267817" iyz="0.00000000823881" izz="0.00000386625776"/>
|
| 1422 |
+
</inertial>
|
| 1423 |
+
<visual>
|
| 1424 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1425 |
+
<geometry>
|
| 1426 |
+
<mesh filename="meshes/right_hand_middle_1_link.STL"/>
|
| 1427 |
+
</geometry>
|
| 1428 |
+
<material name="white">
|
| 1429 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1430 |
+
</material>
|
| 1431 |
+
</visual>
|
| 1432 |
+
<collision>
|
| 1433 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1434 |
+
<geometry>
|
| 1435 |
+
<mesh filename="meshes/right_hand_middle_1_link.STL"/>
|
| 1436 |
+
</geometry>
|
| 1437 |
+
</collision>
|
| 1438 |
+
</link>
|
| 1439 |
+
<joint name="right_hand_index_0_joint" type="revolute">
|
| 1440 |
+
<origin xyz="0.0777 -0.0016 0.0285" rpy="0 0 0"/>
|
| 1441 |
+
<axis xyz="0 0 1"/>
|
| 1442 |
+
<parent link="right_hand_palm_link"/>
|
| 1443 |
+
<child link="right_hand_index_0_link"/>
|
| 1444 |
+
<limit effort="1.4" velocity="12" lower="0" upper="1.57079632"/>
|
| 1445 |
+
</joint>
|
| 1446 |
+
<link name="right_hand_index_0_link">
|
| 1447 |
+
<inertial>
|
| 1448 |
+
<origin xyz="0.03547435774 -0.00082788768 0.00038089960" rpy="0 0 0"/>
|
| 1449 |
+
<mass value="0.05885070"/>
|
| 1450 |
+
<inertia ixx="0.00000601573947" ixy="0.00000050770784" ixz="-0.00000027839003" iyy="0.00001274699945" iyz="-0.00000016088850" izz="0.00001234543582"/>
|
| 1451 |
+
</inertial>
|
| 1452 |
+
<visual>
|
| 1453 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1454 |
+
<geometry>
|
| 1455 |
+
<mesh filename="meshes/right_hand_index_0_link.STL"/>
|
| 1456 |
+
</geometry>
|
| 1457 |
+
<material name="white">
|
| 1458 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1459 |
+
</material>
|
| 1460 |
+
</visual>
|
| 1461 |
+
<collision>
|
| 1462 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1463 |
+
<geometry>
|
| 1464 |
+
<mesh filename="meshes/right_hand_index_0_link.STL"/>
|
| 1465 |
+
</geometry>
|
| 1466 |
+
</collision>
|
| 1467 |
+
</link>
|
| 1468 |
+
<joint name="right_hand_index_1_joint" type="revolute">
|
| 1469 |
+
<origin xyz="0.0458 0 0" rpy="0 0 0"/>
|
| 1470 |
+
<axis xyz="0 0 1"/>
|
| 1471 |
+
<parent link="right_hand_index_0_link"/>
|
| 1472 |
+
<child link="right_hand_index_1_link"/>
|
| 1473 |
+
<limit effort="1.4" velocity="12" lower="0" upper="1.74532925"/>
|
| 1474 |
+
</joint>
|
| 1475 |
+
<link name="right_hand_index_1_link">
|
| 1476 |
+
<inertial>
|
| 1477 |
+
<origin xyz="0.02628192939 -0.00171735242 -0.00010778879" rpy="0 0 0"/>
|
| 1478 |
+
<mass value="0.02030626"/>
|
| 1479 |
+
<inertia ixx="0.00000153561368" ixy="0.00000003422130" ixz="-0.00000002549885" iyy="0.00000461267817" iyz="0.00000000823881" izz="0.00000386625776"/>
|
| 1480 |
+
</inertial>
|
| 1481 |
+
<visual>
|
| 1482 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1483 |
+
<geometry>
|
| 1484 |
+
<mesh filename="meshes/right_hand_index_1_link.STL"/>
|
| 1485 |
+
</geometry>
|
| 1486 |
+
<material name="white">
|
| 1487 |
+
<color rgba="0.7 0.7 0.7 1"/>
|
| 1488 |
+
</material>
|
| 1489 |
+
</visual>
|
| 1490 |
+
<collision>
|
| 1491 |
+
<origin xyz="0 0 0" rpy="0 0 0"/>
|
| 1492 |
+
<geometry>
|
| 1493 |
+
<mesh filename="meshes/right_hand_index_1_link.STL"/>
|
| 1494 |
+
</geometry>
|
| 1495 |
+
</collision>
|
| 1496 |
+
</link>
|
| 1497 |
+
</robot>
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_with_hand.xml
ADDED
|
@@ -0,0 +1,748 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<mujoco model="g1_29dof_with_hand">
|
| 2 |
+
<compiler angle="radian" meshdir="meshes" />
|
| 3 |
+
|
| 4 |
+
<default>
|
| 5 |
+
<default class="torso_motor">
|
| 6 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2"/>
|
| 7 |
+
</default>
|
| 8 |
+
<default class="leg_motor">
|
| 9 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2"/>
|
| 10 |
+
</default>
|
| 11 |
+
<default class="ankle_motor">
|
| 12 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2"/>
|
| 13 |
+
</default>
|
| 14 |
+
<default class="arm_motor">
|
| 15 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2"/>
|
| 16 |
+
</default>
|
| 17 |
+
<default class="wrist_motor">
|
| 18 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.1"/>
|
| 19 |
+
</default>
|
| 20 |
+
<default class="finger_motor">
|
| 21 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.1"/>
|
| 22 |
+
</default>
|
| 23 |
+
</default>
|
| 24 |
+
<asset>
|
| 25 |
+
<mesh name="pelvis" file="pelvis.STL" />
|
| 26 |
+
<mesh name="pelvis_contour_link" file="pelvis_contour_link.STL" />
|
| 27 |
+
<mesh name="left_hip_pitch_link" file="left_hip_pitch_link.STL" />
|
| 28 |
+
<mesh name="left_hip_roll_link" file="left_hip_roll_link.STL" />
|
| 29 |
+
<mesh name="left_hip_yaw_link" file="left_hip_yaw_link.STL" />
|
| 30 |
+
<mesh name="left_knee_link" file="left_knee_link.STL" />
|
| 31 |
+
<mesh name="left_ankle_pitch_link" file="left_ankle_pitch_link.STL" />
|
| 32 |
+
<mesh name="left_ankle_roll_link" file="left_ankle_roll_link.STL" />
|
| 33 |
+
<mesh name="right_hip_pitch_link" file="right_hip_pitch_link.STL" />
|
| 34 |
+
<mesh name="right_hip_roll_link" file="right_hip_roll_link.STL" />
|
| 35 |
+
<mesh name="right_hip_yaw_link" file="right_hip_yaw_link.STL" />
|
| 36 |
+
<mesh name="right_knee_link" file="right_knee_link.STL" />
|
| 37 |
+
<mesh name="right_ankle_pitch_link" file="right_ankle_pitch_link.STL" />
|
| 38 |
+
<mesh name="right_ankle_roll_link" file="right_ankle_roll_link.STL" />
|
| 39 |
+
<mesh name="waist_yaw_link" file="waist_yaw_link.STL" />
|
| 40 |
+
<mesh name="waist_roll_link" file="waist_roll_link.STL" />
|
| 41 |
+
<mesh name="torso_link" file="torso_link.STL" />
|
| 42 |
+
<mesh name="logo_link" file="logo_link.STL" />
|
| 43 |
+
<mesh name="head_link" file="head_link.STL" />
|
| 44 |
+
<mesh name="waist_support_link" file="waist_support_link.STL" />
|
| 45 |
+
<mesh name="left_shoulder_pitch_link" file="left_shoulder_pitch_link.STL" />
|
| 46 |
+
<mesh name="left_shoulder_roll_link" file="left_shoulder_roll_link.STL" />
|
| 47 |
+
<mesh name="left_shoulder_yaw_link" file="left_shoulder_yaw_link.STL" />
|
| 48 |
+
<mesh name="left_elbow_link" file="left_elbow_link.STL" />
|
| 49 |
+
<mesh name="left_wrist_roll_link" file="left_wrist_roll_link.STL" />
|
| 50 |
+
<mesh name="left_wrist_pitch_link" file="left_wrist_pitch_link.STL" />
|
| 51 |
+
<mesh name="left_wrist_yaw_link" file="left_wrist_yaw_link.STL" />
|
| 52 |
+
<mesh name="left_hand_palm_link" file="left_hand_palm_link.STL" />
|
| 53 |
+
<mesh name="left_hand_thumb_0_link" file="left_hand_thumb_0_link.STL" />
|
| 54 |
+
<mesh name="left_hand_thumb_1_link" file="left_hand_thumb_1_link.STL" />
|
| 55 |
+
<mesh name="left_hand_thumb_2_link" file="left_hand_thumb_2_link.STL" />
|
| 56 |
+
<mesh name="left_hand_middle_0_link" file="left_hand_middle_0_link.STL" />
|
| 57 |
+
<mesh name="left_hand_middle_1_link" file="left_hand_middle_1_link.STL" />
|
| 58 |
+
<mesh name="left_hand_index_0_link" file="left_hand_index_0_link.STL" />
|
| 59 |
+
<mesh name="left_hand_index_1_link" file="left_hand_index_1_link.STL" />
|
| 60 |
+
<mesh name="right_shoulder_pitch_link" file="right_shoulder_pitch_link.STL" />
|
| 61 |
+
<mesh name="right_shoulder_roll_link" file="right_shoulder_roll_link.STL" />
|
| 62 |
+
<mesh name="right_shoulder_yaw_link" file="right_shoulder_yaw_link.STL" />
|
| 63 |
+
<mesh name="right_elbow_link" file="right_elbow_link.STL" />
|
| 64 |
+
<mesh name="right_wrist_roll_link" file="right_wrist_roll_link.STL" />
|
| 65 |
+
<mesh name="right_wrist_pitch_link" file="right_wrist_pitch_link.STL" />
|
| 66 |
+
<mesh name="right_wrist_yaw_link" file="right_wrist_yaw_link.STL" />
|
| 67 |
+
<mesh name="right_hand_palm_link" file="right_hand_palm_link.STL" />
|
| 68 |
+
<mesh name="right_hand_thumb_0_link" file="right_hand_thumb_0_link.STL" />
|
| 69 |
+
<mesh name="right_hand_thumb_1_link" file="right_hand_thumb_1_link.STL" />
|
| 70 |
+
<mesh name="right_hand_thumb_2_link" file="right_hand_thumb_2_link.STL" />
|
| 71 |
+
<mesh name="right_hand_middle_0_link" file="right_hand_middle_0_link.STL" />
|
| 72 |
+
<mesh name="right_hand_middle_1_link" file="right_hand_middle_1_link.STL" />
|
| 73 |
+
<mesh name="right_hand_index_0_link" file="right_hand_index_0_link.STL" />
|
| 74 |
+
<mesh name="right_hand_index_1_link" file="right_hand_index_1_link.STL" />
|
| 75 |
+
</asset>
|
| 76 |
+
|
| 77 |
+
<worldbody>
|
| 78 |
+
<body name="pelvis" pos="0 0 0.793">
|
| 79 |
+
<inertial pos="0 0 -0.07605" quat="1 0 -0.000399148 0" mass="3.813"
|
| 80 |
+
diaginertia="0.010549 0.0093089 0.0079184" />
|
| 81 |
+
<joint name="floating_base_joint" type="free" limited="false" actuatorfrclimited="false" />
|
| 82 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.2 0.2 0.2 1"
|
| 83 |
+
mesh="pelvis" />
|
| 84 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 85 |
+
mesh="pelvis_contour_link" />
|
| 86 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="pelvis_contour_link" />
|
| 87 |
+
<body name="left_hip_pitch_link" pos="0 0.064452 -0.1027">
|
| 88 |
+
<inertial pos="0.002741 0.047791 -0.02606" quat="0.954862 0.293964 0.0302556 0.030122"
|
| 89 |
+
mass="1.35" diaginertia="0.00181517 0.00153422 0.00116212" />
|
| 90 |
+
<joint name="left_hip_pitch_joint" pos="0 0 0" axis="0 1 0" range="-2.5307 2.8798"
|
| 91 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 92 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.2 0.2 0.2 1"
|
| 93 |
+
mesh="left_hip_pitch_link" />
|
| 94 |
+
<geom type="mesh" rgba="0.2 0.2 0.2 1" mesh="left_hip_pitch_link" />
|
| 95 |
+
<body name="left_hip_roll_link" pos="0 0.052 -0.030465" quat="0.996179 0 -0.0873386 0">
|
| 96 |
+
<inertial pos="0.029812 -0.001045 -0.087934"
|
| 97 |
+
quat="0.977808 -1.97119e-05 0.205576 -0.0403793" mass="1.52"
|
| 98 |
+
diaginertia="0.00254986 0.00241169 0.00148755" />
|
| 99 |
+
<joint name="left_hip_roll_joint" pos="0 0 0" axis="1 0 0" range="-0.5236 2.9671"
|
| 100 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 101 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 102 |
+
mesh="left_hip_roll_link" />
|
| 103 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hip_roll_link" />
|
| 104 |
+
<body name="left_hip_yaw_link" pos="0.025001 0 -0.12412">
|
| 105 |
+
<inertial pos="-0.057709 -0.010981 -0.15078" quat="0.600598 0.15832 0.223482 0.751181"
|
| 106 |
+
mass="1.702" diaginertia="0.00776166 0.00717575 0.00160139" />
|
| 107 |
+
<joint name="left_hip_yaw_joint" pos="0 0 0" axis="0 0 1" range="-2.7576 2.7576"
|
| 108 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 109 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 110 |
+
mesh="left_hip_yaw_link" />
|
| 111 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hip_yaw_link" />
|
| 112 |
+
<body name="left_knee_link" pos="-0.078273 0.0021489 -0.17734"
|
| 113 |
+
quat="0.996179 0 0.0873386 0">
|
| 114 |
+
<inertial pos="0.005457 0.003964 -0.12074"
|
| 115 |
+
quat="0.923418 -0.0327699 0.0158246 0.382067" mass="1.932"
|
| 116 |
+
diaginertia="0.0113804 0.0112778 0.00146458" />
|
| 117 |
+
<joint name="left_knee_joint" pos="0 0 0" axis="0 1 0" range="-0.087267 2.8798"
|
| 118 |
+
actuatorfrcrange="-139 139" class="leg_motor" />
|
| 119 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 120 |
+
rgba="0.7 0.7 0.7 1" mesh="left_knee_link" />
|
| 121 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_knee_link" />
|
| 122 |
+
<body name="left_ankle_pitch_link" pos="0 -9.4445e-05 -0.30001">
|
| 123 |
+
<inertial pos="-0.007269 0 0.011137" quat="0.603053 0.369225 0.369225 0.603053"
|
| 124 |
+
mass="0.074" diaginertia="1.89e-05 1.40805e-05 6.9195e-06" />
|
| 125 |
+
<joint name="left_ankle_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 126 |
+
range="-0.87267 0.5236" actuatorfrcrange="-50 50" class="ankle_motor" />
|
| 127 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 128 |
+
rgba="0.7 0.7 0.7 1" mesh="left_ankle_pitch_link" />
|
| 129 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_ankle_pitch_link" />
|
| 130 |
+
<body name="left_ankle_roll_link" pos="0 0 -0.017558">
|
| 131 |
+
<inertial pos="0.026505 0 -0.016425"
|
| 132 |
+
quat="-0.000481092 0.728482 -0.000618967 0.685065" mass="0.608"
|
| 133 |
+
diaginertia="0.00167218 0.0016161 0.000217621" />
|
| 134 |
+
<joint name="left_ankle_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 135 |
+
range="-0.2618 0.2618" actuatorfrcrange="-50 50" class="ankle_motor" />
|
| 136 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 137 |
+
rgba="0.2 0.2 0.2 1" mesh="left_ankle_roll_link" />
|
| 138 |
+
<geom size="0.005" pos="-0.05 0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 139 |
+
<geom size="0.005" pos="-0.05 -0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 140 |
+
<geom size="0.005" pos="0.12 0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 141 |
+
<geom size="0.005" pos="0.12 -0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 142 |
+
</body>
|
| 143 |
+
</body>
|
| 144 |
+
</body>
|
| 145 |
+
</body>
|
| 146 |
+
</body>
|
| 147 |
+
</body>
|
| 148 |
+
<body name="right_hip_pitch_link" pos="0 -0.064452 -0.1027">
|
| 149 |
+
<inertial pos="0.002741 -0.047791 -0.02606" quat="0.954862 -0.293964 0.0302556 -0.030122"
|
| 150 |
+
mass="1.35" diaginertia="0.00181517 0.00153422 0.00116212" />
|
| 151 |
+
<joint name="right_hip_pitch_joint" pos="0 0 0" axis="0 1 0" range="-2.5307 2.8798"
|
| 152 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 153 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.2 0.2 0.2 1"
|
| 154 |
+
mesh="right_hip_pitch_link" />
|
| 155 |
+
<geom type="mesh" rgba="0.2 0.2 0.2 1" mesh="right_hip_pitch_link" />
|
| 156 |
+
<body name="right_hip_roll_link" pos="0 -0.052 -0.030465" quat="0.996179 0 -0.0873386 0">
|
| 157 |
+
<inertial pos="0.029812 0.001045 -0.087934" quat="0.977808 1.97119e-05 0.205576 0.0403793"
|
| 158 |
+
mass="1.52" diaginertia="0.00254986 0.00241169 0.00148755" />
|
| 159 |
+
<joint name="right_hip_roll_joint" pos="0 0 0" axis="1 0 0" range="-2.9671 0.5236"
|
| 160 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 161 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 162 |
+
mesh="right_hip_roll_link" />
|
| 163 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hip_roll_link" />
|
| 164 |
+
<body name="right_hip_yaw_link" pos="0.025001 0 -0.12412">
|
| 165 |
+
<inertial pos="-0.057709 0.010981 -0.15078" quat="0.751181 0.223482 0.15832 0.600598"
|
| 166 |
+
mass="1.702" diaginertia="0.00776166 0.00717575 0.00160139" />
|
| 167 |
+
<joint name="right_hip_yaw_joint" pos="0 0 0" axis="0 0 1" range="-2.7576 2.7576"
|
| 168 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 169 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 170 |
+
mesh="right_hip_yaw_link" />
|
| 171 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hip_yaw_link" />
|
| 172 |
+
<body name="right_knee_link" pos="-0.078273 -0.0021489 -0.17734"
|
| 173 |
+
quat="0.996179 0 0.0873386 0">
|
| 174 |
+
<inertial pos="0.005457 -0.003964 -0.12074"
|
| 175 |
+
quat="0.923439 0.0345276 0.0116333 -0.382012" mass="1.932"
|
| 176 |
+
diaginertia="0.011374 0.0112843 0.00146452" />
|
| 177 |
+
<joint name="right_knee_joint" pos="0 0 0" axis="0 1 0" range="-0.087267 2.8798"
|
| 178 |
+
actuatorfrcrange="-139 139" class="leg_motor" />
|
| 179 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 180 |
+
rgba="0.7 0.7 0.7 1" mesh="right_knee_link" />
|
| 181 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_knee_link" />
|
| 182 |
+
<body name="right_ankle_pitch_link" pos="0 9.4445e-05 -0.30001">
|
| 183 |
+
<inertial pos="-0.007269 0 0.011137" quat="0.603053 0.369225 0.369225 0.603053"
|
| 184 |
+
mass="0.074" diaginertia="1.89e-05 1.40805e-05 6.9195e-06" />
|
| 185 |
+
<joint name="right_ankle_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 186 |
+
range="-0.87267 0.5236" actuatorfrcrange="-50 50" class="ankle_motor" />
|
| 187 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 188 |
+
rgba="0.7 0.7 0.7 1" mesh="right_ankle_pitch_link" />
|
| 189 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_ankle_pitch_link" />
|
| 190 |
+
<body name="right_ankle_roll_link" pos="0 0 -0.017558">
|
| 191 |
+
<inertial pos="0.026505 0 -0.016425"
|
| 192 |
+
quat="0.000481092 0.728482 0.000618967 0.685065" mass="0.608"
|
| 193 |
+
diaginertia="0.00167218 0.0016161 0.000217621" />
|
| 194 |
+
<joint name="right_ankle_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 195 |
+
range="-0.2618 0.2618" actuatorfrcrange="-50 50" class="ankle_motor" />
|
| 196 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 197 |
+
rgba="0.2 0.2 0.2 1" mesh="right_ankle_roll_link" />
|
| 198 |
+
<geom size="0.005" pos="-0.05 0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 199 |
+
<geom size="0.005" pos="-0.05 -0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 200 |
+
<geom size="0.005" pos="0.12 0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 201 |
+
<geom size="0.005" pos="0.12 -0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 202 |
+
</body>
|
| 203 |
+
</body>
|
| 204 |
+
</body>
|
| 205 |
+
</body>
|
| 206 |
+
</body>
|
| 207 |
+
</body>
|
| 208 |
+
<body name="waist_yaw_link">
|
| 209 |
+
<inertial pos="0.003964 0 0.018769" quat="-0.0178291 0.628464 0.0282471 0.777121"
|
| 210 |
+
mass="0.244" diaginertia="0.000158561 0.000124229 9.67669e-05" />
|
| 211 |
+
<joint name="waist_yaw_joint" pos="0 0 0" axis="0 0 1" range="-2.618 2.618"
|
| 212 |
+
actuatorfrcrange="-88 88" class="torso_motor" />
|
| 213 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 214 |
+
mesh="waist_yaw_link" />
|
| 215 |
+
<body name="waist_roll_link" pos="-0.0039635 0 0.035">
|
| 216 |
+
<inertial pos="0 -0.000236 0.010111" quat="0.99979 0.020492 0 0" mass="0.047"
|
| 217 |
+
diaginertia="7.515e-06 6.40206e-06 3.98394e-06" />
|
| 218 |
+
<joint name="waist_roll_joint" pos="0 0 0" axis="1 0 0" range="-0.52 0.52"
|
| 219 |
+
actuatorfrcrange="-50 50" class="torso_motor"/>
|
| 220 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 221 |
+
mesh="waist_roll_link" />
|
| 222 |
+
<body name="torso_link" pos="0 0 0.019">
|
| 223 |
+
<inertial pos="0.00331658 0.000261533 0.179856"
|
| 224 |
+
quat="0.999831 0.000376204 0.0179895 -0.00377704" mass="9.598"
|
| 225 |
+
diaginertia="0.12407 0.111951 0.0325382" />
|
| 226 |
+
<joint name="waist_pitch_joint" pos="0 0 0" axis="0 1 0" range="-0.52 0.52"
|
| 227 |
+
actuatorfrcrange="-50 50" class="torso_motor"/>
|
| 228 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 229 |
+
mesh="torso_link" />
|
| 230 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="torso_link" />
|
| 231 |
+
<geom pos="0.0039635 0 -0.054" quat="1 0 0 0" type="mesh" contype="0" conaffinity="0"
|
| 232 |
+
group="1" density="0" rgba="0.2 0.2 0.2 1" mesh="logo_link" />
|
| 233 |
+
<geom pos="0.0039635 0 -0.054" quat="1 0 0 0" type="mesh" rgba="0.2 0.2 0.2 1"
|
| 234 |
+
mesh="logo_link" />
|
| 235 |
+
<geom pos="0.0039635 0 -0.054" type="mesh" contype="0" conaffinity="0" group="1"
|
| 236 |
+
density="0" rgba="0.2 0.2 0.2 1" mesh="head_link" />
|
| 237 |
+
<geom pos="0.0039635 0 -0.054" type="mesh" rgba="0.2 0.2 0.2 1" mesh="head_link" />
|
| 238 |
+
<geom pos="0.0039635 0 -0.054" quat="1 0 0 0" type="mesh" contype="0" conaffinity="0"
|
| 239 |
+
group="1" density="0" rgba="0.7 0.7 0.7 1" mesh="waist_support_link" />
|
| 240 |
+
<geom pos="0.0039635 0 -0.054" quat="1 0 0 0" type="mesh" rgba="0.7 0.7 0.7 1"
|
| 241 |
+
mesh="waist_support_link" />
|
| 242 |
+
<site name="imu" size="0.01" pos="-0.03959 -0.00224 0.13792" />
|
| 243 |
+
<body name="left_shoulder_pitch_link" pos="0.0039563 0.10022 0.23778"
|
| 244 |
+
quat="0.990264 0.139201 1.38722e-05 -9.86868e-05">
|
| 245 |
+
<inertial pos="0 0.035892 -0.011628" quat="0.654152 0.0130458 -0.326267 0.68225"
|
| 246 |
+
mass="0.718" diaginertia="0.000465864 0.000432842 0.000406394" />
|
| 247 |
+
<joint name="left_shoulder_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 248 |
+
range="-3.0892 2.6704" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 249 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 250 |
+
rgba="0.7 0.7 0.7 1" mesh="left_shoulder_pitch_link" />
|
| 251 |
+
<geom size="0.03 0.025" pos="0 0.04 -0.01" quat="0.707107 0 0.707107 0"
|
| 252 |
+
type="cylinder" rgba="0.7 0.7 0.7 1" />
|
| 253 |
+
<body name="left_shoulder_roll_link" pos="0 0.038 -0.013831"
|
| 254 |
+
quat="0.990268 -0.139172 0 0">
|
| 255 |
+
<inertial pos="-0.000227 0.00727 -0.063243"
|
| 256 |
+
quat="0.701256 -0.0196223 -0.00710317 0.712604" mass="0.643"
|
| 257 |
+
diaginertia="0.000691311 0.000618011 0.000388977" />
|
| 258 |
+
<joint name="left_shoulder_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 259 |
+
range="-1.5882 2.2515" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 260 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 261 |
+
rgba="0.7 0.7 0.7 1" mesh="left_shoulder_roll_link" />
|
| 262 |
+
<geom size="0.03 0.015" pos="-0.004 0.006 -0.053" type="cylinder"
|
| 263 |
+
rgba="0.7 0.7 0.7 1" />
|
| 264 |
+
<body name="left_shoulder_yaw_link" pos="0 0.00624 -0.1032">
|
| 265 |
+
<inertial pos="0.010773 -0.002949 -0.072009"
|
| 266 |
+
quat="0.716879 -0.0964829 -0.0679942 0.687134" mass="0.734"
|
| 267 |
+
diaginertia="0.00106187 0.00103217 0.000400661" />
|
| 268 |
+
<joint name="left_shoulder_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 269 |
+
range="-2.618 2.618" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 270 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 271 |
+
rgba="0.7 0.7 0.7 1" mesh="left_shoulder_yaw_link" />
|
| 272 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_shoulder_yaw_link" />
|
| 273 |
+
<body name="left_elbow_link" pos="0.015783 0 -0.080518">
|
| 274 |
+
<inertial pos="0.064956 0.004454 -0.010062"
|
| 275 |
+
quat="0.541765 0.636132 0.388821 0.388129" mass="0.6"
|
| 276 |
+
diaginertia="0.000443035 0.000421612 0.000259353" />
|
| 277 |
+
<joint name="left_elbow_joint" pos="0 0 0" axis="0 1 0" range="-1.0472 2.0944"
|
| 278 |
+
actuatorfrcrange="-25 25" class="arm_motor" />
|
| 279 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 280 |
+
rgba="0.7 0.7 0.7 1" mesh="left_elbow_link" />
|
| 281 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_elbow_link" />
|
| 282 |
+
<body name="left_wrist_roll_link" pos="0.1 0.00188791 -0.01">
|
| 283 |
+
<inertial pos="0.0171394 0.000537591 4.8864e-07"
|
| 284 |
+
quat="0.575338 0.411667 -0.574906 0.411094" mass="0.085445"
|
| 285 |
+
diaginertia="5.48211e-05 4.96646e-05 3.57798e-05" />
|
| 286 |
+
<joint name="left_wrist_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 287 |
+
range="-1.97222 1.97222" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 288 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 289 |
+
rgba="0.7 0.7 0.7 1" mesh="left_wrist_roll_link" />
|
| 290 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_wrist_roll_link" />
|
| 291 |
+
<body name="left_wrist_pitch_link" pos="0.038 0 0">
|
| 292 |
+
<inertial pos="0.0229999 -0.00111685 -0.00111658"
|
| 293 |
+
quat="0.249998 0.661363 0.293036 0.643608" mass="0.48405"
|
| 294 |
+
diaginertia="0.000430353 0.000429873 0.000164648" />
|
| 295 |
+
<joint name="left_wrist_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 296 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 297 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 298 |
+
rgba="0.7 0.7 0.7 1" mesh="left_wrist_pitch_link" />
|
| 299 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_wrist_pitch_link" />
|
| 300 |
+
<body name="left_wrist_yaw_link" pos="0.046 0 0">
|
| 301 |
+
<inertial pos="0.0885506 0.00212216 -0.000374562"
|
| 302 |
+
quat="0.487149 0.493844 0.513241 0.505358" mass="0.457415"
|
| 303 |
+
diaginertia="0.00105989 0.000895419 0.000323842" />
|
| 304 |
+
<joint name="left_wrist_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 305 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 306 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 307 |
+
rgba="0.7 0.7 0.7 1" mesh="left_wrist_yaw_link" />
|
| 308 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_wrist_yaw_link" />
|
| 309 |
+
<geom pos="0.0415 0.003 0" quat="1 0 0 0" type="mesh" contype="0"
|
| 310 |
+
conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 311 |
+
mesh="left_hand_palm_link" />
|
| 312 |
+
<geom pos="0.0415 0.003 0" quat="1 0 0 0" type="mesh" rgba="0.7 0.7 0.7 1"
|
| 313 |
+
mesh="left_hand_palm_link" />
|
| 314 |
+
<body name="left_hand_thumb_0_link" pos="0.067 0.003 0">
|
| 315 |
+
<inertial pos="-0.000884246 -0.00863407 0.000944293"
|
| 316 |
+
quat="0.462991 0.643965 -0.460173 0.398986" mass="0.0862366"
|
| 317 |
+
diaginertia="1.6546e-05 1.60058e-05 1.43741e-05" />
|
| 318 |
+
<joint name="left_hand_thumb_0_joint" pos="0 0 0" axis="0 1 0"
|
| 319 |
+
range="-1.0472 1.0472" actuatorfrcrange="-2.45 2.45"
|
| 320 |
+
class="finger_motor" />
|
| 321 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 322 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_thumb_0_link" />
|
| 323 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_thumb_0_link" />
|
| 324 |
+
<body name="left_hand_thumb_1_link" pos="-0.0025 -0.0193 0">
|
| 325 |
+
<inertial pos="-0.000827888 -0.0354744 -0.0003809"
|
| 326 |
+
quat="0.685598 0.705471 -0.15207 0.0956069" mass="0.0588507"
|
| 327 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 328 |
+
<joint name="left_hand_thumb_1_joint" pos="0 0 0" axis="0 0 1"
|
| 329 |
+
range="-0.724312 1.0472" actuatorfrcrange="-1.4 1.4"
|
| 330 |
+
class="finger_motor" />
|
| 331 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 332 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_thumb_1_link" />
|
| 333 |
+
<geom size="0.01 0.015 0.01" pos="-0.001 -0.032 0" type="box"
|
| 334 |
+
rgba="0.7 0.7 0.7 1" />
|
| 335 |
+
<body name="left_hand_thumb_2_link" pos="0 -0.0458 0">
|
| 336 |
+
<inertial pos="-0.00171735 -0.0262819 0.000107789"
|
| 337 |
+
quat="0.703174 0.710977 -0.00017564 -0.00766553" mass="0.0203063"
|
| 338 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 339 |
+
<joint name="left_hand_thumb_2_joint" pos="0 0 0" axis="0 0 1"
|
| 340 |
+
range="0 1.74533" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 341 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 342 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_thumb_2_link" />
|
| 343 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_thumb_2_link" />
|
| 344 |
+
</body>
|
| 345 |
+
</body>
|
| 346 |
+
</body>
|
| 347 |
+
<body name="left_hand_middle_0_link" pos="0.1192 0.0046 -0.0285">
|
| 348 |
+
<inertial pos="0.0354744 0.000827888 0.0003809"
|
| 349 |
+
quat="0.391313 0.552395 0.417187 0.606373" mass="0.0588507"
|
| 350 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 351 |
+
<joint name="left_hand_middle_0_joint" pos="0 0 0" axis="0 0 1"
|
| 352 |
+
range="-1.5708 0" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 353 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 354 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_middle_0_link" />
|
| 355 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_middle_0_link" />
|
| 356 |
+
<body name="left_hand_middle_1_link" pos="0.0458 0 0">
|
| 357 |
+
<inertial pos="0.0262819 0.00171735 -0.000107789"
|
| 358 |
+
quat="0.502612 0.491799 0.502639 0.502861" mass="0.0203063"
|
| 359 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 360 |
+
<joint name="left_hand_middle_1_joint" pos="0 0 0" axis="0 0 1"
|
| 361 |
+
range="-1.74533 0" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 362 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 363 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_middle_1_link" />
|
| 364 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_middle_1_link" />
|
| 365 |
+
</body>
|
| 366 |
+
</body>
|
| 367 |
+
<body name="left_hand_index_0_link" pos="0.1192 0.0046 0.0285">
|
| 368 |
+
<inertial pos="0.0354744 0.000827888 0.0003809"
|
| 369 |
+
quat="0.391313 0.552395 0.417187 0.606373" mass="0.0588507"
|
| 370 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 371 |
+
<joint name="left_hand_index_0_joint" pos="0 0 0" axis="0 0 1"
|
| 372 |
+
range="-1.5708 0" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 373 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 374 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_index_0_link" />
|
| 375 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_index_0_link" />
|
| 376 |
+
<body name="left_hand_index_1_link" pos="0.0458 0 0">
|
| 377 |
+
<inertial pos="0.0262819 0.00171735 -0.000107789"
|
| 378 |
+
quat="0.502612 0.491799 0.502639 0.502861" mass="0.0203063"
|
| 379 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 380 |
+
<joint name="left_hand_index_1_joint" pos="0 0 0" axis="0 0 1"
|
| 381 |
+
range="-1.74533 0" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 382 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 383 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_index_1_link" />
|
| 384 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_index_1_link" />
|
| 385 |
+
</body>
|
| 386 |
+
</body>
|
| 387 |
+
</body>
|
| 388 |
+
</body>
|
| 389 |
+
</body>
|
| 390 |
+
</body>
|
| 391 |
+
</body>
|
| 392 |
+
</body>
|
| 393 |
+
</body>
|
| 394 |
+
<body name="right_shoulder_pitch_link" pos="0.0039563 -0.10021 0.23778"
|
| 395 |
+
quat="0.990264 -0.139201 1.38722e-05 9.86868e-05">
|
| 396 |
+
<inertial pos="0 -0.035892 -0.011628" quat="0.68225 -0.326267 0.0130458 0.654152"
|
| 397 |
+
mass="0.718" diaginertia="0.000465864 0.000432842 0.000406394" />
|
| 398 |
+
<joint name="right_shoulder_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 399 |
+
range="-3.0892 2.6704" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 400 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 401 |
+
rgba="0.7 0.7 0.7 1" mesh="right_shoulder_pitch_link" />
|
| 402 |
+
<geom size="0.03 0.025" pos="0 -0.04 -0.01" quat="0.707107 0 0.707107 0"
|
| 403 |
+
type="cylinder" rgba="0.7 0.7 0.7 1" />
|
| 404 |
+
<body name="right_shoulder_roll_link" pos="0 -0.038 -0.013831"
|
| 405 |
+
quat="0.990268 0.139172 0 0">
|
| 406 |
+
<inertial pos="-0.000227 -0.00727 -0.063243"
|
| 407 |
+
quat="0.712604 -0.00710317 -0.0196223 0.701256" mass="0.643"
|
| 408 |
+
diaginertia="0.000691311 0.000618011 0.000388977" />
|
| 409 |
+
<joint name="right_shoulder_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 410 |
+
range="-2.2515 1.5882" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 411 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 412 |
+
rgba="0.7 0.7 0.7 1" mesh="right_shoulder_roll_link" />
|
| 413 |
+
<geom size="0.03 0.015" pos="-0.004 -0.006 -0.053" type="cylinder"
|
| 414 |
+
rgba="0.7 0.7 0.7 1" />
|
| 415 |
+
<body name="right_shoulder_yaw_link" pos="0 -0.00624 -0.1032">
|
| 416 |
+
<inertial pos="0.010773 0.002949 -0.072009"
|
| 417 |
+
quat="0.687134 -0.0679942 -0.0964829 0.716879" mass="0.734"
|
| 418 |
+
diaginertia="0.00106187 0.00103217 0.000400661" />
|
| 419 |
+
<joint name="right_shoulder_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 420 |
+
range="-2.618 2.618" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 421 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 422 |
+
rgba="0.7 0.7 0.7 1" mesh="right_shoulder_yaw_link" />
|
| 423 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_shoulder_yaw_link" />
|
| 424 |
+
<body name="right_elbow_link" pos="0.015783 0 -0.080518">
|
| 425 |
+
<inertial pos="0.064956 -0.004454 -0.010062"
|
| 426 |
+
quat="0.388129 0.388821 0.636132 0.541765" mass="0.6"
|
| 427 |
+
diaginertia="0.000443035 0.000421612 0.000259353" />
|
| 428 |
+
<joint name="right_elbow_joint" pos="0 0 0" axis="0 1 0" range="-1.0472 2.0944"
|
| 429 |
+
actuatorfrcrange="-25 25" class="arm_motor" />
|
| 430 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 431 |
+
rgba="0.7 0.7 0.7 1" mesh="right_elbow_link" />
|
| 432 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_elbow_link" />
|
| 433 |
+
<body name="right_wrist_roll_link" pos="0.1 -0.00188791 -0.01">
|
| 434 |
+
<inertial pos="0.0171394 -0.000537591 4.8864e-07"
|
| 435 |
+
quat="0.411667 0.575338 -0.411094 0.574906" mass="0.085445"
|
| 436 |
+
diaginertia="5.48211e-05 4.96646e-05 3.57798e-05" />
|
| 437 |
+
<joint name="right_wrist_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 438 |
+
range="-1.97222 1.97222" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 439 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 440 |
+
rgba="0.7 0.7 0.7 1" mesh="right_wrist_roll_link" />
|
| 441 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_wrist_roll_link" />
|
| 442 |
+
<body name="right_wrist_pitch_link" pos="0.038 0 0">
|
| 443 |
+
<inertial pos="0.0229999 0.00111685 -0.00111658"
|
| 444 |
+
quat="0.643608 0.293036 0.661363 0.249998" mass="0.48405"
|
| 445 |
+
diaginertia="0.000430353 0.000429873 0.000164648" />
|
| 446 |
+
<joint name="right_wrist_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 447 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 448 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 449 |
+
rgba="0.7 0.7 0.7 1" mesh="right_wrist_pitch_link" />
|
| 450 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_wrist_pitch_link" />
|
| 451 |
+
<body name="right_wrist_yaw_link" pos="0.046 0 0">
|
| 452 |
+
<inertial pos="0.0885506 -0.00212216 0.000573742"
|
| 453 |
+
quat="0.507224 0.511377 0.494292 0.486717" mass="0.457415"
|
| 454 |
+
diaginertia="0.0010598 0.000895373 0.0003238" />
|
| 455 |
+
<joint name="right_wrist_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 456 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 457 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 458 |
+
rgba="0.7 0.7 0.7 1" mesh="right_wrist_yaw_link" />
|
| 459 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_wrist_yaw_link" />
|
| 460 |
+
<geom pos="0.0415 -0.003 0" quat="1 0 0 0" type="mesh" contype="0"
|
| 461 |
+
conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 462 |
+
mesh="right_hand_palm_link" />
|
| 463 |
+
<geom pos="0.0415 -0.003 0" quat="1 0 0 0" type="mesh"
|
| 464 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_palm_link" />
|
| 465 |
+
<body name="right_hand_thumb_0_link" pos="0.067 -0.003 0">
|
| 466 |
+
<inertial pos="-0.000884246 0.00863407 0.000944293"
|
| 467 |
+
quat="0.643965 0.462991 -0.398986 0.460173" mass="0.0862366"
|
| 468 |
+
diaginertia="1.6546e-05 1.60058e-05 1.43741e-05" />
|
| 469 |
+
<joint name="right_hand_thumb_0_joint" pos="0 0 0" axis="0 1 0"
|
| 470 |
+
range="-1.0472 1.0472" actuatorfrcrange="-2.45 2.45"
|
| 471 |
+
class="finger_motor" />
|
| 472 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 473 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_thumb_0_link" />
|
| 474 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hand_thumb_0_link" />
|
| 475 |
+
<body name="right_hand_thumb_1_link" pos="-0.0025 0.0193 0">
|
| 476 |
+
<inertial pos="-0.000827888 0.0354744 -0.0003809"
|
| 477 |
+
quat="0.705471 0.685598 -0.0956069 0.15207" mass="0.0588507"
|
| 478 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 479 |
+
<joint name="right_hand_thumb_1_joint" pos="0 0 0" axis="0 0 1"
|
| 480 |
+
range="-1.0472 0.724312" actuatorfrcrange="-1.4 1.4"
|
| 481 |
+
class="finger_motor" />
|
| 482 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 483 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_thumb_1_link" />
|
| 484 |
+
<geom size="0.01 0.015 0.01" pos="-0.001 0.032 0" type="box"
|
| 485 |
+
rgba="0.7 0.7 0.7 1" />
|
| 486 |
+
<body name="right_hand_thumb_2_link" pos="0 0.0458 0">
|
| 487 |
+
<inertial pos="-0.00171735 0.0262819 0.000107789"
|
| 488 |
+
quat="0.710977 0.703174 0.00766553 0.00017564" mass="0.0203063"
|
| 489 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 490 |
+
<joint name="right_hand_thumb_2_joint" pos="0 0 0" axis="0 0 1"
|
| 491 |
+
range="-1.74533 0" actuatorfrcrange="-1.4 1.4"
|
| 492 |
+
class="finger_motor" />
|
| 493 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 494 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_thumb_2_link" />
|
| 495 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1"
|
| 496 |
+
mesh="right_hand_thumb_2_link" />
|
| 497 |
+
</body>
|
| 498 |
+
</body>
|
| 499 |
+
</body>
|
| 500 |
+
<body name="right_hand_middle_0_link" pos="0.1192 -0.0046 -0.0285">
|
| 501 |
+
<inertial pos="0.0354744 -0.000827888 0.0003809"
|
| 502 |
+
quat="0.606373 0.417187 0.552395 0.391313" mass="0.0588507"
|
| 503 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 504 |
+
<joint name="right_hand_middle_0_joint" pos="0 0 0" axis="0 0 1"
|
| 505 |
+
range="0 1.5708" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 506 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 507 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_middle_0_link" />
|
| 508 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hand_middle_0_link" />
|
| 509 |
+
<body name="right_hand_middle_1_link" pos="0.0458 0 0">
|
| 510 |
+
<inertial pos="0.0262819 -0.00171735 -0.000107789"
|
| 511 |
+
quat="0.502861 0.502639 0.491799 0.502612" mass="0.0203063"
|
| 512 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 513 |
+
<joint name="right_hand_middle_1_joint" pos="0 0 0" axis="0 0 1"
|
| 514 |
+
range="0 1.74533" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 515 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 516 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_middle_1_link" />
|
| 517 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hand_middle_1_link" />
|
| 518 |
+
</body>
|
| 519 |
+
</body>
|
| 520 |
+
<body name="right_hand_index_0_link" pos="0.1192 -0.0046 0.0285">
|
| 521 |
+
<inertial pos="0.0354744 -0.000827888 0.0003809"
|
| 522 |
+
quat="0.606373 0.417187 0.552395 0.391313" mass="0.0588507"
|
| 523 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 524 |
+
<joint name="right_hand_index_0_joint" pos="0 0 0" axis="0 0 1"
|
| 525 |
+
range="0 1.5708" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 526 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 527 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_index_0_link" />
|
| 528 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hand_index_0_link" />
|
| 529 |
+
<body name="right_hand_index_1_link" pos="0.0458 0 0">
|
| 530 |
+
<inertial pos="0.0262819 -0.00171735 -0.000107789"
|
| 531 |
+
quat="0.502861 0.502639 0.491799 0.502612" mass="0.0203063"
|
| 532 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 533 |
+
<joint name="right_hand_index_1_joint" pos="0 0 0" axis="0 0 1"
|
| 534 |
+
range="0 1.74533" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 535 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 536 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_index_1_link" />
|
| 537 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hand_index_1_link" />
|
| 538 |
+
</body>
|
| 539 |
+
</body>
|
| 540 |
+
</body>
|
| 541 |
+
</body>
|
| 542 |
+
</body>
|
| 543 |
+
</body>
|
| 544 |
+
</body>
|
| 545 |
+
</body>
|
| 546 |
+
</body>
|
| 547 |
+
</body>
|
| 548 |
+
</body>
|
| 549 |
+
</body>
|
| 550 |
+
</body>
|
| 551 |
+
</worldbody>
|
| 552 |
+
|
| 553 |
+
<actuator>
|
| 554 |
+
<motor name="left_hip_pitch" joint="left_hip_pitch_joint" ctrlrange="-88 88" />
|
| 555 |
+
<motor name="left_hip_roll" joint="left_hip_roll_joint" ctrlrange="-88 88" />
|
| 556 |
+
<motor name="left_hip_yaw" joint="left_hip_yaw_joint" ctrlrange="-88 88" />
|
| 557 |
+
<motor name="left_knee" joint="left_knee_joint" ctrlrange="-139 139" />
|
| 558 |
+
<motor name="left_ankle_pitch" joint="left_ankle_pitch_joint" ctrlrange="-50 50" />
|
| 559 |
+
<motor name="left_ankle_roll" joint="left_ankle_roll_joint" ctrlrange="-50 50" />
|
| 560 |
+
|
| 561 |
+
<motor name="right_hip_pitch" joint="right_hip_pitch_joint" ctrlrange="-88 88" />
|
| 562 |
+
<motor name="right_hip_roll" joint="right_hip_roll_joint" ctrlrange="-88 88" />
|
| 563 |
+
<motor name="right_hip_yaw" joint="right_hip_yaw_joint" ctrlrange="-88 88" />
|
| 564 |
+
<motor name="right_knee" joint="right_knee_joint" ctrlrange="-139 139" />
|
| 565 |
+
<motor name="right_ankle_pitch" joint="right_ankle_pitch_joint" ctrlrange="-50 50" />
|
| 566 |
+
<motor name="right_ankle_roll" joint="right_ankle_roll_joint" ctrlrange="-50 50" />
|
| 567 |
+
|
| 568 |
+
<motor name="waist_yaw" joint="waist_yaw_joint" ctrlrange="-88 88" />
|
| 569 |
+
<motor name="waist_roll" joint="waist_roll_joint" ctrlrange="-50 50" />
|
| 570 |
+
<motor name="waist_pitch" joint="waist_pitch_joint" ctrlrange="-50 50" />
|
| 571 |
+
|
| 572 |
+
<motor name="left_shoulder_pitch" joint="left_shoulder_pitch_joint" ctrlrange="-25 25" />
|
| 573 |
+
<motor name="left_shoulder_roll" joint="left_shoulder_roll_joint" ctrlrange="-25 25" />
|
| 574 |
+
<motor name="left_shoulder_yaw" joint="left_shoulder_yaw_joint" ctrlrange="-25 25" />
|
| 575 |
+
<motor name="left_elbow" joint="left_elbow_joint" ctrlrange="-25 25" />
|
| 576 |
+
<motor name="left_wrist_roll" joint="left_wrist_roll_joint" ctrlrange="-25 25" />
|
| 577 |
+
<motor name="left_wrist_pitch" joint="left_wrist_pitch_joint" ctrlrange="-5 5" />
|
| 578 |
+
<motor name="left_wrist_yaw" joint="left_wrist_yaw_joint" ctrlrange="-5 5" />
|
| 579 |
+
|
| 580 |
+
<motor name="left_hand_thumb_0" joint="left_hand_thumb_0_joint" ctrlrange="-2.45 2.45" />
|
| 581 |
+
<motor name="left_hand_thumb_1" joint="left_hand_thumb_1_joint" ctrlrange="-1.4 1.4" />
|
| 582 |
+
<motor name="left_hand_thumb_2" joint="left_hand_thumb_2_joint" ctrlrange="-1.4 1.4" />
|
| 583 |
+
<motor name="left_hand_middle_0" joint="left_hand_middle_0_joint" ctrlrange="-1.4 1.4" />
|
| 584 |
+
<motor name="left_hand_middle_1" joint="left_hand_middle_1_joint" ctrlrange="-1.4 1.4" />
|
| 585 |
+
<motor name="left_hand_index_0" joint="left_hand_index_0_joint" ctrlrange="-1.4 1.4" />
|
| 586 |
+
<motor name="left_hand_index_1" joint="left_hand_index_1_joint" ctrlrange="-1.4 1.4" />
|
| 587 |
+
|
| 588 |
+
<motor name="right_shoulder_pitch" joint="right_shoulder_pitch_joint" ctrlrange="-25 25" />
|
| 589 |
+
<motor name="right_shoulder_roll" joint="right_shoulder_roll_joint" ctrlrange="-25 25" />
|
| 590 |
+
<motor name="right_shoulder_yaw" joint="right_shoulder_yaw_joint" ctrlrange="-25 25" />
|
| 591 |
+
<motor name="right_elbow" joint="right_elbow_joint" ctrlrange="-25 25" />
|
| 592 |
+
<motor name="right_wrist_roll" joint="right_wrist_roll_joint" ctrlrange="-25 25" />
|
| 593 |
+
<motor name="right_wrist_pitch" joint="right_wrist_pitch_joint" ctrlrange="-5 5" />
|
| 594 |
+
<motor name="right_wrist_yaw" joint="right_wrist_yaw_joint" ctrlrange="-5 5" />
|
| 595 |
+
|
| 596 |
+
<motor name="right_hand_thumb_0" joint="right_hand_thumb_0_joint" ctrlrange="-2.45 2.45" />
|
| 597 |
+
<motor name="right_hand_thumb_1" joint="right_hand_thumb_1_joint" ctrlrange="-1.4 1.4" />
|
| 598 |
+
<motor name="right_hand_thumb_2" joint="right_hand_thumb_2_joint" ctrlrange="-1.4 1.4" />
|
| 599 |
+
<motor name="right_hand_middle_0" joint="right_hand_middle_0_joint" ctrlrange="-1.4 1.4" />
|
| 600 |
+
<motor name="right_hand_middle_1" joint="right_hand_middle_1_joint" ctrlrange="-1.4 1.4" />
|
| 601 |
+
<motor name="right_hand_index_0" joint="right_hand_index_0_joint" ctrlrange="-1.4 1.4" />
|
| 602 |
+
<motor name="right_hand_index_1" joint="right_hand_index_1_joint" ctrlrange="-1.4 1.4" />
|
| 603 |
+
</actuator>
|
| 604 |
+
|
| 605 |
+
<sensor>
|
| 606 |
+
<jointpos name="left_hip_pitch_pos" joint="left_hip_pitch_joint" />
|
| 607 |
+
<jointpos name="left_hip_roll_pos" joint="left_hip_roll_joint" />
|
| 608 |
+
<jointpos name="left_hip_yaw_pos" joint="left_hip_yaw_joint" />
|
| 609 |
+
<jointpos name="left_knee_pos" joint="left_knee_joint" />
|
| 610 |
+
<jointpos name="left_ankle_pitch_pos" joint="left_ankle_pitch_joint" />
|
| 611 |
+
<jointpos name="left_ankle_roll_pos" joint="left_ankle_roll_joint" />
|
| 612 |
+
<jointpos name="right_hip_pitch_pos" joint="right_hip_pitch_joint" />
|
| 613 |
+
<jointpos name="right_hip_roll_pos" joint="right_hip_roll_joint" />
|
| 614 |
+
<jointpos name="right_hip_yaw_pos" joint="right_hip_yaw_joint" />
|
| 615 |
+
<jointpos name="right_knee_pos" joint="right_knee_joint" />
|
| 616 |
+
<jointpos name="right_ankle_pitch_pos" joint="right_ankle_pitch_joint" />
|
| 617 |
+
<jointpos name="right_ankle_roll_pos" joint="right_ankle_roll_joint" />
|
| 618 |
+
<jointpos name="waist_yaw_pos" joint="waist_yaw_joint" />
|
| 619 |
+
<jointpos name="waist_roll_pos" joint="waist_roll_joint" />
|
| 620 |
+
<jointpos name="waist_pitch_pos" joint="waist_pitch_joint" />
|
| 621 |
+
<jointpos name="left_shoulder_pitch_pos" joint="left_shoulder_pitch_joint" />
|
| 622 |
+
<jointpos name="left_shoulder_roll_pos" joint="left_shoulder_roll_joint" />
|
| 623 |
+
<jointpos name="left_shoulder_yaw_pos" joint="left_shoulder_yaw_joint" />
|
| 624 |
+
<jointpos name="left_elbow_pos" joint="left_elbow_joint" />
|
| 625 |
+
<jointpos name="left_wrist_roll_pos" joint="left_wrist_roll_joint" />
|
| 626 |
+
<jointpos name="left_wrist_pitch_pos" joint="left_wrist_pitch_joint" />
|
| 627 |
+
<jointpos name="left_wrist_yaw_pos" joint="left_wrist_yaw_joint" />
|
| 628 |
+
<jointpos name="right_shoulder_pitch_pos" joint="right_shoulder_pitch_joint" />
|
| 629 |
+
<jointpos name="right_shoulder_roll_pos" joint="right_shoulder_roll_joint" />
|
| 630 |
+
<jointpos name="right_shoulder_yaw_pos" joint="right_shoulder_yaw_joint" />
|
| 631 |
+
<jointpos name="right_elbow_pos" joint="right_elbow_joint" />
|
| 632 |
+
<jointpos name="right_wrist_roll_pos" joint="right_wrist_roll_joint" />
|
| 633 |
+
<jointpos name="right_wrist_pitch_pos" joint="right_wrist_pitch_joint" />
|
| 634 |
+
<jointpos name="right_wrist_yaw_pos" joint="right_wrist_yaw_joint" />
|
| 635 |
+
|
| 636 |
+
<jointpos name="left_hand_thumb_0_pos" joint="left_hand_thumb_0_joint" />
|
| 637 |
+
<jointpos name="left_hand_thumb_1_pos" joint="left_hand_thumb_1_joint" />
|
| 638 |
+
<jointpos name="left_hand_thumb_2_pos" joint="left_hand_thumb_2_joint" />
|
| 639 |
+
<jointpos name="left_hand_middle_0_pos" joint="left_hand_middle_0_joint" />
|
| 640 |
+
<jointpos name="left_hand_middle_1_pos" joint="left_hand_middle_1_joint" />
|
| 641 |
+
<jointpos name="left_hand_index_0_pos" joint="left_hand_index_0_joint" />
|
| 642 |
+
<jointpos name="left_hand_index_1_pos" joint="left_hand_index_1_joint" />
|
| 643 |
+
<jointpos name="right_hand_thumb_0_pos" joint="right_hand_thumb_0_joint" />
|
| 644 |
+
<jointpos name="right_hand_thumb_1_pos" joint="right_hand_thumb_1_joint" />
|
| 645 |
+
<jointpos name="right_hand_thumb_2_pos" joint="right_hand_thumb_2_joint" />
|
| 646 |
+
<jointpos name="right_hand_middle_0_pos" joint="right_hand_middle_0_joint" />
|
| 647 |
+
<jointpos name="right_hand_middle_1_pos" joint="right_hand_middle_1_joint" />
|
| 648 |
+
<jointpos name="right_hand_index_0_pos" joint="right_hand_index_0_joint" />
|
| 649 |
+
<jointpos name="right_hand_index_1_pos" joint="right_hand_index_1_joint" />
|
| 650 |
+
|
| 651 |
+
<jointvel name="left_hip_pitch_vel" joint="left_hip_pitch_joint" />
|
| 652 |
+
<jointvel name="left_hip_roll_vel" joint="left_hip_roll_joint" />
|
| 653 |
+
<jointvel name="left_hip_yaw_vel" joint="left_hip_yaw_joint" />
|
| 654 |
+
<jointvel name="left_knee_vel" joint="left_knee_joint" />
|
| 655 |
+
<jointvel name="left_ankle_pitch_vel" joint="left_ankle_pitch_joint" />
|
| 656 |
+
<jointvel name="left_ankle_roll_vel" joint="left_ankle_roll_joint" />
|
| 657 |
+
<jointvel name="right_hip_pitch_vel" joint="right_hip_pitch_joint" />
|
| 658 |
+
<jointvel name="right_hip_roll_vel" joint="right_hip_roll_joint" />
|
| 659 |
+
<jointvel name="right_hip_yaw_vel" joint="right_hip_yaw_joint" />
|
| 660 |
+
<jointvel name="right_knee_vel" joint="right_knee_joint" />
|
| 661 |
+
<jointvel name="right_ankle_pitch_vel" joint="right_ankle_pitch_joint" />
|
| 662 |
+
<jointvel name="right_ankle_roll_vel" joint="right_ankle_roll_joint" />
|
| 663 |
+
<jointvel name="waist_yaw_vel" joint="waist_yaw_joint" />
|
| 664 |
+
<jointvel name="waist_roll_vel" joint="waist_roll_joint" />
|
| 665 |
+
<jointvel name="waist_pitch_vel" joint="waist_pitch_joint" />
|
| 666 |
+
<jointvel name="left_shoulder_pitch_vel" joint="left_shoulder_pitch_joint" />
|
| 667 |
+
<jointvel name="left_shoulder_roll_vel" joint="left_shoulder_roll_joint" />
|
| 668 |
+
<jointvel name="left_shoulder_yaw_vel" joint="left_shoulder_yaw_joint" />
|
| 669 |
+
<jointvel name="left_elbow_vel" joint="left_elbow_joint" />
|
| 670 |
+
<jointvel name="left_wrist_roll_vel" joint="left_wrist_roll_joint" />
|
| 671 |
+
<jointvel name="left_wrist_pitch_vel" joint="left_wrist_pitch_joint" />
|
| 672 |
+
<jointvel name="left_wrist_yaw_vel" joint="left_wrist_yaw_joint" />
|
| 673 |
+
<jointvel name="right_shoulder_pitch_vel" joint="right_shoulder_pitch_joint" />
|
| 674 |
+
<jointvel name="right_shoulder_roll_vel" joint="right_shoulder_roll_joint" />
|
| 675 |
+
<jointvel name="right_shoulder_yaw_vel" joint="right_shoulder_yaw_joint" />
|
| 676 |
+
<jointvel name="right_elbow_vel" joint="right_elbow_joint" />
|
| 677 |
+
<jointvel name="right_wrist_roll_vel" joint="right_wrist_roll_joint" />
|
| 678 |
+
<jointvel name="right_wrist_pitch_vel" joint="right_wrist_pitch_joint" />
|
| 679 |
+
<jointvel name="right_wrist_yaw_vel" joint="right_wrist_yaw_joint" />
|
| 680 |
+
|
| 681 |
+
<jointvel name="left_hand_thumb_0_vel" joint="left_hand_thumb_0_joint" />
|
| 682 |
+
<jointvel name="left_hand_thumb_1_vel" joint="left_hand_thumb_1_joint" />
|
| 683 |
+
<jointvel name="left_hand_thumb_2_vel" joint="left_hand_thumb_2_joint" />
|
| 684 |
+
<jointvel name="left_hand_middle_0_vel" joint="left_hand_middle_0_joint" />
|
| 685 |
+
<jointvel name="left_hand_middle_1_vel" joint="left_hand_middle_1_joint" />
|
| 686 |
+
<jointvel name="left_hand_index_0_vel" joint="left_hand_index_0_joint" />
|
| 687 |
+
<jointvel name="left_hand_index_1_vel" joint="left_hand_index_1_joint" />
|
| 688 |
+
<jointvel name="right_hand_thumb_0_vel" joint="right_hand_thumb_0_joint" />
|
| 689 |
+
<jointvel name="right_hand_thumb_1_vel" joint="right_hand_thumb_1_joint" />
|
| 690 |
+
<jointvel name="right_hand_thumb_2_vel" joint="right_hand_thumb_2_joint" />
|
| 691 |
+
<jointvel name="right_hand_middle_0_vel" joint="right_hand_middle_0_joint" />
|
| 692 |
+
<jointvel name="right_hand_middle_1_vel" joint="right_hand_middle_1_joint" />
|
| 693 |
+
<jointvel name="right_hand_index_0_vel" joint="right_hand_index_0_joint" />
|
| 694 |
+
<jointvel name="right_hand_index_1_vel" joint="right_hand_index_1_joint" />
|
| 695 |
+
|
| 696 |
+
<jointactuatorfrc name="left_hip_pitch_torque" joint="left_hip_pitch_joint" />
|
| 697 |
+
<jointactuatorfrc name="left_hip_roll_torque" joint="left_hip_roll_joint" />
|
| 698 |
+
<jointactuatorfrc name="left_hip_yaw_torque" joint="left_hip_yaw_joint" />
|
| 699 |
+
<jointactuatorfrc name="left_knee_torque" joint="left_knee_joint" />
|
| 700 |
+
<jointactuatorfrc name="left_ankle_pitch_torque" joint="left_ankle_pitch_joint" />
|
| 701 |
+
<jointactuatorfrc name="left_ankle_roll_torque" joint="left_ankle_roll_joint" />
|
| 702 |
+
<jointactuatorfrc name="right_hip_pitch_torque" joint="right_hip_pitch_joint" />
|
| 703 |
+
<jointactuatorfrc name="right_hip_roll_torque" joint="right_hip_roll_joint" />
|
| 704 |
+
<jointactuatorfrc name="right_hip_yaw_torque" joint="right_hip_yaw_joint" />
|
| 705 |
+
<jointactuatorfrc name="right_knee_torque" joint="right_knee_joint" />
|
| 706 |
+
<jointactuatorfrc name="right_ankle_pitch_torque" joint="right_ankle_pitch_joint" />
|
| 707 |
+
<jointactuatorfrc name="right_ankle_roll_torque" joint="right_ankle_roll_joint" />
|
| 708 |
+
<jointactuatorfrc name="waist_yaw_torque" joint="waist_yaw_joint" />
|
| 709 |
+
<jointactuatorfrc name="waist_roll_torque" joint="waist_roll_joint" />
|
| 710 |
+
<jointactuatorfrc name="waist_pitch_torque" joint="waist_pitch_joint" />
|
| 711 |
+
<jointactuatorfrc name="left_shoulder_pitch_torque" joint="left_shoulder_pitch_joint" />
|
| 712 |
+
<jointactuatorfrc name="left_shoulder_roll_torque" joint="left_shoulder_roll_joint" />
|
| 713 |
+
<jointactuatorfrc name="left_shoulder_yaw_torque" joint="left_shoulder_yaw_joint" />
|
| 714 |
+
<jointactuatorfrc name="left_elbow_torque" joint="left_elbow_joint" />
|
| 715 |
+
<jointactuatorfrc name="left_wrist_roll_torque" joint="left_wrist_roll_joint" />
|
| 716 |
+
<jointactuatorfrc name="left_wrist_pitch_torque" joint="left_wrist_pitch_joint" />
|
| 717 |
+
<jointactuatorfrc name="left_wrist_yaw_torque" joint="left_wrist_yaw_joint" />
|
| 718 |
+
<jointactuatorfrc name="right_shoulder_pitch_torque" joint="right_shoulder_pitch_joint" />
|
| 719 |
+
<jointactuatorfrc name="right_shoulder_roll_torque" joint="right_shoulder_roll_joint" />
|
| 720 |
+
<jointactuatorfrc name="right_shoulder_yaw_torque" joint="right_shoulder_yaw_joint" />
|
| 721 |
+
<jointactuatorfrc name="right_elbow_torque" joint="right_elbow_joint" />
|
| 722 |
+
<jointactuatorfrc name="right_wrist_roll_torque" joint="right_wrist_roll_joint" />
|
| 723 |
+
<jointactuatorfrc name="right_wrist_pitch_torque" joint="right_wrist_pitch_joint" />
|
| 724 |
+
<jointactuatorfrc name="right_wrist_yaw_torque" joint="right_wrist_yaw_joint" />
|
| 725 |
+
|
| 726 |
+
<jointactuatorfrc name="left_hand_thumb_0_torque" joint="left_hand_thumb_0_joint" />
|
| 727 |
+
<jointactuatorfrc name="left_hand_thumb_1_torque" joint="left_hand_thumb_1_joint" />
|
| 728 |
+
<jointactuatorfrc name="left_hand_thumb_2_torque" joint="left_hand_thumb_2_joint" />
|
| 729 |
+
<jointactuatorfrc name="left_hand_middle_0_torque" joint="left_hand_middle_0_joint" />
|
| 730 |
+
<jointactuatorfrc name="left_hand_middle_1_torque" joint="left_hand_middle_1_joint" />
|
| 731 |
+
<jointactuatorfrc name="left_hand_index_0_torque" joint="left_hand_index_0_joint" />
|
| 732 |
+
<jointactuatorfrc name="left_hand_index_1_torque" joint="left_hand_index_1_joint" />
|
| 733 |
+
<jointactuatorfrc name="right_hand_thumb_0_torque" joint="right_hand_thumb_0_joint" />
|
| 734 |
+
<jointactuatorfrc name="right_hand_thumb_1_torque" joint="right_hand_thumb_1_joint" />
|
| 735 |
+
<jointactuatorfrc name="right_hand_thumb_2_torque" joint="right_hand_thumb_2_joint" />
|
| 736 |
+
<jointactuatorfrc name="right_hand_middle_0_torque" joint="right_hand_middle_0_joint" />
|
| 737 |
+
<jointactuatorfrc name="right_hand_middle_1_torque" joint="right_hand_middle_1_joint" />
|
| 738 |
+
<jointactuatorfrc name="right_hand_index_0_torque" joint="right_hand_index_0_joint" />
|
| 739 |
+
<jointactuatorfrc name="right_hand_index_1_torque" joint="right_hand_index_1_joint" />
|
| 740 |
+
|
| 741 |
+
<framequat name="imu_quat" objtype="site" objname="imu" />
|
| 742 |
+
<gyro name="imu_gyro" site="imu" />
|
| 743 |
+
<accelerometer name="imu_acc" site="imu" />
|
| 744 |
+
|
| 745 |
+
<framepos name="frame_pos" objtype="site" objname="imu" />
|
| 746 |
+
<framelinvel name="frame_vel" objtype="site" objname="imu" />
|
| 747 |
+
</sensor>
|
| 748 |
+
</mujoco>
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_with_hand_rev_1_0_activatedfinger.xml
ADDED
|
@@ -0,0 +1,669 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<mujoco model="g1_29dof_with_hand_rev_1_0">
|
| 2 |
+
<compiler angle="radian" meshdir="meshes" />
|
| 3 |
+
<default>
|
| 4 |
+
<default class="torso_motor">
|
| 5 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2" />
|
| 6 |
+
</default>
|
| 7 |
+
<default class="leg_motor">
|
| 8 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2" />
|
| 9 |
+
</default>
|
| 10 |
+
<default class="ankle_motor">
|
| 11 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2" />
|
| 12 |
+
</default>
|
| 13 |
+
<default class="arm_motor">
|
| 14 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.2" />
|
| 15 |
+
</default>
|
| 16 |
+
<default class="wrist_motor">
|
| 17 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.1" />
|
| 18 |
+
</default>
|
| 19 |
+
<default class="finger_motor">
|
| 20 |
+
<joint damping="0.05" armature="0.01" frictionloss="0.1" />
|
| 21 |
+
</default>
|
| 22 |
+
|
| 23 |
+
</default>
|
| 24 |
+
|
| 25 |
+
<asset>
|
| 26 |
+
<mesh name="pelvis" file="pelvis.STL" />
|
| 27 |
+
<mesh name="pelvis_contour_link" file="pelvis_contour_link.STL" />
|
| 28 |
+
<mesh name="left_hip_pitch_link" file="left_hip_pitch_link.STL" />
|
| 29 |
+
<mesh name="left_hip_roll_link" file="left_hip_roll_link.STL" />
|
| 30 |
+
<mesh name="left_hip_yaw_link" file="left_hip_yaw_link.STL" />
|
| 31 |
+
<mesh name="left_knee_link" file="left_knee_link.STL" />
|
| 32 |
+
<mesh name="left_ankle_pitch_link" file="left_ankle_pitch_link.STL" />
|
| 33 |
+
<mesh name="left_ankle_roll_link" file="left_ankle_roll_link.STL" />
|
| 34 |
+
<mesh name="right_hip_pitch_link" file="right_hip_pitch_link.STL" />
|
| 35 |
+
<mesh name="right_hip_roll_link" file="right_hip_roll_link.STL" />
|
| 36 |
+
<mesh name="right_hip_yaw_link" file="right_hip_yaw_link.STL" />
|
| 37 |
+
<mesh name="right_knee_link" file="right_knee_link.STL" />
|
| 38 |
+
<mesh name="right_ankle_pitch_link" file="right_ankle_pitch_link.STL" />
|
| 39 |
+
<mesh name="right_ankle_roll_link" file="right_ankle_roll_link.STL" />
|
| 40 |
+
<mesh name="waist_yaw_link" file="waist_yaw_link_rev_1_0.STL" />
|
| 41 |
+
<mesh name="waist_roll_link" file="waist_roll_link_rev_1_0.STL" />
|
| 42 |
+
<mesh name="torso_link" file="torso_link_rev_1_0.STL" />
|
| 43 |
+
<mesh name="logo_link" file="logo_link.STL" />
|
| 44 |
+
<mesh name="head_link" file="head_link.STL" />
|
| 45 |
+
<mesh name="left_shoulder_pitch_link" file="left_shoulder_pitch_link.STL" />
|
| 46 |
+
<mesh name="left_shoulder_roll_link" file="left_shoulder_roll_link.STL" />
|
| 47 |
+
<mesh name="left_shoulder_yaw_link" file="left_shoulder_yaw_link.STL" />
|
| 48 |
+
<mesh name="left_elbow_link" file="left_elbow_link.STL" />
|
| 49 |
+
<mesh name="left_wrist_roll_link" file="left_wrist_roll_link.STL" />
|
| 50 |
+
<mesh name="left_wrist_pitch_link" file="left_wrist_pitch_link.STL" />
|
| 51 |
+
<mesh name="left_wrist_yaw_link" file="left_wrist_yaw_link.STL" />
|
| 52 |
+
<mesh name="left_hand_palm_link" file="left_hand_palm_link.STL" />
|
| 53 |
+
<mesh name="left_hand_thumb_0_link" file="left_hand_thumb_0_link.STL" />
|
| 54 |
+
<mesh name="left_hand_thumb_1_link" file="left_hand_thumb_1_link.STL" />
|
| 55 |
+
<mesh name="left_hand_thumb_2_link" file="left_hand_thumb_2_link.STL" />
|
| 56 |
+
<mesh name="left_hand_middle_0_link" file="left_hand_middle_0_link.STL" />
|
| 57 |
+
<mesh name="left_hand_middle_1_link" file="left_hand_middle_1_link.STL" />
|
| 58 |
+
<mesh name="left_hand_index_0_link" file="left_hand_index_0_link.STL" />
|
| 59 |
+
<mesh name="left_hand_index_1_link" file="left_hand_index_1_link.STL" />
|
| 60 |
+
<mesh name="right_shoulder_pitch_link" file="right_shoulder_pitch_link.STL" />
|
| 61 |
+
<mesh name="right_shoulder_roll_link" file="right_shoulder_roll_link.STL" />
|
| 62 |
+
<mesh name="right_shoulder_yaw_link" file="right_shoulder_yaw_link.STL" />
|
| 63 |
+
<mesh name="right_elbow_link" file="right_elbow_link.STL" />
|
| 64 |
+
<mesh name="right_wrist_roll_link" file="right_wrist_roll_link.STL" />
|
| 65 |
+
<mesh name="right_wrist_pitch_link" file="right_wrist_pitch_link.STL" />
|
| 66 |
+
<mesh name="right_wrist_yaw_link" file="right_wrist_yaw_link.STL" />
|
| 67 |
+
<mesh name="right_hand_palm_link" file="right_hand_palm_link.STL" />
|
| 68 |
+
<mesh name="right_hand_thumb_0_link" file="right_hand_thumb_0_link.STL" />
|
| 69 |
+
<mesh name="right_hand_thumb_1_link" file="right_hand_thumb_1_link.STL" />
|
| 70 |
+
<mesh name="right_hand_thumb_2_link" file="right_hand_thumb_2_link.STL" />
|
| 71 |
+
<mesh name="right_hand_middle_0_link" file="right_hand_middle_0_link.STL" />
|
| 72 |
+
<mesh name="right_hand_middle_1_link" file="right_hand_middle_1_link.STL" />
|
| 73 |
+
<mesh name="right_hand_index_0_link" file="right_hand_index_0_link.STL" />
|
| 74 |
+
<mesh name="right_hand_index_1_link" file="right_hand_index_1_link.STL" />
|
| 75 |
+
</asset>
|
| 76 |
+
|
| 77 |
+
<worldbody>
|
| 78 |
+
<body name="pelvis" pos="0 0 0.793">
|
| 79 |
+
<inertial pos="0 0 -0.07605" quat="1 0 -0.000399148 0" mass="3.813"
|
| 80 |
+
diaginertia="0.010549 0.0093089 0.0079184" />
|
| 81 |
+
<joint name="floating_base_joint" type="free" limited="false" actuatorfrclimited="false" />
|
| 82 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.2 0.2 0.2 1"
|
| 83 |
+
mesh="pelvis" />
|
| 84 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 85 |
+
mesh="pelvis_contour_link" />
|
| 86 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="pelvis_contour_link" />
|
| 87 |
+
<site name="imu_in_pelvis" size="0.01" pos="0.04525 0 -0.08339" />
|
| 88 |
+
<body name="left_hip_pitch_link" pos="0 0.064452 -0.1027">
|
| 89 |
+
<inertial pos="0.002741 0.047791 -0.02606" quat="0.954862 0.293964 0.0302556 0.030122"
|
| 90 |
+
mass="1.35" diaginertia="0.00181517 0.00153422 0.00116212" />
|
| 91 |
+
<joint name="left_hip_pitch_joint" pos="0 0 0" axis="0 1 0" range="-2.5307 2.8798"
|
| 92 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 93 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.2 0.2 0.2 1"
|
| 94 |
+
mesh="left_hip_pitch_link" />
|
| 95 |
+
<geom type="mesh" rgba="0.2 0.2 0.2 1" mesh="left_hip_pitch_link" />
|
| 96 |
+
<body name="left_hip_roll_link" pos="0 0.052 -0.030465" quat="0.996179 0 -0.0873386 0">
|
| 97 |
+
<inertial pos="0.029812 -0.001045 -0.087934"
|
| 98 |
+
quat="0.977808 -1.97119e-05 0.205576 -0.0403793" mass="1.52"
|
| 99 |
+
diaginertia="0.00254986 0.00241169 0.00148755" />
|
| 100 |
+
<joint name="left_hip_roll_joint" pos="0 0 0" axis="1 0 0" range="-0.5236 2.9671"
|
| 101 |
+
actuatorfrcrange="-139 139" class="leg_motor" />
|
| 102 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 103 |
+
mesh="left_hip_roll_link" />
|
| 104 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hip_roll_link" />
|
| 105 |
+
<body name="left_hip_yaw_link" pos="0.025001 0 -0.12412">
|
| 106 |
+
<inertial pos="-0.057709 -0.010981 -0.15078" quat="0.600598 0.15832 0.223482 0.751181"
|
| 107 |
+
mass="1.702" diaginertia="0.00776166 0.00717575 0.00160139" />
|
| 108 |
+
<joint name="left_hip_yaw_joint" pos="0 0 0" axis="0 0 1" range="-2.7576 2.7576"
|
| 109 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 110 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 111 |
+
mesh="left_hip_yaw_link" />
|
| 112 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hip_yaw_link" />
|
| 113 |
+
<body name="left_knee_link" pos="-0.078273 0.0021489 -0.17734"
|
| 114 |
+
quat="0.996179 0 0.0873386 0">
|
| 115 |
+
<inertial pos="0.005457 0.003964 -0.12074"
|
| 116 |
+
quat="0.923418 -0.0327699 0.0158246 0.382067" mass="1.932"
|
| 117 |
+
diaginertia="0.0113804 0.0112778 0.00146458" />
|
| 118 |
+
<joint name="left_knee_joint" pos="0 0 0" axis="0 1 0" range="-0.087267 2.8798"
|
| 119 |
+
actuatorfrcrange="-139 139" class="leg_motor" />
|
| 120 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 121 |
+
rgba="0.7 0.7 0.7 1" mesh="left_knee_link" />
|
| 122 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_knee_link" />
|
| 123 |
+
<body name="left_ankle_pitch_link" pos="0 -9.4445e-05 -0.30001">
|
| 124 |
+
<inertial pos="-0.007269 0 0.011137" quat="0.603053 0.369225 0.369225 0.603053"
|
| 125 |
+
mass="0.074" diaginertia="1.89e-05 1.40805e-05 6.9195e-06" />
|
| 126 |
+
<joint name="left_ankle_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 127 |
+
range="-0.87267 0.5236" actuatorfrcrange="-50 50" class="ankle_motor" />
|
| 128 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 129 |
+
rgba="0.7 0.7 0.7 1" mesh="left_ankle_pitch_link" />
|
| 130 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_ankle_pitch_link" />
|
| 131 |
+
<body name="left_ankle_roll_link" pos="0 0 -0.017558">
|
| 132 |
+
<inertial pos="0.026505 0 -0.016425"
|
| 133 |
+
quat="-0.000481092 0.728482 -0.000618967 0.685065" mass="0.608"
|
| 134 |
+
diaginertia="0.00167218 0.0016161 0.000217621" />
|
| 135 |
+
<joint name="left_ankle_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 136 |
+
range="-0.2618 0.2618" actuatorfrcrange="-50 50" class="ankle_motor" />
|
| 137 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 138 |
+
rgba="0.2 0.2 0.2 1" mesh="left_ankle_roll_link" />
|
| 139 |
+
<geom size="0.005" pos="-0.05 0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 140 |
+
<geom size="0.005" pos="-0.05 -0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 141 |
+
<geom size="0.005" pos="0.12 0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 142 |
+
<geom size="0.005" pos="0.12 -0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 143 |
+
</body>
|
| 144 |
+
</body>
|
| 145 |
+
</body>
|
| 146 |
+
</body>
|
| 147 |
+
</body>
|
| 148 |
+
</body>
|
| 149 |
+
<body name="right_hip_pitch_link" pos="0 -0.064452 -0.1027">
|
| 150 |
+
<inertial pos="0.002741 -0.047791 -0.02606" quat="0.954862 -0.293964 0.0302556 -0.030122"
|
| 151 |
+
mass="1.35" diaginertia="0.00181517 0.00153422 0.00116212" />
|
| 152 |
+
<joint name="right_hip_pitch_joint" pos="0 0 0" axis="0 1 0" range="-2.5307 2.8798"
|
| 153 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 154 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.2 0.2 0.2 1"
|
| 155 |
+
mesh="right_hip_pitch_link" />
|
| 156 |
+
<geom type="mesh" rgba="0.2 0.2 0.2 1" mesh="right_hip_pitch_link" />
|
| 157 |
+
<body name="right_hip_roll_link" pos="0 -0.052 -0.030465" quat="0.996179 0 -0.0873386 0">
|
| 158 |
+
<inertial pos="0.029812 0.001045 -0.087934" quat="0.977808 1.97119e-05 0.205576 0.0403793"
|
| 159 |
+
mass="1.52" diaginertia="0.00254986 0.00241169 0.00148755" />
|
| 160 |
+
<joint name="right_hip_roll_joint" pos="0 0 0" axis="1 0 0" range="-2.9671 0.5236"
|
| 161 |
+
actuatorfrcrange="-139 139" class="leg_motor" />
|
| 162 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 163 |
+
mesh="right_hip_roll_link" />
|
| 164 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hip_roll_link" />
|
| 165 |
+
<body name="right_hip_yaw_link" pos="0.025001 0 -0.12412">
|
| 166 |
+
<inertial pos="-0.057709 0.010981 -0.15078" quat="0.751181 0.223482 0.15832 0.600598"
|
| 167 |
+
mass="1.702" diaginertia="0.00776166 0.00717575 0.00160139" />
|
| 168 |
+
<joint name="right_hip_yaw_joint" pos="0 0 0" axis="0 0 1" range="-2.7576 2.7576"
|
| 169 |
+
actuatorfrcrange="-88 88" class="leg_motor" />
|
| 170 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 171 |
+
mesh="right_hip_yaw_link" />
|
| 172 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hip_yaw_link" />
|
| 173 |
+
<body name="right_knee_link" pos="-0.078273 -0.0021489 -0.17734"
|
| 174 |
+
quat="0.996179 0 0.0873386 0">
|
| 175 |
+
<inertial pos="0.005457 -0.003964 -0.12074"
|
| 176 |
+
quat="0.923439 0.0345276 0.0116333 -0.382012" mass="1.932"
|
| 177 |
+
diaginertia="0.011374 0.0112843 0.00146452" />
|
| 178 |
+
<joint name="right_knee_joint" pos="0 0 0" axis="0 1 0" range="-0.087267 2.8798"
|
| 179 |
+
actuatorfrcrange="-139 139" class="leg_motor" />
|
| 180 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 181 |
+
rgba="0.7 0.7 0.7 1" mesh="right_knee_link" />
|
| 182 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_knee_link" />
|
| 183 |
+
<body name="right_ankle_pitch_link" pos="0 9.4445e-05 -0.30001">
|
| 184 |
+
<inertial pos="-0.007269 0 0.011137" quat="0.603053 0.369225 0.369225 0.603053"
|
| 185 |
+
mass="0.074" diaginertia="1.89e-05 1.40805e-05 6.9195e-06" />
|
| 186 |
+
<joint name="right_ankle_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 187 |
+
range="-0.87267 0.5236" actuatorfrcrange="-50 50" class="ankle_motor" />
|
| 188 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 189 |
+
rgba="0.7 0.7 0.7 1" mesh="right_ankle_pitch_link" />
|
| 190 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_ankle_pitch_link" />
|
| 191 |
+
<body name="right_ankle_roll_link" pos="0 0 -0.017558">
|
| 192 |
+
<inertial pos="0.026505 0 -0.016425"
|
| 193 |
+
quat="0.000481092 0.728482 0.000618967 0.685065" mass="0.608"
|
| 194 |
+
diaginertia="0.00167218 0.0016161 0.000217621" />
|
| 195 |
+
<joint name="right_ankle_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 196 |
+
range="-0.2618 0.2618" actuatorfrcrange="-50 50" class="ankle_motor" />
|
| 197 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 198 |
+
rgba="0.2 0.2 0.2 1" mesh="right_ankle_roll_link" />
|
| 199 |
+
<geom size="0.005" pos="-0.05 0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 200 |
+
<geom size="0.005" pos="-0.05 -0.025 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 201 |
+
<geom size="0.005" pos="0.12 0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 202 |
+
<geom size="0.005" pos="0.12 -0.03 -0.03" rgba="0.2 0.2 0.2 1" />
|
| 203 |
+
</body>
|
| 204 |
+
</body>
|
| 205 |
+
</body>
|
| 206 |
+
</body>
|
| 207 |
+
</body>
|
| 208 |
+
</body>
|
| 209 |
+
<body name="waist_yaw_link">
|
| 210 |
+
<inertial pos="0.003494 0.000233 0.018034" quat="0.289697 0.591001 -0.337795 0.672821"
|
| 211 |
+
mass="0.214" diaginertia="0.000163531 0.000107714 0.000102205" />
|
| 212 |
+
<joint name="waist_yaw_joint" pos="0 0 0" axis="0 0 1" range="-2.618 2.618"
|
| 213 |
+
actuatorfrcrange="-88 88" class="torso_motor" />
|
| 214 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 215 |
+
mesh="waist_yaw_link" />
|
| 216 |
+
<body name="waist_roll_link" pos="-0.0039635 0 0.044">
|
| 217 |
+
<inertial pos="0 2.3e-05 0" quat="0.5 0.5 -0.5 0.5" mass="0.086"
|
| 218 |
+
diaginertia="8.245e-06 7.079e-06 6.339e-06" />
|
| 219 |
+
<joint name="waist_roll_joint" pos="0 0 0" axis="1 0 0" range="-0.52 0.52"
|
| 220 |
+
actuatorfrcrange="-50 50" class="torso_motor" />
|
| 221 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 222 |
+
mesh="waist_roll_link" />
|
| 223 |
+
<body name="torso_link">
|
| 224 |
+
<inertial pos="0.00203158 0.000339683 0.184568"
|
| 225 |
+
quat="0.999803 -6.03319e-05 0.0198256 0.00131986" mass="7.818"
|
| 226 |
+
diaginertia="0.121847 0.109825 0.0273735" />
|
| 227 |
+
<joint name="waist_pitch_joint" pos="0 0 0" axis="0 1 0" range="-0.52 0.52"
|
| 228 |
+
actuatorfrcrange="-50 50" class="torso_motor" />
|
| 229 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 230 |
+
mesh="torso_link" />
|
| 231 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="torso_link" />
|
| 232 |
+
<geom pos="0.0039635 0 -0.044" quat="1 0 0 0" type="mesh" contype="0" conaffinity="0"
|
| 233 |
+
group="1" density="0" rgba="0.2 0.2 0.2 1" mesh="logo_link" />
|
| 234 |
+
<geom pos="0.0039635 0 -0.044" quat="1 0 0 0" type="mesh" rgba="0.2 0.2 0.2 1"
|
| 235 |
+
mesh="logo_link" />
|
| 236 |
+
<geom pos="0.0039635 0 -0.044" type="mesh" contype="0" conaffinity="0" group="1"
|
| 237 |
+
density="0" rgba="0.2 0.2 0.2 1" mesh="head_link" />
|
| 238 |
+
<geom pos="0.0039635 0 -0.044" type="mesh" rgba="0.2 0.2 0.2 1" mesh="head_link" />
|
| 239 |
+
<site name="imu_in_torso" size="0.01" pos="-0.03959 -0.00224 0.14792" />
|
| 240 |
+
<body name="left_shoulder_pitch_link" pos="0.0039563 0.10022 0.24778"
|
| 241 |
+
quat="0.990264 0.139201 1.38722e-05 -9.86868e-05">
|
| 242 |
+
<inertial pos="0 0.035892 -0.011628" quat="0.654152 0.0130458 -0.326267 0.68225"
|
| 243 |
+
mass="0.718" diaginertia="0.000465864 0.000432842 0.000406394" />
|
| 244 |
+
<joint name="left_shoulder_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 245 |
+
range="-3.0892 2.6704" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 246 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 247 |
+
rgba="0.7 0.7 0.7 1" mesh="left_shoulder_pitch_link" />
|
| 248 |
+
<geom size="0.03 0.025" pos="0 0.04 -0.01" quat="0.707107 0 0.707107 0"
|
| 249 |
+
type="cylinder" rgba="0.7 0.7 0.7 1" />
|
| 250 |
+
<body name="left_shoulder_roll_link" pos="0 0.038 -0.013831"
|
| 251 |
+
quat="0.990268 -0.139172 0 0">
|
| 252 |
+
<inertial pos="-0.000227 0.00727 -0.063243"
|
| 253 |
+
quat="0.701256 -0.0196223 -0.00710317 0.712604" mass="0.643"
|
| 254 |
+
diaginertia="0.000691311 0.000618011 0.000388977" />
|
| 255 |
+
<joint name="left_shoulder_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 256 |
+
range="-1.5882 2.2515" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 257 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 258 |
+
rgba="0.7 0.7 0.7 1" mesh="left_shoulder_roll_link" />
|
| 259 |
+
<geom size="0.03 0.015" pos="-0.004 0.006 -0.053" type="cylinder"
|
| 260 |
+
rgba="0.7 0.7 0.7 1" />
|
| 261 |
+
<body name="left_shoulder_yaw_link" pos="0 0.00624 -0.1032">
|
| 262 |
+
<inertial pos="0.010773 -0.002949 -0.072009"
|
| 263 |
+
quat="0.716879 -0.0964829 -0.0679942 0.687134" mass="0.734"
|
| 264 |
+
diaginertia="0.00106187 0.00103217 0.000400661" />
|
| 265 |
+
<joint name="left_shoulder_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 266 |
+
range="-2.618 2.618" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 267 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 268 |
+
rgba="0.7 0.7 0.7 1" mesh="left_shoulder_yaw_link" />
|
| 269 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_shoulder_yaw_link" />
|
| 270 |
+
<body name="left_elbow_link" pos="0.015783 0 -0.080518">
|
| 271 |
+
<inertial pos="0.064956 0.004454 -0.010062"
|
| 272 |
+
quat="0.541765 0.636132 0.388821 0.388129" mass="0.6"
|
| 273 |
+
diaginertia="0.000443035 0.000421612 0.000259353" />
|
| 274 |
+
<joint name="left_elbow_joint" pos="0 0 0" axis="0 1 0" range="-1.0472 2.0944"
|
| 275 |
+
actuatorfrcrange="-25 25" class="arm_motor" />
|
| 276 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 277 |
+
rgba="0.7 0.7 0.7 1" mesh="left_elbow_link" />
|
| 278 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_elbow_link" />
|
| 279 |
+
<body name="left_wrist_roll_link" pos="0.1 0.00188791 -0.01">
|
| 280 |
+
<inertial pos="0.0171394 0.000537591 4.8864e-07"
|
| 281 |
+
quat="0.575338 0.411667 -0.574906 0.411094" mass="0.085445"
|
| 282 |
+
diaginertia="5.48211e-05 4.96646e-05 3.57798e-05" />
|
| 283 |
+
<joint name="left_wrist_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 284 |
+
range="-1.97222 1.97222" actuatorfrcrange="-25 25" class="wrist_motor" />
|
| 285 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 286 |
+
rgba="0.7 0.7 0.7 1" mesh="left_wrist_roll_link" />
|
| 287 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_wrist_roll_link" />
|
| 288 |
+
<body name="left_wrist_pitch_link" pos="0.038 0 0">
|
| 289 |
+
<inertial pos="0.0229999 -0.00111685 -0.00111658"
|
| 290 |
+
quat="0.249998 0.661363 0.293036 0.643608" mass="0.48405"
|
| 291 |
+
diaginertia="0.000430353 0.000429873 0.000164648" />
|
| 292 |
+
<joint name="left_wrist_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 293 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 294 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 295 |
+
rgba="0.7 0.7 0.7 1" mesh="left_wrist_pitch_link" />
|
| 296 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_wrist_pitch_link" />
|
| 297 |
+
<body name="left_wrist_yaw_link" pos="0.046 0 0">
|
| 298 |
+
<inertial pos="0.0885506 0.00212216 -0.000374562"
|
| 299 |
+
quat="0.487149 0.493844 0.513241 0.505358" mass="0.457415"
|
| 300 |
+
diaginertia="0.00105989 0.000895419 0.000323842" />
|
| 301 |
+
<joint name="left_wrist_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 302 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 303 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 304 |
+
rgba="0.7 0.7 0.7 1" mesh="left_wrist_yaw_link" />
|
| 305 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_wrist_yaw_link" />
|
| 306 |
+
<geom pos="0.0415 0.003 0" quat="1 0 0 0" type="mesh" contype="0"
|
| 307 |
+
conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 308 |
+
mesh="left_hand_palm_link" />
|
| 309 |
+
<geom pos="0.0415 0.003 0" quat="1 0 0 0" type="mesh" rgba="0.7 0.7 0.7 1"
|
| 310 |
+
mesh="left_hand_palm_link" />
|
| 311 |
+
<body name="left_hand_thumb_0_link" pos="0.067 0.003 0">
|
| 312 |
+
<inertial pos="-0.000884246 -0.00863407 0.000944293"
|
| 313 |
+
quat="0.462991 0.643965 -0.460173 0.398986" mass="0.0862366"
|
| 314 |
+
diaginertia="1.6546e-05 1.60058e-05 1.43741e-05" />
|
| 315 |
+
<joint name="left_hand_thumb_0_joint" pos="0 0 0" axis="0 1 0"
|
| 316 |
+
range="-1.0472 1.0472" actuatorfrcrange="-2.45 2.45"
|
| 317 |
+
class="finger_motor" />
|
| 318 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 319 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_thumb_0_link" />
|
| 320 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_thumb_0_link" />
|
| 321 |
+
<body name="left_hand_thumb_1_link" pos="-0.0025 -0.0193 0">
|
| 322 |
+
<inertial pos="-0.000827888 -0.0354744 -0.0003809"
|
| 323 |
+
quat="0.685598 0.705471 -0.15207 0.0956069" mass="0.0588507"
|
| 324 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 325 |
+
<joint name="left_hand_thumb_1_joint" pos="0 0 0" axis="0 0 1"
|
| 326 |
+
range="-0.724312 1.0472" actuatorfrcrange="-1.4 1.4"
|
| 327 |
+
class="finger_motor" />
|
| 328 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 329 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_thumb_1_link" />
|
| 330 |
+
<geom size="0.01 0.015 0.01" pos="-0.001 -0.032 0" type="box"
|
| 331 |
+
rgba="0.7 0.7 0.7 1" />
|
| 332 |
+
<body name="left_hand_thumb_2_link" pos="0 -0.0458 0">
|
| 333 |
+
<inertial pos="-0.00171735 -0.0262819 0.000107789"
|
| 334 |
+
quat="0.703174 0.710977 -0.00017564 -0.00766553" mass="0.0203063"
|
| 335 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 336 |
+
<joint name="left_hand_thumb_2_joint" pos="0 0 0" axis="0 0 1"
|
| 337 |
+
range="0 1.74533" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 338 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 339 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_thumb_2_link" />
|
| 340 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_thumb_2_link" />
|
| 341 |
+
</body>
|
| 342 |
+
</body>
|
| 343 |
+
</body>
|
| 344 |
+
<body name="left_hand_middle_0_link" pos="0.1192 0.0046 -0.0285">
|
| 345 |
+
<inertial pos="0.0354744 0.000827888 0.0003809"
|
| 346 |
+
quat="0.391313 0.552395 0.417187 0.606373" mass="0.0588507"
|
| 347 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 348 |
+
<joint name="left_hand_middle_0_joint" pos="0 0 0" axis="0 0 1"
|
| 349 |
+
range="-1.5708 0" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 350 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 351 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_middle_0_link" />
|
| 352 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_middle_0_link" />
|
| 353 |
+
<body name="left_hand_middle_1_link" pos="0.0458 0 0">
|
| 354 |
+
<inertial pos="0.0262819 0.00171735 -0.000107789"
|
| 355 |
+
quat="0.502612 0.491799 0.502639 0.502861" mass="0.0203063"
|
| 356 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 357 |
+
<joint name="left_hand_middle_1_joint" pos="0 0 0" axis="0 0 1"
|
| 358 |
+
range="-1.74533 0" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 359 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 360 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_middle_1_link" />
|
| 361 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_middle_1_link" />
|
| 362 |
+
</body>
|
| 363 |
+
</body>
|
| 364 |
+
<body name="left_hand_index_0_link" pos="0.1192 0.0046 0.0285">
|
| 365 |
+
<inertial pos="0.0354744 0.000827888 0.0003809"
|
| 366 |
+
quat="0.391313 0.552395 0.417187 0.606373" mass="0.0588507"
|
| 367 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 368 |
+
<joint name="left_hand_index_0_joint" pos="0 0 0" axis="0 0 1"
|
| 369 |
+
range="-1.5708 0" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 370 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 371 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_index_0_link" />
|
| 372 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_index_0_link" />
|
| 373 |
+
<body name="left_hand_index_1_link" pos="0.0458 0 0">
|
| 374 |
+
<inertial pos="0.0262819 0.00171735 -0.000107789"
|
| 375 |
+
quat="0.502612 0.491799 0.502639 0.502861" mass="0.0203063"
|
| 376 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 377 |
+
<joint name="left_hand_index_1_joint" pos="0 0 0" axis="0 0 1"
|
| 378 |
+
range="-1.74533 0" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 379 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 380 |
+
rgba="0.7 0.7 0.7 1" mesh="left_hand_index_1_link" />
|
| 381 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="left_hand_index_1_link" />
|
| 382 |
+
</body>
|
| 383 |
+
</body>
|
| 384 |
+
</body>
|
| 385 |
+
</body>
|
| 386 |
+
</body>
|
| 387 |
+
</body>
|
| 388 |
+
</body>
|
| 389 |
+
</body>
|
| 390 |
+
</body>
|
| 391 |
+
<body name="right_shoulder_pitch_link" pos="0.0039563 -0.10021 0.24778"
|
| 392 |
+
quat="0.990264 -0.139201 1.38722e-05 9.86868e-05">
|
| 393 |
+
<inertial pos="0 -0.035892 -0.011628" quat="0.68225 -0.326267 0.0130458 0.654152"
|
| 394 |
+
mass="0.718" diaginertia="0.000465864 0.000432842 0.000406394" />
|
| 395 |
+
<joint name="right_shoulder_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 396 |
+
range="-3.0892 2.6704" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 397 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 398 |
+
rgba="0.7 0.7 0.7 1" mesh="right_shoulder_pitch_link" />
|
| 399 |
+
<geom size="0.03 0.025" pos="0 -0.04 -0.01" quat="0.707107 0 0.707107 0"
|
| 400 |
+
type="cylinder" rgba="0.7 0.7 0.7 1" />
|
| 401 |
+
<body name="right_shoulder_roll_link" pos="0 -0.038 -0.013831"
|
| 402 |
+
quat="0.990268 0.139172 0 0">
|
| 403 |
+
<inertial pos="-0.000227 -0.00727 -0.063243"
|
| 404 |
+
quat="0.712604 -0.00710317 -0.0196223 0.701256" mass="0.643"
|
| 405 |
+
diaginertia="0.000691311 0.000618011 0.000388977" />
|
| 406 |
+
<joint name="right_shoulder_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 407 |
+
range="-2.2515 1.5882" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 408 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 409 |
+
rgba="0.7 0.7 0.7 1" mesh="right_shoulder_roll_link" />
|
| 410 |
+
<geom size="0.03 0.015" pos="-0.004 -0.006 -0.053" type="cylinder"
|
| 411 |
+
rgba="0.7 0.7 0.7 1" />
|
| 412 |
+
<body name="right_shoulder_yaw_link" pos="0 -0.00624 -0.1032">
|
| 413 |
+
<inertial pos="0.010773 0.002949 -0.072009"
|
| 414 |
+
quat="0.687134 -0.0679942 -0.0964829 0.716879" mass="0.734"
|
| 415 |
+
diaginertia="0.00106187 0.00103217 0.000400661" />
|
| 416 |
+
<joint name="right_shoulder_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 417 |
+
range="-2.618 2.618" actuatorfrcrange="-25 25" class="arm_motor" />
|
| 418 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 419 |
+
rgba="0.7 0.7 0.7 1" mesh="right_shoulder_yaw_link" />
|
| 420 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_shoulder_yaw_link" />
|
| 421 |
+
<body name="right_elbow_link" pos="0.015783 0 -0.080518">
|
| 422 |
+
<inertial pos="0.064956 -0.004454 -0.010062"
|
| 423 |
+
quat="0.388129 0.388821 0.636132 0.541765" mass="0.6"
|
| 424 |
+
diaginertia="0.000443035 0.000421612 0.000259353" />
|
| 425 |
+
<joint name="right_elbow_joint" pos="0 0 0" axis="0 1 0" range="-1.0472 2.0944"
|
| 426 |
+
actuatorfrcrange="-25 25" class="arm_motor" />
|
| 427 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 428 |
+
rgba="0.7 0.7 0.7 1" mesh="right_elbow_link" />
|
| 429 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_elbow_link" />
|
| 430 |
+
<body name="right_wrist_roll_link" pos="0.1 -0.00188791 -0.01">
|
| 431 |
+
<inertial pos="0.0171394 -0.000537591 4.8864e-07"
|
| 432 |
+
quat="0.411667 0.575338 -0.411094 0.574906" mass="0.085445"
|
| 433 |
+
diaginertia="5.48211e-05 4.96646e-05 3.57798e-05" />
|
| 434 |
+
<joint name="right_wrist_roll_joint" pos="0 0 0" axis="1 0 0"
|
| 435 |
+
range="-1.97222 1.97222" actuatorfrcrange="-25 25" class="wrist_motor" />
|
| 436 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 437 |
+
rgba="0.7 0.7 0.7 1" mesh="right_wrist_roll_link" />
|
| 438 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_wrist_roll_link" />
|
| 439 |
+
<body name="right_wrist_pitch_link" pos="0.038 0 0">
|
| 440 |
+
<inertial pos="0.0229999 0.00111685 -0.00111658"
|
| 441 |
+
quat="0.643608 0.293036 0.661363 0.249998" mass="0.48405"
|
| 442 |
+
diaginertia="0.000430353 0.000429873 0.000164648" />
|
| 443 |
+
<joint name="right_wrist_pitch_joint" pos="0 0 0" axis="0 1 0"
|
| 444 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 445 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 446 |
+
rgba="0.7 0.7 0.7 1" mesh="right_wrist_pitch_link" />
|
| 447 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_wrist_pitch_link" />
|
| 448 |
+
<body name="right_wrist_yaw_link" pos="0.046 0 0">
|
| 449 |
+
<inertial pos="0.0885506 -0.00212216 -0.000374562"
|
| 450 |
+
quat="0.505358 0.513241 0.493844 0.487149" mass="0.457415"
|
| 451 |
+
diaginertia="0.00105989 0.000895419 0.000323842" />
|
| 452 |
+
<joint name="right_wrist_yaw_joint" pos="0 0 0" axis="0 0 1"
|
| 453 |
+
range="-1.61443 1.61443" actuatorfrcrange="-5 5" class="wrist_motor" />
|
| 454 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 455 |
+
rgba="0.7 0.7 0.7 1" mesh="right_wrist_yaw_link" />
|
| 456 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_wrist_yaw_link" />
|
| 457 |
+
<geom pos="0.0415 -0.003 0" quat="1 0 0 0" type="mesh" contype="0"
|
| 458 |
+
conaffinity="0" group="1" density="0" rgba="0.7 0.7 0.7 1"
|
| 459 |
+
mesh="right_hand_palm_link" />
|
| 460 |
+
<geom pos="0.0415 -0.003 0" quat="1 0 0 0" type="mesh"
|
| 461 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_palm_link" />
|
| 462 |
+
<body name="right_hand_thumb_0_link" pos="0.067 -0.003 0">
|
| 463 |
+
<inertial pos="-0.000884246 0.00863407 0.000944293"
|
| 464 |
+
quat="0.643965 0.462991 -0.398986 0.460173" mass="0.0862366"
|
| 465 |
+
diaginertia="1.6546e-05 1.60058e-05 1.43741e-05" />
|
| 466 |
+
<joint name="right_hand_thumb_0_joint" pos="0 0 0" axis="0 1 0"
|
| 467 |
+
range="-1.0472 1.0472" actuatorfrcrange="-2.45 2.45"
|
| 468 |
+
class="finger_motor" />
|
| 469 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 470 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_thumb_0_link" />
|
| 471 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hand_thumb_0_link" />
|
| 472 |
+
<body name="right_hand_thumb_1_link" pos="-0.0025 0.0193 0">
|
| 473 |
+
<inertial pos="-0.000827888 0.0354744 -0.0003809"
|
| 474 |
+
quat="0.705471 0.685598 -0.0956069 0.15207" mass="0.0588507"
|
| 475 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 476 |
+
<joint name="right_hand_thumb_1_joint" pos="0 0 0" axis="0 0 1"
|
| 477 |
+
range="-1.0472 0.724312" actuatorfrcrange="-1.4 1.4"
|
| 478 |
+
class="finger_motor" />
|
| 479 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 480 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_thumb_1_link" />
|
| 481 |
+
<geom size="0.01 0.015 0.01" pos="-0.001 0.032 0" type="box"
|
| 482 |
+
rgba="0.7 0.7 0.7 1" />
|
| 483 |
+
<body name="right_hand_thumb_2_link" pos="0 0.0458 0">
|
| 484 |
+
<inertial pos="-0.00171735 0.0262819 0.000107789"
|
| 485 |
+
quat="0.710977 0.703174 0.00766553 0.00017564" mass="0.0203063"
|
| 486 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 487 |
+
<joint name="right_hand_thumb_2_joint" pos="0 0 0" axis="0 0 1"
|
| 488 |
+
range="-1.74533 0" actuatorfrcrange="-1.4 1.4"
|
| 489 |
+
class="finger_motor" />
|
| 490 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 491 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_thumb_2_link" />
|
| 492 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1"
|
| 493 |
+
mesh="right_hand_thumb_2_link" />
|
| 494 |
+
</body>
|
| 495 |
+
</body>
|
| 496 |
+
</body>
|
| 497 |
+
<body name="right_hand_middle_0_link" pos="0.1192 -0.0046 -0.0285">
|
| 498 |
+
<inertial pos="0.0354744 -0.000827888 0.0003809"
|
| 499 |
+
quat="0.606373 0.417187 0.552395 0.391313" mass="0.0588507"
|
| 500 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 501 |
+
<joint name="right_hand_middle_0_joint" pos="0 0 0" axis="0 0 1"
|
| 502 |
+
range="0 1.5708" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 503 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 504 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_middle_0_link" />
|
| 505 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hand_middle_0_link" />
|
| 506 |
+
<body name="right_hand_middle_1_link" pos="0.0458 0 0">
|
| 507 |
+
<inertial pos="0.0262819 -0.00171735 -0.000107789"
|
| 508 |
+
quat="0.502861 0.502639 0.491799 0.502612" mass="0.0203063"
|
| 509 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 510 |
+
<joint name="right_hand_middle_1_joint" pos="0 0 0" axis="0 0 1"
|
| 511 |
+
range="0 1.74533" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 512 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 513 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_middle_1_link" />
|
| 514 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hand_middle_1_link" />
|
| 515 |
+
</body>
|
| 516 |
+
</body>
|
| 517 |
+
<body name="right_hand_index_0_link" pos="0.1192 -0.0046 0.0285">
|
| 518 |
+
<inertial pos="0.0354744 -0.000827888 0.0003809"
|
| 519 |
+
quat="0.606373 0.417187 0.552395 0.391313" mass="0.0588507"
|
| 520 |
+
diaginertia="1.28514e-05 1.22902e-05 5.9666e-06" />
|
| 521 |
+
<joint name="right_hand_index_0_joint" pos="0 0 0" axis="0 0 1"
|
| 522 |
+
range="0 1.5708" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 523 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 524 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_index_0_link" />
|
| 525 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hand_index_0_link" />
|
| 526 |
+
<body name="right_hand_index_1_link" pos="0.0458 0 0">
|
| 527 |
+
<inertial pos="0.0262819 -0.00171735 -0.000107789"
|
| 528 |
+
quat="0.502861 0.502639 0.491799 0.502612" mass="0.0203063"
|
| 529 |
+
diaginertia="4.61314e-06 3.86645e-06 1.53495e-06" />
|
| 530 |
+
<joint name="right_hand_index_1_joint" pos="0 0 0" axis="0 0 1"
|
| 531 |
+
range="0 1.74533" actuatorfrcrange="-1.4 1.4" class="finger_motor" />
|
| 532 |
+
<geom type="mesh" contype="0" conaffinity="0" group="1" density="0"
|
| 533 |
+
rgba="0.7 0.7 0.7 1" mesh="right_hand_index_1_link" />
|
| 534 |
+
<geom type="mesh" rgba="0.7 0.7 0.7 1" mesh="right_hand_index_1_link" />
|
| 535 |
+
</body>
|
| 536 |
+
</body>
|
| 537 |
+
</body>
|
| 538 |
+
</body>
|
| 539 |
+
</body>
|
| 540 |
+
</body>
|
| 541 |
+
</body>
|
| 542 |
+
</body>
|
| 543 |
+
</body>
|
| 544 |
+
</body>
|
| 545 |
+
</body>
|
| 546 |
+
</body>
|
| 547 |
+
</body>
|
| 548 |
+
</worldbody>
|
| 549 |
+
|
| 550 |
+
<actuator>
|
| 551 |
+
<!-- <motor name="fx" joint="floating_base_joint" gear="1 0 0 0 0 0" />
|
| 552 |
+
<motor name="fy" joint="floating_base_joint" gear="0 1 0 0 0 0" />
|
| 553 |
+
<motor name="fz" joint="floating_base_joint" gear="0 0 1 0 0 0" />
|
| 554 |
+
<motor name="tx" joint="floating_base_joint" gear="0 0 0 1 0 0" />
|
| 555 |
+
<motor name="ty" joint="floating_base_joint" gear="0 0 0 0 1 0" />
|
| 556 |
+
<motor name="tz" joint="floating_base_joint" gear="0 0 0 0 0 1" /> -->
|
| 557 |
+
|
| 558 |
+
<motor name="left_hip_pitch_joint" joint="left_hip_pitch_joint" />
|
| 559 |
+
<motor
|
| 560 |
+
name="left_hip_roll_joint" joint="left_hip_roll_joint" />
|
| 561 |
+
<motor name="left_hip_yaw_joint"
|
| 562 |
+
joint="left_hip_yaw_joint" />
|
| 563 |
+
<motor name="left_knee_joint" joint="left_knee_joint" />
|
| 564 |
+
<motor
|
| 565 |
+
name="left_ankle_pitch_joint" joint="left_ankle_pitch_joint" />
|
| 566 |
+
<motor
|
| 567 |
+
name="left_ankle_roll_joint" joint="left_ankle_roll_joint" />
|
| 568 |
+
<motor
|
| 569 |
+
name="right_hip_pitch_joint" joint="right_hip_pitch_joint" />
|
| 570 |
+
<motor
|
| 571 |
+
name="right_hip_roll_joint" joint="right_hip_roll_joint" />
|
| 572 |
+
<motor name="right_hip_yaw_joint"
|
| 573 |
+
joint="right_hip_yaw_joint" />
|
| 574 |
+
<motor name="right_knee_joint" joint="right_knee_joint" />
|
| 575 |
+
<motor
|
| 576 |
+
name="right_ankle_pitch_joint" joint="right_ankle_pitch_joint" />
|
| 577 |
+
<motor
|
| 578 |
+
name="right_ankle_roll_joint" joint="right_ankle_roll_joint" />
|
| 579 |
+
<motor name="waist_yaw_joint"
|
| 580 |
+
joint="waist_yaw_joint" />
|
| 581 |
+
<motor name="waist_roll_joint" joint="waist_roll_joint" />
|
| 582 |
+
<motor
|
| 583 |
+
name="waist_pitch_joint" joint="waist_pitch_joint" />
|
| 584 |
+
<motor name="left_shoulder_pitch_joint"
|
| 585 |
+
joint="left_shoulder_pitch_joint" />
|
| 586 |
+
<motor name="left_shoulder_roll_joint"
|
| 587 |
+
joint="left_shoulder_roll_joint" />
|
| 588 |
+
<motor name="left_shoulder_yaw_joint"
|
| 589 |
+
joint="left_shoulder_yaw_joint" />
|
| 590 |
+
<motor name="left_elbow_joint" joint="left_elbow_joint" />
|
| 591 |
+
<motor
|
| 592 |
+
name="left_wrist_roll_joint" joint="left_wrist_roll_joint" />
|
| 593 |
+
<motor
|
| 594 |
+
name="left_wrist_pitch_joint" joint="left_wrist_pitch_joint" />
|
| 595 |
+
<motor
|
| 596 |
+
name="left_wrist_yaw_joint" joint="left_wrist_yaw_joint" />
|
| 597 |
+
<motor
|
| 598 |
+
name="left_hand_thumb_0_joint" joint="left_hand_thumb_0_joint" />
|
| 599 |
+
<motor
|
| 600 |
+
name="left_hand_thumb_1_joint" joint="left_hand_thumb_1_joint" />
|
| 601 |
+
<motor
|
| 602 |
+
name="left_hand_thumb_2_joint" joint="left_hand_thumb_2_joint" />
|
| 603 |
+
<motor
|
| 604 |
+
name="left_hand_middle_0_joint" joint="left_hand_middle_0_joint" />
|
| 605 |
+
<motor
|
| 606 |
+
name="left_hand_middle_1_joint" joint="left_hand_middle_1_joint" />
|
| 607 |
+
<motor
|
| 608 |
+
name="left_hand_index_0_joint" joint="left_hand_index_0_joint" />
|
| 609 |
+
<motor
|
| 610 |
+
name="left_hand_index_1_joint" joint="left_hand_index_1_joint" />
|
| 611 |
+
<motor
|
| 612 |
+
name="right_shoulder_pitch_joint" joint="right_shoulder_pitch_joint" />
|
| 613 |
+
<motor
|
| 614 |
+
name="right_shoulder_roll_joint" joint="right_shoulder_roll_joint" />
|
| 615 |
+
<motor
|
| 616 |
+
name="right_shoulder_yaw_joint" joint="right_shoulder_yaw_joint" />
|
| 617 |
+
<motor
|
| 618 |
+
name="right_elbow_joint" joint="right_elbow_joint" />
|
| 619 |
+
<motor name="right_wrist_roll_joint"
|
| 620 |
+
joint="right_wrist_roll_joint" />
|
| 621 |
+
<motor name="right_wrist_pitch_joint"
|
| 622 |
+
joint="right_wrist_pitch_joint" />
|
| 623 |
+
<motor name="right_wrist_yaw_joint"
|
| 624 |
+
joint="right_wrist_yaw_joint" />
|
| 625 |
+
<motor name="right_hand_thumb_0_joint"
|
| 626 |
+
joint="right_hand_thumb_0_joint" />
|
| 627 |
+
<motor name="right_hand_thumb_1_joint"
|
| 628 |
+
joint="right_hand_thumb_1_joint" />
|
| 629 |
+
<motor name="right_hand_thumb_2_joint"
|
| 630 |
+
joint="right_hand_thumb_2_joint" />
|
| 631 |
+
<motor name="right_hand_index_0_joint"
|
| 632 |
+
joint="right_hand_index_0_joint" />
|
| 633 |
+
<motor name="right_hand_index_1_joint"
|
| 634 |
+
joint="right_hand_index_1_joint" />
|
| 635 |
+
<motor name="right_hand_middle_0_joint"
|
| 636 |
+
joint="right_hand_middle_0_joint" />
|
| 637 |
+
<motor name="right_hand_middle_1_joint"
|
| 638 |
+
joint="right_hand_middle_1_joint" /> --> </actuator>
|
| 639 |
+
|
| 640 |
+
<sensor>
|
| 641 |
+
<gyro name="imu-torso-angular-velocity" site="imu_in_torso" noise="5e-4" cutoff="34.9" />
|
| 642 |
+
<accelerometer name="imu-torso-linear-acceleration" site="imu_in_torso" noise="1e-2"
|
| 643 |
+
cutoff="157" />
|
| 644 |
+
<gyro name="imu-pelvis-angular-velocity" site="imu_in_pelvis" noise="5e-4" cutoff="34.9" />
|
| 645 |
+
<accelerometer name="imu-pelvis-linear-acceleration" site="imu_in_pelvis" noise="1e-2"
|
| 646 |
+
cutoff="157" />
|
| 647 |
+
</sensor>
|
| 648 |
+
|
| 649 |
+
|
| 650 |
+
<!-- setup scene -->
|
| 651 |
+
<!-- <statistic center="1.0 0.7 1.0" extent="0.8"/>
|
| 652 |
+
<visual>
|
| 653 |
+
<headlight diffuse="0.6 0.6 0.6" ambient="0.1 0.1 0.1" specular="0.9 0.9 0.9"/>
|
| 654 |
+
<rgba haze="0.15 0.25 0.35 1"/>
|
| 655 |
+
<global azimuth="-140" elevation="-20"/>
|
| 656 |
+
</visual>
|
| 657 |
+
<asset>
|
| 658 |
+
<texture type="skybox" builtin="flat" rgb1="0 0 0" rgb2="0 0 0" width="512" height="3072"/>
|
| 659 |
+
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1
|
| 660 |
+
0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300"/>
|
| 661 |
+
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5"
|
| 662 |
+
reflectance="0.2"/>
|
| 663 |
+
</asset>
|
| 664 |
+
<worldbody>
|
| 665 |
+
<light pos="1 0 3.5" dir="0 0 -1" directional="true"/>
|
| 666 |
+
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane"/>
|
| 667 |
+
</worldbody> -->
|
| 668 |
+
</mujoco>
|
| 669 |
+
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/lift_box_43dof.xml
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<mujoco model="g1_43dof_lift_box scene">
|
| 2 |
+
<include file="g1_29dof_with_hand_rev_1_0_activatedfinger.xml" />
|
| 3 |
+
<!-- Note that the hand model in g1_29dof_with_hand.xml is not stable for simulation. -->
|
| 4 |
+
|
| 5 |
+
<statistic center="0 0 0.5" extent="2.0" />
|
| 6 |
+
|
| 7 |
+
<visual>
|
| 8 |
+
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0" />
|
| 9 |
+
<rgba haze="0.15 0.25 0.35 1" />
|
| 10 |
+
<global azimuth="-130" elevation="-20" />
|
| 11 |
+
</visual>
|
| 12 |
+
|
| 13 |
+
<asset>
|
| 14 |
+
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512"
|
| 15 |
+
height="3072" />
|
| 16 |
+
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4"
|
| 17 |
+
rgb2="0.1 0.2 0.3"
|
| 18 |
+
markrgb="0.8 0.8 0.8" width="300" height="300" />
|
| 19 |
+
<texture type="2d" name="table" builtin="flat" rgb1="0.7 0.6 0.5" width="512" height="512" />
|
| 20 |
+
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5"
|
| 21 |
+
reflectance="0.2" />
|
| 22 |
+
<material name="table" texture="table" texuniform="true" reflectance="0.1" />
|
| 23 |
+
<texture type="2d" name="cube" builtin="flat" rgb1="0.3 0.7 0.8" width="512" height="512" />
|
| 24 |
+
<material name="cube" texture="cube" texuniform="true" reflectance="0.1" />
|
| 25 |
+
</asset>
|
| 26 |
+
|
| 27 |
+
<worldbody>
|
| 28 |
+
<light pos="0 0 1.5" dir="0 0 -1" directional="true" />
|
| 29 |
+
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane" />
|
| 30 |
+
<!-- Site -->
|
| 31 |
+
<site name="com_marker" pos="0.1 0 0" size="0.05" rgba="1 0 0 1" type="sphere" />
|
| 32 |
+
|
| 33 |
+
<body name="table_body" pos="0.6 0 0.4">
|
| 34 |
+
<geom name="table_top" pos="0 0 0.3" size="0.5 1.0 0.05" type="box" material="table"/>
|
| 35 |
+
<geom name="table_leg1" pos="0.0 0.9 -0.05" size="0.5 0.05 0.4" type="box" material="table"/>
|
| 36 |
+
<geom name="table_leg2" pos="0.0 -0.9 -0.05" size="0.5 0.05 0.4" type="box" material="table"/>
|
| 37 |
+
</body>
|
| 38 |
+
<body name="box_body" pos="0.35 0 0.9">
|
| 39 |
+
<joint type="free" damping="0.0005" name="box_joint" />
|
| 40 |
+
<geom name="box" size="0.1 0.1 0.1" type="box" material="cube" solimp="0.998 0.998 0.001"
|
| 41 |
+
solref="0.001 2" density="100" friction="0.95 0.3 0.1" />
|
| 42 |
+
</body>
|
| 43 |
+
|
| 44 |
+
</worldbody>
|
| 45 |
+
|
| 46 |
+
<default>
|
| 47 |
+
<geom friction="1.0" />
|
| 48 |
+
</default>
|
| 49 |
+
</mujoco>
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/meshes/left_ankle_pitch_link.STL
ADDED
|
Binary file (71.2 kB). View file
|
|
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/meshes/left_elbow_link.STL
ADDED
|
Binary file (88.8 kB). View file
|
|
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/meshes/left_hand_thumb_0_link.STL
ADDED
|
Binary file (8.88 kB). View file
|
|
|
GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/meshes/left_wrist_pitch_link.STL
ADDED
|
Binary file (86 kB). View file
|
|
|