Skip to content

feat: add option to read LiDAR data from rosbag#277

Draft
hakuturu583 wants to merge 24 commits into
mainfrom
feat/rosbag-lidar-reader
Draft

feat: add option to read LiDAR data from rosbag#277
hakuturu583 wants to merge 24 commits into
mainfrom
feat/rosbag-lidar-reader

Conversation

@hakuturu583
Copy link
Copy Markdown

@hakuturu583 hakuturu583 commented Jun 1, 2026

Summary

  • Add use_rosbag option to T4Devkit that reads LiDAR point cloud data directly from rosbag2 files (input_bag/) instead of processed .pcd.bin files
  • Support db3 (SQLite3) and mcap format rosbag2 files via the rosbags library (pure Python, no ROS2 installation required)
  • Add --use-rosbag and --topic-mapping CLI flags to t4viz commands (scene, instance, pointcloud)
  • Returns the same LidarPointCloud format (4×N float32 array) as file-based loading, fully transparent to downstream code
  • Add TopicMapping dataclass (attrs-based) with input validation for channel-to-topic mapping
  • Add pandar_msgs/msg/PandarScan (Hesai raw packet) decoding support with sensor_type parameter
  • Support XT32 and OT128 sensor models with per-channel elevation angles from official Hesai datasheets
  • Fix rerun 0.29.0 API compatibility (set_time_secondsset_time, ImageEncodedEncodedImage)
Screenshot from 2026-06-01 16-57-36

Key design decisions

  • rosbags as required dependency: Added to [project.dependencies] so it is always available.
  • TopicMapping dataclass: Validates that channel names are non-empty strings and topic names start with /. Accepts both list[TopicMapping] and dict[str, str] (auto-converted) for ergonomics. Optional sensor_type field for PandarScan topics.
  • Explicit sensor_type for PandarScan: Instead of auto-detecting the sensor model from factory bytes or channel count, the user must specify the Hesai model name (e.g. "OT128", "XT32") via TopicMapping.sensor_type. This avoids ambiguity and validates channel count at init time.
  • OT128 elevation angles: Uses the exact per-channel elevation values from the official Hesai OT128 Angle Correction File (128 channels, non-uniform spacing from +14.985° to -24.765°).
  • Timestamp indexing: Uses rosbags Reader.messages() API to build the timestamp index. The underlying cursor lazily evaluates rows so payloads are not loaded into memory all at once.
  • Thread-safe: get_pointcloud() uses a lock to support concurrent access from ThreadPoolExecutor in the rendering pipeline.
  • Fallback behavior: If the rosbag doesn't contain a matching channel, falls back to file-based loading automatically.
  • LiDAR only: Camera and radar rosbag support is out of scope for this PR.

Usage

# PointCloud2 topics — with dict (auto-converted to TopicMapping)
t4 = T4Devkit("path/to/dataset", use_rosbag=True,
              topic_mapping={"LIDAR_CONCAT": "/sensing/lidar/concatenated/pointcloud"})
pc = t4.get_lidar_pointcloud(sample_data_token)

# PandarScan topics — requires TopicMapping with sensor_type
from t4_devkit.rosbag.topic_mapping import TopicMapping
t4 = T4Devkit(
    "path/to/dataset",
    use_rosbag=True,
    topic_mapping=[
        TopicMapping(
            channel="LIDAR_CONCAT",
            topic="/sensing/lidar/top/pandar_packets",
            sensor_type="OT128",
        ),
    ],
)

topic_mapping keys must match T4 sample_data.channel names, values must be ROS topic names in the rosbag. If omitted, PointCloud2 topics are auto-detected. PandarScan topics always require explicit topic_mapping with sensor_type.

Supported Hesai sensor models

Model Channels Vertical FOV Elevation spacing
XT32 32 +15° to -16° (31°) Uniform 1°
OT128 128 +14.985° to -24.765° (39.75°) Non-uniform (per-channel from datasheet)

Test plan

  • Unit tests for PointCloud2 → LidarPointCloud conversion (6 tests)
  • Integration tests for Rosbag2Reader with synthetic db3 bags (9 tests)
  • Unit tests for TopicMapping validation (9 tests)
  • PandarScan decoder unit tests (5 tests: single block, zero distance, azimuth 90°, multiple blocks, channel count mismatch)
  • PandarScan integration tests (4 tests: mock conversion, empty packets, unsupported sensor, multiple packets)
  • Rosbag2Reader PandarScan integration tests (4 tests: missing sensor_type, invalid sensor_type, topic mapping, get_pointcloud)
  • Existing tests pass unchanged (default use_rosbag=False)
  • ruff check passes
  • Manual test with real OT128 rosbag dataset (633,408 points per frame)

🤖 Generated with Claude Code

Add `use_rosbag` option to T4Devkit that reads LiDAR point cloud data
directly from rosbag2 (db3/mcap) files in `input_bag/` instead of
processed `.pcd.bin` files. Uses the `rosbags` library (pure Python,
no ROS2 required) as an optional dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added ci Continuous Integration (CI) processes and testing dependencies Pull requests that update a dependency file new-feature New feature or request labels Jun 1, 2026
hakuturu583 and others added 2 commits June 1, 2026 07:19
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jun 1, 2026
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

☂️ Python Coverage

current status: ❌

Overall Coverage

Lines Covered Coverage Threshold Status
4618 3807 82% 50% 🟢

New Files

File Coverage Status
t4_devkit/rosbag/init.py 100% 🟢
t4_devkit/rosbag/pandar_decoder.py 93% 🟢
t4_devkit/rosbag/pointcloud2.py 92% 🟢
t4_devkit/rosbag/reader.py 72% 🔴
t4_devkit/rosbag/topic_mapping.py 100% 🟢
TOTAL 91% 🔴

Modified Files

File Coverage Status
t4_devkit/helper/rendering.py 17% 🔴
t4_devkit/tier4.py 78% 🔴
t4_devkit/viewer/viewer.py 87% 🟢
TOTAL 61% 🔴

updated for commit: a493059 by action🐍

hakuturu583 and others added 3 commits June 1, 2026 17:10
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@hakuturu583 hakuturu583 requested a review from ktro2828 June 1, 2026 09:34
@hakuturu583 hakuturu583 marked this pull request as ready for review June 1, 2026 09:35
@ktro2828 ktro2828 requested a review from Copilot June 1, 2026 09:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a rosbag2-backed LiDAR loading path to T4Devkit, enabling visualization and downstream consumers to transparently read PointCloud2 data from input_bag/ instead of preprocessed .pcd.bin files.

Changes:

  • Introduces use_rosbag and topic_mapping options in T4Devkit, plus a get_lidar_pointcloud() API used by the rendering pipeline.
  • Adds a t4_devkit.rosbag module (Rosbag2Reader, TopicMapping, PointCloud2→LidarPointCloud conversion) and corresponding test coverage.
  • Extends t4viz CLI commands with --use-rosbag and --topic-mapping, and documents rosbag usage; adds rosbags as a dependency.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/rosbag/init.py Adds package marker for rosbag-related tests.
tests/rosbag/test_pointcloud2.py Unit tests for PointCloud2 → LidarPointCloud conversion behavior.
tests/rosbag/test_reader.py Integration tests for Rosbag2Reader against a synthetic rosbag.
tests/rosbag/test_topic_mapping.py Validation and conversion tests for TopicMapping.
t4_devkit/tier4.py Adds rosbag initialization and get_lidar_pointcloud() fallback logic.
t4_devkit/rosbag/init.py Exposes rosbag reader and mapping types.
t4_devkit/rosbag/reader.py Implements Rosbag2Reader with timestamp indexing and message retrieval.
t4_devkit/rosbag/pointcloud2.py Implements PointCloud2 parsing into the devkit point cloud format.
t4_devkit/rosbag/topic_mapping.py Adds validated channel↔topic mapping datatype utilities.
t4_devkit/helper/rendering.py Switches rendering to use T4Devkit.get_lidar_pointcloud().
t4_devkit/cli/visualize.py Adds --use-rosbag / --topic-mapping and parsing helper.
pyproject.toml Adds required dependency on rosbags.
docs/tutorials/render.md Documents rosbag LiDAR reading and CLI usage.
docs/tutorials/initialize.md Documents optional input_bag/ dataset layout.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread t4_devkit/tier4.py
Comment thread t4_devkit/rosbag/reader.py Outdated
Comment thread t4_devkit/rosbag/reader.py Outdated
Comment thread t4_devkit/rosbag/pointcloud2.py Outdated
Comment thread t4_devkit/cli/visualize.py Outdated
hakuturu583 and others added 6 commits June 2, 2026 09:04
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@hakuturu583 hakuturu583 marked this pull request as draft June 2, 2026 01:07
hakuturu583 and others added 2 commits June 2, 2026 10:36
Support reading pandar_msgs/msg/PandarScan topics in addition to
PointCloud2, enabling LiDAR point cloud extraction from rosbags that
contain raw Hesai UDP packets (e.g. XT32, XT32M2X).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PointCloudColorMode.SEGMENTATION
if self._has_lidarseg()
else PointCloudColorMode.DISTANCE
)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that LiDAR point clouds are never loaded from rosbag in t4viz scene/instance command because they force to set pointcloud_color_mode=PointCloudColorMode.Segmentation if the dataset contains lidarseg data.

hakuturu583 and others added 3 commits June 2, 2026 14:35
…d add OT128 support

Replace AT128/AT128P sensor models with OT128 using official Hesai elevation
angles from the Angle Correction CSV. Fix 90° yaw rotation by converting from
Hesai native coordinates (x=right, y=forward) to ROS sensor frame (x=forward,
y=left, z=up). Also update PandarPacket definition to use fixed uint8[1500]
buffer with size field, add sensor_type validation in Rosbag2Reader, improve
reader performance with O(1) topic connection lookup, and update rerun API calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rsion

The Hesai sensor frame uses native coordinates and the /tf_static tree
includes the full rotation from sensor frame to base_link. Revert the
incorrect Hesai-to-ROS axis swap in the decoder and instead read
/tf_static from the rosbag to compute the composed transform. Add
frame_id parameter to TopicMapping so users can specify the sensor's
TF frame (e.g. "hesai_top") for automatic coordinate transformation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
hakuturu583 and others added 2 commits June 2, 2026 15:00
Add per-channel azimuth offset from the OT128 Angle Correction CSV.
Channels 25-88 have offsets up to ±4.6° which caused visible projection
misalignment without correction. XT32 azimuth offsets are all 0 per the
official CSV. Also verified XT32 elevation angles match the CSV exactly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace (R, t) tuple representation with 4x4 homogeneous matrices throughout
TF handling. Add get_sensor2ego() public method for resolving /tf_static chain
from any sensor frame to target frame. Extract _DEFAULT_TARGET_FRAME constant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
hakuturu583 and others added 4 commits June 3, 2026 12:19
… chunk-filter off-by-one (#279)

* fix(rosbag): widen Reader.messages start by 1ns to dodge rosbags MCAP chunk-filter off-by-one

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style(pre-commit): autofix

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: hakuturu583 <10348912+hakuturu583@users.noreply.github.com>
…tion

Use the UDP Sequence field (u32 LE) defined in Hesai specs to detect
dropped packets within a PandarScan message. XT32 stores the sequence
in the last 4 bytes; OT128 at 30 bytes from the end (per their
respective User Manuals, Section 3.1.2 Tail / Additional information).

By default (min_completeness=1.0), any scan with missing packets is
rejected with ValueError. Callers can lower the threshold or disable
the check with min_completeness=0.0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci Continuous Integration (CI) processes and testing dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation new-feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants