Skip to content

Commit 4d1c729

Browse files
authored
[FEATURE] Add parsing of joint friction and damping for URDF files. (Genesis-Embodied-AI#1833)
1 parent 5756169 commit 4d1c729

File tree

2 files changed

+39
-15
lines changed

2 files changed

+39
-15
lines changed

genesis/utils/urdf.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,6 @@ def parse_urdf(morph, surface):
218218
j_info["n_qs"] = 1
219219
j_info["n_dofs"] = 1
220220
j_info["init_qpos"] = np.zeros(1)
221-
222221
elif joint.joint_type == "continuous":
223222
j_info["dofs_motion_ang"] = np.array([joint.axis])
224223
j_info["dofs_motion_vel"] = np.zeros((1, 3))
@@ -229,7 +228,6 @@ def parse_urdf(morph, surface):
229228
j_info["n_qs"] = 1
230229
j_info["n_dofs"] = 1
231230
j_info["init_qpos"] = np.zeros(1)
232-
233231
elif joint.joint_type == "prismatic":
234232
j_info["dofs_motion_ang"] = np.zeros((1, 3))
235233
j_info["dofs_motion_vel"] = np.array([joint.axis])
@@ -247,7 +245,6 @@ def parse_urdf(morph, surface):
247245
j_info["n_qs"] = 1
248246
j_info["n_dofs"] = 1
249247
j_info["init_qpos"] = np.zeros(1)
250-
251248
elif joint.joint_type == "floating":
252249
j_info["dofs_motion_ang"] = np.eye(6, 3, -3)
253250
j_info["dofs_motion_vel"] = np.eye(6, 3)
@@ -258,28 +255,30 @@ def parse_urdf(morph, surface):
258255
j_info["n_qs"] = 7
259256
j_info["n_dofs"] = 6
260257
j_info["init_qpos"] = np.concatenate([gu.zero_pos(), gu.identity_quat()])
261-
262258
else:
263259
gs.raise_exception(f"Unsupported URDF joint type: {joint.joint_type}")
264260

265-
j_info["dofs_invweight"] = np.full((j_info["n_dofs"],), fill_value=-1.0)
266-
j_info["dofs_frictionloss"] = np.zeros(j_info["n_dofs"])
267261
j_info["sol_params"] = gu.default_solver_params()
268-
j_info["dofs_kp"] = gu.default_dofs_kp(j_info["n_dofs"])
269-
j_info["dofs_kv"] = gu.default_dofs_kv(j_info["n_dofs"])
270-
j_info["dofs_force_range"] = np.tile([-np.inf, np.inf], (j_info["n_dofs"], 1))
262+
j_info["dofs_invweight"] = np.full((j_info["n_dofs"],), fill_value=-1.0)
271263

272-
j_info["dofs_damping"] = np.zeros(j_info["n_dofs"])
264+
joint_friction, joint_damping = 0.0, 0.0
265+
if joint.dynamics is not None:
266+
joint_friction, joint_damping = joint.dynamics.friction, joint.dynamics.damping
267+
j_info["dofs_frictionloss"] = np.full(j_info["n_dofs"], joint_friction)
268+
j_info["dofs_damping"] = np.full(j_info["n_dofs"], joint_damping)
273269
j_info["dofs_armature"] = np.zeros(j_info["n_dofs"])
274270
if joint.joint_type not in ("floating", "fixed") and morph.default_armature is not None:
275271
j_info["dofs_armature"] = np.full((j_info["n_dofs"],), morph.default_armature)
276272

273+
j_info["dofs_kp"] = gu.default_dofs_kp(j_info["n_dofs"])
274+
j_info["dofs_kv"] = gu.default_dofs_kv(j_info["n_dofs"])
277275
if joint.safety_controller is not None:
278276
if joint.safety_controller.k_position is not None:
279277
j_info["dofs_kp"] = np.tile(joint.safety_controller.k_position, j_info["n_dofs"])
280278
if joint.safety_controller.k_velocity is not None:
281279
j_info["dofs_kv"] = np.tile(joint.safety_controller.k_velocity, j_info["n_dofs"])
282280

281+
j_info["dofs_force_range"] = np.tile([-np.inf, np.inf], (j_info["n_dofs"], 1))
283282
if joint.limit is not None and joint.limit.effort is not None:
284283
j_info["dofs_force_range"] = np.tile([-joint.limit.effort, joint.limit.effort], (j_info["n_dofs"], 1))
285284

tests/test_rigid_physics.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def chain_capsule_hinge_capsule(asset_tmp_path):
222222
return _build_chain_capsule_hinge(asset_tmp_path, enable_mesh=False)
223223

224224

225-
def _build_multi_pendulum(n):
225+
def _build_multi_pendulum(n, joint_damping, joint_friction):
226226
"""Generate an URDF model of a multi-link pendulum with n segments."""
227227
urdf = ET.Element("robot", name="multi_pendulum")
228228

@@ -238,6 +238,7 @@ def _build_multi_pendulum(n):
238238
ET.SubElement(joint, "parent", link=parent_link)
239239
ET.SubElement(joint, "child", link=f"PendulumArm_{i}")
240240
ET.SubElement(joint, "limit", effort=str(100.0 * (n - i)), velocity="30.0")
241+
ET.SubElement(joint, "dynamics", damping=str(joint_damping), friction=str(joint_friction))
241242

242243
# Arm link
243244
arm = ET.SubElement(urdf, "link", name=f"PendulumArm_{i}")
@@ -276,14 +277,19 @@ def _build_multi_pendulum(n):
276277
return urdf
277278

278279

280+
@pytest.fixture
281+
def pendulum_with_joint_dynamics(joint_damping, joint_friction):
282+
return _build_multi_pendulum(n=1, joint_damping=joint_damping, joint_friction=joint_friction)
283+
284+
279285
@pytest.fixture(scope="session")
280-
def pendulum(asset_tmp_path):
281-
return _build_multi_pendulum(n=1)
286+
def pendulum():
287+
return _build_multi_pendulum(n=1, joint_damping=0.0, joint_friction=0.0)
282288

283289

284290
@pytest.fixture(scope="session")
285-
def double_pendulum(asset_tmp_path):
286-
return _build_multi_pendulum(n=2)
291+
def double_pendulum():
292+
return _build_multi_pendulum(n=2, joint_damping=0.0, joint_friction=0.0)
287293

288294

289295
@pytest.fixture(scope="session")
@@ -2302,6 +2308,25 @@ def test_urdf_mimic(show_viewer, tol):
23022308
assert_allclose(gs_qpos[-1], gs_qpos[-2], tol=tol)
23032309

23042310

2311+
@pytest.mark.required
2312+
@pytest.mark.parametrize("model_name", ["pendulum_with_joint_dynamics"])
2313+
@pytest.mark.parametrize("joint_damping, joint_friction", [(1.0, 2.0)])
2314+
@pytest.mark.parametrize("backend", [gs.cpu])
2315+
def test_urdf_joint_dynamics(joint_damping, joint_friction, xml_path):
2316+
scene = gs.Scene()
2317+
robot = scene.add_entity(
2318+
gs.morphs.URDF(
2319+
file=xml_path,
2320+
pos=(0, 0, 0.8),
2321+
convexify=True,
2322+
),
2323+
)
2324+
assert_allclose(robot.joints[0].dofs_damping, 0.0, tol=gs.EPS)
2325+
assert_allclose(robot.joints[1].dofs_damping, joint_damping, tol=gs.EPS)
2326+
assert_allclose(robot.joints[0].dofs_frictionloss, 0.0, tol=gs.EPS)
2327+
assert_allclose(robot.joints[1].dofs_frictionloss, joint_friction, tol=gs.EPS)
2328+
2329+
23052330
@pytest.mark.required
23062331
@pytest.mark.parametrize("backend", [gs.cpu])
23072332
def test_gravity(show_viewer, tol):

0 commit comments

Comments
 (0)