Skip to content

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)
API Reference
Complete API documentation for OccupancyGrid, including parameters, attributes, and methods.
View Reference →

Parameters

ParameterTypeDefaultDescription
datanp.ndarrayRequired(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.
resolutionfloatRequiredMeters per cell.
origin_xfloat0.0World x-coordinate of cell (0, 0)'s lower-left corner.
origin_yfloat0.0World y-coordinate of cell (0, 0)'s lower-left corner.
origin_yawfloat0.0Rotation 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

ExceptionCondition
TypeErrordata is not an np.ndarray
ValueErrordata.dtype is not int8
ValueErrordata is not 2-D
ValueErrordata contains a value outside {UNKNOWN}[FREE, OCCUPIED] (i.e. outside {-1}[0, 100])

Constants

ConstantValueDescription
FREE0Cell is known to be unoccupied.
OCCUPIED100Cell is known to be occupied.
UNKNOWN-1Cell occupancy is unknown.

These are class-level constants, accessible as OccupancyGrid.FREE (or off any instance) without constructing a grid.

Attributes

AttributeTypeDescription
datanp.ndarrayDefensive copy of the underlying (H, W) int8 grid. Mutating the returned array does not affect the OccupancyGrid.
shapetuple[int, int](height, width) cell counts.
heightintGrid height in cells (shape[0]).
widthintGrid width in cells (shape[1]).
resolutionfloatMeters per cell.
origin_xfloatWorld x-coordinate of cell (0, 0)'s lower-left corner.
origin_yfloatWorld y-coordinate of cell (0, 0)'s lower-left corner.
origin_yawfloatGrid'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

MethodTypeDescription
OccupancyGrid.coerce(value)OccupancyGridConverts 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

OperationBehavior
g == otherTrue 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()