Skip to main content

SE(3) LiDAR-Inertial Odometry Python bindings

Project description

SE(3)-LIO Python bindings

Python bindings for the ROS-agnostic SE(3) LiDAR-Inertial Odometry C++ core.

Install

Linux x86_64 wheels are on PyPI (the C++ core is bundled in):

pip install se3-lio          # add [viz] for the live Polyscope viewer

Build from source

The bindings link the C++ core, which needs OpenMP (libgomp); Eigen and Sophus are fetched and compiled in. Build inside the project's ROS2 Docker image (docker/ros2/), where OpenMP is available.

# inside the container, from the repo root
pip install --no-build-isolation -ve ./python/   # requires: pip install pybind11 scikit-build-core
# or, with build isolation (pulls build deps automatically):
pip install -ve ./python/

Usage (high-level API)

import numpy as np
from se3_lio import SE3LIO, SE3LIOConfig, load_node_params

config = SE3LIOConfig(downsample_resolution=0.5, max_iter=4, verbose=False)
odom = SE3LIO(config, lidar_extrinsic=np.eye(4))

# or load the ROS2 node's params.yaml (same mapping as lio_node.cpp):
params = load_node_params("config/ntu.yaml")
odom = SE3LIO(params["config"], params["extrinsic"])

# points:      (N, 3) float xyz in the LiDAR frame
# point_times: (N,)   float per-point time offset from frame start [s]
# imu:         (M, 7) float rows of [t, ax, ay, az, gx, gy, gz]
state, cloud = odom.register_frame(points, point_times, imu, frame_stamp)
print(state.pose, state.vel, state.covariance)   # cloud: (N,3) deskewed, body frame

register_frame mirrors the per-frame data path of the ROS2 node: it builds a synced measurement, applies the LiDAR extrinsic, sorts points by relative timestamp, and runs one estimatePose step. Set verbose=True to enable the core's per-frame stdout logging (off by default).

CLI pipeline

se3_lio_pipeline runs odometry over a rosbag and writes a TUM trajectory — the Python equivalent of the node, offline. The input format is auto-detected:

input format LiDAR reader
rosbag2 directory ROS2 Livox CustomMsg rosbag2_py
*.bag file ROS1 Ouster PointCloud2 rosbags
# ROS2 / Livox (rosbag2 directory)
se3_lio_pipeline <rosbag_dir> --config my_rig.yaml --imu-topic /livox/imu --lidar-topic /livox/lidar \
    --max-frames 300 --output results/

# ROS1 / Ouster (e.g. NTU VIRAL .bag)
se3_lio_pipeline eee_01.bag --config config/ntu.yaml \
    --max-frames 1500 --output results/
# -> results/<bag>_se3lio.tum  + a summary (frames, path length, final pose)

--config is a small YAML giving the LiDAR→IMU extrinsic (and, optionally, topics + algorithm overrides); keys you omit fall back to the SE3LIOConfig code defaults. The repo's config/*.yaml cover our datasets — for your own rig, write just the extrinsic and pass the topics on the CLI:

# my_rig.yaml -> sensors: { t_exts: [x,y,z], q_exts: [w,x,y,z] }
se3_lio_pipeline my.bag --config my_rig.yaml \
    --imu-topic /my/imu --lidar-topic /my/points

Use --input-type ros2-livox|ros1-ouster to override auto-detection. It reads the bag, reproduces the node's conversion + synchronization (rosbag.py / ros1bag.py), and runs OdometryPipeline over the frames. Use the same pieces programmatically:

from se3_lio import load_node_params
from se3_lio.datasets import RosbagDataset
from se3_lio.pipeline import OdometryPipeline

p = load_node_params("config/ntu.yaml")
dataset = RosbagDataset(bag_dir, p["imu_topic"], p["lidar_topic"], p["min_range"])
pipeline = OdometryPipeline(dataset, p["config"], p["extrinsic"]).run()
pipeline.save_tum("traj.tum")
print(pipeline.summary())

Visualization (Polyscope)

se3_lio_pipeline --visualize opens a live Polyscope viewer: the current scan (gravity-aligned world frame) and the trajectory, with play/pause [space], step [N], center [C], and screenshot [S].

pip install se3-lio[viz]               # adds polyscope
se3_lio_pipeline eee_01.bag --config config/ntu.yaml \
    --max-frames 1500 --visualize

The viewer lives in se3_lio/viz/polyscope_viz.py (PolyscopeVisualizer, lazily importing polyscope). It implements the pipeline logger interface (log_frame), following KISS-ICP / GenZ-ICP's Polyscope viewers.

Visualization (Rerun)

--rerun-save writes a Rerun .rrd (open it in the viewer, below): a 3D view (sliding submap, trajectory, sensor pose with TF axes, camera-follow) plus scalar plots (linear/angular speed, compute time, CPU, RAM). Logger: se3_lio/viz/rerun_logger.py.

pip install se3-lio[rerun]             # adds rerun-sdk (pinned, see below)
se3_lio_pipeline eee_01.bag --config config/ntu.yaml --rerun-save out.rrd

Version: the [rerun] extra pins rerun-sdk==0.33.1, because .rrd files are only guaranteed to open in a matching viewer version and the logger uses version-specific APIs. Keep the viewer in lockstep — since the host Python may be too old for a recent SDK, use a dedicated env:

conda create -n rerun033 python=3.11 -y
conda run -n rerun033 pip install rerun-sdk==0.33.1
conda run -n rerun033 rerun out.rrd    # native viewer (matches the .rrd)

Alternatively serve the web viewer from the same SDK (rr.serve_web_viewer) so no local install has to match. When upgrading rerun, bump the pin, fix any logger API breaks, rebuild, and regenerate the .rrd (or rerun rrd migrate).

Raw binding

The _-prefixed names (se3_lio_pybind._SE3LIO, _SE3LIOConfig, _State) are the raw binding the high-level API is built on.

import numpy as np
from se3_lio import se3_lio_pybind as lio

config = lio._SE3LIOConfig()
config.downsample_resolution = 0.5
config.max_iter = 4

odom = lio._SE3LIO(config, np.eye(4))  # second arg: 4x4 LiDAR->body extrinsic

# points:      (N, 3) float64 xyz in the LiDAR frame
# point_times: (N,)   float64 per-point time offset from frame start [s]
# imu:         (M, 7) float64 rows of [t, ax, ay, az, gx, gy, gz]
state, cloud = odom._register_frame(points, point_times, imu, frame_stamp)

print(state.pose)        # 4x4 SE(3) pose; cloud: (N,3) deskewed body-frame points
print(state.vel, state.bg, state.ba, state.grav)
print(state.covariance)  # 18x18

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

se3_lio-0.2.0.tar.gz (23.7 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

se3_lio-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (459.7 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

se3_lio-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (458.7 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

se3_lio-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (457.7 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

se3_lio-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (458.2 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

se3_lio-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (458.5 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

File details

Details for the file se3_lio-0.2.0.tar.gz.

File metadata

  • Download URL: se3_lio-0.2.0.tar.gz
  • Upload date:
  • Size: 23.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for se3_lio-0.2.0.tar.gz
Algorithm Hash digest
SHA256 d51c473f78ea42afeacb14a1d0404d84eb8d82d100f84b2c968ceef4d6392a94
MD5 6ffb15cbb341c39d795267e41b5471a0
BLAKE2b-256 6b025e57d42cf55bd00695f801f74251655ae27181ec3e2d3a895b673b126200

See more details on using hashes here.

Provenance

The following attestation bundles were made for se3_lio-0.2.0.tar.gz:

Publisher: pypi.yml on url-kaist/se3-lio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file se3_lio-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for se3_lio-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e3e3eb64b26377771072cfdb9ecb8120b1e110ee0a40c53fe473d13fb0d12b5e
MD5 f3428ddd9da150988d3d6eb9653c3867
BLAKE2b-256 55c1248f577b76fda1e7bac3f95bebf4fee4f8e8a4a736348da3b6728d0711fa

See more details on using hashes here.

Provenance

The following attestation bundles were made for se3_lio-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on url-kaist/se3-lio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file se3_lio-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for se3_lio-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6f23b952dd71d9738b64a193e647f236f31d15356d41af34730463df424022e6
MD5 1903c21fc5dbafe98f3cc3afeba94617
BLAKE2b-256 aec9441fdb22acd22220ce95927126d45d4256a191609e84c61d832597cc81f7

See more details on using hashes here.

Provenance

The following attestation bundles were made for se3_lio-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on url-kaist/se3-lio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file se3_lio-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for se3_lio-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7ca102cf748aa8993cd5c04b9c7b09dd251be897f069bd6b0bbeb557eb59d835
MD5 b54721029fca87b31ba39b1ee7e95959
BLAKE2b-256 56cf0afe6e380db20280c7e7a0e9f5bff97f70ee58c104740a99e4835d8e83af

See more details on using hashes here.

Provenance

The following attestation bundles were made for se3_lio-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on url-kaist/se3-lio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file se3_lio-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for se3_lio-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f0936498050c61a3145cf494bf88cf748ed23ffad2a13e27e68b4627b33263c3
MD5 ef68e577473f43eef76ba374f54476c1
BLAKE2b-256 c7b12c41bae5881271d16a708750c20b1390b7efaca77780a4f4e68f7966ba58

See more details on using hashes here.

Provenance

The following attestation bundles were made for se3_lio-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on url-kaist/se3-lio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file se3_lio-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for se3_lio-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1346d225fa943f7c36d108c3db9d437febf3442bdb0c32eb49fac4fecb99ba4f
MD5 fe347354bd9b73af77012333192b7243
BLAKE2b-256 40bbf599bb49c3f7dcf6e35a8dc4ce2e6b2acd7d0437e47e345b4e60e073b167

See more details on using hashes here.

Provenance

The following attestation bundles were made for se3_lio-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on url-kaist/se3-lio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page