You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Configure a depth camera sensor converted to LaserScan with inf_is_valid: true (or any sensor where inf readings are clamped to range_max - epsilon).
Set obstacle_max_rangesmaller than the sensor's range_max. For example: obstacle_max_range: 0.70, sensor range_max: 0.80.
Use a typical costmap resolution: 0.05.
Run the robot in an empty environment (no real obstacles). Rotate the robot in place.
Expected behavior
The local costmap should remain clear — no LETHAL_OBSTACLE cells should appear because all sensor readings are inf (no real obstacles), and the projected points at range_max - epsilon ≈ 0.7999 m exceed obstacle_max_range = 0.70 m.
Actual behavior
Spurious LETHAL_OBSTACLE (254) cells appear on the local costmap, especially during rotation. The noise pattern follows the sensor's arc at the boundary of its projected range.
Root cause
PR #5697 (commit 80b72d27, backported to Jazzy as 3320ebf7) replaced the original world-distance obstacle range check with a cell-space distance check. The original code was:
The filter evaluates 14 > 14 → FALSE → the point passes and is marked LETHAL_OBSTACLE, even though the actual world distance (0.7999 m) clearly exceeds obstacle_max_range (0.70 m).
The truncation from double to unsigned int in hypot loses the fractional part (14.866 → 14), while cellDistance uses ceil which rounds up, creating a systematic boundary mismatch.
Proposed fix
Add a world-distance pre-filter before the cell-distance checks, restoring the meter-consistent semantics that existed prior to PR #5697 while keeping the cell-space checks for alignment with raytrace/clearing behavior:
// Pre-filter by world distance to avoid cell discretization boundary// effects where hypot(dx,dy) truncation makes far points appear in rangeconstdouble wdx = px - obs.origin_.x;
constdouble wdy = py - obs.origin_.y;
constdouble world_dist_sq = wdx * wdx + wdy * wdy;
if (world_dist_sq > obs.obstacle_max_range_ * obs.obstacle_max_range_) {
continue;
}
if (world_dist_sq < obs.obstacle_min_range_ * obs.obstacle_min_range_) {
continue;
}
Additional information
ROS1's costmap_2dObstacleLayer uses a continuous squared-distance check (sq_dist >= sq_obstacle_range) and does not have this issue.
The bug is most easily triggered when obstacle_max_range is small relative to sensor range_max, with inf_is_valid: true (so inf readings are clamped to range_max - epsilon and projected into the point cloud).
Bug report
Required Info:
8287ff2c2320990f52c75f1877b9876b8c7a77e6(includes backport3320ebf7of PR Update obstacle layer usage of max ranges #5697)Steps to reproduce issue
LaserScanwithinf_is_valid: true(or any sensor whereinfreadings are clamped torange_max - epsilon).obstacle_max_rangesmaller than the sensor'srange_max. For example:obstacle_max_range: 0.70, sensorrange_max: 0.80.resolution: 0.05.Expected behavior
The local costmap should remain clear — no
LETHAL_OBSTACLEcells should appear because all sensor readings areinf(no real obstacles), and the projected points atrange_max - epsilon ≈ 0.7999 mexceedobstacle_max_range = 0.70 m.Actual behavior
Spurious
LETHAL_OBSTACLE(254) cells appear on the local costmap, especially during rotation. The noise pattern follows the sensor's arc at the boundary of its projected range.Root cause
PR #5697 (commit
80b72d27, backported to Jazzy as3320ebf7) replaced the original world-distance obstacle range check with a cell-space distance check. The original code was:It was changed to:
The cell-space check alone does not guarantee consistency with the meter-based
obstacle_max_rangeparameter due to discretization boundary effects:obstacle_max_range= 0.70 mdx,dy(grid offsets)cell_disthypot(10, 11) = √221 ≈ 14.866→ truncated tounsigned int→ 14max_range_cellscellDistance(0.70) = ceil(0.70 / 0.05) = ceil(14.0) = 14The filter evaluates
14 > 14→ FALSE → the point passes and is markedLETHAL_OBSTACLE, even though the actual world distance (0.7999 m) clearly exceedsobstacle_max_range(0.70 m).The truncation from
doubletounsigned intinhypotloses the fractional part (14.866 → 14), whilecellDistanceusesceilwhich rounds up, creating a systematic boundary mismatch.Proposed fix
Add a world-distance pre-filter before the cell-distance checks, restoring the meter-consistent semantics that existed prior to PR #5697 while keeping the cell-space checks for alignment with raytrace/clearing behavior:
Additional information
costmap_2dObstacleLayeruses a continuous squared-distance check (sq_dist >= sq_obstacle_range) and does not have this issue.obstacle_max_rangeis small relative to sensorrange_max, withinf_is_valid: true(soinfreadings are clamped torange_max - epsilonand projected into the point cloud).80b72d27(main), backported as3320ebf7(Jazzy) and0412cea6(Humble).