Add CpuLidarSensor for physics-based lidar without rendering#593
Open
apojomovsky wants to merge 22 commits intogazebosim:mainfrom
Open
Add CpuLidarSensor for physics-based lidar without rendering#593apojomovsky wants to merge 22 commits intogazebosim:mainfrom
apojomovsky wants to merge 22 commits intogazebosim:mainfrom
Conversation
14 tasks
ahcorde
reviewed
Feb 20, 2026
964987d to
8bde31b
Compare
Contributor
|
Would it make sense to directly think about multiple-return lidars when implementing this? Just today I've asked about it :) #594 . You now have the whole implementation in your head. How much work do you think this would bring? |
- New CpuLidarSensor class extending Sensor (no rendering dependency) - Load() validates sdf::SensorType::LIDAR - Integration test verifies sensor creation via SensorFactory - New gz-sensors-cpu_lidar CMake component Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
- Parse sdf::Lidar from SDF in Load() - Expose accessors: AngleMin/Max, VerticalAngleMin/Max, RangeMin/Max, RayCount, VerticalRayCount - Test verifies all parsed values match SDF input Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
- GenerateRays() converts SDF lidar parameters (angles, samples, range) into (start, end) vector pairs in entity frame - Tests verify single-layer and multi-layer ray generation - Ray directions use spherical coordinates (azimuth + inclination) Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
- RayResult struct holds hit point, fraction, normal - SetRaycastResults() converts fractions to ranges - No-hit (NaN fraction) maps to +inf per REP-117 - Out-of-range values clamped to ±inf - Ranges() accessor for computed range data Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
- Advertise LaserScan on sensor topic in Load() - Update() populates and publishes LaserScan message with ranges, angles, frame_id, timestamp - HasConnections() checks publisher subscribers - Test verifies message fields and range values via transport Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
…scan Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
…d math Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
…eline Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Update() could be called before SetRaycastResults() when transport subscribers connect before the first physics step completes. Accessing the empty ranges vector caused a segfault in the PointCloud publishing path. Return early if ranges haven't been populated yet. Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Amp <amp@ampcode.com> Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Claude Opus 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Claude Sonnet 4.6 Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Generated-by: Copilot Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
Signed-off-by: Alexis Pojomovsky <apojomovsky@gmail.com>
8bde31b to
0c40b53
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🎉 New feature
This PR is 2 out of 3 that implement: #26
Summary
Add
CpuLidarSensor, a new sensor class that extendsgz::sensors::Sensordirectly (notRenderingSensor), receives raycast results from a system plugin, applies noise, and publishesLaserScanandPointCloudPackedmessages over gz-transport. Zero dependency ongz-rendering.The existing
GpuLidarSensorrequires Ogre2 and a GPU, making it unusable on headless cloud machines, containers, and CI/CD environments. Gazebo Classic had a CPU-basedRaySensorbacked by the physics engine; this is the new-architectureequivalent.
CpuLidarSensorextendsSensorinstead of the existingLidarclass becauseLidarextendsRenderingSensor, which would pull ingz-renderingas a transitive dependency. The SDF parsing, noise application, and message publishing logic is reimplemented without that dependency.GenerateRays()produces entity-frame ray pairs from the SDF lidar configuration.SetRaycastResults()accepts fractions from the physics engine and converts them to ranges (fraction × ray_length). Misses (NaN fraction) produce+infper REP-117. For 3D scans with multiple vertical layers,LaserScanpublishes the middle ring as a 2D slice whilePointCloudPackedpublishes all rings.Test it
Checklist
codecheckpassed (See contributing)Generated-by: Claude Opus 4.6
Disclaimer: The code here was reviewed, tested, and profiled by hand by the author.
Note to maintainers: Remember to use Squash-Merge and edit the commit message to match the pull request summary while retaining
Signed-off-byandGenerated-bymessages.