Pose Velocity Acceleration (PVA) Sensor#
The Pose Velocity Acceleration (PVA) sensor is a ground-truth sensor for reading
the kinematic state of a frame in the simulation. It reports the sensor pose in
the world frame, projected gravity, linear and angular velocities in the sensor
frame, and coordinate accelerations in the sensor frame. Unlike
Imu, the PVA sensor does not model proper
acceleration from an accelerometer. Use the IMU sensor when the observation
should include accelerometer-like gravity bias behavior.
The sensor can be attached to a rigid body or to a child prim under a rigid-body ancestor. If the configured prim is not itself rigid, Isaac Lab queries the closest rigid ancestor and composes the fixed transform to the requested prim with the configured sensor offset.
Consider a simple environment with an Anymal Quadruped equipped with PVA sensors on its front feet.
# Pre-defined configs
##
from isaaclab_assets.robots.anymal import ANYMAL_C_CFG # isort: skip
@configclass
class PvaSensorSceneCfg(InteractiveSceneCfg):
"""Design the scene with sensors on the robot."""
# ground plane
ground = AssetBaseCfg(prim_path="/World/defaultGroundPlane", spawn=sim_utils.GroundPlaneCfg())
# lights
dome_light = AssetBaseCfg(
prim_path="/World/Light", spawn=sim_utils.DomeLightCfg(intensity=3000.0, color=(0.75, 0.75, 0.75))
)
Retrieving values from the sensor follows the same pattern as the other Isaac
Lab sensors. The data fields are exposed as ProxyArray
buffers and can be converted to Torch tensors with the torch property.
pva_data = scene["pva_LF"].data
print("Pose in world frame: ", pva_data.pose_w.torch)
print("Linear velocity in PVA frame: ", pva_data.lin_vel_b.torch)
print("Angular velocity in PVA frame: ", pva_data.ang_vel_b.torch)
print("Linear acceleration in PVA frame: ", pva_data.lin_acc_b.torch)
print("Angular acceleration in PVA frame: ", pva_data.ang_acc_b.torch)
print("Projected gravity in PVA frame: ", pva_data.projected_gravity_b.torch)
The complete demo can be run with:
uv run --extra isaacsim python scripts/demos/sensors/pva_sensor.py
./isaaclab.sh -p scripts/demos/sensors/pva_sensor.py
Code for pva_sensor.py
1# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
2# All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5
6"""Launch Isaac Sim Simulator first."""
7
8import argparse
9
10from isaaclab.app import AppLauncher
11
12# add argparse arguments
13parser = argparse.ArgumentParser(description="Example on using the PVA sensor.")
14parser.add_argument("--num_envs", type=int, default=1, help="Number of environments to spawn.")
15parser.add_argument(
16 "--physics",
17 default="isaacsim_physx",
18 choices=["isaacsim_physx"],
19 help="Physics backend.",
20)
21# append AppLauncher cli args
22AppLauncher.add_app_launcher_args(parser)
23# demos should open Kit visualizer by default
24parser.set_defaults(visualizer=["kit"])
25# parse the arguments
26args_cli = parser.parse_args()
27
28# launch omniverse app
29app_launcher = AppLauncher(args_cli)
30simulation_app = app_launcher.app
31
32"""Rest everything follows."""
33
34import torch
35
36import isaaclab.sim as sim_utils
37from isaaclab.assets import AssetBaseCfg
38from isaaclab.scene import InteractiveScene, InteractiveSceneCfg
39from isaaclab.sensors import PvaCfg
40from isaaclab.utils.configclass import configclass
41
42##
43# Pre-defined configs
44##
45from isaaclab_assets.robots.anymal import ANYMAL_C_CFG # isort: skip
46
47
48@configclass
49class PvaSensorSceneCfg(InteractiveSceneCfg):
50 """Design the scene with sensors on the robot."""
51
52 # ground plane
53 ground = AssetBaseCfg(prim_path="/World/defaultGroundPlane", spawn=sim_utils.GroundPlaneCfg())
54
55 # lights
56 dome_light = AssetBaseCfg(
57 prim_path="/World/Light", spawn=sim_utils.DomeLightCfg(intensity=3000.0, color=(0.75, 0.75, 0.75))
58 )
59
60 # robot
61 robot = ANYMAL_C_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
62
63 pva_LF = PvaCfg(prim_path="{ENV_REGEX_NS}/Robot/LF_FOOT", debug_vis=True)
64
65 pva_RF = PvaCfg(prim_path="{ENV_REGEX_NS}/Robot/RF_FOOT", debug_vis=True)
66
67
68def run_simulator(sim: sim_utils.SimulationContext, scene: InteractiveScene):
69 """Run the simulator."""
70 # Define simulation stepping
71 sim_dt = sim.get_physics_dt()
72 sim_time = 0.0
73 count = 0
74
75 # Simulate physics
76 while simulation_app.is_running():
77 if count % 500 == 0:
78 # reset counter
79 count = 0
80 # reset the scene entities
81 # root state
82 # we offset the root state by the origin since the states are written in simulation world frame
83 # if this is not done, then the robots will be spawned at the (0, 0, 0) of the simulation world
84 root_pose = scene["robot"].data.default_root_pose.torch.clone()
85 root_pose[:, :3] += scene.env_origins
86 scene["robot"].write_root_link_pose_to_sim_index(root_pose=root_pose)
87 root_vel = scene["robot"].data.default_root_vel.torch.clone()
88 scene["robot"].write_root_com_velocity_to_sim_index(root_velocity=root_vel)
89 # set joint positions with some noise
90 joint_pos, joint_vel = (
91 scene["robot"].data.default_joint_pos.torch.clone(),
92 scene["robot"].data.default_joint_vel.torch.clone(),
93 )
94 joint_pos += torch.rand_like(joint_pos) * 0.1
95 scene["robot"].write_joint_position_to_sim_index(position=joint_pos)
96 scene["robot"].write_joint_velocity_to_sim_index(velocity=joint_vel)
97 # clear internal buffers
98 scene.reset()
99 print("[INFO]: Resetting robot state...")
100 # Apply default actions to the robot
101 # -- generate actions/commands
102 targets = scene["robot"].data.default_joint_pos.torch
103 # -- apply action to the robot
104 scene["robot"].set_joint_position_target_index(target=targets)
105 # -- write data to sim
106 scene.write_data_to_sim()
107 # perform step
108 sim.step()
109 # update sim-time
110 sim_time += sim_dt
111 count += 1
112 # update buffers
113 scene.update(sim_dt)
114
115 # print information from the sensors
116 print("-------------------------------")
117 print(scene["pva_LF"])
118 print("Received linear velocity: ", scene["pva_LF"].data.lin_vel_b)
119 print("Received angular velocity: ", scene["pva_LF"].data.ang_vel_b)
120 print("Received linear acceleration: ", scene["pva_LF"].data.lin_acc_b)
121 print("Received angular acceleration: ", scene["pva_LF"].data.ang_acc_b)
122 print("-------------------------------")
123 print(scene["pva_RF"])
124 print("Received linear velocity: ", scene["pva_RF"].data.lin_vel_b)
125 print("Received angular velocity: ", scene["pva_RF"].data.ang_vel_b)
126 print("Received linear acceleration: ", scene["pva_RF"].data.lin_acc_b)
127 print("Received angular acceleration: ", scene["pva_RF"].data.ang_acc_b)
128
129
130def main():
131 """Main function."""
132
133 # Initialize the simulation context
134 sim_cfg = sim_utils.SimulationCfg(dt=0.005, device=args_cli.device)
135 sim = sim_utils.SimulationContext(sim_cfg)
136 # Set main camera
137 sim.set_camera_view(eye=[3.5, 3.5, 3.5], target=[0.0, 0.0, 0.0])
138 # design scene
139 scene_cfg = PvaSensorSceneCfg(num_envs=args_cli.num_envs, env_spacing=2.0)
140 scene = InteractiveScene(scene_cfg)
141 # Play the simulator
142 sim.reset()
143 # Now we are ready!
144 print("[INFO]: Setup complete...")
145 # Run the simulator
146 run_simulator(sim, scene)
147
148
149if __name__ == "__main__":
150 # run the main function
151 main()
152 # close sim app
153 simulation_app.close()