feat(perception): sky detector for outdoor navigation (Issue #307) #313

Merged
sl-jetson merged 1 commits from sl-perception/issue-307-sky-detect into main 2026-03-03 00:20:05 -05:00
Collaborator

Summary

  • Add _sky_detector.py: SkyResult NamedTuple; detect_sky() with dual HSV band masking — blue sky (H∈[90,130], S∈[40,255], V∈[80,255]) OR overcast/grey sky (S∈[0,50], V∈[185,255]), OR-combined via cv2.bitwise_or; sky_fraction computed over configurable top scan_frac region; horizon_y = bottommost row where per-row sky fraction ≥ row_threshold (−1 when no sky detected)
  • Add sky_detect_node.py: subscribes /camera/color/image_raw (BEST_EFFORT), publishes Float32 /saltybot/sky_fraction and Int32 /saltybot/horizon_y per frame; scan_frac (default 0.60) and row_threshold (default 0.30) ROS params
  • Register sky_detector console script in setup.py
  • 33/33 unit tests pass (pure Python, no ROS2 required)

Downstream uses

  • Outdoor/indoor detection: sky_fraction > 0.10 → likely outdoor
  • Camera tilt correction: horizon_y deviation from expected row estimates pitch tilt
  • SLAM mode switching: high sky_fraction → outdoor SLAM parameters

Test plan

  • python3 -m pytest test/test_sky_detector.py -v → 33 passed
  • Launch: ros2 run saltybot_bringup sky_detector
  • Point at sky → /saltybot/sky_fraction > 0.8
  • Indoors → /saltybot/sky_fraction ≈ 0.0, /saltybot/horizon_y == -1
  • Horizon in frame → /saltybot/horizon_y tracks sky/ground boundary

🤖 Generated with Claude Code

## Summary - Add `_sky_detector.py`: `SkyResult` NamedTuple; `detect_sky()` with dual HSV band masking — blue sky (H∈[90,130], S∈[40,255], V∈[80,255]) OR overcast/grey sky (S∈[0,50], V∈[185,255]), OR-combined via `cv2.bitwise_or`; `sky_fraction` computed over configurable top `scan_frac` region; `horizon_y` = bottommost row where per-row sky fraction ≥ `row_threshold` (−1 when no sky detected) - Add `sky_detect_node.py`: subscribes `/camera/color/image_raw` (BEST_EFFORT), publishes `Float32 /saltybot/sky_fraction` and `Int32 /saltybot/horizon_y` per frame; `scan_frac` (default 0.60) and `row_threshold` (default 0.30) ROS params - Register `sky_detector` console script in `setup.py` - 33/33 unit tests pass (pure Python, no ROS2 required) ## Downstream uses - Outdoor/indoor detection: `sky_fraction > 0.10` → likely outdoor - Camera tilt correction: `horizon_y` deviation from expected row estimates pitch tilt - SLAM mode switching: high `sky_fraction` → outdoor SLAM parameters ## Test plan - [ ] `python3 -m pytest test/test_sky_detector.py -v` → 33 passed - [ ] Launch: `ros2 run saltybot_bringup sky_detector` - [ ] Point at sky → `/saltybot/sky_fraction` > 0.8 - [ ] Indoors → `/saltybot/sky_fraction` ≈ 0.0, `/saltybot/horizon_y` == -1 - [ ] Horizon in frame → `/saltybot/horizon_y` tracks sky/ground boundary 🤖 Generated with [Claude Code](https://claude.com/claude-code)
sl-perception added 1 commit 2026-03-02 21:40:02 -05:00
- Add _sky_detector.py: SkyResult NamedTuple; detect_sky() with dual HSV
  band masking (blue sky H∈[90,130]/S∈[40,255]/V∈[80,255] OR overcast
  S∈[0,50]/V∈[185,255]), cv2.bitwise_or combined mask; sky_fraction over
  configurable top scan_frac region; horizon_y = bottommost row where
  per-row sky fraction ≥ row_threshold (−1 when no sky detected)
- Add sky_detect_node.py: subscribes /camera/color/image_raw (BEST_EFFORT),
  publishes Float32 /saltybot/sky_fraction and Int32 /saltybot/horizon_y
  per frame; scan_frac (default 0.60) and row_threshold (default 0.30) params
- Register sky_detector console script in setup.py
- 33/33 unit tests pass (no ROS2 required)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sl-jetson merged commit 0b35a61217 into main 2026-03-03 00:20:05 -05:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: seb/saltylab-firmware#313
No description provided.