Skip to content

Commit 0aac115

Browse files
committed
Fix joint friction loss.
1 parent 75c5ed1 commit 0aac115

File tree

5 files changed

+60
-27
lines changed

5 files changed

+60
-27
lines changed

genesis/engine/solvers/rigid/constraint_solver_decomp.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,22 +1035,22 @@ def add_frictionloss_constraints(
10351035
for i_d in range(joints_info.dof_start[I_j], joints_info.dof_end[I_j]):
10361036
I_d = [i_d, i_b] if ti.static(static_rigid_sim_config.batch_dofs_info) else i_d
10371037

1038-
if dofs_info.frictionloss[I_d] > 0:
1038+
if dofs_info.frictionloss[I_d] > gs.EPS:
10391039
jac = 1.0
10401040
jac_qvel = jac * dofs_state.vel[i_d, i_b]
10411041
imp, aref = gu.imp_aref(joints_info.sol_params[I_j], 0.0, jac_qvel, 0.0)
1042-
diag = ti.max(dofs_info.invweight[I_d] * (1 - imp) / imp, gs.EPS)
1042+
diag = ti.max(dofs_info.invweight[I_d] * (1.0 - imp) / imp, gs.EPS)
10431043

1044-
n_con = constraint_state.n_constraints[i_b]
1044+
i_con = ti.atomic_add(constraint_state.n_constraints[i_b], 1)
10451045
ti.atomic_add(constraint_state.n_constraints_frictionloss[i_b], 1)
1046-
constraint_state.n_constraints[i_b] = n_con + 1
1047-
constraint_state.diag[n_con, i_b] = diag
1048-
constraint_state.aref[n_con, i_b] = aref
1049-
constraint_state.efc_D[n_con, i_b] = 1 / diag
1050-
constraint_state.efc_frictionloss[n_con, i_b] = dofs_info.frictionloss[I_d]
1046+
1047+
constraint_state.diag[i_con, i_b] = diag
1048+
constraint_state.aref[i_con, i_b] = aref
1049+
constraint_state.efc_D[i_con, i_b] = 1.0 / diag
1050+
constraint_state.efc_frictionloss[i_con, i_b] = dofs_info.frictionloss[I_d]
10511051
for i_d2 in range(n_dofs):
1052-
constraint_state.jac[n_con, i_d2, i_b] = gs.ti_float(0.0)
1053-
constraint_state.jac[n_con, i_d, i_b] = jac
1052+
constraint_state.jac[i_con, i_d2, i_b] = gs.ti_float(0.0)
1053+
constraint_state.jac[i_con, i_d, i_b] = jac
10541054

10551055

10561056
@ti.func
@@ -1430,19 +1430,21 @@ def func_ls_point_fn(
14301430
alpha,
14311431
constraint_state: array_class.ConstraintState,
14321432
):
1433+
ne = constraint_state.n_constraints_equality[i_b]
1434+
nef = ne + constraint_state.n_constraints_frictionloss[i_b]
1435+
14331436
tmp_quad_total_0, tmp_quad_total_1, tmp_quad_total_2 = gs.ti_float(0.0), gs.ti_float(0.0), gs.ti_float(0.0)
14341437
tmp_quad_total_0 = constraint_state.quad_gauss[0, i_b]
14351438
tmp_quad_total_1 = constraint_state.quad_gauss[1, i_b]
14361439
tmp_quad_total_2 = constraint_state.quad_gauss[2, i_b]
14371440
for i_c in range(constraint_state.n_constraints[i_b]):
14381441
x = constraint_state.Jaref[i_c, i_b] + alpha * constraint_state.jv[i_c, i_b]
1439-
active = 1
1440-
ne = constraint_state.n_constraints_equality[i_b]
1441-
nef = ne + constraint_state.n_constraints_frictionloss[i_b]
14421442
qf_0 = constraint_state.quad[i_c, 0, i_b]
14431443
qf_1 = constraint_state.quad[i_c, 1, i_b]
14441444
qf_2 = constraint_state.quad[i_c, 2, i_b]
1445-
if i_c >= ne and i_c < nef:
1445+
1446+
active = gs.ti_bool(True) # Equality constraints
1447+
if ne <= i_c and i_c < nef: # Friction constraints
14461448
f = constraint_state.efc_frictionloss[i_c, i_b]
14471449
r = 1.0 / ti.max(constraint_state.efc_D[i_c, i_b], gs.EPS)
14481450
rf = r * f
@@ -1457,7 +1459,7 @@ def func_ls_point_fn(
14571459
f * constraint_state.jv[i_c, i_b]
14581460
)
14591461
qf_2 = 0.0
1460-
elif i_c >= nef:
1462+
elif nef <= i_c: # Contact constraints
14611463
active = x < 0
14621464

14631465
tmp_quad_total_0 += qf_0 * active
@@ -1835,6 +1837,8 @@ def func_update_constraint(
18351837
static_rigid_sim_config: ti.template(),
18361838
):
18371839
n_dofs = constraint_state.qfrc_constraint.shape[0]
1840+
ne = constraint_state.n_constraints_equality[i_b]
1841+
nef = ne + constraint_state.n_constraints_frictionloss[i_b]
18381842

18391843
constraint_state.prev_cost[i_b] = cost[i_b]
18401844
cost[i_b] = gs.ti_float(0.0)
@@ -1843,11 +1847,10 @@ def func_update_constraint(
18431847
for i_c in range(constraint_state.n_constraints[i_b]):
18441848
if ti.static(static_rigid_sim_config.solver_type == gs.constraint_solver.Newton):
18451849
constraint_state.prev_active[i_c, i_b] = constraint_state.active[i_c, i_b]
1846-
constraint_state.active[i_c, i_b] = 1
1850+
constraint_state.active[i_c, i_b] = True
1851+
18471852
floss_force = gs.ti_float(0.0)
1848-
ne = constraint_state.n_constraints_equality[i_b]
1849-
nef = ne + constraint_state.n_constraints_frictionloss[i_b]
1850-
if i_c >= ne and i_c < nef:
1853+
if ne <= i_c and i_c < nef: # Friction constraints
18511854
f = constraint_state.efc_frictionloss[i_c, i_b]
18521855
r = 1.0 / ti.max(constraint_state.efc_D[i_c, i_b], gs.EPS)
18531856
rf = r * f
@@ -1858,7 +1861,7 @@ def func_update_constraint(
18581861
floss_cost_local = linear_neg * f * (-0.5 * rf - constraint_state.Jaref[i_c, i_b])
18591862
floss_cost_local += linear_pos * f * (-0.5 * rf + constraint_state.Jaref[i_c, i_b])
18601863
cost[i_b] = cost[i_b] + floss_cost_local
1861-
elif i_c >= nef:
1864+
elif nef <= i_c: # Contact constraints
18621865
constraint_state.active[i_c, i_b] = constraint_state.Jaref[i_c, i_b] < 0
18631866

18641867
constraint_state.efc_force[i_c, i_b] = floss_force + (

genesis/engine/solvers/rigid/rigid_solver_decomp.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -952,11 +952,8 @@ def _func_constraint_force(self):
952952
# from genesis.utils.tools import create_timer
953953

954954
# timer = create_timer(name="constraint_force", level=2, ti_sync=True, skip_first_call=True)
955-
if self._enable_collision or self._enable_joint_limit or self.n_equalities > 0:
956-
self.constraint_solver.constraint_state.n_constraints.fill(0)
957-
self.constraint_solver.constraint_state.n_constraints_equality.fill(0)
958-
self._func_constraint_clear()
959-
# timer.stamp("constraint_solver.clear")
955+
self._func_constraint_clear()
956+
# timer.stamp("constraint_solver.clear")
960957

961958
if self._enable_collision:
962959
self.collider.detection()
@@ -969,6 +966,7 @@ def _func_constraint_force(self):
969966
def _func_constraint_clear(self):
970967
self.constraint_solver.constraint_state.n_constraints.fill(0)
971968
self.constraint_solver.constraint_state.n_constraints_equality.fill(0)
969+
self.constraint_solver.constraint_state.n_constraints_frictionloss.fill(0)
972970
self.collider._collider_state.n_contacts.fill(0)
973971

974972
def _func_forward_dynamics(self):

genesis/utils/array_class.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def get_constraint_state(constraint_solver, solver):
184184
"efc_D": V(dtype=gs.ti_float, shape=solver._batch_shape(len_constraints_)),
185185
"efc_frictionloss": V(dtype=gs.ti_float, shape=solver._batch_shape(len_constraints_)),
186186
"efc_force": V(dtype=gs.ti_float, shape=solver._batch_shape(len_constraints_)),
187-
"active": V(dtype=gs.ti_int, shape=solver._batch_shape(len_constraints_)),
187+
"active": V(dtype=gs.ti_bool, shape=solver._batch_shape(len_constraints_)),
188188
"prev_active": V(dtype=gs.ti_int, shape=solver._batch_shape(len_constraints_)),
189189
"qfrc_constraint": V(dtype=gs.ti_float, shape=solver._batch_shape(solver.n_dofs_)),
190190
"qacc": V(dtype=gs.ti_float, shape=solver._batch_shape(solver.n_dofs_)),

tests/test_render.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def test_segmentation(segmentation_level, particle_mode):
118118

119119

120120
@pytest.mark.required
121-
@pytest.mark.flaky(reruns=3, condition=(sys.platform == "darwin"))
121+
@pytest.mark.flaky(reruns=3, condition=(sys.platform == "darwin"), reason="Flaky on MacOS with CPU-based OpenGL")
122122
def test_batched_offscreen_rendering(tmp_path, show_viewer, tol):
123123
scene = gs.Scene(
124124
vis_options=gs.options.VisOptions(
@@ -275,6 +275,7 @@ def test_batched_offscreen_rendering(tmp_path, show_viewer, tol):
275275

276276

277277
@pytest.mark.required
278+
@pytest.mark.flaky(reruns=3, condition=(sys.platform == "darwin"), reason="Flaky on MacOS with CPU-based OpenGL")
278279
def test_render_api(show_viewer):
279280
scene = gs.Scene(
280281
show_viewer=show_viewer,

tests/test_rigid_physics.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,6 +1654,37 @@ def test_mass_mat(show_viewer, tol):
16541654
assert_allclose(mass_mat, mass_mat_1, tol=tol)
16551655

16561656

1657+
@pytest.mark.required
1658+
@pytest.mark.parametrize("backend", [gs.cpu])
1659+
def test_frictionloss_advanced(show_viewer, tol):
1660+
scene = gs.Scene(
1661+
show_viewer=show_viewer,
1662+
show_FPS=False,
1663+
)
1664+
scene.add_entity(gs.morphs.Plane())
1665+
asset_path = get_hf_dataset(pattern="SO101/*")
1666+
robot = scene.add_entity(
1667+
morph=gs.morphs.MJCF(
1668+
file=f"{asset_path}/SO101/so101_new_calib.xml",
1669+
),
1670+
)
1671+
box = scene.add_entity(
1672+
gs.morphs.Box(
1673+
size=(0.025, 0.025, 0.025),
1674+
),
1675+
)
1676+
scene.build(n_envs=0)
1677+
1678+
scene.reset()
1679+
box.set_pos(torch.tensor((0.1, 0.0, 1.0), dtype=gs.tc_float, device=gs.device))
1680+
for _ in range(200):
1681+
scene.step()
1682+
1683+
assert_allclose(robot.get_contacts()["position"][:, 2].min(), 0.0, tol=1e-4)
1684+
# assert_allclose(torch.stack([geom.get_AABB() for geom in robot.geoms])[:, :, 2].min(), 0.0, tol=1e-3)
1685+
assert_allclose(box.get_dofs_velocity(), 0.0, tol=tol)
1686+
1687+
16571688
@pytest.mark.parametrize("backend", [gs.cpu])
16581689
def test_nonconvex_collision(show_viewer):
16591690
scene = gs.Scene(

0 commit comments

Comments
 (0)