Python example: mrpt_maps_example.py

Point clouds, occupancy grids, voxel maps and multi-maps with mrpt.maps.

Modules: mrpt.maps, mrpt.config, mrpt.obs, mrpt.math, mrpt.poses

  1#!/usr/bin/env python3
  2"""
  3Point clouds, occupancy grids, voxel maps and multi-maps with mrpt.maps.
  4
  5Demonstrates:
  6  - CSimplePointsMap: point cloud creation, numpy import/export
  7  - COccupancyGridMap2D: create, set/get cells, numpy export
  8"""
  9
 10import numpy as np
 11import tempfile, os
 12from mrpt.maps import CSimplePointsMap, COccupancyGridMap2D
 13
 14# ---------------------------------------------------------------------------
 15# CSimplePointsMap — XYZ point cloud
 16# ---------------------------------------------------------------------------
 17pts = CSimplePointsMap()
 18
 19# Insert individual points
 20for i in range(5):
 21    pts.insertPoint(float(i), float(i) * 0.1, 0.0)
 22
 23print(f"CSimplePointsMap: {len(pts)} points")
 24x, y, z = pts.getPoint(2)
 25print(f"  point[2]: ({x:.2f}, {y:.2f}, {z:.2f})")
 26
 27# NumPy round-trip
 28cloud = np.array([[1.0, 2.0, 3.0],
 29                  [4.0, 5.0, 6.0],
 30                  [7.0, 8.0, 9.0]], dtype=np.float32)
 31pts2 = CSimplePointsMap()
 32pts2.setPointsFromNumpy(cloud)
 33arr = pts2.getPointsAsNumpy()
 34print(f"\nNumPy round-trip: {arr.shape}")
 35np.testing.assert_allclose(arr, cloud, atol=1e-5)
 36print("  numpy round-trip ✓")
 37
 38# Save/load text
 39with tempfile.NamedTemporaryFile(suffix=".txt", delete=False) as f:
 40    fname = f.name
 41try:
 42    pts2.save3D_to_text_file(fname)
 43    pts3 = CSimplePointsMap()
 44    pts3.load3D_from_text_file(fname)
 45    assert pts3.size() == 3
 46    print(f"  save/load text ✓ ({pts3.size()} points)")
 47finally:
 48    os.unlink(fname)
 49
 50# ---------------------------------------------------------------------------
 51# COccupancyGridMap2D — probabilistic 2D occupancy grid
 52# ---------------------------------------------------------------------------
 53grid = COccupancyGridMap2D(-5.0, 5.0, -5.0, 5.0, 0.1)  # 10x10 m, 0.1 m/cell
 54print(f"\nCOccupancyGridMap2D: {grid.getSizeX()}x{grid.getSizeY()} cells, "
 55      f"res={grid.getResolution()} m")
 56
 57# Mark an obstacle cell (low probability = occupied)
 58grid.setCell(50, 50, 0.1)
 59grid.setPos(1.0, 1.0, 0.1)
 60
 61print(f"  cell(50,50) occupancy = {grid.getCell(50,50):.2f}")
 62print(f"  pos(1,1) occupancy    = {grid.getPos(1.0,1.0):.2f}")
 63
 64# Index ↔ metric conversion
 65ix = grid.x2idx(1.0)
 66iy = grid.y2idx(1.0)
 67print(f"  pos(1,1) → cell index ({ix},{iy})")
 68print(f"  cell({ix},{iy}) → pos ({grid.idx2x(ix):.2f},{grid.idx2y(iy):.2f})")
 69
 70# NumPy export
 71g_np = grid.getAsNumpy()
 72print(f"\nGrid as numpy: shape={g_np.shape}, dtype={g_np.dtype}")
 73assert g_np.shape == (grid.getSizeY(), grid.getSizeX())
 74print("  numpy export ✓")
 75
 76# ---------------------------------------------------------------------------
 77# CMultiMetricMap: several maps defined in a config file, updated together
 78# ---------------------------------------------------------------------------
 79import math
 80from mrpt.config import CConfigFileMemory
 81from mrpt.maps import CMultiMetricMap, TSetOfMetricMapInitializers, CVoxelMap, COctoMap
 82from mrpt.obs import CObservation2DRangeScan, CSensoryFrame
 83from mrpt.math import TPoint3D
 84from mrpt.poses import CPose3D
 85
 86map_defs = TSetOfMetricMapInitializers()
 87map_defs.loadFromConfigFile(CConfigFileMemory(
 88    "[Maps]\noccupancyGrid_count=1\npointsMap_count=1\n"
 89    "[Maps_occupancyGrid_00_creationOpts]\nresolution=0.05\n"), "Maps")
 90multimap = CMultiMetricMap(map_defs)
 91print(f"\n{multimap}: {[type(m).__name__ for m in multimap]}")
 92
 93scan = CObservation2DRangeScan()
 94scan.aperture = math.pi
 95scan.resizeScan(181)
 96for i in range(181):
 97    scan.setScanRange(i, 3.0)
 98    scan.setScanRangeValidity(i, True)
 99sf = CSensoryFrame()
100sf.insert(scan)
101multimap.insertObs(sf)  # inserted into both maps
102points = next(m for m in multimap if isinstance(m, CSimplePointsMap))
103print(f"  points after inserting a scan: {len(points)}")
104print(f"  observation log-likelihood at origin: "
105      f"{multimap.computeObservationLikelihood(scan, CPose3D()):.2f}")
106
107# ---------------------------------------------------------------------------
108# 3D occupancy: sparse voxel map and octomap
109# ---------------------------------------------------------------------------
110voxels = CVoxelMap(0.1)
111voxels.insertPointCloudAsRays(points, TPoint3D(0, 0, 0))
112wall_pt = points.getPoint(90)  # (x, y, z) of the central ray end point
113print(f"\nCVoxelMap: {len(voxels.getOccupiedVoxels())} occupied voxels, "
114      f"p(occupied) at a wall = {voxels.getPointOccupancy(*wall_pt):.2f}, "
115      f"at the sensor = {voxels.getPointOccupancy(0.5, 0.0, 0.0):.2f}")
116
117octo = COctoMap(0.1)
118octo.insertPointCloud(points, 0.0, 0.0, 0.0)
119print(f"COctoMap: {octo.size()} nodes")