# SaltyBot Obstacle Memory Map (Issue #453)

Persistent spatial memory system for tracking obstacles and hazards detected by LIDAR. Maintains a 2D occupancy grid that accumulates detections over time with temporal decay.

## Features

### 1. Occupancy Grid Map
- **Resolution**: 10cm per cell (configurable)
- **Grid Size**: 100×100 cells by default (~10×10 meters centered on robot)
- **Cell States**:
  - **Unknown**: Never observed (-1 in OccupancyGrid)
  - **Free**: Definitely free space (0% occupancy)
  - **Obstacle**: Detected obstacle (0–100% based on confidence)
  - **Hazard**: Persistent hazard with 3+ detections (high confidence)

### 2. Hazard Classification
- **Detection-based**: 3+ observations of same location = hazard
- **Permanent**: Hazards persist even with temporal decay
- **Confidence Tracking**: 0.0–1.0 based on detection history
- **Quality Metric**: Increases confidence with repeated detections

### 3. Temporal Decay
- **Hazard Decay**: 95% per day (30-day half-life)
  - Decays slowly due to persistence
  - Never drops below 30% confidence
- **Obstacle Decay**: 85% per day (~21-day half-life)
  - Faster decay than hazards
  - Reverts to free space when confidence < 20%
- **Decay Interval**: Applied every hour

### 4. LIDAR Integration
- **Input**: LaserScan on `/scan` (or `/saltybot/scan`)
- **Odometry**: Robot position from `/odom`
- **Ray Casting**: Marks hit points as obstacles, intermediate points as free
- **Range Filtering**: Configurable min/max range (default 0.1–10.0m)

### 5. ROS2 Navigation Integration
- **Output**: `/saltybot/obstacle_map` (nav_msgs/OccupancyGrid)
- **Format**: Standard OccupancyGrid for Nav2 costmap
- **Frequency**: Published at 5 Hz
- **Frame**: Map frame compatible with move_base

### 6. Persistence
- **Storage**: YAML file at `/home/seb/saltybot-data/obstacle_map.yaml`
- **Format**: Grid metadata + cell states with timestamps
- **Auto-Save**: Every 5 minutes (configurable)
- **Load on Startup**: Restores previous session's map

## Configuration

Edit `config/obstacle_memory.yaml`:

```yaml
grid_width: 100
grid_height: 100
grid_resolution: 0.1
map_file: "/home/seb/saltybot-data/obstacle_map.yaml"
auto_save_interval: 300.0
scan_max_range: 10.0
scan_min_range: 0.1
publish_rate_hz: 5.0
decay_interval_seconds: 3600.0
```

## Running

### Launch the obstacle memory node
```bash
ros2 launch saltybot_obstacle_memory obstacle_memory.launch.py
```

### Direct execution
```bash
ros2 run saltybot_obstacle_memory obstacle_memory
```

## Integration Points

1. **Navigation Stack** (Nav2)
   - Consumes `/saltybot/obstacle_map` in costmap_2d_ros
   - Influences pathfinding and local costmap

2. **LIDAR Driver** (e.g., saltybot_sensors)
   - Publishes `/scan` or `/saltybot/scan`
   - Ray angles, distances, and timestamp

3. **Odometry Provider** (e.g., wheel encoders + IMU)
   - Publishes `/odom`
   - Robot pose (x, y, theta)

4. **Dashboard/WebUI**
   - Subscribes to `/saltybot/obstacle_map`
   - Displays as overlay on navigation view
   - Hazard visualization

## Performance

- **Memory**: ~100KB per 100×100 grid
- **Computation**: O(n) per LIDAR scan (n = number of rays)
- **Persistence**: O(width×height) per save (~1ms for 100×100)
- **Decay**: O(width×height) per hour (~5ms for 100×100)
