ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FUEL无人机自主探索框架在Ubuntu 20.04上的编译指南与避坑实录

FUEL无人机自主探索框架在Ubuntu 20.04上的编译指南与避坑实录 我花了差不多两个晚上加一个白天才让FUEL这个无人机自主探索框架在Ubuntu 20.04上老老实实地编译通过。中间踩过的坑比想象中多但也比想象中更“套路”。这篇文章就当作一份编译日志把整个过程中值得记录的细节都摊开写出来给准备在这个系统上折腾FUEL的朋友指一条不太绕的路。FUEL全称 Faster UAV Exploration using Local planning是港大 MaRS 实验室开源的一套无人机自主探索方案。它的核心能力是让无人机在完全没有先验地图的未知环境里自己规划路径、自己决定下一步往哪飞一边飞一边建图一边扩展已知区域。它和我们常听到的 RRT、RRT* 这类采样探索策略不太一样走的是 B 样条轨迹优化的路子路径更平滑探索效率也更高。如果你在做无人机 SLAM、路径规划或者毕业设计想用一套现成框架跑自主探索这个项目非常值得完整编译一遍。下面写的内容默认你对 Linux 命令和 ROS 基本概念有了解但如果只是照步骤操作也有机会一次跑通。1. 先搞清楚FUEL到底是什么再决定要不要编译它1.1 FUEL在无人机自主探索里的定位无人机自主探索这个方向说白了就是解决三个问题我在地图哪里周围有什么下一步该飞去哪。前面两个问题主要靠 SLAM 和感知第三个问题是典型的规划问题也是 FUEL 最花力气的地方。FUEL 的全称里有个 Local planning说明它的策略重点在“局部”。它不会像传统探索算法那样把全局地图割成格子然后做全覆盖路径而是维护一个局部范围的可行空间用 B 样条曲线来参数化候选轨迹然后在一个带碰撞惩罚和探索收益的目标函数里做优化。采样的点不多但结构很巧妙每条轨迹都有一个“探索方向”无人机沿着这条轨迹飞的时候会不断发现新的未知区域。和它同门派的还有 Faster 和 EWOK 等几个框架。Faster 更偏快速飞行EWOK 强调了多机协同FUEL 则比较适合单机在未知环境里稳扎稳打地探索。如果你只是需要一架飞机在一个封闭环境里自己转悠着建图FUEL 是很合适的起点。1.2 从代码仓库结构看它为什么会吃编译功夫拉下来 FUEL 的源码之后你会发现它的依赖链不是一两个库那么简单。除了 ROS 自身的基础包之外主要涉及 Eigen、PCL、OpenCV、GTSAM 这类重量级库还有一些 MaRS 实验室自己维护的工具包比如 planar_geometry、trajectory_planner甚至还会带上一个模拟仿真用的环境。这些依赖里ROS 和 PCL 在 Ubuntu 20.04 上都能用 apt 直接装Eigen 也可以从 apt 拿但 GTSAM 就不一样了。GTSAM 是佐治亚理工出来的因子图优化库FUEL 的轨迹优化后端大量用到了它。Ubuntu 20.04 的软件源里并没有一个稳定的 libgtsam-dev 给你直接安装版本也普遍偏老所以你几乎只能源码自己编。源码编 GTSAM 本身就要花十来分钟到半小时中间还会吃不少内存这是第一个劝退点。第二个劝退点是项目本身包含多个仓库之间相互引用。如果只把 FUEL 主仓库克隆下来却发现缺少几个依赖包编译的时候会直接提示找不到某个 package非常让人头疼。所以第一步不是急着敲 catkin_make而是先把整条依赖链理清楚。2. Ubuntu 20.04 下的环境准备与依赖安装2.1 ROS Noetic 的安装与几个容易忽略的确认项FUEL 官方主要在 ROS 环境下开发测试Ubuntu 20.04 对应的 ROS 发行版是 Noetic。这个版本和 18.04 上的 Melodic 差得不多但底层用的是 Python 3编出来的东西也更多依赖较新的编译器所以系统别搞太旧。安装 ROS Noetic 最稳的方式还是用官方源但国内网络环境下很多人会选择清华或中科大的镜像源速度会好不少。这个看个人网络情况我自己的做法是换清华源编辑 /etc/apt/sources.list用清华的 ubuntu 源再把 ROS 源也换成清华镜像整个 apt 速度会舒服很多。注意 Ubuntu 20.04 是 FocalROS repo 的镜像地址也要对应 focal。装完 ros-noetic-desktop-full 之后有四件事我建议提前确认rosdep 能不能正常 update很多编译自动找依赖的环节都靠它。初始化失败就多试几次或者手动把 /etc/ros/rosdep/sources.list.d/ 下面的源文件配好。工作环境变量有没有写好比如 source /opt/ros/noetic/setup.bash 有没有加进 ~/.bashrc。cmake 版本最好不低于 3.16Ubuntu 20.04 自带的 cmake 一般是 3.16.3够用。gcc/g 是 9.4不要手贱去装更高版本的 gcc 当默认编译器PCL 和很多旧代码对 GCC 版本很敏感升级后反而容易编不过。2.2 核心依赖库逐个安装我实际编译时依赖库的安装顺序是这样的先按依赖深度从底层开始装起sudo apt update sudo apt install libeigen3-dev libpcl-dev pcl-tools libopencv-dev sudo apt install libboost-all-dev libyaml-cpp-dev libprotobuf-dev protobuf-compiler sudo apt install libqt5widgets5 qtbase5-devEigen 和 PCL 是重头戏PCL 又依赖 VTK、Boost所以让 apt 自动处理就好。有些人会踩到 Eigen 和 PCL 版本冲突的问题最常见的是 PCL 里自带的 Eigen 头文件和系统里 /usr/include/eigen3 下的版本不一致导致编译时 Eigen 的宏定义对不上。真要遇到直接用系统的 libeigen3-dev并且在编译前确认 /usr/include/eigen3 是存在的。OpenCV 在 Ubuntu 20.04 上默认装的是 4.2如果只跑 FUEL 算法本身OpenCV 的版本没有太大影响但如果你后面想接真机视觉会有相机驱动库的版本兼容问题这个后面再说。2.3 手动编译 GTSAM 的那半小时GTSAM 是整个编译链路里最耿直的硬骨头。我建议单独下载源码单独编译安装不要指望它能被 catkin 流程顺手搞定。虽然把 GTSAM 放进 catkin_ws/src 里也能编但你会发现它每次都会重新走一遍完整构建非常拖时间而且一旦 CMake 变量有冲突排查起来很费劲。我当时用的版本是 GTSAM 4.0.3这也是 FUEL 官方 README 里推荐的版本区间。太新的 4.2 系列在某些接口上变过反而会编译报错。操作流程git clone https://github.com/borglab/gtsam.git cd gtsam git checkout 4.0.3 mkdir build cd build cmake -DGTSAM_BUILD_TESTSOFF -DGTSAM_BUILD_UNSTABLEON -DGTSAM_USE_SYSTEM_EIGENON .. make -j4 sudo make install这里几个 CMake 选项你得知道是干嘛的。-DGTSAM_BUILD_TESTSOFF 关掉了测试代码省一大波编译时间。-DGTSAM_BUILD_UNSTABLEON 则是把 GTSAM 里的 unstable 模块也编上FUEL 的优化器用到了其中一部分接口少了它后面会提示找不到 gtsam_unstable。-DGTSAM_USE_SYSTEM_EIGENON 是让 GTSAM 使用系统安装的 Eigen而不是把自己打包的 Eigen 再编一遍这样后续和 PCL、ROS 的 Eigen 引用才一致。编完之后可以确认一下pkg-config --modversion gtsam能输出版本号就是成了。如果 pkg-config 没找到可能是 /usr/local/lib/pkgconfig 不在 PKG_CONFIG_PATH 里手动加一下就行。2.4 创建工作空间和拉取源码的正确姿势FUEL 不是一个单包仓库它编译后会产生多个节点比如 planner 节点、模拟器节点、RVIZ 可视化配置等。你把它放进 catkin 工作空间结构大概是mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone https://github.com/HKUST-Aerial-Robotics/FUEL.git但只拉这一个仓库大概率不够。FUEL 依赖的一些 MaRS 本地工具包虽然有的通过 git submodule 方式挂载但如果你用的是普通 clone子模块并没有自动拉全。所以下一步一定要执行cd FUEL git submodule update --init --recursive完成后检查一下 FUEL 目录下是否有子模块目录被填上。如果官方仓库更新了或你拉的是某个分支可能部分子模块失效这时候以官方 README 里的依赖清单为准把缺失的仓库手动克隆到 src 目录下。这里要说一个很多人栽过的坑子模块拉取失败是很正常的网络问题不要慌重新执行 git submodule update 多试几次通了之后再往下走。如果网络质量一直不理想可以考虑错峰重试但绝对不建议用网上流传的某些“加速”手段去改 git 配置很容易引入安全风险。3. 编译过程实录与几个关键参数3.1 第一次 catkin_make 的预期与报错现场依赖装齐了接下来正式编译。我仍然建议用 catkin_make因为 FUEL 的构建系统是按照 catkin_make 的使用习惯设计的虽然 catkin build 也能用但某些依赖顺序和传递变量可能不一样遇到问题反而更难定位。cd ~/catkin_ws catkin_make -j4第一次编译我预期会发生两个大环节先是 ROS 自身的 message 和 service 生成然后是各个依赖包逐个编译最后编译 FUEL 的核心库和可执行文件。因为 GTSAM 已经提前装好这里省了很多时间。第一次报错出现最多的往往是某些依赖的 CMake 找不到。常见的几种提示Could not find a package configuration file provided by GTSAM这说明 GTSAM 编译安装有问题或者 CMake 搜索路径不对。解决办法是 export GTSAM_DIR/usr/local/lib/cmake/GTSAM或者重新执行 GTSAM 的 make install。Could not find Eigen3这个基本上是 Eigen 头文件路径问题Ubuntu 20.04 里 Eigen 头文件在 /usr/include/eigen3很多项目默认找 /usr/include/eigen3/Eigen没毛病。如果某些包坚持要 /usr/local/include/eigen3就做软链接。Could not find PCLPCL 没装或者版本不对sudo apt install libpcl-dev 重装一次基本能解决。3.2 控制并发线程数编译内存的生死门catkin_make 的默认行为是使用所有 CPU 核心数去并行编译这在内存小的机器上非常致命。GTSAM 那种重模板库还能接受PCL 相关节点编译的时候内存占用会瞬时冲到几个 GB。我当时用的是一台 16GB 内存的机器CPU 是 8 核直接 catkin_make 跑到一半就出现虚拟内存耗尽进程被内核杀掉报错信息里能看到 g: internal compiler error: Killed (program cc1plus)。解决办法有两个一是用 -j4 限制并发度我自己用 -j4 比较稳二是如果内存实在紧张还可以用 -j2。如果编译过程中还是被 OOM 杀死临时增加 swap 是最实际的手段sudo fallocate -l 8G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile加上 swap 之后编译速度会慢一点点但至少不会中途死亡。这里有个经验之谈不要同时开着浏览器的一大堆标签页去编内存那点余量就是这么被吃掉的。编译期间我习惯关掉 Chrome或者至少关掉那些常驻内存的网页实测下来编译成功率高很多。3.3 分阶段编译用小目标先验证依赖链如果你不想等整套编译跑完才发现某个依赖有错可以用 catkin_make 指定某个包先编catkin_make -j4 --pkg gtsam 2/dev/null catkin_make -j4 --pkg fuel_planner虽然 FUEL 的包名不一定就叫 fuel_planner具体名字可以用命令行补全或者去 src 目录下看包名但这个思路值得参考先把依赖包编完再去编主包。如果依赖包里有问题报错范围会小很多排查起来也快。我第一次就是浪费时间在整包编译上最后发现只是某个子模块没拉下来。3.4 编译顺序与 CMake 参数的最终选择整套编译我建议按这个顺序走先编译所有非 FUEL 核心的依赖包比如 plan_geometry、trajectory_planner、simulator 这类。如果某个仓库有单独的 README先按 README 来。再编译 FUEL 的主规划库这样主库在搜索依赖时路径已经建立好。最后再编译可视化、demo 启动这类外围包。实际运行时FUEL 的 CMakeLists 里可能也提供了一些编译选项比如选择是否使用仿真环境、是否启用某些测试节点。在你没有十足把握前不要乱加 -DFUEL_xxxOFF 这类关闭选项很多功能默认开启强行关闭会导致运行时缺依赖。4. 常见编译失败场景与排查技巧实录4.1 编译错误速查表我把自己遇到的、以及在群里看到别人遇到的典型编译错误整理成了下面这张表希望你在看到同样报错时不用再慌一遍。报错特征大概率原因处理办法找不到 GTSAMConfig.cmakeGTSAM 没装或路径不对确认 pkg-config 能找到手动 export GTSAM_DIR/usr/include/eigen3/Eigen 找不到Eigen 头文件目录缺失安装 libeigen3-dev 或做软链接提示 g internal compiler error: Killed内存不足进程被杀限制并发线程数加 swap提示 undefined reference to gtsam::...GTSAM 编译版本与头文件不匹配重新编译安装 GTSAM注意版本一致提示找不到 planar_geometry 包依赖仓库没拉全git submodule update 或手动克隆依赖仓库到 src编译时提示 Qt 相关错误缺 qtbase5-devsudo apt install qtbase5-dev提示 /usr/bin/ld 找不到 libproj.soPROJ 库版本问题sudo apt install libproj-dev或用 PCL 自带的 projROS 消息生成时报 Python 错误Noetic 默认 Python3但项目里写了 Python2检查 package.xml 与 CMakeLists确认用的 python34.2 三个特别容易误伤的细节第一个是 CMake 缓存问题。第一次编译失败后你会想改参数再编但 catkin 工作空间里已经生成了 CMakeCache.txt很多改动不会自动生效。这时候我最推荐的做法是把 build 和 devel 目录删掉重新来rm -rf build devel catkin_make -j4宁可重新编也不要带着半坏不坏的缓存硬撑着继续。曾经有人在一个缓存残留的 workspace 里反复碰运气浪费了一整天最后清掉重编反而十分钟过了。第二个是编译器和 GPU 驱动之间的关系。如果你机器上有 NVIDIA 驱动、CUDA尤其要注意不要随便把 gcc 切换成更新版本。ROS Noetic 官方支持 gcc 9换到 gcc 10 或者 11 之后PCL 的模板实例化会踩到 ABI 兼容问题编译日志里会出现莫名其妙的内核错误。第三个是路径中包含中文或空格。这个真的是老生常谈但每次都会有人栽。把 ~/catkin_ws 放在一个纯英文、无空格的绝对路径下编译时不要带路径里的空格。我见过有人把仓库放在 /home/张三/桌面/catkin_ws 这种路径下CMake 直接说找不到文件。4.3 怎么判断当前编译已经可以进行到哪一步编译过程中如果长时间卡在某一个包上没有输出不要慌。有些包比如 GTSAM 或者 PCL 的某些模块编译一个翻译单元就要占用大量 CPU表现就是终端里长时间停在同一行。这时候检查 CPU 状态最靠谱htop如果看到 cc1plus 或 g 的进程 CPU 占用率很高说明它还在干活耐心等如果 CPU 全部空闲、终端也没输出那大概率是卡在下载依赖或等待某个文件锁。这是最典型的两类“假死”。特别是虚拟机用户如果给了多个虚核但宿主机的 CPU 核数不够编译特别容易看起来像死机一样。5. 编译通过后怎么跑起Demo并验证探索效果5.1 在仿真环境里启动FUEL Demo编译成功之后不要急着上真机先在仿真里跑通一次完整探索流程。FUEL 仓库里带有一个仿真环境和一些 RVIZ 可视化配置。启动前先读一下仓库根目录的 README官方给的启动命令一般长这样source ~/catkin_ws/devel/setup.bash roslaunch fuel_planner rviz.launch如果你拉下来的仓库里 launch 文件名不一样可以用这个命令先看roslaunch --files fuel_planner它会把该包下所有 launch 文件列出来再启动对应的那个。启动之后RVIZ 窗口会显示无人机模型、地图、预测轨迹等信息。注意有些 demo 需要先加载一张已有地图或者手动发布一个起点而有些 demo 会自动生成一个未知环境。这些差异跟拉取时的分支有关尽量以 README 为准别盲目套用别人视频里的操作。5.2 如何判断自主探索真的在工作跑起来之后你可能会发现 RVIZ 里的地图在慢慢扩展无人机不断朝某个方向飞飞一段后又拐向另一边。这说明 FUEL 已经在自己探索环境了。但怎么判断它“探索得好不好”我一般看三个指标地图覆盖率增长是否连续。好的探索过程应该是稳定增长而不是长期在一个区域磨蹭。轨迹是否平滑。B 样条优化出来的路径理论上不会有明显折角如果轨迹频繁抖动说明参数没调好或点云质量不行。计算负载是否稳定。FUEL 的规划器如果在局部优化时频繁等待说明局部地图更新太慢或者规划线程和感知线程有阻塞这在仿真里不容易暴露要专门盯一下节点频率。更好的验证方式是用 rosbag 记录整个探索过程跑完之后离线复盘rosbag record -a -O fuel_explore.bag回放的时候可以反复看探索路径分析哪些区域探索顺序不合理哪些地方存在重复扫描。这个数据可以用来调整 FUEL 里的探索增益参数、视场角设置等。5.3 从仿真到真机前必须想清楚的三件事仿真只是算法层面的验证真机和仿真的差距非常大。我建议按下面这个顺序逐步推近第一步在仿真里换模型。把默认飞机模型换成你自己的机架参数包括飞行速度上限、加速度上限、最大倾斜角让规划器知道你真实飞机的物理限制。第二步接入你自己的 SLAM 输出。FUEL 的探索算法依赖里程计和点云地图你可以先用 Cartographer 或 FAST-LIO 输出再灌给 FUEL 规划器。第三步加入避障安全距离的余量。仿真里 PCD 地图没有噪声真机点云会有各种离群点和动态物体碰撞检测距离至少要留出百分之二十的余量。这里特别提醒真机飞行一定要在地面站里看实时日志而且第一圈建议速度上限调低比如只有默认值的四分之一等确认探索逻辑稳定了再慢慢放开。6. 编译通过之后还能怎么继续扩展6.1 把FUEL接进自己的自主探索系统如果你不满足于只跑 demo想把 FUEL 的核心规划模块抽出来用到自己的无人机平台上其实并不需要改太多东西。FUEL 的包设计上已经把状态估计、地图输入和规划器的接口分得比较开你只需要在 launch 文件里把点云话题和里程计话题指向你自己的节点输出即可。但这里有个小坑FUEL 对点云的时间同步有要求如果你用的是视觉 SLAM 输出带畸变的点云很容易导致前端匹配不上探索过程会频繁报错。这也是为什么很多人在真机上跑 FUEL 之前会先把自己 SLAM 的点云质量检查一遍。6.2 能从这个项目里学到的东西个人认为FUEL 代码里最有学习价值的不是它的探索策略本身而是它的工程组织方式。它把感知、规划、控制分成几个相对独立的模块每个模块通过 ROS topic 通信模块内部保持高内聚。这种结构对做毕业设计、实验室课题的人来说特别值得模仿。哪怕你后面不走探索这个方向挑几个模块去读也能学到不少关于局部地图表示、碰撞检测、轨迹优化接口设计的思路。还有一点FUEL 使用了不少现代 C 特性比如模板、智能指针、函数式回调读代码的过程本身也是一次不错的现代 C 项目实践。编译它的时候多留意报错对应的源码位置你会发现 CMake 报错其实是在提醒你哪个依赖没满足背后的依赖管理思路比单纯“让编译通过”重要得多。这里的经验是不要试图一次性把整个工程的全部报错都读懂拿到一个报错就先解决一个解决一个就会让下一个更清晰。第一次编译通过之后你再去把整个工程删掉重编几乎全程无坑那就算是真正把环境吃透了。
返回列表