Repository navigation
[Bug Report] Sensors return their reset values for an extra update period when read right after a reset #8652
Description
Describe the bug
Since #5782 (for #4970), the Isaac Sim PhysX and Newton update kernels of ContactSensor, Imu, Pva and
JointWrenchSensor (eight kernels) skip environments whose timestamp is still 0, i.e. not stepped since their
reset. The OVPhysX Imu, Pva and JointWrenchSensor kernels have the same guard (#5421, #5702, #5706). A read
between scene.reset(env_ids) and the next physics step therefore returns the reset values instead of pre-reset
physics data, as intended.
SensorBase still counts that read as an update. _update_outdated_buffers calls _mark_buffers_updated
(source/isaaclab/isaaclab/sensors/sensor_base.py:442-458), whose update_outdated_envs_kernel
(source/isaaclab/isaaclab/sensors/kernels.py:38-57) clears is_outdated for these environments although nothing
was captured, so they are not captured again before their update period elapses. With an update_period longer
than the time to the next read, the following reads return the reset values for one more full update period.
#5782 describes the outdated flag as re-armed "at the sensor's configured update period" and states that "the
next step's read pulls fresh post-reset physics data". With an update period longer than the time to the next
read, the two do not agree, and which one holds depends on whether something read the sensor right after the
reset. With that read, the reset values are returned until the update period elapses. Without it, the reset leaves
the environment outdated, so the first env step after the reset returns physics data.
ManagerBasedRLEnv.step and DirectRLEnv.step compute the observations right after _reset_idx
(manager_based_rl_env.py:252 and :282, direct_rl_env.py:430 and :468), so this read happens on every
environment reset.
- Affected: every sensor whose update kernel has the
timestamp == 0guard, i.e.ContactSensor(Isaac Sim PhysX,
Newton) andImu,Pva,JointWrenchSensor(Isaac Sim PhysX, Newton, OVPhysX). - Not affected: ray casters, frame transformers and cameras, which capture at that read.
- With the default
update_period = 0the next physics step makes the sensor due again, so there is no effect.
The official tasks that use these sensors keep periods of at most one env step.
Steps to reproduce
A cube rests on the ground with an IMU whose update period is two env steps (decimation 2, dt 0.005 s). The
loop mirrors ManagerBasedRLEnv.step. The second reset is followed by a read before the next physics step.
"""A read right after ``scene.reset()`` delays the next sensor update by a full update period.
A cube rests on the ground with an IMU whose update period is two env steps. The loop mirrors
``ManagerBasedRLEnv.step``: ``decimation`` physics steps, then a read. The second reset is followed by a
read before the next physics step, as the observations computed right after ``_reset_idx`` do.
usage: python repro_skipped_capture_after_reset.py --physics {isaacsim_physx,newton_mjwarp,ovphysx}
"""
import argparse
from isaaclab.app import add_launcher_args, launch_simulation
parser = argparse.ArgumentParser()
parser.add_argument("--physics", default="isaacsim_physx", choices=["isaacsim_physx", "newton_mjwarp", "ovphysx"])
add_launcher_args(parser)
args_cli = parser.parse_args()
import torch
import isaaclab.sim as sim_utils
from isaaclab.assets import RigidObjectCfg
from isaaclab.physics import PhysicsCfg
from isaaclab.scene import InteractiveSceneCfg
from isaaclab.sensors import ImuCfg
from isaaclab.terrains import TerrainImporterCfg
from isaaclab.utils import configclass
DT = 0.005
DECIMATION = 2
@configclass
class SceneCfg(InteractiveSceneCfg):
terrain = TerrainImporterCfg(prim_path="/World/ground", terrain_type="plane")
cube = RigidObjectCfg(
prim_path="{ENV_REGEX_NS}/Cube",
spawn=sim_utils.CuboidCfg(
size=(0.2, 0.2, 0.2),
rigid_props=sim_utils.UsdPhysicsRigidBodyCfg(),
mass_props=sim_utils.MassCfg(mass=1.0),
collision_props=sim_utils.UsdPhysicsCollisionCfg(),
),
init_state=RigidObjectCfg.InitialStateCfg(pos=(0.0, 0.0, 0.1)),
)
# update period of two env steps (four physics steps)
imu = ImuCfg(prim_path="{ENV_REGEX_NS}/Cube", update_period=2 * DECIMATION * DT)
with launch_simulation(PhysicsCfg(), args_cli) as physics_cfg:
from isaaclab.scene import InteractiveScene
from isaaclab.sim import SimulationContext
sim = SimulationContext(sim_utils.SimulationCfg(dt=DT, device=args_cli.device, physics=physics_cfg))
scene = InteractiveScene(SceneCfg(num_envs=1, env_spacing=2.0))
sim.reset()
imu = scene["imu"]
def env_step():
for _ in range(DECIMATION):
scene.write_data_to_sim()
sim.step(render=False)
scene.update(DT)
def acc() -> float:
return torch.linalg.norm(imu.data.lin_acc_b.torch[0]).item()
for _ in range(50): # let the cube settle, reading every env step
env_step()
acc()
print(f"[{args_cli.physics}] resting cube: |lin_acc_b| = {acc():.2f}")
scene.reset() # no read before the next env step
env_step()
print(f"[{args_cli.physics}] reset, no read: after 1 env step = {acc():.2f}")
for _ in range(10):
env_step()
acc()
scene.reset()
right_after = acc() # the observations read right after the reset
env_step()
first = acc()
env_step()
second = acc()
print(
f"[{args_cli.physics}] reset, read right away: {right_after:.2f}, after 1 env step = {first:.2f},"
f" after 2 env steps = {second:.2f}"
)Actual (develop):
[isaacsim_physx] resting cube: |lin_acc_b| = 9.81
[isaacsim_physx] reset, no read: after 1 env step = 9.81
[isaacsim_physx] reset, read right away: 0.00, after 1 env step = 0.00, after 2 env steps = 9.81
[newton_mjwarp] resting cube: |lin_acc_b| = 9.81
[newton_mjwarp] reset, no read: after 1 env step = 9.81
[newton_mjwarp] reset, read right away: 0.00, after 1 env step = 0.00, after 2 env steps = 9.81
[ovphysx] resting cube: |lin_acc_b| = 9.81
[ovphysx] reset, no read: after 1 env step = 9.81
[ovphysx] reset, read right away: 0.00, after 1 env step = 0.00, after 2 env steps = 9.81
Expected on every backend: after 1 env step = 9.81 in both reset cases, as without the read.
The other guarded sensors behave the same. Extended version of the script: two envs, a floating two-body
articulation with one revolute joint and a JointWrenchSensor, the cube resting on its side (so its projected
gravity differs from the reset value), every sensor with update_period = 2 * step_dt, and env 0 reset in place
with scene.reset([0]):
| Env 0, first env step after the reset: with the read / without it | Isaac Sim PhysX | Newton | OVPhysX |
|---|---|---|---|
JointWrenchSensor, force norm of the revolute joint [N] |
0.00 / 2.01 | 0.00 / 4.91 | 0.00 / 2.35 |
ContactSensor (history_length=3), normal force [N] |
0.00 / 9.81 | 0.00 / 9.81 | no guard (1) |
Pva, projected gravity |
(0, 0, -1) / (0, -1, 0) | (0, 0, -1) / (0, -1, 0) | (0, 0, -1) / (0, -1, 0) |
Imu, linear acceleration norm [m/s^2] |
0.00 / 9.81 | 0.00 / 9.81 | 0.00 / 9.81 |
(1) The OVPhysX ContactSensor has no timestamp == 0 guard, so it is not affected; it returns the pre-reset
forces at that read instead, which is reported separately.
System Info
- Commit: b9a673a and 06f2d42 (develop); the sensor code is unchanged on develop fa7ef08
- Isaac Sim Version: 6.1.0 (Isaac Sim PhysX); the PhysX output is the same with Isaac Sim 6.2.0 on develop 9b6d2d8
(environment synced from itsuv.lock); Newton at develop's pin (5ea82eef, MuJoCo Warp 3.14); OVPhysX 0.6.4 - OS: Ubuntu 24.04
- GPU: NVIDIA RTX PRO 5000 Blackwell
- CUDA: 13.0
- GPU Driver: 580.126.20
Additional context
release/3.0.0 (6bfde87) behaves the same: its clock is older (timestamp - timestamp_last_update), but
update_outdated_envs_kernel clears is_outdated in the same way.
Checklist
- I have checked that there is no similar issue in the repo (required)
- I have checked that the issue is not in running Isaac Sim itself and is related to the repo
Acceptance Criteria
- After a read between
scene.reset(env_ids)and the next physics step that skips the capture, the first read
after the next physics step returns physics data. - The later updates of these sensors happen at the same steps as before.
- Sensors that capture right after a reset (ray casters, frame transformers, cameras) do not refresh again
before their update period elapses.
Activity
RandomOakForest commentedon Oct 16, 2026
Thank you for posting this and adding the PR. The team will review it.
Fix sensor freshness, reset cadence, and native coverage (isaac-sim#8780