Repository navigation
RTX Lidar point cloud becomes geometrically inconsistent during rapid sensor motion #624
|
Hi Isaac Sim team, DescriptionI observed a geometric inconsistency issue in RTX lidar point clouds when the sensor undergoes rapid motion. The issue was also reproduced through ROS2 point cloud publication. I recorded a ROS2 bag containing:
Step to reproduceI created a minimal reproducible repository containing the simulation setup and instructions: https://github.com/yuheisugano/isaacsim-lidar-vehicle-repro.git Isaac Sim Version
Operating System (OS)
GPU Name
GPU Driver and CUDA versions
LogsA log file is in Additional Information
Please let me know if additional logs, videos, or reduced test cases would be helpful. |
Replies: 2 comments 6 replies
|
Hi @yuheisugano, Thank you for positing this issue and also for sharing the repro. On first thought if your rendering rate matches your lidar scan rate exactly — both at 10 Hz. With rendering_dt: 0.1 and scanRateBaseHz: 10.0 (the Example_Rotary default), one full 360° sweep is built from a single GPU render frame. All rays are cast from the sensor's pose at that one instant, but the motion compensation pipeline treats them as if they were emitted progressively across the 100 ms sweep at interpolated poses. At ~5 m/s with steering, that 100 ms of "phantom" pose variation introduces the sliding/smearing you're seeing. |
|
Update — we root-caused this and there's a clean fix. The smear isn't a rendering or motion-compensation bug; it comes from how the cloud is transformed on the consumer side. When you read the cloud in the sensor frame and transform it to world using the lidar prim's read-time USD pose, that single pose doesn't match the per-ray emission poses the sweep was motion-compensated against. During fast motion the mismatch shows up as the ~ Fix: have the RTX pipeline emit the cloud already in the WORLD frame, and consume it verbatim (no USD-pose transform). In WORLD mode the engine resolves every return with its own motion-compensated per-ray pose, so the timing offset never enters: attributes = {
"omni:sensor:Core:outputMotionCompensationState": "COMPENSATED",
"omni:sensor:Core:outputFrameOfReference": "WORLD", # <-- the key change
"omni:sensor:Core:scanType": "ROTARY",
"omni:sensor:Core:elementsCoordsType": "CARTESIAN",
}
# consumer: points are already world-frame; do NOT multiply by the prim pose.On a minimal repro (kinematic lidar carrier, 8 m/s + sine steering, past a static wall) this takes the wall-return residual from +2.36 m (naive read-time-pose transform) down to ~0 m (mean +0.0003 m, max 0.016 m) while the sensor is approaching the wall — i.e. the scans are geometrically consistent, which is what matters for SLAM/odometry. I've attached a minimal runnable version Two notes:
Let us know if this resolves it on your vehicle setup. |



Update — we root-caused this and there's a clean fix.
The smear isn't a rendering or motion-compensation bug; it comes from how the cloud is transformed on the consumer side. When you read the cloud in the sensor frame and transform it to world using the lidar prim's read-time USD pose, that single pose doesn't match the per-ray emission poses the sweep was motion-compensated against. During fast motion the mismatch shows up as the ~
2·v·dtslide you measured.Fix: have the RTX pipeline emit the cloud already in the WORLD frame, and consume it verbatim (no USD-pose transform). In WORLD mode the engine resolves every return with its own motion-compensated per-ray pose, so the timing offset …