支持 H32 DLogCapture(MSOP+DIFOP)导出到 V1 中间格式

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
lichun.qu
2026-08-05 08:58:31 +08:00
co-authored by Cursor
parent 4ff176d184
commit 30f7e66db3
14 changed files with 993 additions and 43 deletions
+34 -9
View File
@@ -1,6 +1,6 @@
"""Decode RoboSense H32 MSOP V2 .rscap into Cartesian frames (metres).
"""Decode RoboSense H32 MSOP packets into Cartesian frames (metres).
Angle / distance conventions follow ``RSLidarH32_3D_RawCaptureNet48``:
Angle / distance conventions follow the H32 Medulla plugins:
azimuth = normalize(-(block_az + horizontal[ch])), altitude = vertical[ch],
distance_mm = raw * distance_unit_mm, then:
@@ -8,13 +8,14 @@ distance_mm = raw * distance_unit_mm, then:
y = d_m * cos(alt) * sin(az)
z = d_m * sin(alt)
MSOP-only captures do not include DIFOP; vertical angles default to a uniform
-16°…+16° fan, horizontal channel offsets default to 0.
When DIFOP is unavailable, vertical angles default to a uniform -16°…+16° fan
and horizontal channel offsets default to 0.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Iterable
import numpy as np
@@ -140,8 +141,8 @@ def _block_points(
return np.column_stack([xs, ys, zs]).astype(np.float64, copy=False)
def iter_h32_frames(
capture: CaptureFile,
def iter_h32_frames_from_packets(
packets: Iterable[bytes],
*,
min_frame_points: int = MIN_FRAME_POINTS_DEFAULT,
frame_stride: int = 1,
@@ -151,7 +152,7 @@ def iter_h32_frames(
vertical_deg: np.ndarray | None = None,
horizontal_deg: np.ndarray | None = None,
) -> list[LidarFrameExport]:
"""Assemble MSOP packets into frames using the 270°→90° azimuth wrap."""
"""Assemble raw MSOP packets into frames using the 270°→90° azimuth wrap."""
vertical = default_vertical_deg() if vertical_deg is None else np.asarray(vertical_deg, dtype=np.float64)
horizontal = default_horizontal_deg() if horizontal_deg is None else np.asarray(horizontal_deg, dtype=np.float64)
@@ -189,8 +190,7 @@ def iter_h32_frames(
end_s = start_s + 0.1
frames.append(LidarFrameExport(t_start_s=start_s, t_end_s=end_s, points_xyz=points))
for chunk in capture.chunks:
packet = chunk.raw
for packet in packets:
if len(packet) != PACKET_LENGTH:
continue
packet_t = device_timestamp_ms(packet) * 1e-3
@@ -222,3 +222,28 @@ def iter_h32_frames(
emit()
return frames
def iter_h32_frames(
capture: CaptureFile,
*,
min_frame_points: int = MIN_FRAME_POINTS_DEFAULT,
frame_stride: int = 1,
min_range_m: float = 0.3,
max_range_m: float = 120.0,
max_points_per_frame: int | None = None,
vertical_deg: np.ndarray | None = None,
horizontal_deg: np.ndarray | None = None,
) -> list[LidarFrameExport]:
"""Assemble MSOP packets from a V2 .rscap capture into frames."""
return iter_h32_frames_from_packets(
(chunk.raw for chunk in capture.chunks),
min_frame_points=min_frame_points,
frame_stride=frame_stride,
min_range_m=min_range_m,
max_range_m=max_range_m,
max_points_per_frame=max_points_per_frame,
vertical_deg=vertical_deg,
horizontal_deg=horizontal_deg,
)