feat: outdoor nav — OSM routing + geofence (#59) #67

Merged
seb merged 1 commits from sl-perception/outdoor-nav into main 2026-03-01 01:00:43 -05:00
Collaborator

Summary

Implements Phase 2d: outdoor autonomous navigation for SaltyBot. Uses SIM7600X GPS (/gps/fix) from PR #65 and Nav2 stack from PR #49.

saltybot_outdoor package:

  • osm_router_node — Overpass API query (footway/cycleway/path/pedestrian), haversine A*, Douglas–Peucker simplification, flat-earth ENU projection; publishes /outdoor/route (Path for RViz) + /outdoor/waypoints (PoseArray for follower)
  • gps_waypoint_follower_node — subscribes /gps/fix + /outdoor/waypoints; quality-adaptive goal tolerances (2 m cellular, 0.30 m RTK); sends NavigateThroughPoses to Nav2; services /outdoor/start_navigation / /outdoor/stop_navigation
  • geofence_node — ray-casting polygon boundary check at 2 Hz; publishes /outdoor/abort + zero /cmd_vel on violation; /outdoor/reload_fence service for hot-reload
  • outdoor_nav.launch.py — dual EKF (odom + map frames) + navsat_transform_node + all nodes; Nav2 NOT started here (runs in saltybot-nav2 container)
  • outdoor_nav_params.yaml — outdoor Nav2 overrides: 1.5 m/s, no static_layer, 2 m GPS goal tolerance
  • ekf_outdoor.yamlrobot_localization dual-EKF config; fuses wheel odom + IMU (local), adds GPS odometry (global)
  • geofence_vertices.yaml — template with usage instructions

RTK upgrade path: SIM7600X ±2.5 m → u-blox ZED-F9P ±2 cm via NTRIP over cellular; set use_rtk:=true, tolerances auto-tighten to 0.30 m.

docker-compose.yml: fixes malformed saltybot-surround block; adds saltybot-outdoor service (depends on saltybot-nav2, OSM tile cache on NVMe).

Closes #59.

Test plan

  • docker compose up -d saltybot-outdoor — verify all nodes start
  • ros2 topic echo /outdoor/gps_status — verify SIM7600X fix reported
  • ros2 param set /osm_router goal_lat <lat> && ros2 param set /osm_router goal_lon <lon>
  • ros2 service call /outdoor/plan_route std_srvs/srv/Trigger '{}' — verify Overpass query + waypoints published
  • ros2 topic echo /outdoor/route — verify nav_msgs/Path in RViz
  • ros2 service call /outdoor/start_navigation std_srvs/srv/Trigger '{}' — verify Nav2 receives goal
  • Set fence_vertices in geofence_vertices.yaml, verify abort on exit
  • RTK: connect ZED-F9P, verify /gps/fix status=2, tolerance auto-tightens

🤖 Generated with Claude Code

## Summary Implements Phase 2d: outdoor autonomous navigation for SaltyBot. Uses SIM7600X GPS (`/gps/fix`) from PR #65 and Nav2 stack from PR #49. **`saltybot_outdoor` package:** - `osm_router_node` — Overpass API query (footway/cycleway/path/pedestrian), haversine A*, Douglas–Peucker simplification, flat-earth ENU projection; publishes `/outdoor/route` (Path for RViz) + `/outdoor/waypoints` (PoseArray for follower) - `gps_waypoint_follower_node` — subscribes `/gps/fix` + `/outdoor/waypoints`; quality-adaptive goal tolerances (2 m cellular, 0.30 m RTK); sends `NavigateThroughPoses` to Nav2; services `/outdoor/start_navigation` / `/outdoor/stop_navigation` - `geofence_node` — ray-casting polygon boundary check at 2 Hz; publishes `/outdoor/abort` + zero `/cmd_vel` on violation; `/outdoor/reload_fence` service for hot-reload - `outdoor_nav.launch.py` — dual EKF (`odom` + `map` frames) + `navsat_transform_node` + all nodes; Nav2 NOT started here (runs in `saltybot-nav2` container) - `outdoor_nav_params.yaml` — outdoor Nav2 overrides: 1.5 m/s, no `static_layer`, 2 m GPS goal tolerance - `ekf_outdoor.yaml` — `robot_localization` dual-EKF config; fuses wheel odom + IMU (local), adds GPS odometry (global) - `geofence_vertices.yaml` — template with usage instructions **RTK upgrade path:** SIM7600X ±2.5 m → u-blox ZED-F9P ±2 cm via NTRIP over cellular; set `use_rtk:=true`, tolerances auto-tighten to 0.30 m. **`docker-compose.yml`:** fixes malformed `saltybot-surround` block; adds `saltybot-outdoor` service (depends on `saltybot-nav2`, OSM tile cache on NVMe). Closes #59. ## Test plan - [ ] `docker compose up -d saltybot-outdoor` — verify all nodes start - [ ] `ros2 topic echo /outdoor/gps_status` — verify SIM7600X fix reported - [ ] `ros2 param set /osm_router goal_lat <lat> && ros2 param set /osm_router goal_lon <lon>` - [ ] `ros2 service call /outdoor/plan_route std_srvs/srv/Trigger '{}'` — verify Overpass query + waypoints published - [ ] `ros2 topic echo /outdoor/route` — verify nav_msgs/Path in RViz - [ ] `ros2 service call /outdoor/start_navigation std_srvs/srv/Trigger '{}'` — verify Nav2 receives goal - [ ] Set `fence_vertices` in `geofence_vertices.yaml`, verify abort on exit - [ ] RTK: connect ZED-F9P, verify `/gps/fix` status=2, tolerance auto-tightens 🤖 Generated with [Claude Code](https://claude.com/claude-code)
sl-perception added 1 commit 2026-03-01 00:53:25 -05:00
Implements Phase 2d outdoor autonomous navigation for SaltyBot.
GPS source: SIM7600X /gps/fix from PR #65 (saltybot_cellular).

saltybot_outdoor package:
- osm_router_node: Overpass API + A* haversine graph + Douglas-Peucker
  simplification, /outdoor/route (Path) + /outdoor/waypoints (PoseArray)
- gps_waypoint_follower_node: GPS->Nav2 navigate_through_poses bridge,
  quality-adaptive tolerances (2m cellular / 0.30m RTK)
- geofence_node: ray-casting polygon safety, emergency stop on violation
- outdoor_nav.launch.py: dual-EKF + navsat_transform + all nodes
- outdoor_nav_params.yaml: 1.5m/s, no static_layer, 2m GPS tolerance
- ekf_outdoor.yaml: robot_localization dual-EKF + navsat_transform
- geofence_vertices.yaml: template with usage instructions

docker-compose.yml: fix malformed saltybot-surround block; add
saltybot-outdoor service (depends on saltybot-nav2, OSM NVMe cache)

SLAM-SETUP-PLAN.md: Phase 2d done

RTK upgrade: SIM7600X (+-2.5m) -> ZED-F9P (+-2cm), set use_rtk:=true

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
seb merged commit b3c03e096f into main 2026-03-01 01:00:43 -05:00
seb deleted branch sl-perception/outdoor-nav 2026-03-01 01:00:43 -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#67
No description provided.