Skip to content

Commit 74fe8bd

Browse files
committed
[BUG FIX] Preserve external forces across sub-steps. (Genesis-Embodied-AI#1290)
1 parent 12c8777 commit 74fe8bd

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

genesis/engine/simulator.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ def step(self, in_backward=False):
263263
if self.cur_substep_local == 0 and not in_backward:
264264
self.save_ckpt()
265265

266+
if self.rigid_solver.is_active():
267+
self.rigid_solver._kernel_clear_external_force()
268+
266269
def _step_grad(self):
267270
for _ in range(self._substeps - 1, -1, -1):
268271

genesis/engine/solvers/rigid/rigid_solver_decomp.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1695,7 +1695,9 @@ def _func_forward_dynamics(self):
16951695
# self._func_actuation()
16961696
self._func_bias_force()
16971697
self._func_compute_qacc()
1698-
# FIXME: External forces should be cleared at the end of the step, not during substeps.
1698+
1699+
@ti.kernel
1700+
def _kernel_clear_external_force(self):
16991701
self._func_clear_external_force()
17001702

17011703
def substep(self):

tests/test_rigid_physics.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,6 +2122,55 @@ def test_urdf_mimic(show_viewer, tol):
21222122
assert_allclose(gs_qpos[-1], gs_qpos[-2], tol=tol)
21232123

21242124

2125+
@pytest.mark.required
2126+
@pytest.mark.parametrize("backend", [gs.cpu])
2127+
def test_drone_hover_same_with_and_without_substeps(show_viewer, tol):
2128+
base_rpm = 15000
2129+
scene_ref = gs.Scene(
2130+
show_viewer=show_viewer,
2131+
sim_options=gs.options.SimOptions(
2132+
dt=0.002,
2133+
substeps=1,
2134+
),
2135+
)
2136+
drone_ref = scene_ref.add_entity(
2137+
morph=gs.morphs.Drone(
2138+
file="urdf/drones/cf2x.urdf",
2139+
pos=(0, 0, 1.0),
2140+
),
2141+
)
2142+
scene_ref.build()
2143+
2144+
for _ in range(2500):
2145+
drone_ref.set_propellels_rpm([base_rpm, base_rpm, base_rpm, base_rpm])
2146+
scene_ref.step()
2147+
2148+
pos_ref = drone_ref.get_dofs_position()
2149+
2150+
scene_test = gs.Scene(
2151+
show_viewer=show_viewer,
2152+
sim_options=gs.options.SimOptions(
2153+
dt=0.01,
2154+
substeps=5,
2155+
),
2156+
)
2157+
drone_test = scene_test.add_entity(
2158+
morph=gs.morphs.Drone(
2159+
file="urdf/drones/cf2x.urdf",
2160+
pos=(0, 0, 1.0),
2161+
),
2162+
)
2163+
scene_test.build()
2164+
2165+
for _ in range(500):
2166+
drone_test.set_propellels_rpm([base_rpm, base_rpm, base_rpm, base_rpm])
2167+
scene_test.step()
2168+
2169+
pos_test = drone_test.get_dofs_position()
2170+
2171+
assert_allclose(pos_ref, pos_test, tol=tol)
2172+
2173+
21252174
@pytest.mark.required
21262175
@pytest.mark.parametrize("backend", [gs.cpu])
21272176
def test_drone_advanced(show_viewer):

0 commit comments

Comments
 (0)