Python example: mrpt_poses_example.py

SE(2) and SE(3) pose composition, Lie algebra and pose PDFs with mrpt.poses.

Modules: mrpt.poses, mrpt.math

  1#!/usr/bin/env python3
  2"""
  3SE(2) and SE(3) pose composition, Lie algebra and pose PDFs with mrpt.poses.
  4
  5Demonstrates:
  6  - CPose2D: 2D pose composition, inverse, norm
  7  - CPose3D: 3D pose, static builders, rotation matrix, inverseComposePoint
  8  - CPose3DPDFGaussian: Gaussian PDF over SE(3)
  9  - SE_average2 / SE_average3: pose averaging on the Lie group
 10  - CPoint2D / CPoint3D: bare point types
 11"""
 12
 13import math
 14import numpy as np
 15from mrpt.poses import (
 16    CPose2D, CPose3D,
 17    CPose3DPDFGaussian,
 18    SE_average2, SE_average3,
 19    CPoint2D, CPoint3D,
 20)
 21
 22# ---------------------------------------------------------------------------
 23# CPose2D — 2D pose arithmetic
 24# ---------------------------------------------------------------------------
 25print("── CPose2D ─────────────────────────────────")
 26p1 = CPose2D(1.0, 2.0, math.radians(45.0))
 27print(f"p1 = {p1}")
 28
 29p1.x += 0.5
 30p1.phi = math.radians(90.0)
 31print(f"p1 modified: {p1}  norm={p1.norm():.4f}")
 32
 33p2 = CPose2D(2.0, 0.0, 0.0)
 34p3 = p1 + p2
 35print(f"p3 = p1 + p2: {p3}")
 36
 37p3_inv = p3.inverse()
 38print(f"p3 inverse:   {p3_inv}")
 39
 40# round-trip: p + (-p) ≈ identity
 41identity = p3 + p3_inv
 42print(f"p3 + p3_inv ≈ 0: x={identity.x:.6f} y={identity.y:.6f}")
 43assert abs(identity.x) < 1e-6 and abs(identity.y) < 1e-6
 44print("  composition round-trip ✓")
 45
 46# ---------------------------------------------------------------------------
 47# CPose3D — 3D pose
 48# ---------------------------------------------------------------------------
 49print("\n── CPose3D ─────────────────────────────────")
 50p3d = CPose3D.FromXYZYawPitchRoll(1.0, 2.0, 3.0, math.radians(30), 0, 0)
 51print(f"p3d = {p3d}")
 52print(f"  z = {p3d.z:.4f}")
 53
 54p3d.z = 5.0
 55print(f"  z after set: {p3d.z:.4f}")
 56
 57import numpy as np
 58rot = np.array(p3d.getRotationMatrix().as_numpy())
 59print(f"  rotation matrix (3x3 numpy):\n{rot}")
 60assert rot.shape == (3, 3)
 61
 62# inverseComposePoint: transform a global point to robot frame
 63global_pt = p3d.inverseComposePoint(1.0, 2.0, 5.0)
 64print(f"  inverseComposePoint((1,2,5)): {global_pt}")
 65
 66# ---------------------------------------------------------------------------
 67# CPoint2D / CPoint3D
 68# ---------------------------------------------------------------------------
 69pt2 = CPoint2D(3.0, 4.0)
 70pt3 = CPoint3D(1.0, 2.0, 3.0)
 71print(f"\nCPoint2D: {pt2}")
 72print(f"CPoint3D: {pt3}")
 73
 74# ---------------------------------------------------------------------------
 75# CPose3DPDFGaussian — Gaussian distribution over SE(3)
 76# ---------------------------------------------------------------------------
 77print("\n── CPose3DPDFGaussian ──────────────────────")
 78mean_pose = CPose3D(0, 0, 0, 0, 0, 0)
 79pdf = CPose3DPDFGaussian(mean_pose)
 80print(f"PDF mean: {pdf.mean}")
 81
 82pdf.mean = CPose3D(10, 0, 0, 0, 0, 0)
 83print(f"PDF mean after set: {pdf.mean}")
 84
 85sample = pdf.drawSingleSample()
 86print(f"Random sample: {sample}")
 87
 88# ---------------------------------------------------------------------------
 89# SE_average3 — Lie-group mean of SE(3) poses
 90# ---------------------------------------------------------------------------
 91print("\n── SE_average3 ─────────────────────────────")
 92avg = SE_average3()
 93avg.append(CPose3D(10.0,  0.0, 0.0, 0, 0, 0))
 94avg.append(CPose3D(10.1,  0.1, 0.0, 0, 0, 0))
 95avg.append(CPose3D( 9.9, -0.1, 0.0, 0, 0, 0))
 96result = avg.get_average()
 97print(f"Average of 3 poses near (10,0,0): {result}")
 98assert abs(result.x - 10.0) < 0.2
 99print("  average check ✓")
100
101# SE_average2 — same for SE(2)
102avg2 = SE_average2()
103avg2.append(CPose2D(1.0, 0.0, 0.0))
104avg2.append(CPose2D(1.2, 0.0, 0.0))
105result2 = avg2.get_average()
106print(f"\nAverage of 2D poses: {result2}")
107
108# ---------------------------------------------------------------------------
109# Particle-based pose PDFs
110# ---------------------------------------------------------------------------
111from mrpt.math import TPose2D
112from mrpt.poses import CPosePDFParticles
113
114particles = CPosePDFParticles(1000)
115particles.resetUniform(-1.0, 1.0, -1.0, 1.0)
116cov, mean = particles.getCovarianceAndMean()
117print(f"\n1000 uniform particles: mean={mean}")
118print(f"  covariance diagonal: {np.diag(np.asarray(cov))}")
119particles.resetAroundSetOfPoses([TPose2D(5.0, 0.0, 0.0)], 1000, 0.1, 0.1, 0.05)
120print(f"  after resetAroundSetOfPoses: mean={particles.getMean()}")
121arr = particles.getParticlesAsNumpy()  # columns: x, y, phi, log_weight
122print(f"  particles as numpy: shape={arr.shape}")