Skip to content

fix: properly filter blanked RPLidar angles using any() in _path_processor#2141

Open
Ridwannurudeen wants to merge 3 commits intoOpenMind:mainfrom
Ridwannurudeen:fix/rplidar-blanked-angle-filtering
Open

fix: properly filter blanked RPLidar angles using any() in _path_processor#2141
Ridwannurudeen wants to merge 3 commits intoOpenMind:mainfrom
Ridwannurudeen:fix/rplidar-blanked-angle-filtering

Conversation

@Ridwannurudeen
Copy link

Summary

Fixes #2138

A continue statement inside a nested loop caused the RPLidar angle blanking logic to silently fail. Readings from blanked angle ranges (fixed chassis reflections) passed through to the path planner as phantom obstacles, potentially triggering unnecessary stops or evasive maneuvers on any robot with non-empty angles_blanked.

Root cause

In _path_processor (line 453), the blanking check was structured as:

for b in self.angles_blanked:
    if angle >= b[0] and angle <= b[1]:
        continue  # only skips inner loop iteration

The continue targets the inner for b in self.angles_blanked loop, not the outer for angle, distance in data loop. So regardless of whether an angle matched a blanked range, execution always fell through to complexes.append(...) at line 472.

Notably, the standalone test script system_hw_test/rptest.py (lines 276-282) already implements this correctly using a flag + break pattern, confirming this was a regression when the logic was ported into the provider class.

Fix

Replace the broken nested loop with a single any() expression:

if any(b[0] <= angle <= b[1] for b in self.angles_blanked):
    continue  # now correctly skips the outer loop

This works because any() collapses the inner loop into a boolean expression, so continue now operates on the outer for angle, distance in data loop as intended. The generator inside any() short-circuits on the first match, preserving the same early-exit behavior as break.

Affected configurations

Any robot with non-empty angles_blanked was impacted:

  • config/turtlebot4.json5 — blanks [-180, -160] and [110, 180]
  • config/turtlebot4_lidar.json5
  • config/turtlebot4_lidar_gps.json5
  • config/test_lidar.json5

Robots with angles_blanked: [] (all Go2 configs) were unaffected since the inner loop never executed.

Tests added

  • test_path_processor_filters_blanked_angles: Feeds 4 sensor readings through _path_processor with angles_blanked=[[-170, -150]]. Verifies that the 2 readings landing inside the blanked range are excluded and the 2 outside it survive. Each test angle is traced through the mounting offset and coordinate conversion to confirm correctness.

  • test_path_processor_no_blanking_when_empty: Feeds 3 valid readings with angles_blanked=[] and verifies all 3 pass through, ensuring the fix doesn't introduce false positives.

Test plan

  • ruff check — 0 errors
  • ruff format --check — already formatted
  • Both new tests pass with the fix applied
  • Verified the fix matches the proven pattern in rptest.py
  • Confirmed any() short-circuits on first match (no performance regression)

…cessor

Closes OpenMind#2138

The angle blanking logic in _path_processor used a `continue` inside a
nested `for b in self.angles_blanked` loop (lines 453-457). That
`continue` only skipped to the next blanked range in the inner loop
instead of skipping the outer `for angle, distance in data` iteration.
As a result, readings from blanked angles were never actually filtered
and always reached `complexes.append(...)`, sending phantom obstacles
from fixed chassis reflections to the path planner.

Replace the nested loop with `any(b[0] <= angle <= b[1] for ...)` which
evaluates the blanking check as a single expression. When a match is
found, the outer loop's `continue` fires correctly, skipping the
reading. This approach:

- Fixes the control flow bug in one line
- Short-circuits on the first matching range (same as break)
- Matches how rptest.py already handles blanking correctly (lines 276-282)

Add two tests exercising _path_processor directly:
- test_path_processor_filters_blanked_angles: verifies readings inside
  [-170, -150] are excluded while readings outside pass through
- test_path_processor_no_blanking_when_empty: verifies no readings are
  lost when angles_blanked is empty

Affected configs: turtlebot4.json5, turtlebot4_lidar.json5,
turtlebot4_lidar_gps.json5, test_lidar.json5 — any robot with
non-empty angles_blanked was seeing phantom obstacles.
@Ridwannurudeen Ridwannurudeen requested review from a team as code owners February 6, 2026 11:13
@github-actions github-actions bot added robotics Robotics code changes python Python code tests Test files labels Feb 6, 2026
@letmehateu
Copy link

letmehateu commented Feb 6, 2026

#2139
Already approved by reviewer

@codecov
Copy link

codecov bot commented Feb 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@Wanbogang
Copy link
Collaborator

Hi @Ridwannurudeen
You can run pyright first locally, if everything passes, you can push to github.

Ruff split the long single-line `if` statement across multiple lines,
which moved the `# type: ignore` comment to the closing parenthesis
(line 20) instead of the line where `_singleton_instance` is actually
accessed (line 19). Pyright could not see the suppression and reported
reportAttributeAccessIssue.

Moved the comment to the attribute access line and narrowed the
suppression to `attr-defined` for specificity.
@letmehateu
Copy link

letmehateu commented Feb 6, 2026

Hi @Ridwannurudeen You can run pyright first locally, if everything passes, you can push to github.

Sorry, but i already mentioned this issue in my PR and got approve

@Ridwannurudeen
Copy link
Author

Thanks @Wanbogang — good catch. The pyright failure was due to a # type: ignore comment landing on the wrong line after ruff reformatted a multi-line conditional. Pushed a fix that places the suppression on the actual attribute access line. Both pyright and ruff pass locally now.

@letmehateu
Copy link

letmehateu commented Feb 6, 2026

Thanks @Wanbogang — good catch. The pyright failure was due to a # type: ignore comment landing on the wrong line after ruff reformatted a multi-line conditional. Pushed a fix that places the suppression on the actual attribute access line. Both pyright and ruff pass locally now.

Sorry, why you ignoring me?
To be honest it's unprofessional. If you found same issues, you can open yours, if PR already pinned to issue

@Ridwannurudeen
Copy link
Author

Hey @letmehateu — apologies for not acknowledging your PR first, that was my oversight. I should have engaged with #2139 before opening a separate one.

My PR takes a slightly different approach (single any() expression instead of the flag pattern) and adds test coverage for the filtering logic, but I totally respect that you identified and reported the bug. Happy to let the maintainers decide which direction they prefer.

@0xbyt4
Copy link
Collaborator

0xbyt4 commented Feb 6, 2026

#2139 Already approved by reviewer

for public 1 issues multiple developer can open PRs , the best one will merge after approve with multiple reviewers.

@Wanbogang
Copy link
Collaborator

Thanks @Wanbogang — good catch. The pyright failure was due to a # type: ignore comment landing on the wrong line after ruff reformatted a multi-line conditional. Pushed a fix that places the suppression on the actual attribute access line. Both pyright and ruff pass locally now.

Sorry, why you ignoring me? To be honest it's unprofessional. If you found same issues, you can open yours, if PR already pinned to issue

Hi @letmehateu
I am not ignoring you. I even suggested improvements to you. Actually, the main problem is that you tagged [bounty] in the issue. Because this is open source, everyone has the opportunity to improve it. I also have to be fair. I hope you can understand. Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Python code robotics Robotics code changes tests Test files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: continue in nested loop fails to filter blanked RPLidar angles — phantom obstacles reach path planner

4 participants