OccupancyGrid
SUMMARY
A grid representing occupancy in a 2D environment.
python
import numpy as np
from telekinesis import datatypes
grid = datatypes.OccupancyGrid(np.zeros((1, 1), dtype=np.int8), resolution=1.0)Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
data | np.ndarray | Required | (H, W) int8 array of cell values (FREE, OCCUPIED, or UNKNOWN). A contiguous input array is stored by reference, not copied — pass arr.copy() explicitly if the source array may be mutated afterward. |
resolution | float | Required | Meters per cell. |
origin_x | float | 0.0 | World x-coordinate of cell (0, 0)'s lower-left corner. |
origin_y | float | 0.0 | World y-coordinate of cell (0, 0)'s lower-left corner. |
origin_yaw | float | 0.0 | Rotation of the grid relative to world axes, in radians. ROS represents this as a quaternion on info.origin.orientation; here it's stored as a plain yaw float instead. |
Raises
| Exception | Condition |
|---|---|
TypeError | data is not an np.ndarray |
ValueError | data.dtype is not int8 |
ValueError | data is not 2-D |
ValueError | data contains a value outside {UNKNOWN} ∪ [FREE, OCCUPIED] (i.e. outside {-1} ∪ [0, 100]) |
Constants
| Constant | Value | Description |
|---|---|---|
FREE | 0 | Cell is known to be unoccupied. |
OCCUPIED | 100 | Cell is known to be occupied. |
UNKNOWN | -1 | Cell occupancy is unknown. |
These are class-level constants, accessible as OccupancyGrid.FREE (or off any instance) without constructing a grid.
Attributes
| Attribute | Type | Description |
|---|---|---|
data | np.ndarray | Defensive copy of the underlying (H, W) int8 grid. Mutating the returned array does not affect the OccupancyGrid. |
shape | tuple[int, int] | (height, width) cell counts. |
height | int | Grid height in cells (shape[0]). |
width | int | Grid width in cells (shape[1]). |
resolution | float | Meters per cell. |
origin_x | float | World x-coordinate of cell (0, 0)'s lower-left corner. |
origin_y | float | World y-coordinate of cell (0, 0)'s lower-left corner. |
origin_yaw | float | Grid's rotation relative to world axes, in radians. |
None of these attributes have setters — an OccupancyGrid is immutable after construction (unless you mutate the array you originally passed in, since it's stored by reference rather than copied).
Methods
| Method | Type | Description |
|---|---|---|
OccupancyGrid.coerce(value) | OccupancyGrid | Converts a dict of grid fields into an OccupancyGrid. Accepts a dict with data and resolution keys; origin_x, origin_y, and origin_yaw are optional. If value is already an OccupancyGrid, it is returned unchanged. |
Operators
| Operation | Behavior |
|---|---|
g == other | True only if other is also an OccupancyGrid with element-equal grid data and equal resolution/origin_x/origin_y/origin_yaw. False if other is an OccupancyGrid that differs in any of those. NotImplemented (effectively False) if other isn't an OccupancyGrid. |
np.asarray(g) | Returns a copy of the (H, W) int8 grid as an np.ndarray (metadata is not included); NumPy functions accept an OccupancyGrid directly. Passing copy=False raises ValueError. |
Visualization
python
import rerun as rr
# Your code block
# ....
rr.init("occupancy_grid_example", spawn=True)
datatypes.visualize(grid, entity_path="/grid", label="OccupancyGrid")Example
python
"""Demonstrates the Telekinesis OccupancyGrid datatype."""
import time
import numpy as np
import rerun as rr
from loguru import logger
from telekinesis import datatypes
def occupancy_grid_example():
"""Demonstrate creation, inspection, operations, visualization, and serialization."""
# ======================= Create ============================================
height, width = 20, 20
data = np.full((height, width), datatypes.OccupancyGrid.UNKNOWN, dtype=np.int8)
data[10, 5] = datatypes.OccupancyGrid.OCCUPIED
data[10, 6] = datatypes.OccupancyGrid.FREE
data[10, 7] = datatypes.OccupancyGrid.OCCUPIED
grid = datatypes.OccupancyGrid(
data, resolution=0.05, origin_x=-5.0, origin_y=-5.0, origin_yaw=0.0
)
logger.info(f"Created OccupancyGrid: {grid}")
# ======================= Inspect ===========================================
logger.info(f"data=\n{grid.data}")
logger.info(f"shape={grid.shape}")
logger.info(f"height={grid.height}")
logger.info(f"width={grid.width}")
logger.info(f"resolution={grid.resolution} m/cell")
logger.info(f"origin_x={grid.origin_x}")
logger.info(f"origin_y={grid.origin_y}")
logger.info(f"origin_yaw={grid.origin_yaw}")
logger.info(f"FREE={datatypes.OccupancyGrid.FREE}")
logger.info(f"OCCUPIED={datatypes.OccupancyGrid.OCCUPIED}")
logger.info(f"UNKNOWN={datatypes.OccupancyGrid.UNKNOWN}")
# ======================= Operations =========================================
occupied = int(np.sum(grid.data == datatypes.OccupancyGrid.OCCUPIED))
free = int(np.sum(grid.data == datatypes.OccupancyGrid.FREE))
unknown = int(np.sum(grid.data == datatypes.OccupancyGrid.UNKNOWN))
logger.info(f"occupied={occupied}, free={free}, unknown={unknown}")
numpy_array = np.asarray(grid)
logger.info(f"NumPy array via __array__: shape={numpy_array.shape}, dtype={numpy_array.dtype}")
logger.info(f"grid == grid: {grid == grid}")
# ======================= Visualize =========================================
rr.init("occupancy_grid_example", spawn=True)
datatypes.visualize(grid, entity_path="/occupancy_grid", label="Occupancy Grid")
# ======================= Serialize / Deserialize ===========================
start = time.perf_counter()
serialized = datatypes.serialize(grid)
serialization_ms = (time.perf_counter() - start) * 1000
start = time.perf_counter()
deserialized = datatypes.deserialize(serialized)["param_0"]
deserialization_ms = (time.perf_counter() - start) * 1000
logger.info(f"Deserialized OccupancyGrid: {deserialized}")
logger.info(f"Round-trip successful: {grid == deserialized}")
logger.info(f"Serialization time: {serialization_ms:.3f} ms")
logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")
if __name__ == "__main__":
occupancy_grid_example()
