Python example: mrpt_obs_example.py

Sensor observations, odometry motion models and rawlogs with mrpt.obs.

Modules: mrpt.obs, mrpt.poses, mrpt.core

  1#!/usr/bin/env python3
  2"""
  3Sensor observations, odometry motion models and rawlogs with mrpt.obs.
  4
  5Demonstrates:
  6  - CObservation2DRangeScan: 2D laser scan, numpy helpers
  7  - CObservationOdometry: odometry reading
  8  - CObservationIMU: IMU data
  9  - CActionRobotMovement2D + CActionCollection
 10  - CSensoryFrame: bundle of observations
 11"""
 12
 13import math, numpy as np
 14from mrpt.obs import (
 15    CObservation2DRangeScan,
 16    CObservationOdometry,
 17    CObservationIMU,
 18    CActionRobotMovement2D,
 19    CActionCollection,
 20    CSensoryFrame,
 21)
 22from mrpt.poses import CPose2D, CPose3D
 23from mrpt.core import Clock
 24
 25# ---------------------------------------------------------------------------
 26# CObservation2DRangeScan
 27# ---------------------------------------------------------------------------
 28scan = CObservation2DRangeScan()
 29scan.sensorLabel = "LIDAR_FRONT"
 30scan.aperture   = math.pi           # 180° FOV
 31scan.maxRange   = 80.0
 32scan.rightToLeft = True
 33scan.resizeScan(360)                # 0.5° resolution
 34
 35# Fill synthetic ranges (arc at 5 m)
 36for i in range(360):
 37    scan.setScanRange(i, 5.0)
 38    scan.setScanRangeValidity(i, True)
 39
 40print(f"CObservation2DRangeScan: {scan}")
 41print(f"  getScanSize = {scan.getScanSize()}")
 42print(f"  getScanRange(180) = {scan.getScanRange(180):.2f} m")
 43
 44ranges = scan.getScanRangesAsNumpy()
 45valid  = scan.getValidRangesAsNumpy()
 46print(f"  ranges numpy: shape={ranges.shape}, mean={ranges.mean():.2f}")
 47assert valid.all(), "All rays should be valid"
 48print("  validity check ✓")
 49
 50# ---------------------------------------------------------------------------
 51# CObservationOdometry
 52# ---------------------------------------------------------------------------
 53odo = CObservationOdometry()
 54odo.sensorLabel = "ODO"
 55odo.odometry    = CPose2D(1.5, 0.0, 0.1)
 56print(f"\nCObservationOdometry: {odo.odometry}")
 57
 58# ---------------------------------------------------------------------------
 59# CActionRobotMovement2D + CActionCollection
 60# ---------------------------------------------------------------------------
 61action = CActionRobotMovement2D()
 62# Probabilistic odometry increment, from a Gaussian motion model:
 63motion_model = CActionRobotMovement2D.TMotionModelOptions()
 64motion_model.modelSelection = CActionRobotMovement2D.mmGaussian
 65action.computeFromOdometry(CPose2D(0.5, 0.0, 0.05), motion_model)
 66print(f"\nOdometry pose change PDF mean: {action.poseChange.getMean()}")
 67
 68col = CActionCollection()
 69col.insert(action)
 70print(f"\nCActionCollection: {col.size()} actions")
 71assert col.size() == 1
 72
 73# ---------------------------------------------------------------------------
 74# CSensoryFrame — bundle of observations
 75# ---------------------------------------------------------------------------
 76sf = CSensoryFrame()
 77sf.insert(scan)
 78sf.insert(odo)
 79print(f"\nCSensoryFrame: {sf.size()} observations")
 80assert sf.size() == 2
 81
 82# ---------------------------------------------------------------------------
 83# Datasets: CRawlog (actions + observations) and CSimpleMap (keyframes)
 84# ---------------------------------------------------------------------------
 85import os, tempfile
 86from mrpt.obs import CRawlog, CSimpleMap
 87from mrpt.poses import CPose3DPDFGaussian
 88
 89rawlog = CRawlog()
 90rawlog.insert(col)  # the action collection
 91rawlog.insert(sf)   # the sensory frame
 92simplemap = CSimpleMap()
 93simplemap.insert(CPose3DPDFGaussian(CPose3D()), sf)
 94
 95with tempfile.TemporaryDirectory() as tmpdir:
 96    fname = os.path.join(tmpdir, "demo.rawlog")
 97    assert rawlog.saveToRawLogFile(fname)
 98    loaded = CRawlog()
 99    assert loaded.loadFromRawLogFile(fname)
100    print(f"\nRawlog saved and loaded back: {loaded}")
101    for i, entry in enumerate(loaded):
102        print(f"  [{i}] {type(entry).__name__}")
103    # Large rawlogs are better processed as a stream, see
104    # CRawlog.ReadFromArchive() in global_localization.py
105
106print(f"CSimpleMap: {simplemap}, first keyframe pose: {simplemap[0].pose.getMean()}")