添加 LiDAR-IMU 外参标定流水线与说明文档

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
lichun.qu
2026-08-01 12:02:37 +08:00
co-authored by Cursor
commit cf1fad7594
40 changed files with 5502 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
"""Command-line entry point for LiDARIMU calibration."""
from __future__ import annotations
import argparse
from pathlib import Path
from .contracts import CalibrationMode, CalibrationRequest, CalibrationStatus, SessionInput
from .pipeline import describe_pipeline, run_calibration
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="LiDARIMU extrinsic calibration (V1)")
subcommands = parser.add_subparsers(dest="command", required=True)
plan = subcommands.add_parser("plan", help="显示标定阶段,不读取数据")
plan.add_argument("--vehicle-config", help="车辆配置路径(仅展示,plan 不读取)")
plan.add_argument(
"--mode",
choices=[mode.value for mode in CalibrationMode],
default=CalibrationMode.ROTATION_ONLY.value,
)
run = subcommands.add_parser("run", help="执行 V1 标定流水线")
run.add_argument("--session-id", default="session0")
run.add_argument("--imu", required=True, help="IMU CSV/NPZ 路径")
run.add_argument("--lidar", required=True, help="LiDAR 会话目录(含 frames_index.csv")
run.add_argument("--vehicle-config", required=True, help="车辆配置 YAML")
run.add_argument("--output", required=True, help="输出目录")
run.add_argument(
"--mode",
choices=[mode.value for mode in CalibrationMode],
default=CalibrationMode.ROTATION_ONLY.value,
)
run.add_argument("--max-iterations", type=int, default=2)
run.add_argument("--time-offset-search-s", type=float, default=1.0)
run.add_argument("--min-pair-rotation-deg", type=float, default=3.0)
run.add_argument("--min-pair-translation-m", type=float, default=0.3)
return parser
def main(argv: list[str] | None = None) -> int:
parser = build_parser()
args = parser.parse_args(argv)
if args.command == "plan":
request = CalibrationRequest(
vehicle_config=Path(args.vehicle_config) if args.vehicle_config else None,
requested_mode=CalibrationMode(args.mode),
)
print("LiDARIMU calibration stages:")
print(f"requested mode: {request.requested_mode.value}")
for index, stage in enumerate(describe_pipeline(request), start=1):
print(f"{index}. {stage.name}: {stage.responsibility}")
return 0
if args.command == "run":
request = CalibrationRequest(
vehicle_config=Path(args.vehicle_config),
sessions=(
SessionInput(
session_id=args.session_id,
imu_source=Path(args.imu),
lidar_source=Path(args.lidar),
),
),
requested_mode=CalibrationMode(args.mode),
output_directory=Path(args.output),
max_iterations=args.max_iterations,
min_pair_rotation_deg=args.min_pair_rotation_deg,
min_pair_translation_m=args.min_pair_translation_m,
time_offset_search_s=args.time_offset_search_s,
)
result = run_calibration(request)
print(f"status: {result.status.value}")
print(f"message: {result.message}")
if result.time_offset_s is not None:
print(f"time_offset_s (t_imu = t_lidar + dt): {result.time_offset_s:.6f}")
if result.T_IMU_lidar is not None:
print("T_IMU_lidar:")
print(result.T_IMU_lidar)
print(f"report directory: {args.output}")
return 0 if result.status != CalibrationStatus.BLOCKED else 2
parser.error(f"unknown command {args.command}")
return 2
if __name__ == "__main__":
raise SystemExit(main())