新增独立RTK与IMU外参标定流程及质量验证
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run the independent RTK--IMU calibration against the project inventory."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from imu_lidar.rtk_imu_replay import load_inventory, load_sessions, run_calibration
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--inventory",
|
||||
type=Path,
|
||||
default=ROOT / "artifacts" / "rtk_imu_inventory_v1" / "rtk_session_inventory.csv",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-dir",
|
||||
type=Path,
|
||||
default=ROOT / "artifacts" / "rtk_imu_calibration_v1",
|
||||
)
|
||||
parser.add_argument("--session", action="append", help="session id to include; repeatable")
|
||||
parser.add_argument("--batch", action="append", help="batch id to include; repeatable")
|
||||
parser.add_argument("--rotation-only", action="store_true")
|
||||
parser.add_argument("--no-loo", action="store_true")
|
||||
parser.add_argument("--knot-step-s", type=float, default=2.0)
|
||||
parser.add_argument("--per-batch", action="store_true")
|
||||
parser.add_argument("--rtk-frame-definition", default='')
|
||||
parser.add_argument("--rtk-reference-point", default='')
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
entries = load_inventory(args.inventory)
|
||||
if args.session:
|
||||
selected = set(args.session)
|
||||
entries = [entry for entry in entries if entry.session_id in selected]
|
||||
if args.batch:
|
||||
selected_batches = set(args.batch)
|
||||
entries = [entry for entry in entries if entry.batch_id in selected_batches]
|
||||
if not entries:
|
||||
raise SystemExit("no inventory rows match the requested selection")
|
||||
sessions = load_sessions(entries)
|
||||
rotation, translation = run_calibration(
|
||||
sessions,
|
||||
args.output_dir,
|
||||
rotation_only=args.rotation_only,
|
||||
compute_loo=not args.no_loo,
|
||||
knot_step_s=args.knot_step_s,
|
||||
rtk_frame_definition=args.rtk_frame_definition,
|
||||
rtk_reference_point=args.rtk_reference_point,
|
||||
)
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"output": str(args.output_dir.resolve()),
|
||||
"sessions": [session.session_id for session in sessions],
|
||||
"rotation_ok": rotation.ok,
|
||||
"rotation_rpy_deg": rotation.rpy_deg.tolist(),
|
||||
"rotation_rms_deg": rotation.residual_rms_deg,
|
||||
"translation_ok": None if translation is None else translation.ok,
|
||||
"translation_m": None if translation is None else translation.t_RTK_IMU_m.tolist(),
|
||||
},
|
||||
ensure_ascii=False,
|
||||
indent=2,
|
||||
)
|
||||
)
|
||||
|
||||
if args.per_batch:
|
||||
for batch in sorted({entry.batch_id for entry in entries}):
|
||||
batch_entries = [entry for entry in entries if entry.batch_id == batch]
|
||||
if len(batch_entries) < 2:
|
||||
continue
|
||||
run_calibration(
|
||||
load_sessions(batch_entries),
|
||||
args.output_dir / "per_batch" / batch,
|
||||
rotation_only=args.rotation_only,
|
||||
compute_loo=False,
|
||||
knot_step_s=args.knot_step_s,
|
||||
rtk_frame_definition=args.rtk_frame_definition,
|
||||
rtk_reference_point=args.rtk_reference_point,
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user