ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Ubuntu 18.04 上 patchwork++ 点云地面分割从编译到调参

Ubuntu 18.04 上 patchwork++ 点云地面分割从编译到调参 拿到一台装了 Ubuntu 18.04 的工控机手里是一台 16 线激光雷达任务是把点云里的地面分割掉好让后续的聚类和障碍物检测干净一点。网上关于 patchwork 的教程不少但大多数只写到“编译通过”就结束真正到了“用自己的数据跑起来”这一步各种问题就冒出来了。这篇我就把整个过程摊开讲从环境准备、源码编译、rosbag 录制、话题映射到 rviz 验证和参数调整尽量覆盖你在 Ubuntu 18.04 ROS Melodic 下会遇到的所有主流问题。标题敢写“全网最详细”我就按这个标准来写。1. patchwork 到底强在哪为什么地面分割是绕不开的第一步1.1 地面分割为什么难不是把点云压平那么简单很多人第一次接触地面分割会觉得“地面不就是 z 值最低的那些点吗直接按高度截断不就行了”。真这么干过的人都知道这套思路在室内平整地面上勉强能用换到户外立刻崩。问题出在三个地方。第一地面本身不一定是平面。园区道路有坡度停车场有缓坡甚至一个普通的减速带都会让“全局平面假设”失效。第二雷达安装角度和振动会让点云产生倾斜你把 z 阈值一卡近处的马路牙子全被当成地面砍掉了。第三负障碍物比如沟渠、下坡台阶在点云里形成的“空洞”用高度阈值根本分不出来。所以地面分割本质上要做的事情是在不知道地面几何形态的前提下尽可能准确地把“属于地面的点”和“属于障碍物的点”分开同时要快、要稳、要能在嵌入式平台上实时跑。1.2 patchwork 的四个核心步骤GLE、GNL、区域提升、时间回退patchwork 是 Patchwork 的改进版本发表于 ICRA 2022一句话概括就是先把空间切成小块每个小块单独判断是不是地面再把相邻的小块合并成完整地面。这套思路比起“拿一个平面去拟合所有点”要合理得多。具体来说它把点云投影成类似 range image 的结构在径向和方位角方向划分出一个个 bin栅格。对每个 bin 做几件事GLEGround Likelihood Estimation对每个 bin 做 RANSAC 平面拟合用拟合出的平面高度、法向量、残差等特征打分判断这个 bin 是不是地面。GNLGround Norm Likelihood对拟合平面法向量做进一步约束。地面的法向量应该大致垂直如果一个 bin 拟合出来的平面法向量歪得离谱那大概率是障碍物表面而不是地面。Region-wise Ground Plane Fitting区域提升相邻的、被判定为地面的 bin 会互相连通形成一个大的地面区域。这一步能有效解决“同一个地面被分成碎片”的问题。Temporal Ground Revert时间回退利用帧间信息把短时间内反复横跳的 bin 恢复到更稳定的状态减少闪烁。这套流程直接用代码写出来并不复杂工程上真正花时间的是调参和适配数据。1.3 和常见替代方案对比RANSAC、Ray Ground Filter我把常见的几种方法放在一起对比一下方便你判断为什么选 patchwork方法思路优点缺点全局 RANSAC对所有点拟合一个平面实现简单室内效果好户外起伏地面直接失效计算量大Ray Ground Filter按射线角度扫描判地面速度快适合低线束雷达对噪声敏感近距离效果差参数多高度阈值z h 即地面最快不能处理坡度、倾斜、负障碍物patchwork分块拟合 区域提升鲁棒、实时、不平整地面效果好参数需要针对雷达调整我自己的实测感受是patchwork 对 16 线雷达的适配性很好近距离地面分割干净远距离略有损失但能接受。如果你手里是 64 线或固态雷达效果会更好。2. Ubuntu 18.04 ROS Melodic 环境先把地基打牢2.1 版本选择为什么是 Melodic而不是 NoeticUbuntu 18.04 对应的 ROS 1 发行版是 Melodic。虽然 Noetic 可以通过编译源码的方式在 18.04 上运行但官方并不推荐而且很多第三方包包括 pcl_ros、robot_localization 等在 Melodic 下的预编译包最全。既然标题锁定 Ubuntu 18.04那就直接用 Melodic省掉一堆源码编译的麻烦。系统要求不多说建议装好系统后先做两件事把 apt 源换成国内镜像然后sudo apt update sudo apt upgrade。这一步能避免后面编译时下载依赖慢到怀疑人生。2.2 ROS 安装官方步骤 vs 社区一键脚本ROS Melodic 的安装有两条路官方手动步骤或者社区的一键脚本。官方步骤大致是这样sudo sh -c echo deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main /etc/apt/sources.list.d/ros-latest.list sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 sudo apt update sudo apt install ros-melodic-desktop-full装完之后初始化 rosdepsudo rosdep init rosdep update echo source /opt/ros/melodic/setup.bash ~/.bashrc source ~/.bashrc社区的一键脚本鱼香ROS我实际用过对新手非常友好它会自动帮你处理源、密钥、依赖等问题命令就一行wget http://fishros.com/install -O fishros . fishros按提示选择“一键安装 ROS Melodic桌面完整版”就行。我的建议是如果你对 ROS 已经很熟官方步骤完全够如果想省时间脚本方案更稳毕竟它把很多国产源、DNS 问题都提前处理好了。2.3 rosdep update 超时的完整应对链路这是 Ubuntu 18.04 装 ROS 时出现频率最高的报错没有之一。热搜词里那句(the read operation timed out,)基本人手一份。先别急着百度复制粘贴按下面这个思路排查一遍以后遇到任何网络超时类问题都不慌。第一步看现象。卡在rosdep update的 reading 阶段报错信息类似ERROR: error loading sources list: The read operation timed out第二步判断原因。rosdep 更新时需要访问raw.githubusercontent.com上的 rosdistro 仓库而这个域名在国内的 DNS 解析经常出问题导致 TCP 连接超时。第三步验证。执行getent hosts raw.githubusercontent.com如果返回的 IP 是空的或者解析极慢说明 DNS 有问题。这时候修改/etc/hosts是最直接的手段sudo nano /etc/hosts在文件末尾加一行IP 地址以你实际 ping 出来的可用地址为准不同地区、不同时间会变不要抄网上过期的185.199.108.133 raw.githubusercontent.com保存后重新执行rosdep update。我遇到的情况是改完 hosts 基本一次就过了。如果还是超时可以考虑把 rosdistro 仓库 clone 到本地把20-default.list里的源改成file://本地路径但这属于进阶操作正常改 hosts 足够解决 95% 的问题。2.4 依赖确认PCL、Eigen、OpenMP 版本patchwork 的核心依赖是 PCL 和 Eigen。Ubuntu 18.04 自带的 PCL 是 1.8.1Eigen 是 3.3.4完全满足 patchwork 的要求所以不需要额外升级。检查一下有没有装全dpkg -l | grep libpcl dpkg -l | grep libeigen如果输出为空装上sudo apt install libpcl-dev libeigen3-devOpenMP 是编译期自动用的gcc 自带不用额外折腾。另外确认一下 CMake 版本官方源里的 CMake 是 3.10.2部分 patchwork 版本要求 3.13建议提前升一下sudo apt install cmake装完执行cmake --version如果低于 3.13后面编译时大概率会报CMake 3.13 or higher is required到时候再想办法升级也不迟。3. patchwork 源码编译从 clone 到第一次跑通 demo3.1 仓库结构核心库和 ROS 包装层的关系patchwork 在 GitHub 上有两个仓库url-robotics/patchwork-plusplus是纯 C 核心库url-robotics/patchwork-plusplus-ros是 ROS 包装层。我们跑 ROS 环境只需要 clone 后者它内部会通过子模块方式把核心库拉下来。所以 clone 的时候一定要加--recurse-submodules否则你执行的目录里是空的编译直接报找不到源码cd ~/catkin_ws/src git clone --recurse-submodules https://github.com/url-robotics/patchwork-plusplus-ros.git注意--recurse-submodules这一条我身边不止一个人在这里翻车clone 完目录里没有源文件还以为是被墙了。3.2 编译前的工程梳理CMake 版本和子模块打开patchwork-plusplus-ros的CMakeLists.txt能看到它通过FetchContent或add_subdirectory的方式引用核心库。不同版本写法不一样但编译方式都一样直接用 catkin_make。在 Ubuntu 18.04 上CMake 3.10.2 可能会触发最低版本校验失败。如果你遇到这个两个解决方案方案一添加 Kitware 官方源升级 CMakewget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2/dev/null | sudo apt-key add - sudo apt-add-repository deb https://apt.kitware.com/ubuntu/ bionic main sudo apt update sudo apt install cmake方案二用 pip 装新版推荐更快pip3 install --user cmake export PATH~/.local/bin:$PATH验证cmake --version确保是 3.13 以上再继续。3.3 catkin_make 全流程与验证环境没问题后编译就很简单了cd ~/catkin_ws catkin_make第一次编译会拉取子模块、编译 PCL 相关代码耗时 3~5 分钟不用急。编译完成后 source 一下source ~/catkin_ws/devel/setup.bash验证是否成功rospack list | grep patchwork如果输出里有patchworkpp或类似的名字说明编译并通过了。不同版本的包名可能不同有的叫patchworkpp有的叫patchwork_plusplus以你 clone 到的实际为准后续 roslaunch 时用rospack list确认是对的。3.4 三个常见编译错误及定位思路编译阶段我遇到过且修复过的错误列出来供你对照错误一找不到杂项 Boost 组件Could NOT find Boost (missing: Boost::filesystem)Ubuntu 18.04 自带的 Boost 库默认可能没装全。执行sudo apt install libboost-all-dev即可解决。这个错误的特点是“PCL 都编译过了卡在 Boost 链接上”原因通常是 CMake 里find_package(Boost REQUIRED COMPONENTS system filesystem)缺了组件。错误二C 标准不匹配error: no matching function for call to pcl::...部分 patchwork 版本是在 C17 标准下写的而 catkin_make 默认可能没有正确传递-stdc17。解决方法是在CMakeLists.txt里确认set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON)或者编译时加上-DCMAKE_CXX_FLAGS-stdc17。错误三OpenMP 未启用fatal error: omp.h: No such file or directory正常 gcc 会自带 omp.h但如果你系统里 gcc 版本混乱可能出现找不到的情况。检查ls /usr/lib/gcc/x86_64-linux-gnu/*/include/omp.h不行就sudo apt install libomp-dev。4. 接入自己采集的数据bag 录制、话题映射与格式适配4.1 雷达驱动和点云话题的确认不管你是 Velodyne、速腾还是 Ouster第一步都是把雷达驱动跑起来确认点云话题名和消息类型。用rostopic list查看有哪些话题重点找名字像/xxx_points的然后用rostopic echo /rslidar_points | head确认消息类型是sensor_msgs/PointCloud2同时看一遍点云里的字段。常见雷达驱动发布的消息通常包含x, y, z, intensity部分还带ring, timestamp。patchwork 只需要 xyz额外字段不影响它工作。4.2 用 rosbag 录制自己的数据录制是个好习惯可以脱离雷达硬件反复调试。录制命令很简单话题名按你实际的来rosbag record -O ~/mydata.bag /rslidar_points如果想录制一段时间后自动停止可以用__duration:60rosbag record -O ~/mydata.bag --duration60 /rslidar_points录完检查一下 bag 里的信息和话题rosbag info ~/mydata.bag重点看 time 和 duration确认数据不是空的。我之前有一次录了 3 分钟回放才发现话题名写错实际存了个空话题白白浪费了半天。4.3 让 patchwork 订阅你的话题参数和 launch 修改patchwork 的 ROS 节点会订阅一个点云话题话题名通常在 launch 文件里配置。打开它的launch目录里的文件你会看到类似这样的内容node pkgpatchworkpp namepatchworkpp_node typepatchworkpp_node outputscreen param nameinput_pointcloud_topic value/rslidar_points/ /node把value改成你自己的话题名。如果你不想改 launch 文件也可以在运行节点时通过参数覆盖rosrun patchworkpp patchworkpp_node _input_pointcloud_topic:/rslidar_points修改完启动节点前先回放 bagrosbag play ~/mydata.bag --clock然后另开终端启动 patchwork 节点。这时候用rostopic list确认输出话题是否存在常见的是/patchworkpp/cloud_ground和/patchworkpp/cloud_nonground。4.4 PointCloud2 字段问题intensity 缺失与 is_dense大多数雷达驱动发布的是带 intensity 的 PointCloud2patchwork 内部用的是pcl::PointCloudpcl::PointXYZI所以正常情况没问题。但如果你的雷达驱动只发布pcl::PointXYZ类型没有 intensity部分版本的 patchwork 可能直接编译不过或者运行时报字段转换错误。解决办法是换一个驱动或者写一个简单的节点把 PointXYZ 转成 PointXYZIrosrun pcl_ros pointcloud_to_pcd input:/raw_cloud如果只是消息里的intensity字段为空全为 0其实不影响分割效果因为地面判断用的是几何特征不是反射强度。还有一个小坑是is_dense标志。如果点云里有 NaN 点且is_dense为 falsePCL 的部分滤波操作会变慢甚至报错。建议录制前在雷达驱动里把 NaN 点过滤掉或者用pcl_ros的passthrough节点预处理一下。5. 实跑实测rviz 可视化与参数调优5.1 启动节点与 rviz 配置编译通过、话题接好后完整的启动流程是终端 1 回放数据rosbag play ~/mydata.bag --clock终端 2 启动 patchworkroslaunch patchworkpp patchworkpp.launch终端 3 启动 rvizrosrun rviz rviz在 rviz 里添加两个 PointCloud2 显示组件一个选/patchworkpp/cloud_ground建议绿色一个选/patchworkpp/cloud_nonground建议红色。Fixed Frame 设为你的雷达 frame_id比如velodyne或rslidar。如果你只在 rviz 里看到一朵“云”但地面和障碍物没有分开大概率不是算法问题而是话题没配上或者 frame_id 对不上。这个我在第 6 节会详细展开。5.2 影响分割效果的几个关键参数patchwork 的 launch 文件里有一堆参数真正需要理解的其实没几个。我把核心参数整理成了表参数名作用我的推荐值sensor_height雷达离地高度米影响地面先验0.5~0.8num_iterRANSAC 迭代次数3max_flatness平面平坦度阈值越小越严格0.005elevation_threshold仰角阈值度数越大地面判定越宽松2.0z_thresholdZ 轴高度阈值0.2min_range/max_range处理距离范围米0.5 / 80调参核心逻辑如果地面被分得太多部分障碍物被当成地面说明地面判定太宽松调低elevation_threshold、调小max_flatness。如果地面漏分严重明显的地面点被当成障碍物说明地面判定太严格调高elevation_threshold、调大z_threshold。sensor_height一定要填准确。你填 0.3 但雷达实际装了 0.8地面先验就是错的分割结果漂移很正常。我调试时习惯先调elevation_threshold因为 16 线雷达的水平分辨率低一条扫描线打到远处的点间距很大仰角阈值直接决定这些点算“地面还是障碍物”。5.3 结果验证把非地面点云保存成 PCD调试过程中光看 rviz 有时候不够直观。我推荐把分割结果存成 PCD 文件用pcl_viewer离线检查这样能放大细节排查出在 rviz 里一闪而过的帧。rosrun pcl_ros pointcloud_to_pcd input:/patchworkpp/cloud_nonground这条命令会在当前目录生成一串以时间戳命名的.pcd文件然后查看pcl_viewer 1234567890.123.pcdPCD 文件的好处是可以自由旋转、缩放近距离检查马路牙子、草丛边缘有没有被误分割。我用这个方法发现过一个问题在密集的灌木丛区域patchwork 会把部分植被当成地面后来通过调高elevation_threshold解决了。5.4 一段真实数据的处理效果观察我自己的数据是一条园区的柏油路路边有低矮绿化带中间有一段上坡。原始点云大约 1.5 万个点分割后人眼观察平整路面分割干净边缘贴合度高。上坡段没有出现“地面断裂”这得益于区域提升环节。绿化带边缘有少量点被划到地面但不影响后续聚类因为聚类的阈值通常比这大。远处 30 米外的路肩有零星点被误判为障碍物属于可接受范围。如果我也用 RANSAC 跑同一份数据上坡段直接报废因为全局平面模型压根拟合不了坡度变化。这就是 patchwork 的核心价值所在。6. 踩坑实录完整排查链路按这个思路查一个准一个6.1 rviz 里全是空白先查数据再查坐标系现象节点正常跑roslaunch 没有报错但 rviz 里什么都看不见。排查链路第一步先用命令行确认节点真的有数据输出rostopic hz /patchworkpp/cloud_nonground如果显示频率约等于点云发布频率比如 10 Hz说明节点工作正常问题在显示层。第二步检查 rviz 的 Fixed Frame。点云消息的 frame_id 是velodyne而 rviz 默认的 Fixed Frame 是map中间没有 TF 关联rviz 就会认为坐标变换失败干脆不显示。解决方法把 Fixed Frame 改成velodyne或者另起一个 TF 发布节点把velodyne关联到map。对于离线回放数据来说最简单就是改 Fixed Frame。6.2 节点订阅不到 bag 里的点云话题名和时间戳现象rosbag play正常但 patchwork 节点就是收不到数据。排查链路第一步看 bag 里实际的话题名rosbag info ~/mydata.bag有可能你以为的话题名是/rslidar_points实际是/points_raw。对着改 launch 文件即可。第二步如果话题名没错检查消息类型。用rostopic info /rslidar_points查看是否真的是sensor_msgs/PointCloud2如果是别的类型比如velodyne_msgs/VelodyneScan说明你订阅的是原始包而不是解包后的点云需要启动驱动里的convert节点把 VelodyneScan 转成 PointCloud2。第三步检查时间同步。bag 回放时如果你用了--clock但节点内部没有设置use_sim_time也会出现数据跳过或延迟。在 patchwork 的 launch 文件里加上param name/use_sim_time valuetrue/或者在回放时不要用--clock只播放rosbag play ~/mydata.bag两种方式选一种不要混用。6.3 编译找不到 Boost/PCL不是没装是 CMake 没找到现象catkin_make报错提示Could NOT find Boost或Could NOT find PCL但你检查系统里明明装了。这是我见过的最容易误导人的报错。关键点在于Ubuntu 源里的libpcl-dev是元包它会把 PCL 的实际 CMake 配置文件装到/usr/lib/x86_64-linux-gnu/cmake/pcl/。CMake 找不到通常是以下几个原因你用的是 conda 环境里的 Python 包管理器CMAKE_PREFIX_PATH被改乱了。catkin_make 没有正常 source 系统路径。解决方法是手动指定 PCL 路径catkin_make -DCMAKE_PREFIX_PATH/usr/lib/x86_64-linux-gnu/cmake/pcl如果 Boost 报错先执行sudo apt install libboost-all-dev然后在CMakeLists.txt里确认find_package(Boost REQUIRED COMPONENTS system filesystem)写的组件名和你系统里装的 Boost 版本一致。Ubuntu 18.04 的 Boost 是 1.65.1支持这些组件。6.4 bag 回放时点云跳变sim time 和频率问题现象rviz 里点云画面一跳一跳的像抽帧一样。排查链路第一步看频率。rostopic hz /rslidar_points如果显示 10 Hz但画面卡顿大概率是显示问题调大 rviz 的 PointCloud2 组件的 Decay Time 或降低点云密度即可。第二步如果频率不稳定比如在 3 Hz 和 10 Hz 之间跳说明回放速度不匹配。rosbag play默认按原始时间戳播放如果你电脑性能跟不上消息会堆积。解决方法加-r 0.5降低回放速度rosbag play ~/mydata.bag --clock -r 0.5或者用--pause手动控制播放节奏。第三步检查 patchwork 节点本身的耗时。rostopic hz /patchworkpp/cloud_nonground如果比输入低很多说明分割节点处理不过来。可以用top看 CPU 占用如果单个核满载说明算法在单线程跑去 CMakeLists 里确认 OpenMP 有没有被正确启用。最后再分享几个实际使用的小经验patchwork 跑通之后我最大的感受是地面分割这件事算法选对只占三成剩下七成都在“数据适配”上。rosbag 录制时的话题名、点云字段、frame_id、时间戳任何一个环节不对都会让你在 rviz 前面消耗大量时间。一个小建议是调试时先用一小段 30 秒的 bag 数据反复回放别拿那种录了十几分钟的大文件硬刚。小文件启动快、定位问题快等参数稳定了再换大数据集验证效率会高很多。参数方面不要照抄别人的配置。同一台雷达安装高度差 10 厘米sensor_height的影响就非常明显。先把这一个参数调准再动其他阈值。如果你后续要做障碍物聚类强烈建议把/patchworkpp/cloud_nonground作为下游输入你会发现去掉地面之后再聚类目标数量少一半聚类轮廓干净很多。patchwork 这一步投资最终会在整个感知链路上成倍回馈回来。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进