Skip to content

Perception-Based Localization

Pose Engine

Offline and online 6DoF pose and odometry from lidars and/or cameras. GNSS-independent. Accurate, precise, and deterministic.

Get a free offline pose trajectory See how it works

<2cm & <2mrad
map-relative precision
GNSS-independent
perception-based localization
offline & online
deployment

Why it matters

GNSS isn't a reliable solution.

Urban canyons, solar events, and spoofing/jamming degrade GNSS accuracy, often without a valid quality indicator. Pose Engine localizes to a map using perception sensors, with no dependency on satellite signals.

GNSS-independent

Mapping with lidars or cameras; localization with same plus IMU and encoders. No satellite signal, RTK base station, or environment modification required.

Durable maps

Maps are long-term reliable in dynamic environments with third-party movers and seasonal changes.

Fleet-scale consistency

Every robot (including different types) localizes to the same map. Maps are modular; updates and distribution occur only on regions that change. Localization is consistent.

How it works

Offline: Collect data, get pose.

No special motion required. Collect and upload sensor data, get back a 6DoF trajectory for each body-attached frame of interest.

1
Capture sensor data

Capture data from all sensors (lidars, cameras, radars, IMUs, encoders, GNSS and/or INS units) during normal robot operation. If the robot has not been recently calibrated, collect calibration data immediately before or after.

2
Upload sensor data or run locally

For Pose-as-a-Service with human review, upload the sensor data via the Data Portal API.

python3 upload.py --platform R2 --instance D2 /logs/data.mcap

For local offline pose generation, invoke the Docker file with a path to the data.

docker run --rm -u 1000:1000 -v /logs/data.mcap quay.io/msa/customer:latest localize --platform R2 --instance D2
3
Get a pose trajectory

Receive CSV files per selected sensor coordinate frame: local map pose with body-frame velocities, and ECEF pose if GNSS is included in the sensor data.

Online: Map, bootstrap, localize.

Collect data and build a map of the site. Bootstrap the robot into the map upon initialization. Move within the mapped area and get odometry and pose.

1
Map the site

Move one or more data collection vehicles throughout the site. Capture sensor data from all sensors (lidars, cameras, radars, IMUs, encoders, GNSS and/or INS units). Build a map.

2
Bootstrap into map

Using a hint for starting pose from last known pose, GNSS of any quality, fiducial markers, or even the scene itself, determine the initial robot pose for a new localization session.

3
Get pose and odometry

Get high-frequency, low-latency 6DoF map-relative pose and odometry in whatever representation, message, and channel required by your autonomy stack.

Pose Engine offline outputs

Pose trajectory for annotation and labelling pipelines.

Pose for each sensor coordinate frame. ECEF pose included if GNSS data is provided. Same rigid-transform convention throughout; the local file also carries body-frame velocities.

# world-from-body rigid transform, body-frame velocities
# world frame: local map origin (set at Platform Setup)
# <customer>_<log-id>_<sensor-cf>.local.csv
time_s,               px_m,      py_m,       pz_m,     rx_rad,       ry_rad,       rz_rad,       vx_mps,   vy_mps,    vz_mps,   wx_rps,    wy_rps,    wz_rps
1776371688.261120081, -0.991453, -13.979609, 0.898994, -0.013059700, -0.004910992, -0.945530403, 0.007306, -0.004017, 0.001259, -0.000613, -0.000246, 0.001082
1776371688.271120071, -0.991448, -13.979691, 0.899010, -0.013065724, -0.004917313, -0.945524474, 0.006687, -0.004729, 0.001629, 0.000016,  -0.001170, 0.000193
time_sTime of validity (seconds)
px_m, py_m, pz_mPosition in local map frame (meters)
rx_rad, ry_rad, rz_radRotation as so(3) logarithm; see Rotation note tab
vx_mps, vy_mps, vz_mpsBody-frame linear velocity: +X forward, +Y left, +Z up (m/s)
wx_rps, wy_rps, wz_rpsBody-frame angular velocity: roll, pitch, yaw rate (rad/s)
# world-from-body rigid transform
# world frame: ECEF (only available if GNSS data is provided)
# <customer>_<log-id>_<sensor-cf>.ecef.csv
time_s,               px_m,         py_m,         pz_m,        rx_rad,      ry_rad,      rz_rad
1776371688.261120081, -2687738.311, -4291128.930, 3865469.473, 0.968923418, 0.190917898, -1.392946097
1776371688.301120043, -2687738.311, -4291128.931, 3865469.473, 0.968897924, 0.190896033, -1.392959755
time_sTime of validity (seconds)
px_m, py_m, pz_mPosition in ECEF frame (meters)
rx_rad, ry_rad, rz_radRotation as so(3) logarithm; see Rotation note tab
Rotation convention

Rotation is stored as the so(3) logarithm (axis-angle vector form). The norm of [rx, ry, rz] is the rotation angle in radians; the unit vector is the axis of rotation.

# Recover rotation matrix R from axis-angle vector w = [rx, ry, rz]
import numpy as np
 
def rodrigues(w):
    t = np.linalg.norm(w)
    if t < 1e-9:
        return np.eye(3)
    skew = np.array([[    0, -w[2],  w[1]],
                     [ w[2],     0, -w[0]],
                     [-w[1],  w[0],     0]])
    return np.eye(3) + np.sin(t)/t*skew + (1-np.cos(t))/t**2 * skew@skew
 
# Equivalent library calls:
#   scipy.spatial.transform.Rotation.from_rotvec(w).as_matrix()
#   kornia.geometry.conversions.angle_axis_to_rotation_matrix(w)
#   pypose.mat_from_rotvec(w)
 
# Apply the transform:
#   xyz_world = R @ xyz_body + p

What makes it different

Built for mission-critical production deployment.

Light footprint

CPU-only. No GPU, no inference. 3–4 cores on Jetson Orin or equivalent. Auditable, reproducible results.

Modular maps

Modular spatial chunks. Multi-agent map contributions from heterogeneous platforms. Maps can be updated without full reprocessing.

Reliable

Map support and localization quality metrics provide context for reliable "trust when present" outputs.

Leverages Calibration Anywhere

Accurate extrinsics, intrinsics, and time offsets from Calibration Anywhere directly improve localization accuracy.

Supported sensors

Mapping with lidars or cameras;
localization from same + IMU and/or encoders.

Cameras
  • RGB, multispectral
  • Stereo, depth (stereo or indirect ToF)
  • Rolling shutter and global shutter
  • Fisheye, wide-angle, narrow-angle, catadioptric, pinhole
Lidars
  • 3D mechanical scanning, fixed, and flash lidars
  • Pulse or FMCW (doppler) modulation
IMUs
  • 3DoF gyro + 3DoF accelerometer
Odometry
  • Wheel encoders (shaft ticks or wheel speeds)
GNSS
  • One or more receivers
  • With or without RTK corrections
INS
  • Any reported pose or position estimates

Deployment options

From Pose-as-a-Service to production localization.

Start with offline pose generation in the cloud to build ground truth, fix annotation pipelines, and train better models. Bring that same solution on-prem to run locally on stored data. Deploy online when you're ready to replace your localization stack.

Remote service (Pose-aaS)
Pose for your data pipeline. Human reviewed.
  • Upload sensor data to Data Portal
  • Typical TAT: 1-2 business days with human review
  • Suitable for ground truth generation, annotation and labelling pipelines, and ML model training
On-prem but offline
Pose for your data pipeline. No data transfer.
  • Invoke Docker container with attached sensor data
  • Typical TAT: minutes to hours, depends on the data size
  • Suitable for ground truth generation, annotation and labelling pipelines, and ML model training
Online (on-robot)
Mission-critical online pose in a Docker container.
  • 3–4 cores, CPU only, Jetson Orin or equivalent
  • Configurable output rate, format, and quality signals
  • Supports air-gapped environments
  • Suitable for production deployments

See it work for your robot.

Share sensor data; we'll send you a free pose result. No commitment, no engineers required on your end.

Get a free offline pose trajectory