Skip to content

Commit 41d2ef0

Browse files
authored
Merge pull request #1937 from StanfordVL/fix/curobo-holonomic-joint-limit
Fix curobo holonomic joint limit
2 parents 6430f7d + f0888d3 commit 41d2ef0

File tree

6 files changed

+168
-21
lines changed

6 files changed

+168
-21
lines changed

OmniGibson/omnigibson/action_primitives/curobo.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,27 @@ def __init__(
115115
robot_cfg_path_dict = {
116116
CuRoboEmbodimentSelection.DEFAULT: robot_cfg_path_dict[CuRoboEmbodimentSelection.DEFAULT]
117117
}
118+
print("!" * 100)
119+
# TODO [Wensi]: Check whether this is still true for future releases.
120+
print(
121+
"""
122+
NOTE: Currently (v3.8.0), for cuda architecture 12.0 (e.g. RTX 50-series), using Default embodiment for Tiago or non-DEFAULT embodiment for R1Pro
123+
will raise CUDA illegal memory access error during mg.warmup() due to cuRobo compatibility issues.
124+
Therefore, we automatically exclude these incompatible embodiments when we detect such GPU is being used.
125+
"""
126+
)
127+
if th.cuda.get_device_capability(device) == (12, 0):
128+
if robot.model == "tiago":
129+
print("Detected you are using Tiago with cuda architecture 12.0 GPU: excluding non-DEFAULT embodiment.")
130+
robot_cfg_path_dict = {
131+
CuRoboEmbodimentSelection.DEFAULT: robot_cfg_path_dict[CuRoboEmbodimentSelection.DEFAULT]
132+
}
133+
elif robot.model == "r1pro":
134+
print("Detected you are using R1Pro with cuda architecture 12.0 GPU: excluding DEFAULT embodiment.")
135+
robot_cfg_path_dict = {
136+
k: v for k, v in robot_cfg_path_dict.items() if k != CuRoboEmbodimentSelection.DEFAULT
137+
}
138+
print("!" * 100)
118139
robot_usd_path = robot.usd_path if robot_usd_path is None else robot_usd_path
119140

120141
# This will be shared across all MotionGen instances

OmniGibson/omnigibson/action_primitives/starter_semantic_action_primitives.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
ActionPrimitiveErrorGroup,
2626
BaseActionPrimitiveSet,
2727
)
28-
from omnigibson.action_primitives.curobo import CuRoboEmbodimentSelection, CuRoboMotionGenerator
28+
from omnigibson.action_primitives.curobo import (
29+
CuRoboEmbodimentSelection,
30+
CuRoboMotionGenerator,
31+
)
2932
from omnigibson.controllers import (
3033
InverseKinematicsController,
3134
HolonomicBaseJointController,
@@ -941,8 +944,6 @@ def _plan_joint_motion(
941944
# Grab the first successful trajectory if found
942945
success_idx = th.where(successes)[0].cpu()
943946
if len(success_idx) == 0:
944-
# print("motion planning fails")
945-
# breakpoint()
946947
raise ActionPrimitiveError(
947948
ActionPrimitiveError.Reason.PLANNING_ERROR,
948949
"There is no accessible path from where you are to the desired pose. Try again",
@@ -967,8 +968,7 @@ def _execute_motion_plan(
967968
low_precision=False,
968969
ignore_physics=False,
969970
):
970-
for i, joint_pos in enumerate(q_traj):
971-
# indented_print(f"Executing motion plan step {i + 1}/{len(q_traj)}")
971+
for joint_pos in q_traj:
972972
if ignore_physics:
973973
self.robot.set_joint_positions(joint_pos)
974974
og.sim.step()
@@ -983,9 +983,7 @@ def _execute_motion_plan(
983983
for arm in self.robot.arm_names:
984984
articulation_control_idx.append(self.robot.arm_control_idx[arm])
985985
articulation_control_idx = th.cat(articulation_control_idx)
986-
for j in range(m.MAX_STEPS_FOR_JOINT_MOTION):
987-
# indented_print(f"Step {j + 1}/{m.MAX_STEPS_FOR_JOINT_MOTION}")
988-
986+
for _ in range(m.MAX_STEPS_FOR_JOINT_MOTION):
989987
# We need to call @q_to_action for every step because as the robot base moves, the same base joint_pos will be
990988
# converted to different actions, since HolonomicBaseJointController accepts an action in the robot local frame.
991989
action = self.robot.q_to_action(joint_pos)
@@ -1535,9 +1533,6 @@ def _navigate_to_pose(self, pose_2d, skip_obstacle_update=False):
15351533
self.debug_visual_marker.set_position_orientation(*pose_3d)
15361534
target_pos = {self.robot.base_footprint_link_name: pose_3d[0]}
15371535
target_quat = {self.robot.base_footprint_link_name: pose_3d[1]}
1538-
1539-
# print("base motion planning")
1540-
# breakpoint()
15411536
q_traj = self._plan_joint_motion(
15421537
target_pos,
15431538
target_quat,
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
env:
2+
action_frequency: 30 # (int): environment executes action at the action_frequency rate
3+
physics_frequency: 120 # (int): physics frequency (1 / physics_timestep for physx)
4+
device: null # (None or str): specifies the device to be used if running on the gpu with torch backend
5+
automatic_reset: false # (bool): whether to automatic reset after an episode finishes
6+
flatten_action_space: false # (bool): whether to flatten the action space as a sinle 1D-array
7+
flatten_obs_space: false # (bool): whether the observation space should be flattened when generated
8+
use_external_obs: false # (bool): Whether to use external observations or not
9+
external_sensors: null # (None or list): If specified, list of sensor configurations for external sensors to add. Should specify sensor "type" and any additional kwargs to instantiate the sensor. Each entry should be the kwargs passed to @create_sensor, in addition to position, orientation
10+
11+
render:
12+
viewer_width: 1280
13+
viewer_height: 720
14+
15+
scene:
16+
type: InteractiveTraversableScene
17+
scene_model: Rs_int
18+
trav_map_resolution: 0.1
19+
default_erosion_radius: 0.0
20+
trav_map_with_objects: true
21+
num_waypoints: 1
22+
waypoint_resolution: 0.2
23+
load_object_categories: null
24+
not_load_object_categories: null
25+
load_room_types: ["living_room"]
26+
load_room_instances: null
27+
load_task_relevant_only: false
28+
seg_map_resolution: 1.0
29+
scene_source: OG
30+
include_robots: false
31+
32+
robots:
33+
- type: R1Pro
34+
obs_modalities: [rgb]
35+
include_sensor_names: null
36+
exclude_sensor_names: null
37+
scale: 1.0
38+
self_collisions: true
39+
action_normalize: false
40+
action_type: continuous
41+
grasping_mode: sticky
42+
reset_joint_pos: [
43+
0.0000,
44+
-0.0000,
45+
0.0247,
46+
0.0009,
47+
0.0004,
48+
-0.0000,
49+
0.0000,
50+
0.0000,
51+
0.0000,
52+
0.0000,
53+
0.0,
54+
0.0,
55+
0.0,
56+
0.0,
57+
0.0,
58+
0.0,
59+
0.0,
60+
0.0,
61+
0.0,
62+
0.0,
63+
0.0,
64+
0.0,
65+
0.0,
66+
0.0,
67+
0.0300,
68+
0.0300,
69+
0.0300,
70+
0.0300,
71+
]
72+
sensor_config:
73+
VisionSensor:
74+
sensor_kwargs:
75+
image_height: 128
76+
image_width: 128
77+
controller_config:
78+
base:
79+
name: HolonomicBaseJointController
80+
motor_type: position
81+
command_input_limits: null
82+
use_impedances: false
83+
trunk:
84+
name: JointController
85+
motor_type: position
86+
command_input_limits: null
87+
use_delta_commands: false
88+
use_impedances: false
89+
arm_left:
90+
name: JointController
91+
motor_type: position
92+
command_input_limits: null
93+
use_delta_commands: false
94+
use_impedances: false
95+
arm_right:
96+
name: JointController
97+
motor_type: position
98+
command_input_limits: null
99+
use_delta_commands: false
100+
use_impedances: false
101+
gripper_left:
102+
name: JointController
103+
motor_type: position
104+
command_input_limits: null
105+
use_delta_commands: false
106+
use_impedances: false
107+
gripper_right:
108+
name: JointController
109+
motor_type: position
110+
command_input_limits: null
111+
use_delta_commands: false
112+
use_impedances: false
113+
114+
objects: []
115+
116+
task:
117+
type: DummyTask

OmniGibson/omnigibson/examples/action_primitives/rs_int_example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def main():
2222
2323
It loads Rs_int with a robot, and the robot picks and places an apple.
2424
"""
25-
robot_options = ["R1", "Tiago"]
25+
robot_options = ["R1", "R1Pro", "Tiago"]
2626
robot_type = choose_from_options(options=robot_options, name="robot options", random_selection=False)
2727

2828
# Load the config

OmniGibson/omnigibson/robots/robot.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3452,7 +3452,7 @@ def curobo_path(self):
34523452
if eef_def and eef_def.curobo_path:
34533453
return os.path.join(get_dataset_path("omnigibson-robot-assets"), eef_def.curobo_path)
34543454
else:
3455-
assert False, f"Robot not supported for curobo."
3455+
assert False, "Robot not supported for curobo."
34563456

34573457
# Import here to avoid circular imports
34583458
from omnigibson.action_primitives.curobo import CuRoboEmbodimentSelection
@@ -3479,7 +3479,7 @@ def curobo_attached_object_link_names(self):
34793479
):
34803480
assert (
34813481
self.end_effector in self._definition.manipulation.eef_support_curobo_attached_object_link_names
3482-
), f"Robot not supported for curobo."
3482+
), "Robot not supported for curobo."
34833483

34843484
assert self.is_manipulation
34853485
# By default, sets the standardized path
@@ -4110,15 +4110,19 @@ def q_to_action(self, q):
41104110
), f"Controller [{name}] should be a JointController/HolonomicBaseJointController with use_delta_commands=False!"
41114111
command = q[controller.dof_idx]
41124112
if isinstance(controller, HolonomicBaseJointController):
4113-
# For a holonomic base joint controller, the command should be in the robot local frame
4114-
# For orientation, we need to convert the command to a delta angle
4115-
cur_rz_joint_pos = self.get_joint_positions()[self.base_idx][5]
4113+
# Holonomnic base controller expects delta (x, y, rz) in robot base footprint link frame
4114+
# However, q actions are in absolute (x, y, rz) in robot root frame, so we need to convert them before feeding to the controller
4115+
base_joint_pos = self.get_joint_positions()[self.base_idx]
4116+
cur_rz_joint_pos = base_joint_pos[5]
41164117
delta_q = wrap_angle(command[2] - cur_rz_joint_pos)
41174118

41184119
# For translation, we need to convert the command to the robot local frame
4119-
body_pose = self.get_position_orientation()
4120-
canonical_pos = th.tensor([command[0], command[1], body_pose[0][2]], dtype=th.float32)
4121-
local_pos = T.relative_pose_transform(canonical_pos, th.tensor([0.0, 0.0, 0.0, 1.0]), *body_pose)[0]
4120+
body_pos = base_joint_pos[:3]
4121+
body_quat = T.mat2quat(T.euler_intrinsic2mat(base_joint_pos[3:6]))
4122+
canonical_pos = th.tensor([command[0], command[1], body_pos[2]], dtype=th.float32)
4123+
local_pos = T.relative_pose_transform(
4124+
canonical_pos, th.tensor([0.0, 0.0, 0.0, 1.0]), body_pos, body_quat
4125+
)[0]
41224126
command = th.tensor([local_pos[0], local_pos[1], delta_q])
41234127
action.append(controller._reverse_preprocess_command(command))
41244128
action = th.cat(action, dim=0)

OmniGibson/tests/test_curobo.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,16 @@ def test_curobo():
244244
},
245245
]
246246
for robot_cfg in robot_cfgs:
247+
if th.cuda.is_available() and th.cuda.get_device_capability(0) == (12, 0):
248+
# TODO [Wensi]: Check whether this is still true for future releases.
249+
# Currently (v3.8.0), for cuda architecture 12.0 (e.g. RTX 50-series), using Default embodiment for Tiago or non-DEFAULT embodiment for R1Pro
250+
# will raise CUDA illegal memory access error during mg.warmup() due to cuRobo compatibility issues.
251+
# Therefore, we remove R1Pro for testing if we detect such GPU is being used.
252+
if robot_cfg["model"] == "r1pro":
253+
print(
254+
f"Skipping testing for {robot_cfg['model']} on cuda architecture 12.0 GPU due to cuRobo embodiment compatibility issues."
255+
)
256+
continue
247257
cfg["robots"] = [robot_cfg]
248258

249259
env = og.Environment(configs=cfg)
@@ -284,7 +294,7 @@ def test_curobo():
284294
debug=False,
285295
use_cuda_graph=True,
286296
collision_activation_distance=0.075, # Use larger activation distance for better reproducibility
287-
use_default_embodiment_only=True,
297+
use_default_embodiment_only=False,
288298
)
289299

290300
# Sample values for robot

0 commit comments

Comments
 (0)