☰
毫米波雷达SLAM实战:地下隧道三维建图全流程解析
2026/10/7 6:48:23 网站建设 项目流程

隧道里的灰尘比雾霾还稠密,通风口吹下来的风裹着水汽,头顶的应急灯只够让你勉强看清轮廓。GPS信号进隧道三秒钟就归零,视觉SLAM在这种场景下几乎必挂,激光雷达一遇到扬尘就是一大堆假点。那段时间我在调试一台巡检小车的地下隧道三维建图算法,折腾了三个星期,最后让轨迹收敛下来的,反而是一颗24GHz的毫米波雷达模块,外加上一套用Python写的毫米波雷达SLAM程序。

这篇文章不聊概念,直接讲我怎么把一套“毫米波雷达 + Python + 后端图优化”的三维建图方案从零跑通。内容包括数据预处理、雷达里程计配准、回环检测、GTSAM位姿图优化,以及大量现场踩坑记录。如果你也要在无GPS、阴暗、多尘或者多雾的环境里做机器人定位和三维建图,这篇东西应该能让你少熬半个月的夜。

1. 为什么地下隧道里,毫米波雷达是最后一张底牌

1.1 视觉和激光雷达在地下环境中的失效模式

先说结论:不是激光雷达不行,而是地下隧道的环境对它非常不友好。

我一开始的方案其实是16线激光雷达加摄像头。激光雷达在室内干净场景下表现非常好,点云密、精度高、回环检测也成熟。但隧道现场有两个要命的客观条件:第一是扬尘,隧道检修期地面堆积着大量粉尘,巡检车一开过去,颗粒物直接被气流卷起来,激光点云里会出现一圈“雾状”点,这些点在配准时会被当成真实几何结构,导致里程计越跑越偏。第二是光照剧烈变化,进口段有自然光,中段几乎全黑,出口又是一片强光,摄像头自动曝光根本来不及,视觉特征点数量在黑暗区会快速跌到个位数,紧接而来的就是跟踪丢失。

GPS就更不用说了。隧道里卫星信号完全遮挡,RTK基站信号也进不来,任何依赖GNSS的方案都直接出局。我在现场测过手机和双频GPS模块,全部变成“无定位”。

这种环境下,想要持续、稳定地输出定位和建图结果,就得找一种对光不敏感、对粉尘不敏感、又能直接测距测速的传感器。毫米波雷达就是这个“底牌”。

1.2 毫米波雷达的物理底牌和让人又爱又恨的性格

毫米波雷达工作的频段通常在24GHz到79GHz之间,波长从毫米级到厘米级。它发射出的电磁波能穿透粉尘、小雨、雾气,反射强度由目标的材质、表面粗糙度和几何形状决定。工作原理很简单:雷达发出调频连续波,目标反射回来之后,通过混频、FFT提取出距离、速度和角度信息。

相比激光雷达每帧几万个点,24GHz毫米波雷达模块通常每帧只有几百个点,有的低端模块甚至只有几十个点。稀疏是一个特点,但不是致命伤,真正难处理的是三点:

  • 点云中的目标点不够“干净”,一个金属管道会产生强烈的镜面反射,你会在真实目标后方或侧面看到一串虚假点;
  • 角分辨率低,24GHz雷达的水平角分辨率通常在十几度到几十度,导致同一个点云簇的形状和真实物体差得很远,直接套用点云ICP很容易卡进局部最优;
  • 雷达的强度信息不稳定,同一个墙面在不同距离、不同入射角度下的回波强度差异非常大,用固定强度阈值滤波会误杀大量真实点。

最开始我也按激光雷达的思路去处理这些点云,结果前端配准 ICP 的收敛率只有不到七成,经常在隧道直道上一跑就是两三百米的偏移。后来我意识到,必须把毫米波雷达当成一种“自带噪声倾向的特殊传感器”来对待,而不是一个低精度的激光雷达。后面的所有设计,都是围绕这个认知展开的。

2. 系统架构:一套在隧道路段能扛住的毫米波雷达SLAM方案

2.1 先过一遍主流的雷达SLAM路线

在动笔写代码之前,我把目前几类主流毫米波雷达SLAM方案捋了一遍,这步很值得,因为每个方案背后对应完全不同的数学模型和数据形态。

方案类型核心思想优点隧道场景适用性主要缺点
基于强度图的雷达里程计将雷达扫描结果投影成局部强度图,用图像配准方法估计运动鲁棒性好,工业界应用多适合低速巡检,但对安装姿态敏感需要雷达本身具备较高的角度分辨率
基于点云配准(ICP/NDT)直接对毫米波点云做最近点匹配,迭代求位姿变换实现简单,依赖库成熟适合,但必须做好噪声预处理稀疏点云容易陷入局部极值,需要粗配准
基于关键面/特征点提取(CFEAR等)提取雷达回波中的局部表面点和方向一致性特征,再做配准对雷达噪声有专门适配,计算量低非常适合。在长隧道直线场景表现稳定实现难度高,特征阈值需要现场调参
基于4D雷达的图优化SLAM(MARS-LOAM等)利用4D雷达的距离/方位/俯仰/多普勒信息,结合IMU做紧耦合信息利用率最高很有前景,但需要4D雷达硬件硬件贵,系统复杂,Python生态支持一般

我的硬件是24GHz FMCW雷达模块,点云稀疏,没有完整的俯仰分辨率,4D雷达那套直接排除。强度图方案对雷达角度分辨率要求较高,加上我需要输出三维点云而不是二维栅格地图,所以最终选择了“稀疏点云特征提取 + 雷达里程计 + ScanContext回环 + GTSAM后端优化”这条路线。

2.2 我采用的系统流程和数据流

整套系统在Python里跑的通路如下:

  1. 原始雷达数据从串口/UDP进入,解析出每帧的点云,包含距离、方位角、速度、强度;
  2. 坐标转换,把极坐标转成三维直角坐标;
  3. 点云预处理:速度滤波、强度滤波、基于DBSCAN的离群点剔除;
  4. 关键帧提取:当平移量或旋转角超过阈值时,把当前帧设为关键帧;
  5. 雷达里程计:用上一帧到当前帧的预测位姿做粗变换,再做点云精配准(PyICP);
  6. 回环检测:ScanContext向量检索,加上几何一致性验证;
  7. 后端图优化:构建位姿图,用GTSAM求解;
  8. 地图拼接:把关键帧点云按照优化后的位姿变换到全局坐标系。

这套流程本质上属于“前段里程计 + 后端图优化”的标准SLAM框架,但在每一个模块内部,都为毫米波雷达的特点做了针对性修改。尤其是第3步预处理和第5步配准,是雷达SLAM能跑通的关键。

2.3 硬件选型与时间同步

传感器选型上,我用的是24GHz毫米波雷达开发板,输出点云帧率10Hz,距离分辨率约0.6m,水平视场角约90度。这类模块通常提供每秒几百个点,足够在隧道里提取出墙体结构。

IMU建议一定要加。毫米波雷达点云太稀疏,在长直隧道里,纯雷达里程计的横向漂移非常严重。我用一个消费级六轴IMU辅助做帧间约束,不要求零偏特别低,只要短时间内相对姿态稳定就够了。

时间同步这块,我吃过大亏。开始的时候,我直接把雷达时间戳和IMU时间戳都打上工控机的系统时间,结果雷达的数据是通过串口转发,缓冲有个不可控延迟,IMU时间戳和雷达时间戳之间的偏差最高能到80ms。巡检车时速大约2m/s,80ms的偏差就会带来约16cm的运动畸变,配准精度直接崩掉。后来我把雷达换成支持硬件时间戳输出的版本,同时用PTP同步工控机内部时钟,问题才解决。

3. 点云预处理这个环节,决定了后面所有步骤的生死

3.1 雷达帧数据格式与坐标转换

雷达原始数据通常以极坐标形式给出:每个点包含距离、方位角、速度、强度。有些模块还带有俯仰角,如果没有,三维建图时就需要把z方向近似为0,或者把点云投影到二维高度面上处理。

为了避免现场格式混乱,我先写了一个统一的解析层,把不同雷达的点云统一到一个结构体。核心转换就一个公式:

x = r * cos(elevation) * cos(azimuth) y = r * cos(elevation) * sin(azimuth) z = r * sin(elevation)

其中,r是距离,azimuth是水平角,elevation是俯仰角。下面这段代码是我解析一帧雷达数据的简化版本:

import numpy as np def radar_frame_to_xyz(frame): """ 将一帧雷达原始数据转换为三维点云 frame: dict, 包含 r_arr, azimuth_arr, elevation_arr, velocity_arr, intensity_arr """ r = frame['r_arr'] az = frame['azimuth_arr'] # 弧度 el = frame['elevation_arr'] # 弧度,如果没有俯仰信息则传0 x = r * np.cos(el) * np.cos(az) y = r * np.cos(el) * np.sin(az) z = r * np.sin(el) return np.stack([x, y, z], axis=1)

这步看起来简单,但有两点值得注意:一是雷达坐标系和车体坐标系的关系必须标定好,安装角哪怕偏2度,在30米处的横向误差就有1米多,对后续配准是灾难;二是俯仰角如果没有,就不要强行补一个固定值,否则点云会有系统性的高度偏差。

3.2 强度滤波、速度分割与DBSCAN聚类

毫米波雷达点云里混合着三类点:真实目标点、静止杂波点、多径假目标点。直接拿去跑ICP,配准会被假目标带偏,所以预处理比激光雷达严格得多。

我的处理顺序是:

  1. 强度滤波:对每一帧点云,先统计当前帧所有点的强度分布,取中位数和四分位间距,只保留强度高于median + k * IQR的点。这里我没有用固定阈值,因为隧道里不同区段的墙体材质、湿度差别很大,固定阈值需要在不同区段反复调整,不现实。
  2. 速度滤波:利用多普勒速度信息,剔除“看起来正朝雷达直冲过来”的杂乱目标。例如隧道里的金属管道、通风管道常产生镜面反射,它们本身是静止的,但多径反射点的速度却异常,直接按速度阈值过滤掉。
  3. DBSCAN聚类:把点云按空间邻近度聚类,只保留点数较多、几何尺寸合理的簇。这样做可以去掉散落的孤立噪声点,同时保留墙面、隧道壁等大目标。

DBSCAN的参考代码如下:

from sklearn.cluster import DBSCAN def clean_radar_points(points, velocities, intensities, eps=1.2, min_points=4): """ 对毫米波雷达点云做簇级滤波 - eps: 同一聚类内两点最大距离 - min_points: 一个簇最少点数 """ if len(points) < 2: return points, velocities, intensities clustering = DBSCAN(eps=eps, min_samples=min_points).fit(points) labels = clustering.labels_ # 剔除 label=-1 的噪声点,同时保留通过速度条件的大簇 keep_mask = labels >= 0 return points[keep_mask], velocities[keep_mask], intensities[keep_mask]

eps参数非常关键。激光雷达点云密集,eps可以设小;毫米波雷达点云稀疏,如果设太小,一个墙面会被切成很多碎簇,设太大又可能把两个不同墙面粘连在一起。我实测下来,在24GHz雷达、10Hz帧率、隧道环境下,eps=1.2m、min_points=4整体平衡最好。

3.3 运动畸变补偿

雷达扫描一帧通常也需要几十毫秒。如果雷达在移动,这一帧内的点其实对应的是不同时刻的雷达位置。激光SLAM里常用IMU + 时间戳做运动畸变补偿,雷达也同理。

我在前端维护了一小段IMU位姿历史,每个雷达点的时间戳都对应一个最近邻的IMU姿态估计。把该点从实际测量时刻的雷达坐标系,变换到这一帧开始时刻的雷达坐标系下。Python实现思路如下:

def undistort_frame(points, timestamps, start_time, T_imu_start, T_imu_current_list, T_radar_to_imu): undistorted = [] for p, ts, T_imu_cur in zip(points, timestamps, T_imu_current_list): # 当前时刻点变换到IMU系 p_imu = T_radar_to_imu[:3,:3] @ p + T_radar_to_imu[:3,3] # 当前时刻IMU位姿变换到帧起始时刻IMU位姿 T_cur2start = np.linalg.inv(T_imu_start) @ T_imu_cur p_imu_start = T_cur2start[:3,:3] @ p_imu + T_cur2start[:3,3] p_radar_start = np.linalg.inv(T_radar_to_imu[:3,:3]) @ (p_imu_start - T_radar_to_imu[:3,3]) undistorted.append(p_radar_start) return np.array(undistorted)

实际操作中,只要IMU时间对齐精度在5ms以内,畸变补偿就能把远距离点的位置误差从米级压到分米级。这在隧道这种狭窄空间里非常关键。

4. 雷达里程计:前端配准的实现与长直隧道中的退化问题

4.1 为什么不能直接套用激光SLAM的ICP

最初的实验里,我直接把毫米波雷达点云丢给open3d的 ICP,结果在隧道直道上跑不到200米就开始飘。问题出在雷达点云稀疏,而且几何结构上“前方墙面”的点特别多,侧边墙的点比较少。ICP在做最近点匹配时,前方点云占主导,一旦前方存在镜面反射假点,迭代方向就会被带偏。

另外,毫米波雷达每帧点云之间没有一一对应关系。ICP假设两帧点云的最近点大概率是同一个物理表面的观测,但稀疏雷达点云的每一个点在下一帧里可能完全落在不同的物体上。所以直接套用激光雷达的ICP配准,本质上是匹配两个都含有很大噪声的子集。

正确的做法是:雷达里程计必须分两步走——先做粗配准,再做精配准。

4.2 粗配准 + ICP精配准的Python实现

粗配准的来源有两个:一是上一帧里程计的预测位姿,适用于短时间内的连续性移动;二是IMU积分得到的相对旋转。这里我采用了“IMU旋转 + 轮式里程计/雷达多普勒平均速度平移”来产生初始变换。

这个初始变换不需要很准,但必须把两帧点云拉近到ICP的收敛半径内。之后再用Open3D的点到面ICP做精配准。为了避免动态点影响,精配准前还会再按距离限制过滤掉与预测位置差距太大的点。

实现代码大致如下:

import open3d as o3d def radar_icp(source_pcd, target_pcd, T_init): """ 毫米波雷达两帧点云的ICP精配准 source_pcd, target_pcd: open3d.geometry.PointCloud T_init: 4x4 初值矩阵 """ threshold = 1.5 # 最近点匹配距离阈值,单位米 reg = o3d.pipelines.registration.registration_icp( source_pcd, target_pcd, threshold, T_init, o3d.pipelines.registration.TransformationEstimationPointToPlane(), o3d.pipelines.registration.ICPConvergenceCriteria(max_iteration=50) ) return reg.transformation, reg.fitness, reg.inlier_rmse

这里fitness是内点比例,我把它作为配准质量的观测指标。一般情况下,fitness大于0.5说明配准可信;如果低于0.3,说明当前帧和上一帧之间没有足够的公共区域,或者发生了严重退化。这个指标后面会作为关键帧选取和回环验证的一个参考。

用这种方式,我在隧道里做了大约800米测试段,里程计末尾漂移在13米左右。对于“纯前段里程计”来说,这个数还能接受,但作为最终三维建图还远远不够。

4.3 长直隧道里的退化问题与多传感器约束

隧道场景里最容易遇到的一个退化问题,是长直段。直线段让里程计在沿前进方向上有清晰约束(墙体距离连续变化),但在垂直前进方向上几乎没有几何约束。如果隧道是近似圆柱形的,点云在横向旋转上也不敏感。

换句话说,一个前进2米和前进2米带1度旋转的位姿,在隧道长直段可能产生非常接近的点云匹配误差。ICP会随机选择其中一个,导致每次估计的横向偏移和航向角都有随机误差,而随机误差会随时间累积。

我的缓解办法主要有两个:

  • 加入IMU的积分约束,限制横摆角和横向加速度。即使IMU本身有漂移,它提供的短时间相对姿态信息也足够帮助雷达里程计抵抗横摆角的随机漂移。
  • 加入多普勒平均速度约束。毫米波雷达能直接测到每个点的径向速度,对一整帧点云的速度场求平均,可以估计车体前进速度。这个速度信息用来抑制前进方向上的不合理跳变。

我用的融合方式,是在ICP配准之后做一次简约的扩展卡尔曼滤波,把IMU预测和雷达里程计观测融合。没有做复杂的紧耦合,保证代码量可控,同时也能拿到不错的稳定性。

5. 回环检测与图优化后端,如何把漂移按回来

5.1 基于强度图与ScanContext的毫米波雷达回环检测

纯里程计跑完,占据了全局地图,但这个地图很难直接用来做导航或测量。原因就是前端里程计仍然带着累积误差。在隧道场景里,最有效的“扳回一城”手段,就是回环检测。

回环检测在隧道里的难点是:环境看起来处处相似。一眼放去全是灰色的混凝土墙面,视觉回环如果只看纹理特征,很容易产生高相似度误匹配。但毫米波雷达有一个优势——不同位置的墙体细节、金属管道、消防栓、通风口会产生不同的多径反射模式,这些反射模式虽然在距离上是固定的,在角度上的“背影”却可以作为位置指纹。

我采用的是类似ScanContext的做法:把雷达点云的极坐标投影成“距离-方位角”二维柱状图,每个bin里存放该方位角下最近距离处的回波强度最大值。再把每一帧柱状图编码成向量,检索历史关键帧,看哪些帧和当前帧最相似。

简化版ScanContext生成逻辑:

def generate_scan_context(points, intensities, num_azimuth=60, num_range=20, max_range=40.0): """ 输入:三维点云和强度 输出: num_azimuth x num_range 的方位角-距离强度图 """ sc = np.zeros((num_azimuth, num_range), dtype=np.float32) # 计算方位角索引 azimuth = np.arctan2(points[:, 1], points[:, 0]) # [-pi, pi] dist = np.linalg.norm(points[:, :2], axis=1) az_idx = np.clip(((azimuth + np.pi) / (2 * np.pi) * num_azimuth).astype(int), 0, num_azimuth - 1) r_idx = np.clip((dist / max_range * num_range).astype(int), 0, num_range - 1) for a, r, intensity in zip(az_idx, r_idx, intensities): sc[a, r] = max(sc[a, r], intensity) return sc

在检索时,我用余弦相似度计算两帧ScanContext的匹配分数。比如当前帧和历史帧分数超过0.8,就进入下一步几何验证。

5.2 位姿图构建与GTSAM求解

回环检测给出的是“当前帧和历史帧之间应该很相近”的约束,还不一定是精确位姿。所以我先对这两个候选帧再做一次ICP,如果配准的fitness足够高,就把当前帧和历史帧之间的相对位姿作为回环边,插入位姿图。

位姿图里的每个节点代表一个关键帧的世界位姿,边分为两类:

  • 里程计边:相邻关键帧之间的相对位姿,来自前端雷达里程计;
  • 回环边:非相邻但被检测为回环的关键帧之间的相对位姿。

然后用GTSAM做批量优化。因为地图规模不算太大,我直接用了LevenbergMarquardtOptimizer。代码如下:

import gtsam def build_and_optimize_graph(keyframes_poses, odom_edges, loop_edges): graph = gtsam.NonlinearFactorGraph() initial = gtsam.Values() # 第一个节点固定到原点 prior_noise = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.05, 0.05, 0.05, 0.01, 0.01, 0.01])) graph.add(gtsam.PriorFactorPose3(0, gtsam.Pose3(), prior_noise)) # 添加里程计边 for i, (key_from, key_to, relative_pose, noise_sigmas) in enumerate(odom_edges): model = gtsam.noiseModel.Diagonal.Sigmas(noise_sigmas) graph.add(gtsam.BetweenFactorPose3(key_from, key_to, relative_pose, model)) # 添加回环边,回环边的噪声设置通常更小,因为回环约束更“硬” for i, (key_from, key_to, relative_pose, noise_sigmas) in enumerate(loop_edges): model = gtsam.noiseModel.Diagonal.Sigmas(noise_sigmas * 0.3) graph.add(gtsam.BetweenFactorPose3(key_from, key_to, relative_pose, model)) # 初始值 for key, pose in keyframes_poses.items(): initial.insert(key, pose) params = gtsam.LevenbergMarquardtParams() optimizer = gtsam.LevenbergMarquardtOptimizer(graph, initial, params) result = optimizer.optimize() return result

这里有一个细节:回环边的噪声不能设置得和里程计边一样。雷达ScanContext回环即使通过了几何验证,也可能存在0.3米左右的配准误差,如果你把回环边也当成“绝对正确”,图优化会把前面所有里程计边强行拉歪。我会把回环边的噪声设置成里程计边的0.3倍,既让回环起到强制收敛作用,又不至于过度信任何一条回环约束。

5.3 1.2公里隧道实测的表现与参数记录

最完整的一次测试是在一段约1.2公里的地下行车隧道里做的。地面有少量积水,墙面上有管线支架,每隔30-50米有一处设备箱。车体以约1.5m/s速度行进,总耗时约14分钟。

跑完一轮之后,我记录了三个数据:

  • 纯雷达里程计,最终轨迹终点误差约15.8米,约占总里程的1.3%;
  • 加入IMU约束后,终点误差降到12.4米,约1.03%;
  • 加入ScanContext回环检测和GTSAM后端优化后,终点误差降到9.1米,约0.76%。

这个0.76%还不是整条轨迹上最理想的值。隧道中段有几个连续的“S”型弯道,这些弯道提供了比较强的横向几何约束,后端优化把这几段拉得比较狠。如果你遇到的工况是大型地下车库或者矿道,环境特征更丰富,回环检测的成功率还会提升,整体漂移率通常能控制在0.5%以内。

6. 实战中踩过的坑,和一批更容易被忽略的参数调整细节

6.1 雷达安装位置对多径噪声的影响远超你想象

第一次做现场标定时,我把雷达装在小车后部的金属支架上,正前方有一块竖直的金属挡板。结果跑出来点云里每帧都有两个高强度的对称假目标,距离正好等于小车宽度。这就是典型的镜面多径:雷达波束打到金属板上,形成假反射路径,在点云里产生了一前一后两个点。

后来我把雷达移到车头最前端,周围清理掉大块金属平面,假目标基本消失。多径噪声还有一个特点,就是和雷达天线朝向强相关。你如果非要在隧道里做三维建图,尽量让雷达的视场角避开大面积的平整金属墙面,如果避不开,至少要在预处理阶段把“固定在车体坐标系下的重复假目标”先标定出来,然后模板剔除。

6.2 强度阈值不要固定,要自适应

早期我把强度阈值定成一个固定值,现场调试时发现,在隧道入口段点云非常干净,进隧道30米后墙壁湿度变大,回波整体变强,固定阈值开始把墙面点误删。再往里走,有一段混凝土表面有防水涂料,回波又弱下来,固定阈值又把噪声点全放进来了。

推荐做法是每帧统计强度分位数,用median + k * IQR作为该帧的过滤阈值。k一般取1.0到2.5之间。经验法则:点云越稀疏,k越大,避免误删真实点。

6.3 后端优化的关键帧数量需要控制

隧道长直段跑完,即使前端做了关键帧提取,整体关键帧数量可能还是很多。我第一次后端优化的时候,把全部约4200帧都放进位姿图,GTSAM在笔记本上跑了20多分钟,完全不实时。

后来我把关键帧选取阈值调大,让关键帧之间至少相隔0.4米或者旋转3度,把总关键帧压到约1000帧。后端优化一次大约4秒,满足巡检任务的后处理需求。如果你需要在线实时运行,建议再用“局部窗口优化 + 全局低频回环”的方式,把优化频率降到每10秒一次,也可以跑得动。

6.4 时间同步和调度问题

毫米波雷达和IMU的时间戳如果不同步,后面所有纠偏都是白搭。我这次是蓝牙无线传输雷达数据,结果不仅延迟大,还伴随丢包。后来直接改成串口物理连接,并在驱动层对数据包做序号校验,每丢一帧就告警,把数据完整性问题暴露在早期,而不是等到拼接地图时才发现大范围空洞。

另外,建议现场测试前先录一遍“静止场景数据”,用一个静止的雷达原地采集1分钟,看点云里的静态点会不会出现系统性漂移。如果静止时距离值也在漂,那说明雷达本身没标定好,先别上车。这个小习惯能帮你区分是传感器问题还是算法问题,节省大量排查时间。

6.5 对于三维建图结果的检验

最后提一下地图评价方法。不要只看轨迹终点误差,因为在封闭隧道里,终点误差和内部误差分布可能很不一致。我习惯把后端优化后的点云地图和已知的隧道横断面尺寸做对比,比如量一下左右墙间距、拱顶高度,和设计值做差。毫米波雷达本身测距精度通常在厘米级,但点云稀疏会导致局部拟合误差偏大,所以如果地图尺寸偏差在10厘米以内,就算合格;能压到5厘米以内,说明前端配准和后端优化都基本到位。

这套毫米波雷达SLAM方案,我没有把它做成一个开箱即用的库,它更像是一套“适应雷达脾气”的方法论。每个模块单独拆出来都不复杂,难点在于让它们在一个充满粉尘、无GPS、特征又高度相似的隧道环境里协同工作。后来我又把这套思路迁移到了矿道和地下管廊场景,只需要调整点云预处理的部分阈值和回环检索参数,整体框架不用动。希望这篇实战记录能让你在做类似项目时少走一点弯。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询