
做移动机器人和无人机方向的朋友应该都听过FUEL这套框架。它的全称是Fast UAV Exploration using Incremental Frontier Structure and Hierarchical Planning说人话就是一套让无人机在没有地图的陌生环境里自主探索、自动规划安全轨迹、绕开障碍物、把未知空间逐步测绘出来的完整方案。我这段时间在Ubuntu 20.04下花了两三天功夫把FUEL从源码编译通过并在仿真环境里完整跑通了探索流程这篇文章就是从头到尾的实操记录覆盖环境准备、依赖安装、编译避坑、仿真验证四个环节。适合刚接触自主探索课题的研究生、想复现论文算法的工程师以及准备用Ubuntu 20.04 ROS Noetic做机器人实验、想快速跑通一套完整探索方案的朋友。先说一个基本判断编译科研代码最耗时间的从来不是敲那几条命令而是把依赖关系理顺。FUEL依赖的东西又杂又多ROS组件、Eigen、PCL、OctoMap、NLopt、Gazebo每一个都可能成为编译失败的切入点。而且这类项目往往文档更新滞后README里写的步骤和实际环境常有出入。所以这篇文章我不想只贴命令会把每一步为什么要这么做、失败时怎么定位问题也讲清楚这样你遇到没见过的报错时至少知道往哪个方向排查。1. 项目概述FUEL到底是什么为什么值得折腾1.1 核心功能拆解FUEL解决的是一类很具体的问题在完全没有先验地图的未知环境里无人机如何用有限的机载计算资源高效地找到尚未探索的区域并规划出安全、平滑、可飞的轨迹。它内部大致可以分为三个模块。第一是前沿结构Frontier的增量更新。所谓前沿就是已知地图和未知区域之间的边界。无人机每飞到一个位置传感器扫描一圈地图更新前沿集合也随之变化。FUEL会维护一个增量式的结构专门管理这些不断出现的边界点而不是每帧都从头计算这是它在计算资源受限时还能保持实时性的关键之一。第二是分层规划Hierarchical Planning。探索不能瞎飞得先决定下一步去哪看最划算再决定怎么飞过去不会撞墙。FUEL把这个问题拆成顶层目标点和底层轨迹两个层次顶层根据前沿点的分布、飞行代价、新空间收益等信息评估候选目标底层负责生成一条真正可执行的轨迹。这种分层策略的好处是降低计算复杂度也让行为更可解释。第三是B样条轨迹生成。无人机在探索过程中需要不断重规划轨迹得足够平滑否则物理上根本飞不出来。FUEL用均匀B样条表示轨迹把动力学约束融入到优化问题里生成的时间最短、安全距离足够的轨迹。打个不太严谨的比方这三个模块就像人探索一间黑屋子先判断哪扇门后面我没看过再决定先去哪扇门最合算最后用什么样的路线走过去不会撞到家具。1.2 编译真正的难点在哪接触过科研代码的人都有体会源代码本身通常问题不大问题全在编译环境和依赖版本上。FUEL也不例外我排了一下坑主要集中在几个地方Eigen版本冲突、OctoMap相关包没装齐、NLopt需要源码编译、Gazebo仿真模型下载超时。任何一个环节没处理好都可能让你在编译阶段反复撞墙。另外还要提醒一点ROS Noetic官方支持的发行版就是Ubuntu 20.04不要图新鲜用22.04或者更高版本去硬装Noetic那样会遇到大量Python和依赖兼容问题。如果你已经在更新的系统上入了坑建议直接换20.04省下来的时间远多于重新装系统的成本。1.3 软硬件环境清单我把这次编译和仿真用的环境列成了表格方便你提前对照。项目版本/型号备注操作系统Ubuntu 20.04.6 LTS64位建议单系统或双系统ROS发行版Noetic官方仅支持20.04核心依赖Eigen 3.3.x、PCL 12、OctoMap、NLopt部分需要源码编译仿真器Gazebo 11随desktop-full一起安装CPU4核以上编译时并行度可调到-j4内存建议8GB以上低于8GB严格用-j2磁盘至少留出30GB/home目录空间要足够如果打算用虚拟机跑也不是不行但内存至少要给到8GBCPU给到4核以上否则Gazebo跑起来会非常卡编译也容易OOM。我在虚拟机里试过一次编译阶段勉强能过仿真阶段探索算法每更新一次地图就要卡顿好几秒完全没法验证效果后来老老实实换到实体机上跑。2. 环境准备把Ubuntu 20.04和ROS Noetic收拾利索2.1 系统层面的准备如果你是从零开始操作系统建议直接安装20.04.6 LTS安装时选择安装第三方软件选项这样显卡驱动、WIFI固件等基础组件能一次装好。磁盘分区上把 /home 单独分出来并给足空间很关键因为ROS、Gazebo模型、源码、编译中间文件加起来非常占地方。我给 / 分了80GB/home 分了120GB实际使用下来 /home 还有不少富余但 / 差点不够如果你没有单独分区建议干脆把 / 也给到100GB以上。系统装好后第一件事是更新软件源和系统包。如果你在境内使用把软件源换成阿里云或者清华镜像能显著加快 apt 速度这个是常规操作。更新完系统会下载不少内核和库文件重启一次再开始装ROS能避免很多依赖装的莫名其妙的报错。还要提醒一个小习惯装完系统先别急着乱装软件把基础编译工具链装好这样后续省心很多。2.2 ROS Noetic 完整安装过程ROS Noetic的安装步骤网络上很多我这里给一个经过验证的流程。首先是添加软件源和密钥sudo apt update sudo apt install curl -y sudo sh -c echo deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main /etc/apt/sources.list.d/ros-latest.list curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -这里要提醒一点如果网络访问GitHub不稳定curl那一步可能会卡住或者超时。遇到这种情况你可以改用ROS的国内镜像源或者手动下载密钥文件再导入。不要反复curl同一个命令没有意义直接换源方案来得更快。密钥导入后更新软件源然后安装ROS主体sudo apt update sudo apt install ros-noetic-desktop-fulldesktop-full 包含Gazebo、RVIZ以及绝大多数常用库和插件对FUEL这种需要仿真环境的项目来说是最省事的选择。如果磁盘空间紧张可以用 ros-noetic-desktop 省掉Gazebo但后面就没法跑仿真了。整个安装过程可能持续十几分钟到半小时取决于网速和机器性能中途不要按CtrlC中断。接下来安装ROS常用的Python构建工具和rosdepsudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essentialrosdep初始化是很多新手卡住的地方尤其是update这一步因为默认要访问海外服务器经常失败。我的做法是先把rosdep的下载源配置到国内镜像仓库具体方法网上都有配置教程核心思路是设置一个环境变量指向镜像仓库比如把 。这里啰嗦一句rosdep update失败不要反复重试默认源配置好镜像后再执行基本一次就能过。如果确实因为网络原因无法更新代码编译阶段其实也可以不依赖rosdep但后续一些工具包检查会受影响所以还是建议解决掉。2.3 创建工作空间与基础工具ROS工程都是基于工作空间的我习惯命名为 catkin_ws放在用户目录下。创建和初始化命令很简单mkdir -p ~/catkin_ws/src cd ~/catkin_ws catkin_make第一次编译会生成 devel 和 build 两个目录并把一些基本环境变量配置好。然后把这个工作空间的环境变量加入bashrc这样每次打开终端就不用手动source了echo source ~/catkin_ws/devel/setup.bash ~/.bashrc source ~/.bashrc需要注意的是如果机器上存在多个ROS工作空间bashrc里最后source的那个会生效所以别把旧路径和新路径混在一起。可以用echo $ROS_PACKAGE_PATH检查当前生效的路径对不对确保后续能找到功能包。3. 编译前依赖安装大部分坑都集中在这里3.1 看懂FUEL的依赖清单拿到源码之后第一件事不是急着编译而是先看两个文件README和各个功能包里的package.xml。package.xml里写的是编译该功能包所需的ROS依赖README则会描述额外的非ROS依赖。我给FUEL常用的依赖做了个对照表你在编译前照着检查一遍就行。依赖apt安装包名用途容易漏吗Eigenlibeigen3-dev线性代数运算系统Eigen路径需要额外处理OctoMapros-noetic-octomap、ros-noetic-octomap-msgs、ros-noetic-octomap-ros八叉树地图msgs容易漏PCLros-noetic-pcl-ros、ros-noetic-pcl-conversions点云处理漏了找不到pcl_rosNLopt无标准apt包非线性优化需要源码编译tf2ros-noetic-tf2-eigen坐标变换一般随desktop-full装好3.2 一条龙安装命令先把能通过apt直接安装的依赖一次性装好sudo apt update sudo apt install libeigen3-dev sudo apt install ros-noetic-octomap ros-noetic-octomap-msgs ros-noetic-octomap-ros sudo apt install ros-noetic-pcl-ros ros-noetic-pcl-conversions sudo apt install ros-noetic-tf2-eigen装完之后建议检查一下Eigen的安装情况因为Eigen是头文件库安装本身不复杂但ROS的catkin系统常常会因为找不到正确的Eigen路径而报错。可以用下面这条命令确认ls /usr/include/eigen3/Eigen如果能列出 Eige目录说明系统Eigen装好了。但事情没这么简单很多编译错误其实源自Eigen多版本冲突系统里可能装了一个Eigen版本ROS环境又自带一个Eigen头文件两个路径都会被搜索编译时不知道用哪个就会报一些看起来很无厘头的错误。为了把这个问题一次解决我习惯在编译前把环境变量指到明确路径export Eigen3_DIR/usr/share/eigen3/cmake具体路径可能因版本略有差异可以先用find / -name *Eigen3* 2/dev/null找到实际路径再设置。3.3 NLopt源码编译NLopt是FUEL做轨迹优化时常用的非线性优化库在Ubuntu的官方源里有时候找不到就算能找到版本也偏旧。最稳妥的办法是源码编译流程如下git clone https://github.com/stevengj/nlopt.git cd nlopt mkdir build cd build cmake .. make -j4 sudo make install编译之前记得确保系统有cmake和g基础编译工具链在2.2节已经装过了。NLopt默认安装到/usr/localcmake在搜索依赖时通常会优先找到这个路径所以在编译FUEL时一般不需要额外配置。如果你之前手动装过其他版本的NLopt或者安装到了自定义目录需要在FUEL的CMakeLists.txt里搜索nlopt相关内容手动指定路径。我不想把这个问题写得太玄实际遇到再对照解决就行。3.4 版本冲突与连接问题的思路依赖不齐是编译失败的第一大原因而版本冲突是第二大。安装依赖时我只保留20.04官方源里的版本不要自己手贱去编译安装一个新版Eigen或新版PCL科研代码通常是在特定版本下验证过的版本过高反而会引入不兼容的API变化。另一个常见问题是在同一个catkin工作空间里放了多个项目的代码导致catkin_make把所有包一起编译包与包之间相互依赖混乱。我之前就吃过这个亏在src目录里既有FR自己的包又有FRUEL相关包一编译就报各种找不到包。后来我给FUEL单独建了一个工作空间问题立刻消失。这个建议非常值得参考科研项目尽量独立工作空间别混着放。4. FUEL源码获取与编译4.1 获取源码我是在catkin_ws工作空间里获取源码的cd ~/catkin_ws/src git clone https://github.com/HKUST-Aerial-Robotics/FUEL.git如果网络慢可以考虑用git的代理或者镜像加速不过这里不展开。clone完成后检查一下目录结构确保src下没有其他无关功能包然后就可以开始编译了。在编译之前我个人还会做一步额外的检查把工作空间里的build和devel目录清空避免前一次失败残留的中间文件干扰。命令是cd ~/catkin_ws rm -rf build devel catkin_make第一次失败往往不是代码问题而是上次失败留下的半成品缓存。这个习惯帮我避开了很多莫名其妙的问题。4.2 编译命令与参数选择编译命令本身很简单cd ~/catkin_ws catkin_make -j4-j4表示同时编译4个编译任务。这里要结合自己电脑的内存来决定8GB内存建议-j216GB以上可以试-j8。不要盲目追求并行数高编译过程非常吃内存并行数过高会导致系统直接杀掉编译进程表现就是终端里突然出现Killed或者让系统卡死。很多人在这一步遇到类似幻觉实际不是代码问题而是资源被耗尽。如果你的CPU核心数多但内存不大可以用负载限制catkin_make -j$(nproc) -l2-l2表示系统平均负载不超过2这样编译进程会等待而不是一股脑塞满内存。我第一次编译时用了-j12结果系统直接卡住加了-l之后稳定很多。4.3 编译错误实录与解决方案我把自己在编译过程中遇到的典型错误和解决办法整理出来以下内容比网上大部分教程都更贴近实际情况。错误一找不到Eigen头文件报错形式通常是fatal error: Eigen/Eigen: No such file or directory这个错误很经典产生原因是CMake找到了Eigen的cmake配置但头文件搜索路径指向不一致。解决方法是检查是否存在系统符号链接sudo ln -s /usr/include/eigen3/Eigen /usr/include/Eigen如果 /usr/include/Eigen 已经存在且是旧版本就把它删掉再链接新版本。做完后再编译这个问题基本消失。错误二找不到octomap_msgs包报错形式Could not find a package configuration file provided by octomap_msgs这说明你漏装了octomap的ROS消息包。执行sudo apt install ros-noetic-octomap ros-noetic-octomap-msgs ros-noetic-octomap-ros安装完记得重新source一下ROS环境source /opt/ros/noetic/setup.bash不然新装的包不会进入当前终端的环境变量。错误三找不到nlopt.hpp报错形式fatal error: nlopt.hpp: No such file or directory这是NLopt没装好或者路径不对。如果你已经按3.3节源码编译安装还是报错多半是安装路径不是默认的/usr/local。可以检查find /usr -name nlopt.hpp定位到头文件后把它们复制到 /usr/local/include 下或者修改对应CMakeLists.txt里的搜索路径。错误四C标准版本不匹配报错形式类似error: #error PCL requires C14 or aboveFUEL部分代码可能默认使用较新的C标准而catkin老版本默认用C11。解决办法是在编译时显式指定C14catkin_make -DCMAKE_CXX_STANDARD14 -DCMAKE_CXX_STANDARD_REQUIREDON -j4如果你用的是较新版本的ROS或CMake默认标准可能已经满足但如果出现这类报错这条命令就是标准解。4.4 编译成功的标志编译成功的标志一是终端最后出现多处Built target xxx二是没有红色错误信息。然后执行source ~/catkin_ws/devel/setup.bash再顺手检查一下功能包能否被ROS找到rospack find fuel_planner如果能输出包路径说明编译和配置都成功了。这个时候再去启动launch文件心里就有底了。5. 仿真运行验证让无人机自己动起来5.1 启动前的准备工作编译通过只算走完一半路程仿真能跑起来才算真正完成。启动之前有几个准备工作必须做第一个是确认环境变量echo $ROS_PACKAGE_PATH看看是否包含 /opt/ros/noetic/share 和 ~/catkin_ws/devel/share。如果少了工作空间的路径说明source没生效重新source一次。第二个准备是Gazebo模型问题。FUEL的仿真launch会加载Gazebo世界模型Gazebo首次启动时要联网下载模型文件一旦下载失败仿真就卡在加载界面。这里提供一个通用技巧把gazebo_models模型库提前下载好解压到 ~/.gazebo/models/ 目录下。具体操作方法网上有 gazebo 模型库手动配置 教程照着做一遍就能永久解决模型加载卡住的问题。5.2 启动仿真与探索运行启动FUEL仿真一般进入fuel_autonomy或fuel_launch功能包执行类似这样的命令roslaunch fuel_autonomy simulation.launch如果launch文件名不叫这个可以根据源码目录里的launch文件列表调整。启动后Gazebo会弹出一个带有室内环境的虚拟世界无人机起初停在某个角落几秒后开始自行规划路径。这个过程我第一次看到时还挺震撼无人机先是快速向前飞一段悬停然后旋转机身上的传感器扫描周围接着再飞向下一个区域整个行为链条非常像一个有逻辑的人在探索。需要提醒的是如果launch启动后终端没有报错但Gazebo窗口空白多半是模型加载路径问题如果RVIZ没有自动打开可以手动执行roslaunch对应RVIZ配置文件或者直接在终端里打开RVIZ后手动添加显示项。5.3 RVIZ可视化效果RVIZ是用来观察探索效果的核心工具重点看几个显示选项点云地图显示探索过程中生成的地图数据无人机轨迹显示规划出的飞行路径候选前沿点显示算法当前认定的探索目标代价地图显示障碍物膨胀和安全边界。这几个显示项加齐了就能看到无人机不断飞往新边界地图一点点从黑色变成彩色整个探索过程一目了然。如果这些显示项不知道怎么加最直接的办法是看launch里是否自带RVIZ配置如果有就直接用默认配置。没有的话添加PointCloud2主题话题名称可以从rostopic list里找到一般带 map 或 pointcloud 关键字的就是。5.4 仿真中的性能问题与常见现象仿真运行中最常见的现象是无人机飞着飞着突然停住不动过一会儿继续飞。这通常不是bug而是算法正在计算下一段轨迹或者正在等待传感器数据更新。只要终端没有报错就说明系统在正常工作。但如果停住的时间超过十几秒且CPU占用率接近100%那可能是规划器参数没调对可以稍微放宽探索半径或减小地图分辨率。另一个现象是有时无人机飞得很好但RVIZ里的轨迹显示不出来多数是轨迹话题名和RVIZ配置里不一致。用rostopic list | grep -i traj找出实际话题名再在RVIZ里手动指定即可。6. 常见问题速查表编译和仿真阶段快速定位我把这次踩过的问题汇总成了一张速查表方便你卡住时直接查阅不用从头翻文章。现象可能原因解决办法编译时找不到Eigen头文件Eigen路径配置不一致建立符号链接 /usr/include/eigen3/Eigen 到 /usr/include/Eigen编译时缺少octomap_msgs遗漏ROS依赖包sudo apt install ros-noetic-octomap-msgs编译时找不到nlopt.hppNLopt未安装或路径不对源码安装或找到并复制头文件到 /usr/local/include编译时提示C标准不满足CMake默认C11太低catkin_make -DCMAKE_CXX_STANDARD14编译过程中系统卡死或Killed并行数过高导致内存耗尽改用catkin_make -j2 -l2Gazebo启动卡在加载界面模型文件缺失无法联网下载手动下载gazebo_models放至 ~/.gazebo/models启动launch后无画面环境变量未source或模型路径错误重新source后再试检查模型索引无人机停止运行正在计算轨迹或参数不合理等待几秒若持续不动检查CPU占用和参数RVIZ看不到轨迹话题名不匹配用rostopic list查找并手动添加话题另外补充一个排查思路遇到任何报错先看最上面几行的错误信息而不要盯着最下面的一大批ABORT。CMake报错时真正有用的往往是第一个find_package失败或者第一个fatal error后面的内容基本都是连锁反应。习惯了这种排查方式之后编译成功率会高很多。7. 写在最后一些实际调试心得这次编译FUEL我最大的体会是科研代码的编译问题往往不是代码本身的问题而是环境和版本的问题所以一定要从依赖和环境入手。Eigen的版本冲突、octomap依赖缺失、NLopt路径不对这三个坑占了所有错误的七成以上提前装好并检查路径能避免绝大部分编译失败。第二个体会是编译过程中的资源控制。很多人在大内存机器上习惯不加限制地跑编译实际上编译器的并行任务同时吃内存和CPU一旦超过物理内存系统会进入交换状态时间反而更慢甚至直接Killed。用 -j 和 -l 一起控制是我最能直接推荐的做法。最后再分享一个小技巧每一次编译失败后先在终端执行source /opt/ros/noetic/setup.bash再重试。很多人漏了这一步导致新装的依赖包更新不到当前终端环境里反复编译反复报同一个错误其实就是环境变量没刷新。这个错误最隐蔽也最让人崩溃但解决起来只需要一条命令。FUEL这套框架跑通之后后续可以玩的东西还有很多比如修改传感器模型模拟不同探测距离替换地图分辨率看看对探索效率的影响甚至把探索规划器换成你自己的方法做对比。这些都是在编译通过这个坚实基础上才能展开的希望这篇文章能帮你少走弯路早点把无人机自主探索跑起来。