Describe the bug
While I have seen this bug raised in older versions of IsaacLab, I have yet to see any issues related to IsaacLab 3.0. Querying a camera's position using camera.data.pos_w.torch shows a static position that was created from the USD's default joints at launch time. When I move the robot arm (using DifferentialIKController in my case) the sensor positions do not move, despite being attached to the prim path. To verify that it wasn't related to the controller or my code, I tested this on the tutorial script scripts/tutorials/04_sensors/add_sensors_on_robot.py.
Interestingly, I can see the camera move around when running the simulation in the IsaacSim GUI by selecting it as the rendering perspective. However, if I click on the camera in the prim tree, the sensor coordinate frame remains fixed. Camera data is also from the original fixed perspective, it does not update either.
This is similar to other issues raised in preceding versions of IsaacLab and a temporary fix was found: #3177 (comment)
I had the same issue and looked into it some more.
I was able to fix it by adjusting this part https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab/isaaclab/sensors/camera/camera.py#L622 of camera.py to
env_ids = env_ids.to(torch.int32)
poses, quat = self._view.get_world_poses(env_ids, usd=False)
The usd=False to query the data from fabric (see https://docs.isaacsim.omniverse.nvidia.com/latest/py/source/extensions/isaacsim.core.prims/docs/index.html#isaacsim.core.prims.XFormPrim.get_world_poses) and the conversion to torch.int32 is just a hotfix. Otherwise I get the error message (...)/isaacsim/extscache/omni.warp.core-1.8.2+lx64/warp/types.py", line 3023, in view raise RuntimeError("Cannot cast dtypes of unequal byte size").
Unfortunately this is no longer an option with the new API, as usd is no longer a parameter of get_world_poses.
Similar to the other issues raised, I have tried setting update_latest_camera_pose=True in my CameraCfg but the behavior does not change.
Steps to reproduce
To demonstrate this, I have used the example from scripts/tutorials/04_sensors/add_sensors_on_robot.py and added update_latest_camera_pose=True to the CameraCfg. I also added print(scene["camera"].data.pos_w.torch) to the run_simulator() function to verify this.
# 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
"""
This script demonstrates how to add and simulate on-board sensors for a robot.
We add the following sensors on the quadruped robot, ANYmal-C (ANYbotics):
* USD-Camera: This is a camera sensor that is attached to the robot's base.
* Height Scanner: This is a height scanner sensor that is attached to the robot's base.
* Contact Sensor: This is a contact sensor that is attached to the robot's feet.
.. code-block:: bash
# Usage
./isaaclab.sh -p scripts/tutorials/04_sensors/add_sensors_on_robot.py --enable_cameras --viz kit
"""
"""Launch Isaac Sim Simulator first."""
import argparse
from isaaclab.app import AppLauncher
# add argparse arguments
parser = argparse.ArgumentParser(description="Tutorial on adding sensors on a robot.")
parser.add_argument("--num_envs", type=int, default=2, help="Number of environments to spawn.")
# append AppLauncher cli args
AppLauncher.add_app_launcher_args(parser)
# parse the arguments
args_cli = parser.parse_args()
# launch omniverse app
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app
"""Rest everything follows."""
import torch
import isaaclab.sim as sim_utils
from isaaclab.assets import ArticulationCfg, AssetBaseCfg
from isaaclab.scene import InteractiveScene, InteractiveSceneCfg
from isaaclab.sensors import CameraCfg, ContactSensorCfg, RayCasterCfg, patterns
from isaaclab.utils.configclass import configclass
##
# Pre-defined configs
##
from isaaclab_assets.robots.anymal import ANYMAL_C_CFG # isort: skip
@configclass
class SensorsSceneCfg(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))
)
# robot
robot: ArticulationCfg = ANYMAL_C_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
# sensors
camera = CameraCfg(
prim_path="{ENV_REGEX_NS}/Robot/base/front_cam",
update_period=0.1,
height=480,
width=640,
data_types=["rgb", "distance_to_image_plane"],
spawn=sim_utils.PinholeCameraCfg(
focal_length=24.0, focus_distance=400.0, horizontal_aperture=20.955, clipping_range=(0.1, 1.0e5)
),
update_latest_camera_pose=True,
offset=CameraCfg.OffsetCfg(pos=(0.510, 0.0, 0.015), rot=(0.5, -0.5, 0.5, -0.5), convention="ros"),
)
height_scanner = RayCasterCfg(
prim_path="{ENV_REGEX_NS}/Robot/base",
update_period=0.02,
offset=RayCasterCfg.OffsetCfg(pos=(0.0, 0.0, 20.0)),
ray_alignment="yaw",
pattern_cfg=patterns.GridPatternCfg(resolution=0.1, size=[1.6, 1.0]),
debug_vis=True,
mesh_prim_paths=["/World/defaultGroundPlane"],
)
contact_forces = ContactSensorCfg(
prim_path="{ENV_REGEX_NS}/Robot/.*_FOOT", update_period=0.0, history_length=6, debug_vis=True
)
def run_simulator(sim: sim_utils.SimulationContext, scene: InteractiveScene):
"""Run the simulator."""
# Define simulation stepping
sim_dt = sim.get_physics_dt()
sim_time = 0.0
count = 0
# Simulate physics
while simulation_app.is_running():
# Reset
if count % 500 == 0:
# reset counter
count = 0
# reset the scene entities
# root state
# we offset the root state by the origin since the states are written in simulation world frame
# if this is not done, then the robots will be spawned at the (0, 0, 0) of the simulation world
root_pose = scene["robot"].data.default_root_pose.torch.clone()
root_pose[:, :3] += scene.env_origins
scene["robot"].write_root_pose_to_sim_index(root_pose=root_pose)
root_vel = scene["robot"].data.default_root_vel.torch.clone()
scene["robot"].write_root_velocity_to_sim_index(root_velocity=root_vel)
# set joint positions with some noise
joint_pos, joint_vel = (
scene["robot"].data.default_joint_pos.torch.clone(),
scene["robot"].data.default_joint_vel.torch.clone(),
)
joint_pos += torch.rand_like(joint_pos) * 0.1
scene["robot"].write_joint_position_to_sim_index(position=joint_pos)
scene["robot"].write_joint_velocity_to_sim_index(velocity=joint_vel)
# clear internal buffers
scene.reset()
print("[INFO]: Resetting robot state...")
# Apply default actions to the robot
# -- generate actions/commands
targets = scene["robot"].data.default_joint_pos.torch
# -- apply action to the robot
scene["robot"].set_joint_position_target_index(target=targets)
# -- write data to sim
scene.write_data_to_sim()
# perform step
sim.step()
# update sim-time
sim_time += sim_dt
count += 1
# update buffers
scene.update(sim_dt)
# print information from the sensors
print("-------------------------------")
print(scene["camera"])
print("Received shape of rgb image: ", scene["camera"].data.output["rgb"].shape)
print("Received shape of depth image: ", scene["camera"].data.output["distance_to_image_plane"].shape)
print("-------------------------------")
print(scene["height_scanner"])
print(
"Received max height value: ",
torch.max(scene["height_scanner"].data.ray_hits_w.torch[..., -1]).item(),
)
print("-------------------------------")
print(scene["contact_forces"])
print("Received max contact force of: ", torch.max(scene["contact_forces"].data.net_forces_w).item())
print(scene["camera"].data.pos_w.torch)
def main():
"""Main function."""
# Initialize the simulation context
sim_cfg = sim_utils.SimulationCfg(dt=0.005, device=args_cli.device)
sim = sim_utils.SimulationContext(sim_cfg)
# Set main camera
sim.set_camera_view(eye=[3.5, 3.5, 3.5], target=[0.0, 0.0, 0.0])
# Design scene
scene_cfg = SensorsSceneCfg(num_envs=args_cli.num_envs, env_spacing=2.0)
scene = InteractiveScene(scene_cfg)
# Play the simulator
sim.reset()
# Now we are ready!
print("[INFO]: Setup complete...")
# Run the simulator
run_simulator(sim, scene)
if __name__ == "__main__":
# run the main function
main()
# close sim app
simulation_app.close()
Finally, I modified the ANYMAL_C_CFG default articulation config to start the robot at a higher height to better see movement.
ANYMAL_C_CFG = ArticulationCfg(
spawn=sim_utils.UsdFileCfg(
usd_path=f"{ISAACLAB_NUCLEUS_DIR}/Robots/ANYbotics/ANYmal-C/anymal_c.usd",
# usd_path=f"{ISAAC_NUCLEUS_DIR}/Robots/ANYbotics/anymal_instanceable.usd",
activate_contact_sensors=True,
rigid_props=sim_utils.RigidBodyPropertiesCfg(
disable_gravity=False,
retain_accelerations=False,
linear_damping=0.0,
angular_damping=0.0,
max_linear_velocity=1000.0,
max_angular_velocity=1000.0,
max_depenetration_velocity=1.0,
),
articulation_props=sim_utils.ArticulationRootPropertiesCfg(
enabled_self_collisions=True, solver_position_iteration_count=4, solver_velocity_iteration_count=0
),
# collision_props=sim_utils.CollisionPropertiesCfg(contact_offset=0.02, rest_offset=0.0),
),
init_state=ArticulationCfg.InitialStateCfg(
pos=(0.0, 0.0, 1.6),
joint_pos={
".*HAA": 0.0, # all HAA
".*F_HFE": 0.4, # both front HFE
".*H_HFE": -0.4, # both hind HFE
".*F_KFE": -0.8, # both front KFE
".*H_KFE": 0.8, # both hind KFE
},
),
actuators={"legs": ANYDRIVE_3_LSTM_ACTUATOR_CFG},
soft_joint_pos_limit_factor=0.95,
)
System Info
Describe the characteristic of your environment:
- Commit: 4c6aac2
- Isaac Sim Version: 6.0.1
- OS: Ubuntu 24.04.4
- GPU: NVIDIA GeForce RTX 5060 Laptop GPU
- CUDA: 13.2
- GPU Driver: 595.71.05
Additional context
I have not pulled the most recent commit but didn't see anything in the changelogs or patch branch to indicate this has been addressed.
Edit: Just pulled commit 51b4fb5418, no change in behavior.
Checklist
Acceptance Criteria
Describe the bug
While I have seen this bug raised in older versions of IsaacLab, I have yet to see any issues related to IsaacLab 3.0. Querying a camera's position using
camera.data.pos_w.torchshows a static position that was created from the USD's default joints at launch time. When I move the robot arm (using DifferentialIKController in my case) the sensor positions do not move, despite being attached to the prim path. To verify that it wasn't related to the controller or my code, I tested this on the tutorial scriptscripts/tutorials/04_sensors/add_sensors_on_robot.py.Interestingly, I can see the camera move around when running the simulation in the IsaacSim GUI by selecting it as the rendering perspective. However, if I click on the camera in the prim tree, the sensor coordinate frame remains fixed. Camera data is also from the original fixed perspective, it does not update either.
This is similar to other issues raised in preceding versions of IsaacLab and a temporary fix was found: #3177 (comment)
Unfortunately this is no longer an option with the new API, as
usdis no longer a parameter ofget_world_poses.Similar to the other issues raised, I have tried setting
update_latest_camera_pose=Truein my CameraCfg but the behavior does not change.Steps to reproduce
To demonstrate this, I have used the example from
scripts/tutorials/04_sensors/add_sensors_on_robot.pyand addedupdate_latest_camera_pose=Trueto theCameraCfg. I also addedprint(scene["camera"].data.pos_w.torch)to therun_simulator()function to verify this.Finally, I modified the
ANYMAL_C_CFGdefault articulation config to start the robot at a higher height to better see movement.System Info
Describe the characteristic of your environment:
Additional context
I have not pulled the most recent commit but didn't see anything in the changelogs or patch branch to indicate this has been addressed.
Edit: Just pulled commit
51b4fb5418, no change in behavior.Checklist
Acceptance Criteria
update_latest_camera_pose=Truemove when the rest of the kinematic chain moves.