# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import warp as wp
from isaaclab.sensors.pva import BasePvaData
from isaaclab.utils.warp import ProxyArray
from isaaclab_ov.sensors.kernels import concat_pos_and_quat_to_pose_1d_kernel
[docs]
class PvaData(BasePvaData):
"""Data container for the OVPhysX PVA sensor."""
@property
def pose_w(self) -> ProxyArray:
"""Pose of the sensor origin in world frame [m, unitless].
Shape is (num_instances,), dtype = wp.transformf. In torch this resolves to (num_instances, 7).
The pose is provided in (x, y, z, qx, qy, qz, qw) format.
"""
wp.launch(
concat_pos_and_quat_to_pose_1d_kernel,
dim=self._num_envs,
inputs=[self._pos_w, self._quat_w],
outputs=[self._pose_w],
device=self._device,
)
if self._pose_w_ta is None:
self._pose_w_ta = ProxyArray(self._pose_w)
return self._pose_w_ta
@property
def pos_w(self) -> ProxyArray:
"""Position of the sensor origin in world frame [m].
Shape is (num_instances,), dtype = wp.vec3f. In torch this resolves to (num_instances, 3).
"""
if self._pos_w_ta is None:
self._pos_w_ta = ProxyArray(self._pos_w)
return self._pos_w_ta
@property
def quat_w(self) -> ProxyArray:
"""Orientation of the sensor origin in world frame.
Shape is (num_instances,), dtype = wp.quatf. In torch this resolves to (num_instances, 4).
The orientation is provided in (x, y, z, w) format.
"""
if self._quat_w_ta is None:
self._quat_w_ta = ProxyArray(self._quat_w)
return self._quat_w_ta
@property
def projected_gravity_b(self) -> ProxyArray:
"""Gravity direction unit vector projected on the PVA frame [unitless].
Shape is (num_instances,), dtype = wp.vec3f. In torch this resolves to (num_instances, 3).
"""
if self._projected_gravity_b_ta is None:
self._projected_gravity_b_ta = ProxyArray(self._projected_gravity_b)
return self._projected_gravity_b_ta
@property
def lin_vel_b(self) -> ProxyArray:
"""PVA frame linear velocity relative to the world expressed in PVA frame [m/s].
Shape is (num_instances,), dtype = wp.vec3f. In torch this resolves to (num_instances, 3).
"""
if self._lin_vel_b_ta is None:
self._lin_vel_b_ta = ProxyArray(self._lin_vel_b)
return self._lin_vel_b_ta
@property
def ang_vel_b(self) -> ProxyArray:
"""PVA frame angular velocity relative to the world expressed in PVA frame [rad/s].
Shape is (num_instances,), dtype = wp.vec3f. In torch this resolves to (num_instances, 3).
"""
if self._ang_vel_b_ta is None:
self._ang_vel_b_ta = ProxyArray(self._ang_vel_b)
return self._ang_vel_b_ta
@property
def lin_acc_b(self) -> ProxyArray:
"""Linear acceleration (coordinate) in the PVA frame [m/s^2].
Equal to ``-g`` in freefall, zero at rest.
Shape is (num_instances,), dtype = wp.vec3f. In torch this resolves to (num_instances, 3).
"""
if self._lin_acc_b_ta is None:
self._lin_acc_b_ta = ProxyArray(self._lin_acc_b)
return self._lin_acc_b_ta
@property
def ang_acc_b(self) -> ProxyArray:
"""PVA frame angular acceleration relative to the world expressed in PVA frame [rad/s^2].
Shape is (num_instances,), dtype = wp.vec3f. In torch this resolves to (num_instances, 3).
"""
if self._ang_acc_b_ta is None:
self._ang_acc_b_ta = ProxyArray(self._ang_acc_b)
return self._ang_acc_b_ta
def create_buffers(self, num_envs: int, device: str) -> None:
"""Create internal buffers for sensor data.
Args:
num_envs: Number of environments.
device: Device for tensor storage.
"""
self._num_envs = num_envs
self._device = device
self._pose_w = wp.zeros(num_envs, dtype=wp.transformf, device=device)
self._pos_w = wp.zeros(num_envs, dtype=wp.vec3f, device=device)
self._quat_w = wp.zeros(num_envs, dtype=wp.quatf, device=device)
# Initialize quaternion to identity (w=1): warp quatf is (x,y,z,w)
# Use torch interop to set the w component
quat_torch = wp.to_torch(self._quat_w)
quat_torch[:, 3] = 1.0
self._projected_gravity_b = wp.zeros(num_envs, dtype=wp.vec3f, device=device)
# Initialize projected gravity to (0, 0, -1)
pg_torch = wp.to_torch(self._projected_gravity_b)
pg_torch[:, 2] = -1.0
self._lin_vel_b = wp.zeros(num_envs, dtype=wp.vec3f, device=device)
self._ang_vel_b = wp.zeros(num_envs, dtype=wp.vec3f, device=device)
self._lin_acc_b = wp.zeros(num_envs, dtype=wp.vec3f, device=device)
self._ang_acc_b = wp.zeros(num_envs, dtype=wp.vec3f, device=device)
# -- Pinned ProxyArray cache (one per read property, lazily created on first access)
self._pose_w_ta: ProxyArray | None = None
self._pos_w_ta: ProxyArray | None = None
self._quat_w_ta: ProxyArray | None = None
self._projected_gravity_b_ta: ProxyArray | None = None
self._lin_vel_b_ta: ProxyArray | None = None
self._ang_vel_b_ta: ProxyArray | None = None
self._lin_acc_b_ta: ProxyArray | None = None
self._ang_acc_b_ta: ProxyArray | None = None