Skip to main content

PyTerrainMap

Spatial intelligence platform for multi-robot terrain mapping — an append-only, H3-indexed observation store with temporal decay, a real HTTP/HTTPS API server, and terrain-intelligence helpers, built on a Rust core with PyO3 bindings.

CI PyPI License: Apache 2.0 Python 3.10+

What it is

PyTerrainMap is an append-only observation store for multi-robot terrain data (TerrainMap), indexed spatially on an H3 hexagonal grid and temporally with confidence that decays with age. It exposes spatial + temporal querying, a real HTTP/HTTPS server you can start from Python (start_server(...)), and terrain-intelligence helpers (analyze_terrain(), assess_mobility(), is_accessible(), explain_field()). The core is Rust; the Python bindings are built with PyO3/maturin. Observations can be added and queried but never deleted or overwritten through the normal API.

Features

  • Append-only, H3-indexed store — observations keyed by (H3Cell, ElevationBucket) with exponential/linear confidence decay.
  • Real HTTP/HTTPS API server — pyterrain_map.start_server(host, port, tls=...); tested end-to-end in Rust and Python (including a TLS handshake). Endpoints include GET /health, GET /stats, POST /observations, POST /query/spatial.
  • Terrain intelligence — analyze_terrain() queries real elevation (Open-Meteo / Copernicus DEM GLO-90) at the center and four cardinal points and derives a real measured slope; assess_mobility() scales difficulty, speed, and traversability per robot type (drone / wheeled / quadruped / humanoid).
  • Traversability knowledge graph — implemented and tested.
  • 3D reconstruction and elevation lookup — SLAM keyframe/loop-closure tracking, real multi-view photogrammetry geometry, Cesium 3D Tiles export, and local SRTM tile lookup are reachable from Python through the allowlisted run_op() / ops() JSON bridge (see Advanced operations).
  • Gaussian-splatting probabilistic mapping — fusion and storage work; frontier scoring and semantic classification are partial.
  • Persistent storage — PostgreSQL is real end-to-end from Python (TerrainMap.with_postgres(...), push_observation/push_batch write-through, restore_from_backend()).
  • ROS 2 sensor bridge — duck-typed LaserScan/PointCloud2, odometry, IMU, NavSatFix, RGB, and thermal adapters without importing rclpy/rospy.
  • CLI — pytm (setup, configure, version, query) and pytm-setup.

Who it's for / Use cases

  • Fusing terrain observations from multiple robots into one spatially and temporally queryable index with age-decayed confidence.
  • Standing up an HTTP API over the store for other services to query without building a server layer.
  • Robot-specific mobility assessment — decide whether a drone/wheeled/quadruped/humanoid platform can traverse an area, from real slope data.
  • 3D Tiles export for SLAM/photogrammetry output.
  • Persistence from Python — write-through and restore-on-startup against PostgreSQL.

What it is not

  • Not a full camera-to-map SLAM pipeline. Photogrammetry requires caller-supplied 2D keypoint detections (imaging is deliberately Python-side); slam.track maintains a keyframe pose graph rather than running visual odometry from raw images. Both are exposed through the run_op() JSON bridge with those limits documented.
  • Not fully offline. analyze_terrain() makes a real network call to a public elevation API and raises an error (rather than fabricating data) if it cannot reach it.
  • Not all storage backends are live. SQLite and BigQuery are config/schema types with no live connection; only PostgreSQL is real end-to-end.
  • Gaussian-splatting mapping is partially implemented — frontier "strategic value" scoring and semantic terrain classification are placeholder, and splat temporal decay is a no-op.
  • Not a hosted service and not ML-based object classification.

Project status

Alpha (Development Status 3), version 1.11.0. The append-only store, H3/temporal indexing, HTTP/HTTPS server, PostgreSQL persistence, and terrain-slope intelligence are implemented and tested. The Rust core is now cargo clippy --release -- -D warnings clean (0 warnings) and cargo test passes except for one documented, pre-existing failing test (exploration::gaussian_frontier_integration::tests::test_score_frontier_with_high_uncertainty); the remaining dead-code fields have been wired into real behavior (temporal decay application, cache update policy, scheduler temporal-correction queue, fleet conflict resolution, predictive-caching learning rates, Postgres table name, federated query accessors). Prebuilt wheels are published for macOS arm64 only; other platforms build from the source distribution with a Rust toolchain. See docs/DATA_INTEGRITY.md and docs/ for details.

Installation

pip install pyterrainMap

# or with uv
uv pip install pyterrainMap

python -c "import pyterrain_map; print(pyterrain_map.__version__)"

Requires Python 3.10+. Prebuilt wheels are macOS arm64 only; on other platforms build from source:

git clone https://github.com/Mullassery/PyTerrainMap.git
cd PyTerrainMap
pip install maturin
maturin develop --release

Quick start

import json, time
from pyterrain_map import TerrainMap, Observation, GeoPoint, analyze_terrain, assess_mobility

terrain = TerrainMap()  # in-memory, append-only

terrain.push_observation(Observation(
    robot_id="robot-1", timestamp=int(time.time()),
    lat=40.7128, lon=-74.0060, sensor_type="thermal",
    value_json=json.dumps({"celsius": 22.5}), confidence=0.95,
))

result = terrain.query(GeoPoint(40.7128, -74.0060), region_radius_km=1.0, time_window_seconds=3600)
print(f"Found {result.count} observations, avg confidence {result.avg_confidence:.1%}")

terrain_info = analyze_terrain(40.7128, -74.0060, radius_km=1.0)
for robot_type in ("drone", "wheeled", "quadruped", "humanoid"):
    mobility = assess_mobility(terrain_info, robot_type)
    print(robot_type, mobility.traversable, mobility.difficulty_label())

Grid-map JSON export

Aggregate observations into a lightweight elevation/confidence grid JSON:

from pyterrain_map.gridmap import write_grid_map

write_grid_map(observations, "terrain-grid.json", cell_size_m=10)

Cells carry x, y, mean elevation_m, confidence and observation count. This is a documented JSON interchange for custom viewers; it is not the ROS grid_map binary/message format and does not claim OctoMap compatibility.

Usage

Start the API server (plain HTTP in-process; tls=True uses a self-signed dev certificate):

from pyterrain_map import start_server

handle = start_server(host="127.0.0.1", port=8080)
# GET /health, GET /stats, POST /observations, POST /query/spatial ...
handle.stop()
curl -X POST http://127.0.0.1:8080/observations \
  -H "Content-Type: application/json" \
  -d '{"robot_id":"robot-1","timestamp":1700000000000000,"latitude":40.7128,"longitude":-74.0060,"sensor_type":"thermal","sensor_value":{"celsius":22.5},"confidence":0.9,"metadata":{}}'

curl http://127.0.0.1:8080/stats
pytm setup                       # interactive configuration wizard
pytm query --lat 40.1 --lon -74.5 --radius-km 0.5 --json

PostgreSQL persistence from Python:

terrain = TerrainMap.with_postgres("postgres://user:pass@localhost/terrain", pool_size=5)
terrain.restore_from_backend()

Documentation

Known issues and deferred work

Blocked / failed:

  • Linux/Windows wheels; real SQLite/BigQuery backends.

Rejected / deferred:

  • Full SLAM from scratch.

Full shipped/blocked/rejected detail: QUEUE_STATUS.md.

Contributing

See CONTRIBUTING.md. Bug reports: GitHub Issues. Support: mullassery@gmail.com.

Fleet sync with SyncFleet (operation-capture bridge)

PyTerrainMap pairs with SyncFleet, a secure, local-first, peer-to-peer SQLite synchronization engine. The intended design gives a multi-robot edge swarm an out-of-the-box decentralized map-sharing protocol: each robot accumulates terrain observations in its local PyTerrainMap store, and SyncFleet replicates the selected observation table to authorized peers over mutual-TLS 1.3 — with no cloud round-trip or broker, so it keeps working across intermittent or air-gapped links.

Why they fit together

  • Observations are append-only, so cross-robot inserts never conflict — the case SyncFleet's single-writer default handles cleanly, without needing CRDTs.
  • The observation table maps to a SyncFleet dataset (table allowlist), and each observation UUID becomes an operation entity_id.
  • Both are Rust + Tokio + rustls / TLS 1.3 with an edge, local-first focus.
  • SyncFleet supplies mutual-TLS transport, peer enrollment, and per-dataset ACLs for the replication channel.

Status: operation capture is implemented and tested. pyterrain_map.syncfleet.SyncFleetBridge turns observations into SyncFleet dataset apply operations and registers the terrain dataset. The cross-repo test tests/test_syncfleet_bridge.py runs the real syncfleet binary and verifies the SQLite operation_journal rows. See docs/SYNCFLEET_INTEGRATION.md.

Remaining work: automatic capture from TerrainMap.push_observation (callers invoke the bridge), materialization of replicated operations into a typed table, and a PostgreSQL outbox. Transport, peer enrollment, and ACLs are SyncFleet's existing commands.

Part of the robotics & autonomy family

PyTerrainMap is one of six complementary, composable tools in the Mullassery robotics & autonomy family. Together they form a single stack: perceive → map → simulate → learn → debug → coordinate the fleet.

Tool Role What it does
PyRoboVision Perception Multi-object tracker (Kalman filter + Hungarian algorithm) and trajectory predictor for robot perception.
PyTerrainMap Mapping / SLAM This project — fuses multi-robot terrain observations into a spatial-temporal store, with H3 spatial indexing and SLAM.
PyRoboSimulator Simulation World simulator for autonomous systems, with a FastAPI backend.
PyRoboFrames Learning data Rust-backed ML dataloader for robot-learning datasets (native LeRobot format, Apple Silicon hardware video decode).
PyRoboReplay Mission forensics Forensic-debugging and causal-analysis engine for autonomous robot mission replay.
SyncFleet Fleet coordination Rust + SQLite, peer-to-peer state sync for robotics fleets — mutual-TLS 1.3, version-vector replication, mDNS discovery; conflict resolution on the roadmap.

Each works standalone, but they're complementary by design. The SyncFleet bridge (above) lets terrain observations sync across fleets without relying on a central database.

Browse all projects →

License

Apache License 2.0 — see LICENSE.

Metadata

Release files for pyterrainMap 1.11.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyterrainMap 1.11.0
File Size Uploaded Provenance Actions
pyterrainmap-1.11.0.tar.gz 697.5 kB Without provenance Details for pyterrainmap-1.11.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pyterrainMap 1.11.0
File Interpreter ABI Platform Actions
pyterrainmap-1.11.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details for pyterrainmap-1.11.0-cp310-abi3-macosx_11_0_arm64.whl

Total release size: 3.4 MB

Release files / pyterrainmap-1.11.0.tar.gz

Download URL pyterrainmap-1.11.0.tar.gz
Size 697.5 kB
Tags Source
SHA-256 checksum
How to use checksums
228d6921ac6f204072e8a6439d60356f6e906b9e265ca0a25f49d494bf19876b
BLAKE2b-256 checksum
How to use checksums
d429fc48f864f6c84400d4844b421578f8b3279d46cd37cc651a8d38d9e60d2e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / pyterrainmap-1.11.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL pyterrainmap-1.11.0-cp310-abi3-macosx_11_0_arm64.whl
Size 2.7 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
2ded3f9de3f3ee618d6821372669896db3084afa56f078347efab9416d0d8aff
BLAKE2b-256 checksum
How to use checksums
59439cb94565d0ccd4137d8467c98a4a8e92ff6f7dd8111307dec892faf5b50f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Security for pyterrainMap 1.11.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page