OccupancyGrid & CostMap

OccupancyGrid represents a 2D grid map of the environment where each cell stores an occupancy probability. CostMap extends it with inflated costs around obstacles for safe path planning. Together they form the mapping and planning backbone for autonomous navigation.

When to Use

Use OccupancyGrid when your robot builds maps from sensor data (SLAM) or loads pre-built maps for localization. Use CostMap when you need to plan paths that keep a safe distance from obstacles.

ROS2 Equivalent

nav_msgs/OccupancyGrid -- same grid structure with origin, resolution, and cell values. HORUS adds CostMap as a first-class type (in ROS2 this lives in the costmap_2d package).

Cell Values

ValueMeaning
-1Unknown (unexplored)
0Free space
1-49Probably free (low probability of obstacle)
50-99Probably occupied
100Definitely occupied

Rust Example

use horus::prelude::*;

// Create a 10m x 10m map at 5cm resolution
let origin = Pose2D::new(-5.0, -5.0, 0.0);
let mut grid = OccupancyGrid::new(200, 200, 0.05, origin);

// Mark a cell as occupied
grid.set_occupancy(100, 100, 100);

// Convert between world and grid coordinates
let (gx, gy) = grid.world_to_grid(1.5, 2.0).unwrap();
let (wx, wy) = grid.grid_to_world(gx, gy).unwrap();

// Query occupancy
if grid.is_free(1.5, 2.0) {
    println!("Path is clear");
}

// Create a cost map for path planning
let costmap = CostMap::from_occupancy_grid(grid, 0.55); // 55cm inflation
let cost = costmap.cost(1.5, 2.0);

Python Example

from horus import OccupancyGrid, Topic

# Create a 100x100 grid at 5cm resolution
grid = OccupancyGrid(100, 100, 0.05)

# Set cell values
grid.set_occupancy(50, 50, 100)  # Mark as occupied

# Query the map
if grid.is_free(1.0, 1.0):
    print("Cell is free")

# Coordinate conversion
gx, gy = grid.world_to_grid(1.0, 1.0)
wx, wy = grid.grid_to_world(gx, gy)

# Publish
topic = Topic(OccupancyGrid)
topic.send(grid)

OccupancyGrid Fields

FieldTypeUnitDescription
resolutionf32m/cellMeters per cell. Default: 0.05 (5cm)
widthu32cellsGrid width
heightu32cellsGrid height
originPose2Dm, radWorld pose of the bottom-left corner
dataVec<i8>0--100Cell values, row-major. -1=unknown, 0=free, 100=occupied
frame_id[u8; 32]--Coordinate frame (e.g., "map")
metadata[u8; 64]--Free-form metadata
timestamp_nsu64nsTimestamp in nanoseconds since epoch

OccupancyGrid Methods

MethodSignatureDescription
new(w, h, res, origin)(u32, u32, f32, Pose2D) -> SelfCreate grid initialized to unknown (-1)
world_to_grid(x, y)(f64, f64) -> Option<(u32, u32)>Convert world coordinates to grid indices
grid_to_world(gx, gy)(u32, u32) -> Option<(f64, f64)>Convert grid indices to world coordinates (cell center)
occupancy(gx, gy)(u32, u32) -> Option<i8>Get cell value at grid coordinates
set_occupancy(gx, gy, val)(u32, u32, i8) -> boolSet cell value (clamped to -1..100)
is_free(x, y)(f64, f64) -> boolTrue if occupancy is in 0..50
is_occupied(x, y)(f64, f64) -> boolTrue if occupancy >= 50

CostMap Fields

FieldTypeUnitDescription
occupancy_gridOccupancyGrid--Underlying occupancy grid
costsVec<u8>0--255Cost values per cell. 253=lethal, 255=unknown
inflation_radiusf32mInflation radius. Default: 0.55
cost_scaling_factorf32--Exponential decay factor. Default: 10.0
lethal_costu8--Cost threshold for lethal obstacles. Default: 253

CostMap Methods

MethodSignatureDescription
from_occupancy_grid(grid, radius)(OccupancyGrid, f32) -> SelfCreate costmap with inflation
compute_costs()-> ()Recompute costs from occupancy data
cost(x, y)(f64, f64) -> Option<u8>Get cost at world coordinates

Common Patterns

SLAM pipeline:

LaserScan --> SLAM algorithm --> OccupancyGrid (map)
                             \-> Pose2D (localization)

Path planning pipeline:

OccupancyGrid --> CostMap (inflated) --> path planner --> NavPath
                                                      \-> CmdVel

Inflation: The CostMap applies exponential cost decay around obstacles. A cell at distance d from an obstacle gets cost proportional to (1 - d/radius)^scaling_factor. This creates a smooth gradient that path planners use to keep the robot away from walls and obstacles.