GrabBag/Device/RsLidarDevice/Doc/AngleCoordinateMapping.md
2026-07-11 15:49:14 +08:00

2.7 KiB
Raw Blame History

RSEM4 angle and XYZ formulas

本文只说明 RsLidarDevice 中 RSEM4 雷达角度、距离与 PointCloudCallback 输出 XYZ 之间的正算和逆算公式。

代码依据:Src/RsLidarDevice.cpp::fillRsem4Point()

单位约定

  • 原始距离分辨率:1 unit = 0.005 m
  • 公式中的 distance_m 单位为米。
  • PointCloudCallback 输出的 X/Y/Z 单位为毫米。
  • 代码中的角度单位为 0.01°,例如 1300 = 13.00°
  • 三角函数计算时需要先把 0.01° 转成弧度:
angle_rad = angle_deg01 * pi / 18000

角度定义

水平角:

yaw_deg01 = yawBase_deg01 + yawOffset_deg01[ring / 20]

垂直角:

pitch_deg01 = pitchAngle_deg01[ring] + surfacePitchOffset_deg01[surfaceIndex]

转换成弧度:

yaw_rad   = yaw_deg01 * pi / 18000
pitch_rad = pitch_deg01 * pi / 18000

正算公式angle + distance -> XYZ

雷达内部先按标准球坐标计算:

x0_m = distance_m * cos(pitch_rad) * cos(yaw_rad)
y0_m = distance_m * cos(pitch_rad) * sin(yaw_rad)
z0_m = distance_m * sin(pitch_rad)

再转换成 PointCloudCallback 输出坐标:

X_mm = -y0_m * 1000
Y_mm = -z0_m * 1000
Z_mm =  x0_m * 1000

合并后:

X_mm = -distance_m * cos(pitch_rad) * sin(yaw_rad) * 1000
Y_mm = -distance_m * sin(pitch_rad) * 1000
Z_mm =  distance_m * cos(pitch_rad) * cos(yaw_rad) * 1000

强度值:

intensity = 原始 intensity

逆算公式XYZ -> angle + distance

给定 PointCloudCallback 输出点:

X_mm = point.x
Y_mm = point.y
Z_mm = point.z

距离:

range_mm = sqrt(X_mm * X_mm + Y_mm * Y_mm + Z_mm * Z_mm)
range_m  = range_mm / 1000

水平角:

yaw_rad = atan2(-X_mm, Z_mm)
yaw_deg = yaw_rad * 180 / pi

如果需要归一化到 [0, 360)

if yaw_deg < 0:
    yaw_deg += 360

垂直角:

pitch_rad = asin(-Y_mm / range_mm)
pitch_deg = pitch_rad * 180 / pi

转换成代码中的 0.01° 单位:

yaw_deg01   = yaw_deg * 100
pitch_deg01 = pitch_deg * 100

反推原始角度

上面的逆算得到的是已经叠加 DIFOP 标定补偿后的实际出射角。

如果已知当前点的 ringsurfaceIndex 和 DIFOP 标定表,则可继续反推:

yawBase_deg01 = yaw_deg01 - yawOffset_deg01[ring / 20]
pitchAngle_deg01[ring] = pitch_deg01 - surfacePitchOffset_deg01[surfaceIndex]

如果只拿到 XYZ不知道 ringsurfaceIndex 和 DIFOP 标定表,则不能唯一反推原始包里的 yawAnglepitchAnglesurfaceId

无效点

当输出点为零点时:

X_mm = 0
Y_mm = 0
Z_mm = 0

不能进行角度逆算。零点可能来自距离越界或 surfaceIndex 非法。