Skip to content

Commit fa92933

Browse files
AntoineRichardisaaclab-bot[bot]
authored andcommitted
Use solver-reported accelerations and track runtime gravity in PhysX and OvPhysX IMU/PVA sensors (#7416)
# Description Three related defects in the IMU and PVA sensors, across PhysX and OvPhysX. They were originally split across this PR and #7538 (now closed as superseded); they are combined here because they touch the same kernels and could not be reviewed or merged independently. ## 1. Accelerations were finite-differenced (#1294) Both sensors computed linear acceleration by finite-differencing body velocity between updates. This made the reading depend on the sensor update period, produced a zero or stale reading on the first update, and generated large spurious spikes whenever velocities were written directly (resets, teleports). **PhysX**: the sensors now read `RigidBodyView.get_accelerations()` and transport it to the sensor frame as `a_sensor = a_com + α×r + ω×(ω×r)`. The IMU adds the gravity bias; PVA does not, since PVA reports kinematic acceleration. **OvPhysX**: the sensors read accelerations through the `RIGID_BODY_ACCELERATION` tensor binding with the same transport math. An earlier revision of this PR guarded that behind `hasattr(TT, "RIGID_BODY_ACCELERATION")` and fell back to finite differencing, because the binding had not shipped yet. It has since shipped and the project pins `ovphysx==0.5.11` exactly, so the fallback was unreachable on every supported install and has been removed along with its duplicate kernels and previous-velocity state. This also aligns PhysX and OvPhysX with Newton, whose PVA already computed acceleration from `body_qdd` with exactly this transport. ### `get_accelerations()` accuracy Verified on Isaac Sim 6.0.1 with a constant applied force (expected `a = F/m`): | mass | solver acc | expected | rel. err | |---|---|---|---| | 1 kg | 0.00199992 | 0.002 | 0.004% | | 1 g | 2.00004 | 2.0 | 0.002% | | 1 µg | 2000.0 | 2000.0 | <0.001% | The historical small-mass inaccuracy that motivated the finite-difference implementation is no longer present. ## 2. `OvPhysxManager.get_gravity()` returned a stale value `set_gravity()` authored the new gravity into OvStage and applied it to the running simulation, but `get_gravity()` read `SimulationCfg.gravity`, which the setter never touched. Every call after a live update returned the construction-time value, silently and permanently: ``` get_gravity before set : (0.0, 0.0, -9.81) set_gravity called with: (0.0, 0.0, -3.72) get_gravity after set : (0.0, 0.0, -9.81) ``` The manager now tracks the applied gravity rather than writing back to `cfg.gravity`. Writing back would have been wrong: both `_call_physx` and `_call_ovphysx` in `randomize_physics_scene_gravity` resample from `env.sim.cfg.gravity` as the pristine base, so mutating it would make successive `"add"`/`"scale"` randomizations compound. ## 3. Sensors snapshotted gravity at initialization IMU and PVA read gravity once in `_initialize_impl` and baked it into a static buffer, so gravity randomized at runtime never reached the accelerometer bias or the projected gravity direction. This affected **both** backends and was independent of defect 2 — fixing `get_gravity()` alone would not have changed sensor behavior. Both sensors now re-read scene gravity on every update, skipping the work when it is unchanged. This matters more after change 1, not less: the IMU reading is now literally `solver_a + (−g)`, so a stale `g` enters as a clean additive bias. Randomizing to Mars gravity made a resting body read +9.81 instead of +3.72 — a systematic 6.09 m/s² offset on every sample. Gravity is scene-wide on both backends, so the bias and the gravity direction are passed to the kernels **by value** rather than as per-body buffers. The PhysX recorded launches re-bind the parameter with `set_param_by_name` when it changes, mirroring how `env_mask` is already handled. If per-env gravity ever reaches these backends these go back to arrays, as Newton already does. ## Breaking change The PhysX PVA sensor's `GRAVITY_VEC_W` proxy array becomes the internal `_gravity_vec_w` scene-wide vector, matching what the OvPhysX PVA sensor already called it. It was absent from the data class, the type stubs and the docs. Consumers wanting this quantity should read `pva_sensor.data.projected_gravity_b`. **The identically-named attribute on the asset data classes is untouched.** ## Known remaining gaps (not addressed here) - `GRAVITY_VEC_W` is still snapshotted at construction in the **asset** data classes (`rigid_object_data.py`, `rigid_object_collection_data.py`, `articulation_data.py`) for both backends. Newton fixed its three by binding `ProxyArray(model.gravity[:world_count])` zero-copy, which is not possible here: OvPhysX exposes no scene-gravity tensor binding, and PhysX exposes gravity only as a host-side `Float3`. A fix must use the same pull-based refresh used here, and first needs a decision on whether to converge PhysX/OV onto Newton's m/s² convention (they currently store a normalized direction), which would touch consumers in `isaaclab_experimental` and `isaaclab_tasks_experimental`. - Newton's `Imu` applies no gravity bias at all, unlike the PhysX and OvPhysX IMUs. This looks like a cross-backend behavioral gap rather than a staleness bug. Fixes #1294 ## Type of change - Bug fix (non-breaking change which fixes an issue) - Breaking change (existing functionality will not work without user modification) - Documentation update ## Release backport - [x] <!-- backport-active-release --> Backport this pull request to the active release branch after it merges into `develop` ## Screenshots Not applicable — no visual change. ## Checklist Docker and GPU tests run on demand. Push the commits you want tested, then comment `run-ci` on the pull request. - [x] I have read and understood the [contribution guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html) - [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format` - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] I have added a changelog fragment under `source/<pkg>/changelog.d/` for every touched package (do **not** edit `CHANGELOG.rst` or bump `extension.toml` — CI handles that) - [x] I have added my name to the `CONTRIBUTORS.md` or my name already exists there ## Testing All suites run locally, one file at a time: | Suite | Result | |---|---| | `isaaclab_physx` IMU | 11 passed | | `isaaclab_physx` PVA | 11 passed | | `isaaclab_physx` recorded-launch | 13 passed | | `isaaclab_ov` IMU (default / `-k cuda`) | 12 passed, 14 skipped / 12 passed | | `isaaclab_ov` PVA (default / `-k cuda`) | 13 passed, 15 skipped / 13 passed | | `isaaclab_ov` physics | 53 passed | Regression coverage, each verified to fail without its fix: - `test_set_gravity_writes_and_releases_ovstage_control_resources` — asserts `get_gravity()` round-trips after a successful `set_gravity()`, still reports the previously applied value when the OvStage write fails, and leaves `cfg.gravity` untouched as the randomization base. Without the fix: `assert (0.0, 0.0, -9.81) == approx((0.0, 0.0, -3.72))`, reproducing the reported symptom. - `test_sensor_tracks_runtime_gravity_changes` and `test_imu_replayed_launch_applies_new_gravity_bias` — a mid-run gravity change must reach the *replayed* recorded launch, with an explicit guard that the test is on the recorded path rather than the eager fallback. - `test_velocity_writes_do_not_produce_spurious_acceleration` (IMU and PVA) — velocity teleports must not produce an acceleration spike. Without the fix the PVA case fails with a `99.9998` difference, exactly the `0.1 / dt = 100 m/s²` finite-difference artifact. The OvPhysX IMU tests were updated where they encoded finite-difference artifacts as expected values — most notably `test_gravity_at_rest`, whose old scenario never had the ball at rest (it fell continuously while zero velocity was rewritten each step). It now applies a real support force so the body is genuinely at rest and the accelerometer reads the bias alone, as a real IMU on a table does. --------- Co-authored-by: Kelly Guo <kellyg@nvidia.com> (cherry picked from commit 2d88d27)
1 parent 21b60f9 commit fa92933

21 files changed

Lines changed: 597 additions & 368 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Fixed
2+
^^^^^
3+
4+
* Fixed the :class:`~isaaclab.sensors.BasePva` documentation stating that accelerations may be
5+
computed by numerically differentiating velocities and that accuracy depends on the physics
6+
timestep. Every backend now reads accelerations directly from the solver.

source/isaaclab/isaaclab/sensors/pva/base_pva.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ class BasePva(SensorBase):
3030
3131
.. note::
3232
33-
Depending on the backend, accelerations may be computed via numerical differentiation of velocities
34-
or read directly from the solver. For numerical backends, accuracy depends on the physics timestep;
35-
we recommend at least 200 Hz.
33+
Accelerations are read directly from the physics solver on every backend and transported
34+
from the body center of mass to the sensor frame, so they do not depend on the sensor
35+
update period.
3636
3737
.. note::
3838
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Changed
2+
^^^^^^^
3+
4+
* Changed the IMU and PVA sensors to read rigid-body accelerations from the solver through the
5+
``RIGID_BODY_ACCELERATION`` tensor binding, including the transport terms for the sensor offset
6+
from the center of mass, instead of finite-differencing the body velocity between updates. The
7+
reported acceleration is available from the first update, is independent of the sensor update
8+
period, and no longer spikes when velocities are written directly (for example on environment
9+
resets or teleports).
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Fixed
2+
^^^^^
3+
4+
* Fixed :meth:`~isaaclab_ov.physics.OvPhysxManager.get_gravity` returning the construction-time
5+
gravity after :meth:`~isaaclab_ov.physics.OvPhysxManager.set_gravity` changed the running scene.
6+
The manager now tracks the applied gravity vector, while ``SimulationCfg.gravity`` stays the
7+
nominal value that randomization terms resample from.
8+
* Fixed :class:`~isaaclab_ov.sensors.Imu` and :class:`~isaaclab_ov.sensors.Pva` reporting gravity
9+
captured at sensor initialization. Both sensors now re-read the scene gravity on every update, so
10+
runtime randomization through :func:`~isaaclab.envs.mdp.events.randomize_physics_scene_gravity`
11+
is reflected in the accelerometer bias and the projected gravity direction.

source/isaaclab_ov/isaaclab_ov/physics/ovphysx_manager.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,10 @@ class OvPhysxManager(PhysicsManager):
417417
_pending_clones: ClassVar[list[tuple[str, list[str], list[CloneTransform]]]] = []
418418
_atexit_registered: ClassVar[bool] = False
419419
_scene_data_backend: ClassVar[OvPhysxSceneDataBackend | None] = None
420+
# Gravity currently applied to the running scene [m/s^2]. Seeded from ``SimulationCfg.gravity``
421+
# in :meth:`initialize` and refreshed by :meth:`set_gravity`. ``cfg.gravity`` stays the nominal
422+
# value that randomization terms resample from, so live updates must not be written back to it.
423+
_gravity: ClassVar[tuple[float, float, float] | None] = None
420424

421425
@classmethod
422426
def get_dt(cls) -> float:
@@ -522,6 +526,7 @@ def initialize(cls, sim_context: SimulationContext) -> None:
522526
"""
523527
super().initialize(sim_context)
524528
cls._ensure_physx_schemas_registered()
529+
cls._gravity = tuple(sim_context.cfg.gravity)
525530
cls._warmup_done = False
526531
cls._requires_full_stage = False
527532
cls._stage_usda = None
@@ -688,17 +693,20 @@ def get_physx_instance(cls) -> Any:
688693

689694
@classmethod
690695
def get_gravity(cls) -> tuple[float, float, float]:
691-
"""Return the world-frame gravity vector [m/s^2] from the active simulation cfg.
696+
"""Return the world-frame gravity vector [m/s^2] currently applied to the scene.
692697
693698
Mirrors PhysX's ``SimulationView.get_gravity()`` so backend-agnostic sensor code
694-
can read gravity through one classmethod.
699+
can read gravity through one classmethod. The value tracks :meth:`set_gravity`,
700+
falling back to the simulation cfg until the first live update.
695701
696702
Raises:
697703
RuntimeError: If no simulation is active. Call :meth:`initialize` first.
698704
"""
699705
if cls._sim is None or not hasattr(cls._sim, "cfg"):
700706
raise RuntimeError("OvPhysxManager has not been initialized yet.")
701-
return cls._sim.cfg.gravity
707+
if cls._gravity is None:
708+
return tuple(cls._sim.cfg.gravity)
709+
return cls._gravity
702710

703711
@classmethod
704712
def set_gravity(cls, gravity: tuple[float, float, float]) -> None:
@@ -745,6 +753,10 @@ def set_gravity(cls, gravity: tuple[float, float, float]) -> None:
745753
cls._ovstage.advance_write_floor(ordinal=ordinal).wait()
746754
cls._physx.update_from_ovstage(ordinal, ordinal)
747755

756+
# Only publish once the ordinal has been applied, so a failed write leaves
757+
# :meth:`get_gravity` reporting the gravity the scene is still running with.
758+
cls._gravity = (float(gravity_array[0]), float(gravity_array[1]), float(gravity_array[2]))
759+
748760
@classmethod
749761
def get_scene_data_backend(cls) -> SceneDataBackend:
750762
"""Return the SceneDataBackend for the central SceneDataProvider.

source/isaaclab_ov/isaaclab_ov/sensors/imu/imu.py

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,8 @@ class Imu(BaseImu):
4646
4747
.. note::
4848
49-
Linear acceleration is computed using numerical differentiation from
50-
velocities. Consequently, the IMU sensor accuracy depends on the chosen
51-
physics timestep. For sufficient accuracy, we recommend keeping the
52-
timestep at least 200 Hz.
49+
Linear acceleration is read from the solver and transported from the body center of
50+
mass to the sensor frame, then biased by gravity.
5351
"""
5452

5553
cfg: ImuCfg
@@ -105,15 +103,10 @@ def reset(self, env_ids: Sequence[int] | None = None, env_mask: wp.array | None
105103
env_mask,
106104
self._data._ang_vel_b,
107105
self._data._lin_acc_b,
108-
self._prev_lin_vel_w,
109106
],
110107
device=self._device,
111108
)
112109

113-
def update(self, dt: float, force_recompute: bool = False):
114-
self._dt = dt
115-
super().update(dt, force_recompute)
116-
117110
"""
118111
Implementation.
119112
"""
@@ -149,10 +142,11 @@ def _initialize_impl(self):
149142
" ancestor is unique per env."
150143
)
151144

152-
gravity = SimulationManager.get_gravity()
153-
gravity_bias = torch.tensor((-gravity[0], -gravity[1], -gravity[2]), device=self._device)
154-
gravity_bias_torch = gravity_bias.repeat(self._num_bodies, 1)
155-
self._gravity_bias_w = wp.from_torch(gravity_bias_torch.contiguous(), dtype=wp.vec3f)
145+
# Real IMUs always measure gravity, so the accelerometer is biased by -g. The scene value
146+
# can change at runtime, so it is refreshed on every update instead of snapshotted here.
147+
self._gravity_w: tuple[float, float, float] | None = None
148+
self._gravity_bias_w = wp.vec3f(0.0, 0.0, 0.0)
149+
self._refresh_gravity_bias()
156150

157151
self._initialize_buffers_impl()
158152

@@ -180,14 +174,31 @@ def _invalidate_initialize_callback(self, event) -> None:
180174
self._vel_binding = None
181175
self._com_binding = None
182176

177+
def _refresh_gravity_bias(self):
178+
"""Re-read the scene gravity so runtime randomization reaches the accelerometer bias.
179+
180+
Scene gravity is runtime-mutable (see
181+
:func:`~isaaclab.envs.mdp.events.randomize_physics_scene_gravity`) but scene-wide on
182+
this backend, so the bias is a single vector passed to the kernel by value rather than
183+
a per-body buffer.
184+
"""
185+
gravity = SimulationManager.get_gravity()
186+
gravity = (float(gravity[0]), float(gravity[1]), float(gravity[2]))
187+
if gravity == self._gravity_w:
188+
return
189+
self._gravity_w = gravity
190+
self._gravity_bias_w = wp.vec3f(-gravity[0], -gravity[1], -gravity[2])
191+
183192
def _update_buffers_impl(self, env_mask: wp.array | None = None):
184193
"""Fills the buffers of the sensor data."""
185194
env_mask = self._resolve_indices_and_mask(None, env_mask)
195+
self._refresh_gravity_bias()
186196

187197
# ``read_into`` fills the structured-dtype destination in place through a cached
188198
# float32 reinterpret of the binding's flat shape (no extra copy).
189199
self._root_view.read_into(TT.RIGID_BODY_POSE, self._transforms)
190200
self._root_view.read_into(TT.RIGID_BODY_VELOCITY, self._velocities)
201+
self._root_view.read_into(TT.RIGID_BODY_ACCELERATION, self._accelerations)
191202
# RIGID_BODY_COM_POSE is a CPU tensor type in the OVPhysX wheel.
192203
# For GPU simulations, stage on a pinned CPU buffer then copy into the kernel buffer.
193204
self._root_view.read_into(TT.RIGID_BODY_COM_POSE, self._coms_read_view)
@@ -201,13 +212,12 @@ def _update_buffers_impl(self, env_mask: wp.array | None = None):
201212
env_mask,
202213
self._transforms,
203214
self._velocities,
215+
self._accelerations,
204216
self._coms_buffer,
205217
self._offset_pos_b,
206218
self._offset_quat_b,
207219
self._gravity_bias_w,
208-
1.0 / self._dt,
209220
self._timestamp,
210-
self._prev_lin_vel_w,
211221
self._data._ang_vel_b,
212222
self._data._lin_acc_b,
213223
],
@@ -218,7 +228,7 @@ def _initialize_buffers_impl(self):
218228
"""Create buffers for storing data."""
219229
self._data.create_buffers(num_envs=self._num_bodies, device=self._device)
220230

221-
self._prev_lin_vel_w = wp.zeros(self._num_bodies, dtype=wp.vec3f, device=self._device)
231+
self._accelerations = wp.zeros(self._num_bodies, dtype=wp.spatial_vectorf, device=self._device)
222232

223233
offset_pos_torch = torch.tensor(list(self.cfg.offset.pos), device=self._device).repeat(self._num_bodies, 1)
224234
offset_quat_torch = torch.tensor(list(self.cfg.offset.rot), device=self._device).repeat(self._num_bodies, 1)

source/isaaclab_ov/isaaclab_ov/sensors/imu/kernels.py

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,86 +6,86 @@
66
import warp as wp
77

88

9+
@wp.kernel
10+
def imu_reset_kernel(
11+
env_mask: wp.array(dtype=wp.bool),
12+
out_ang_vel_b: wp.array(dtype=wp.vec3f),
13+
out_lin_acc_b: wp.array(dtype=wp.vec3f),
14+
):
15+
"""Reset the IMU sensor data.
16+
17+
Args:
18+
env_mask: Mask of environments to reset.
19+
out_ang_vel_b: Output angular velocity in the body frame.
20+
out_lin_acc_b: Output linear acceleration in the body frame.
21+
"""
22+
idx = wp.tid()
23+
if not env_mask[idx]:
24+
return
25+
26+
out_ang_vel_b[idx] = wp.vec3f(0.0, 0.0, 0.0)
27+
out_lin_acc_b[idx] = wp.vec3f(0.0, 0.0, 0.0)
28+
29+
930
@wp.kernel
1031
def imu_update_kernel(
1132
# inputs
1233
env_mask: wp.array(dtype=wp.bool),
1334
transforms: wp.array(dtype=wp.transformf),
1435
velocities: wp.array(dtype=wp.spatial_vectorf),
36+
accelerations: wp.array(dtype=wp.spatial_vectorf),
1537
coms: wp.array(dtype=wp.transformf),
1638
offset_pos_b: wp.array(dtype=wp.vec3f),
1739
offset_quat_b: wp.array(dtype=wp.quatf),
18-
gravity_bias_w: wp.array(dtype=wp.vec3f),
19-
inv_dt: wp.float32,
40+
gravity_bias_w: wp.vec3f,
2041
timestamp: wp.array(dtype=wp.float32),
21-
# inputs / outputs
22-
prev_lin_vel_w: wp.array(dtype=wp.vec3f),
2342
# outputs
2443
out_ang_vel_b: wp.array(dtype=wp.vec3f),
2544
out_lin_acc_b: wp.array(dtype=wp.vec3f),
2645
):
27-
"""Update the IMU sensor data.
46+
"""Update the IMU sensor data from solver-reported accelerations.
47+
48+
The solver reports the spatial acceleration at the body center of mass. The sensor sits at a
49+
fixed offset from the body frame, so the linear acceleration is transported to the sensor
50+
point as :math:`a_s = a_{com} + \\alpha \\times r + \\omega \\times (\\omega \\times r)`.
2851
2952
Args:
3053
env_mask: Mask of environments to update.
3154
transforms: Transforms of the bodies.
3255
velocities: Velocities of the bodies.
56+
accelerations: Spatial accelerations of the bodies at their center of mass.
3357
coms: COMs of the bodies.
3458
offset_pos_b: Offset positions of the sensors.
3559
offset_quat_b: Offset quaternions of the sensors.
36-
gravity_bias_w: Gravity bias in the world frame.
37-
inv_dt: Inverse of the time step.
60+
gravity_bias_w: Scene-wide gravity bias in the world frame [m/s^2].
3861
timestamp: Timestamp of the environment.
39-
prev_lin_vel_w: Previous linear velocity in the world frame.
4062
out_ang_vel_b: Output angular velocity in the body frame.
4163
out_lin_acc_b: Output linear acceleration in the body frame.
4264
"""
4365
idx = wp.tid()
4466
if not env_mask[idx]:
4567
return
4668

47-
# Skip envs that have not been stepped since their last reset: OVPhysX velocities still
48-
# hold pre-reset values, so the finite-difference acceleration would be spurious.
69+
# Skip envs that have not been stepped since their last reset: OVPhysX buffers still
70+
# hold pre-reset values, so the reported acceleration would be spurious.
4971
if timestamp[idx] == 0.0:
5072
return
5173

5274
body_quat = wp.transform_get_rotation(transforms[idx])
5375

54-
lin_vel_w = wp.spatial_top(velocities[idx])
5576
ang_vel_w = wp.spatial_bottom(velocities[idx])
77+
lin_acc_w = wp.spatial_top(accelerations[idx])
78+
ang_acc_w = wp.spatial_bottom(accelerations[idx])
5679

5780
com_pos_b = wp.transform_get_translation(coms[idx])
5881
lever_arm = wp.quat_rotate(body_quat, offset_pos_b[idx] - com_pos_b)
59-
lin_vel_w = lin_vel_w + wp.cross(ang_vel_w, lever_arm)
60-
lin_acc_w = (lin_vel_w - prev_lin_vel_w[idx]) * inv_dt + gravity_bias_w[idx]
82+
lin_acc_w = (
83+
lin_acc_w
84+
+ wp.cross(ang_acc_w, lever_arm)
85+
+ wp.cross(ang_vel_w, wp.cross(ang_vel_w, lever_arm))
86+
+ gravity_bias_w
87+
)
6188

6289
sensor_quat = body_quat * offset_quat_b[idx]
6390
out_ang_vel_b[idx] = wp.quat_rotate_inv(sensor_quat, ang_vel_w)
6491
out_lin_acc_b[idx] = wp.quat_rotate_inv(sensor_quat, lin_acc_w)
65-
66-
# Update previous velocity
67-
prev_lin_vel_w[idx] = lin_vel_w
68-
69-
70-
@wp.kernel
71-
def imu_reset_kernel(
72-
env_mask: wp.array(dtype=wp.bool),
73-
out_ang_vel_b: wp.array(dtype=wp.vec3f),
74-
out_lin_acc_b: wp.array(dtype=wp.vec3f),
75-
prev_lin_vel_w: wp.array(dtype=wp.vec3f),
76-
):
77-
"""Reset the IMU sensor data.
78-
79-
Args:
80-
env_mask: Mask of environments to reset.
81-
out_ang_vel_b: Output angular velocity in the body frame.
82-
out_lin_acc_b: Output linear acceleration in the body frame.
83-
prev_lin_vel_w: Previous linear velocity in the world frame.
84-
"""
85-
idx = wp.tid()
86-
if not env_mask[idx]:
87-
return
88-
89-
out_ang_vel_b[idx] = wp.vec3f(0.0, 0.0, 0.0)
90-
out_lin_acc_b[idx] = wp.vec3f(0.0, 0.0, 0.0)
91-
prev_lin_vel_w[idx] = wp.vec3f(0.0, 0.0, 0.0)

0 commit comments

Comments
 (0)