Timsty commited on
Commit
8cf4ead
·
verified ·
1 Parent(s): 700dd75

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/__init__.py +0 -0
  2. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/g1_body.py +67 -0
  3. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/g1_env.py +324 -0
  4. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/g1_hand.py +89 -0
  5. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/__init__.py +0 -0
  6. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/base_sim.py +772 -0
  7. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/image_publish_utils.py +256 -0
  8. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/metric_utils.py +71 -0
  9. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/robocasa_sim.py +63 -0
  10. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/sim_utilts.py +96 -0
  11. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/simulator_factory.py +144 -0
  12. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/sim/unitree_sdk2py_bridge.py +459 -0
  13. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/__init__.py +0 -0
  14. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/command_sender.py +146 -0
  15. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/joint_safety.py +534 -0
  16. GR00T-WholeBodyControl/decoupled_wbc/control/envs/g1/utils/state_processor.py +143 -0
  17. GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/__init__.py +0 -0
  18. GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/async_env_server.py +305 -0
  19. GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/sync_env.py +586 -0
  20. GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/__init__.py +0 -0
  21. GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/cam_key_converter.py +73 -0
  22. GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/controller_utils.py +54 -0
  23. GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/robocasa_env.py +443 -0
  24. GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/robot_key_converter.py +301 -0
  25. GR00T-WholeBodyControl/decoupled_wbc/control/envs/robocasa/utils/sim_utils.py +8 -0
  26. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/__init__.py +0 -0
  27. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/configs.py +483 -0
  28. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/g1_29dof_gear_wbc.yaml +421 -0
  29. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/g1_gear_wbc.yaml +45 -0
  30. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/configs/identifiers.py +14 -0
  31. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/playback_sync_sim_data.py +627 -0
  32. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_camera_viewer.py +249 -0
  33. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_g1_control_loop.py +236 -0
  34. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_g1_data_exporter.py +364 -0
  35. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_navigation_policy_loop.py +68 -0
  36. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_sim_loop.py +61 -0
  37. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_sync_sim_data_collection.py +213 -0
  38. GR00T-WholeBodyControl/decoupled_wbc/control/main/teleop/run_teleop_policy_loop.py +110 -0
  39. GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/instantiation/__init__.py +15 -0
  40. GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/instantiation/g1.py +62 -0
  41. GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof.urdf +1091 -0
  42. GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_old.xml +568 -0
  43. GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_with_hand.urdf +1497 -0
  44. GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_with_hand.xml +748 -0
  45. GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/g1_29dof_with_hand_rev_1_0_activatedfinger.xml +669 -0
  46. GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/lift_box_43dof.xml +49 -0
  47. GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/meshes/left_ankle_pitch_link.STL +0 -0
  48. GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/meshes/left_elbow_link.STL +0 -0
  49. GR00T-WholeBodyControl/decoupled_wbc/control/robot_model/model_data/g1/meshes/left_hand_thumb_0_link.STL +0 -0
  50. 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