Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Repository Guidelines

This project ships a PySide6 desktop app for offline ROS 2 calibration. Keep every contribution tightly scoped and verify changes against recorded `.mcap` rosbags before opening a pull request.

## Project Structure & Module Organization
Core logic lives in `ros2_calib/`: `main.py` wires the GUI, `calibration_widget.py` and `lidar2lidar_o3d_widget.py` host the calibration views, while helpers such as `bag_handler.py`, `calibration.py`, and `ros_utils.py` manage data access and math. GUI assets (icons, screenshots, demo media) reside in `assets/`. Build artifacts (`build/`, `dist/`, `ros2_calib.egg-info/`) are disposable—regenerate them locally instead of committing updates. Configuration and packaging metadata stay in `pyproject.toml` and `MANIFEST.in`.

## Build, Test, and Development Commands
- `python -m venv .venv && source .venv/bin/activate`: set up an isolated toolchain.
- `pip install -e .[dev]`: install the app plus linting/build extras.
- `ruff check`: run linting (E, F, W, I) with a 100-character limit.
- `ruff format`: auto-format Python sources; add `--check` in CI scripts.
- `ros2_calib`: launch the GUI from your shell for quick smoke tests.
- `python -m build`: produce wheels/sdists before publishing.

## Coding Style & Naming Conventions
Use Python 3.10+ features judiciously while keeping type hints for new APIs. Follow Ruff’s defaults: 4-space indentation, trailing commas where practical, and sorted imports. Modules and functions stay `snake_case`; Qt widgets/classes use `PascalCase`; constants stay upper snake. Break long GUI signal chains into helper functions and document non-obvious math with concise comments.

## Testing Guidelines
Automated tests are currently absent—add `pytest` modules alongside new features under `tests/` with files named `test_<feature>.py`. For GUI-heavy changes, describe manual validation: launch `ros2_calib`, load a representative `.mcap`, and confirm TF tree, calibrations, and exports behave as expected. Capture edge cases such as missing `/tf_static` frames or sparse point clouds.

## Commit & Pull Request Guidelines
Follow the existing short, imperative commit style (`add lidar2lidar calibrator`, `bump version to v0.0.6`). Group related changes and avoid bundled assets or builds. PRs should outline motivation, summarize implementation, list validation commands, and attach before/after screenshots for UI tweaks. Link issues when available and note any dependencies (e.g., new ROS bag schema) so reviewers can reproduce results quickly.
62 changes: 42 additions & 20 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

This is a manual LiDAR-Camera calibration tool for ROS 2 that provides a graphical interface for performing extrinsic calibration between LiDAR sensors and cameras. The application is built with PySide6 and operates on recorded rosbag data (.mcap files) without requiring a live ROS 2 environment.
This is a multi-sensor calibration tool for ROS 2 that provides graphical interfaces for performing extrinsic calibration between different sensor types. The application supports both LiDAR-to-Camera and LiDAR-to-LiDAR calibration workflows. It is built with PySide6 and operates on recorded rosbag data (.mcap files) without requiring a live ROS 2 environment.

## Development Commands

Expand Down Expand Up @@ -33,43 +33,65 @@ ruff format

The application follows a modular GUI-based architecture:

**Core Workflow:**
1. User loads a rosbag file (.mcap format)
2. Application displays available topics for selection
3. User selects image, point cloud, and camera info topics
4. Interactive calibration view allows manual 2D-3D correspondences
5. RANSAC-based PnP solver provides initial estimate
6. Scipy least-squares optimization refines the transformation
**Core Workflows:**

**LiDAR-to-Camera Calibration:**
1. User selects LiDAR-to-Camera calibration type
2. User loads a rosbag file (.mcap format)
3. Application displays available topics for selection
4. User selects image, point cloud, and camera info topics
5. Frame selection view allows choosing from multiple synchronized frames
6. Interactive calibration view allows manual 2D-3D correspondences
7. RANSAC-based PnP solver provides initial estimate
8. Scipy least-squares optimization refines the transformation

**LiDAR-to-LiDAR Calibration:**
1. User selects LiDAR-to-LiDAR calibration type
2. User loads a rosbag file (.mcap format)
3. Application displays available topics for selection
4. User selects source and target point cloud topics
5. Transform selection allows setting initial transformation estimate
6. Open3D-based interactive 3D calibration interface
7. Manual adjustment and ICP-based automatic registration
8. Export calibrated transformation matrix

**Key Components:**

- **main.py**: Application entry point with PySide6 QApplication setup
- **main_window.py**: Primary GUI window handling rosbag loading and topic selection
- **calibration_widget.py**: Interactive widget for 2D/3D point selection and visualization
- **main_window.py**: Primary GUI window handling rosbag loading, topic selection, and calibration type selection
- **calibration_widget.py**: Interactive widget for 2D/3D point selection and visualization (LiDAR-to-Camera)
- **lidar2lidar_o3d_widget.py**: Open3D-based interactive 3D calibration interface (LiDAR-to-LiDAR)
- **frame_selection_widget.py**: Frame selection interface for choosing synchronized sensor data
- **calibration.py**: Core mathematical calibration logic using OpenCV and Scipy
- **bag_handler.py**: Rosbag file processing and message extraction utilities
- **ros_utils.py**: Mock ROS 2 message dataclasses (PointCloud2, Image, CameraInfo) and conversion utilities

**Key Components (Continued):**

- **transformation_widget.py**: Node graph visualization for TF trees using NodeGraphQt
- **tf_graph_widget.py**: Interactive TF tree visualization using NodeGraphQt
- **lidar_cleaner.py**: Point cloud processing based on RePLAy ECCV 2024 paper for removing occluded points
- **tf_transformations.py**: Transform utilities for coordinate frame conversions

**Application Flow:** The main application uses a QStackedWidget to manage multiple views:
1. Initial view for rosbag loading and topic selection (main_window.py)
2. Interactive calibration view with 2D/3D visualization (calibration_widget.py)
3. Transform tree visualization and management (transformation_widget.py)
1. Calibration type selection view (LiDAR-to-Camera vs LiDAR-to-LiDAR)
2. Rosbag loading and topic selection (main_window.py)
3. Transform selection and TF tree management
4. Frame selection for synchronized data (LiDAR-to-Camera only)
5. Interactive calibration view:
- 2D/3D visualization (calibration_widget.py) for LiDAR-to-Camera
- Open3D 3D interface (lidar2lidar_o3d_widget.py) for LiDAR-to-LiDAR
6. Calibration export view with transformation results

**Dependencies:** The project uses `rosbags` library for ROS bag processing, avoiding dependency on live ROS 2 installation. All ROS message types are mocked as dataclasses in `ros_utils.py`. NodeGraphQt provides the graph visualization for TF trees. Open3D is used for 3D visualization and point cloud processing in LiDAR-to-LiDAR calibration.

**Dependencies:** The project uses `rosbags` library for ROS bag processing, avoiding dependency on live ROS 2 installation. All ROS message types are mocked as dataclasses in `ros_utils.py`. NodeGraphQt provides the graph visualization for TF trees.
**Calibration Algorithms:**
- **LiDAR-to-Camera**: Two-stage approach using OpenCV's `solvePnPRansac` for robust initial pose estimation followed by Scipy's `least_squares` optimization for refinement. The objective function minimizes reprojection error between 3D LiDAR points and 2D image correspondences.
- **LiDAR-to-LiDAR**: Interactive manual adjustment with automatic ICP (Iterative Closest Point) registration using Open3D. Supports both point-to-point and point-to-plane ICP algorithms for fine-tuning transformations.

**Calibration Algorithm:** Two-stage approach using OpenCV's `solvePnPRansac` for robust initial pose estimation followed by Scipy's `least_squares` optimization for refinement. The objective function minimizes reprojection error between 3D LiDAR points and 2D image correspondences. Point cloud cleaning uses algorithms from the RePLAy paper to remove occluded points.
Point cloud cleaning uses algorithms from the RePLAy paper to remove occluded points.

## Configuration

- **Linting**: Configured in `pyproject.toml` with ruff (line length: 100, select: E, F, W, I)
- **Entry Point**: Defined in `pyproject.toml` as `ros2_calib = "ros2_calib.main:main"`
- **Dependencies**: PySide6, rosbags, numpy, opencv-python-headless, scipy, ruff, NodeGraphQt, transforms3d, setuptools
- **Dependencies**: PySide6, rosbags, numpy, opencv-python-headless, scipy, ruff, NodeGraphQt, transforms3d, open3d, setuptools

## Development Notes

Expand Down
Loading