ARTICLE DETAIL

资讯详情

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

PX4+jmavsim仿真环境搭建:高频编译与启动报错排查实战指南

PX4+jmavsim仿真环境搭建:高频编译与启动报错排查实战指南 1. 先把问题的全貌看清楚这条命令背后到底发生了什么很多刚接触PX4的朋友多半都是卡在这一步按照网上的教程装好了Ubuntu20.04克隆了PX4-Autopilot固件然后在终端里输入make px4_sitl jmavsim结果等到的不是漂亮的无人机仿真界面而是满屏的红色报错。说实话我在这个坑里也爬过不少次。之所以这篇想写jmavsim是因为它和Gazebo相比轻量、启动快、资源占用少特别适合刚把环境搭起来、只想先验证飞控逻辑和MAVSDK通信的初学者。但“轻量”不代表它不挑剔——它对Java版本、编译依赖、子模块完整性、网络环境都有着微妙的要求任何一环掉链子都会在编译或启动阶段给你颜色看。在进入具体错误清单之前我想先帮大家建立一个整体认知框架。PX4在Ubuntu上的仿真环境本质上是一条“固件源码 → 编译工具链 → 仿真地面站”的链路。make px4_sitl jmavsim这条命令实际干了两件大事编译PX4固件的SITLSoftware In The Loop版本启动jmavsim仿真器把这个仿真飞行器“挂”到JMAVSim的可视化世界里。任何一环出了问题报错形式千奇百怪但归起类来无非三种环境问题、依赖问题、源码完整性问题。下面我会把这三大类里最常见的报错逐一拆开讲清楚。2. 环境准备阶段这些前置条件不满足后面全是白搭2.1 系统版本与PX4版本的匹配关系先说一个很容易被忽视的点Ubuntu20.04对应的是PX4的哪些版本以及它们之间的兼容情况。PX4官方对Ubuntu20.04的支持主要是从v1.11之后的版本开始完善的尤其是v1.13和main分支在20.04上的表现比较稳定。如果你用的是特别老的版本比如v1.9、v1.10在20.04上编译时很可能会遇到旧代码与新编译器不兼容的问题比如boost库相关报错、Eigen版本不对等。我的建议很简单在做环境搭建之前先执行git checkout v1.13.3或者直接使用main分支避免用太老的发布版本来折磨自己。毕竟我们的目的是把仿真跑起来而不是在维护古董代码。另外一个常见误区是直接把PX4源码放在共享目录比如Windows和Linux双系统共用的NTFS分区或者虚拟机共享文件夹里编译。PX4编译过程会生成大量符号链接和构建缓存在非Linux原生文件系统上会出现各种诡异的Symlink错误或Permission denied这类问题非常折磨人。正确的做法是把源码放在Linux原生文件系统路径下比如~/PX4-Autopilot。2.2 依赖安装脚本的正确打开方式PX4官方提供了自动化依赖安装脚本路径是PX4-Autopilot/Tools/setup/ubuntu.sh。理论上执行以下命令就能装好大部分依赖cd PX4-Autopilot bash ./Tools/setup/ubuntu.sh但这个脚本在实际执行中有几个坑需要注意第一脚本会通过apt安装大量包如果网络不好很容易中断。中途断掉后不要直接重新跑一遍建议先检查一下是否有未配置完的包执行sudo dpkg --configure -a然后再跑脚本。第二脚本会安装特定版本的gcc、cmake、ninja-build等工具链。如果你系统里之前装过ROS或者其他开发环境可能会存在工具链版本冲突。比如ROS Noetic自带的是Python3和特定版本的catkin而PX4使用的是cmakeninja两者一般可以共存但偶尔会在PYTHON_INTERPRETER的查找上闹脾气。遇到这种情况可以在编译时显式指定Python版本或者把ROS的环境变量临时屏蔽掉再编译。第三也是最常被忽略的脚本安装完依赖之后需要重新登录终端或者执行source ~/.bashrc。原因很简单——它改写了你的PATH和LD_LIBRARY_PATH环境变量。不重新加载的话后续编译时找不到arm-none-eabi-gcc等工具链会抛出一堆command not found的错误。2.3 子模块是否完整第一个隐形杀手如果你是通过git clone https://github.com/PX4/PX4-Autopilot.git方式拉取源码的那大概率在编译时会遇到mavlink、mavlink/mavlink、src/lib/eigen等子模块缺失导致的问题。PX4项目使用了很多git子模块这些子模块负责维护一些基础库的特定版本。判断方法很简单看看PX4-Autopilot目录下有没有内容几乎为空的mavlink或者Tools/simulation相关文件夹。如果发现子模块没拉全执行git submodule update --init --recursive这一步会从GitHub拉取大量子模块内容对网络要求较高。如果在国内网络环境下执行中断可以多试几次或者设置代理后继续。这里给一个我实测有效的技巧把子模块拉取和后续编译分开做。先单独确认git submodule status输出全部正常每行开头不是-号再进行编译。绝大部分“编译时突然报mavlink/xxx.h: No such file or directory”的问题根源就是子模块没拉全。3. 编译阶段的高频报错原因、排查与解决3.1 CMake配置阶段的报错编译一开始CMake就要先跑配置流程。这个过程会检查编译器、库文件、Python环境等。几个最常见的报错如下报错一Could NOT find PackageName这类报错会明确告诉你缺少哪个依赖比如Could NOT find Eigen、Could NOT find MAVLink。解决思路很直接找到对应的依赖包并安装。比如Eigen可以通过如下方式安装sudo apt install libeigen3-dev但这里有个细节PX4官方脚本安装Eigen的方式是直接拉取源码到src/lib/eigen如果你系统里装了版本过新的Eigen反而可能编译报错。遇到这种情况建议优先使用PX4自带版本的Eigen不要为了“省事”而安装系统级Eigen。报错二CMake Error: The current CMake version is lower than the required versionUbuntu20.04默认源里的CMake版本是3.16.xPX4对CMake的最低要求通常是3.10以上按理说够用。但如果你的CMake版本太旧比如之前装过什么软件把CMake降级了就会出现这个报错。解决方式有两种# 方法一用pip安装新版cmake pip3 install --upgrade cmake # 方法二从官网下载安装包手动安装到 /usr/local我个人更推荐方法一因为pip安装的cmake通常会放到~/.local/bin下不会影响到系统其他软件对旧版CMake的依赖。3.2 编译过程中Killed或被系统杀掉的诡异问题这个报错很有迷惑性编译到一半终端突然输出一行Killed整个编译进程就没了。第一次遇到的人往往摸不着头脑还以为是代码写错了。实际上这是Linux系统在内存资源紧张时触发了OOM Killer机制把占用内存最多的进程干掉了。PX4编译px4_sitl时尤其是jmavsim部分需要JVM的参与JVM又是个内存大户。如果虚拟机分配的内存小于4GB很容易被系统杀掉。解决办法很明显物理机的话关掉几个浏览器Tab再编译虚拟机用户把内存上限调整到6GB以上降低并行编译任务数避免多线程同时编译导致内存峰值过高make px4_sitl jmavsim -j2这里多说一句-j参数是并行编译的线程数默认是CPU核心数的两倍。在虚拟机上盲目用-j8反而会因为内存不足而比-j2慢得多。这个经验也适用于后续Gazebo等重型仿真器的编译。3.3 编译报错c: internal compiler error: Killed (program cc1plus)这个和上面的问题本质一样是内存不足导致GCC编译器进程被系统杀掉。但有时候即使物理内存充足也可能是因为单进程内存上限设置过低。可以用ulimit -a查看virtual memory限制。如果是unlimited还没问题一旦有具体数值限制可以通过如下命令临时解除ulimit -s unlimited ulimit -v unlimited另外一个容易被忽略的因素是swap空间。如果你在安装Ubuntu时把swap分区设得太小比如只有1GB当内存不够时会频繁换页拖慢整个编译进程。建议给虚拟机设置至少4GB的swap或者在编译期间手动创建swap文件sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile3.4 Java版本不匹配引发的编译失败jmavsim是用Java编写的编译它需要Java开发环境。PX4官方推荐的是Java 8或者Java 11。Ubuntu20.04默认的OpenJDK很可能就是11一般没问题。但如果你之前装过其他版本的Java系统里有多个Java版本并存容易在编译时找到错误的Java版本。查看当前Java版本java -version javac -version如果版本不对可以用update-alternatives切换sudo update-alternatives --config java sudo update-alternatives --config javac有个容易忽略的细节是jmavsim运行期需要Java运行时环境JRE但编译期还需要Java开发包JDK。有些精简版Ubuntu只装了JRE没装JDK编译时就会出现找不到javac的报错。安装方式sudo apt install openjdk-11-jdk3.5 编译到100%却卡在链接阶段的“Waiting for unfinished jobs...”这种场景多半是链接器在等待某个动态库生成或者文件锁冲突。排查思路是先确认磁盘空间是否足够。PX4整个编译链路的中间产物非常大尤其是build/px4_sitl_default这个目录动辄好几个GB。df -h如果/目录已经满了清理一下旧的内核、apt缓存sudo apt clean sudo apt autoremove还可以干脆删掉整个build目录重新编译一次。很多人担心删了之后要全部重来但如果你已经装好了依赖和子模块第二次编译的速度会快很多因为ccache起到了缓存作用。3.6 缺少头文件或库的fatal error类报错这类报错一般都有明显的提示比如fatal error: rapidjson/document.h: No such file or directory或者fatal error: ncurses.h: No such file or directory。解决方式就是用apt装对应开发包。比较常见的几个开发包sudo apt install libncurses5-dev libncursesw5-dev sudo apt install librapidjson-dev sudo apt install libtinyxml2-dev sudo apt install libogre-1.9-dev需要说明的是有些包在装了ubuntu.sh脚本之后就已经有了但如果你跳过了脚本直接手动装依赖就会漏掉这些。我见过不少人喜欢“精简安装”结果后续每次编译都会冒出来一个新的fatal error其实最开始老老实实跑一次官方脚本就全解决了。4. 启动jmavsim阶段的经典报错与处理编译通过之后考验才刚刚开始。jmavsim启动阶段的问题更多、更隐蔽因为它牵扯到图形界面、网络端口、环境变量等多个层面。这一节我把启动阶段几类典型的错误按场景拆开细说。4.1 启动后黑屏或窗口一闪而过这是jmavsim最让人崩溃的问题之一。明明编译成功了make px4_sitl jmavsim执行后终端滚动了一堆日志但Java窗口要么黑屏要么闪一下就没了。这里有一个非常重要的排查顺序第一步看终端日志。如果日志里有java.lang.UnsatisfiedLinkError字样说明是JNI库加载失败。jmavsim依赖一些native库比如libjMAVSim.so这些库在编译时生成于build/px4_sitl_default/build_jmavsim目录下。如果这个目录不存在或者里面缺少.so文件手动执行一下make px4_sitl jmavsim强制重新生成Java native库。第二步检查显卡兼容性。jmavsim使用OpenGL渲染3D场景。在虚拟机里OpenGL渲染往往会出问题尤其当你没有安装虚拟机增强工具如VMware Tools或VirtualBox Guest Additions时。此时jmavsim虽然能启动但窗口是黑屏的。解决办法安装虚拟机增强工具或者在启动jmavsim之前设置软件渲染环境变量export LIBGL_ALWAYS_SOFTWARE1这个环境变量会强制OpenGL使用软件渲染性能会降低一些但至少画面能显示出来。第三步排查是否有多显示器/远程桌面干扰。如果你是通过VNC或X2Go远程连接UbuntuJava的图形窗口经常会因为GLX扩展问题启动失败。这时候除了设置LIBGL_ALWAYS_SOFTWARE1还可以尝试用Xvfb作为虚拟显示服务器来跑仿真不过一般不建议这么做因为看不到画面。4.2 QGroundControl连接不上端口冲突与IP绑定启动jmavsim后PX4固件里的SITL模块会在UDP端口14540QGC连接和14550数传上监听数据。如果QGroundControl连接不上第一步检查你启动QGC的时候地面站软件是否自动连接了其他端口。常见场景你电脑上开着一个旧的QGC实例它已经占用了14550端口。新启动的jmavsim里的PX4固件就无法绑定该端口日志里会出现Bind error或者Address already in use。排查方法ss -ulpn | grep 14550找到占用端口的进程杀掉它或者在QGC中手动设置通信端口为14550。还有一个容易被忽略的点虚拟机网络模式。如果你在虚拟机里跑PX4仿真宿主机上的QGC要连接虚拟机里的仿真器需要把虚拟机的网络模式设置为桥接模式Bridge否则从宿主机访问不到虚拟机的UDP端口。NAT模式下UDP广播和组播往往不通QGC会自动搜索飞行器但一直搜索不到。4.3 jmavsim界面出来了但无人机没有出现在场景里这种情况通常发生在启动顺序不对的时候。正常流程是make px4_sitl jmavsim会先启动PX4 SITL再自动拉起jmavsim窗口。但如果你手动分开启动比如想在jmavsim已经启动的情况下再重新运行某个固件脚本就需要确保PX4 SITL进程正确连接到了jmavsim的端口。jmavsim监听的是TCP端口4560PX4 SITL通过这个端口与jmavsim通信。检查端口是否被监听ss -tlnp | grep 4560如果没有输出说明jmavsim没有成功进入监听状态很可能是启动时被其他Java进程占用或崩溃。可以尝试关闭所有Java进程后重新启动pkill -f java make px4_sitl jmavsim4.4 出现Exception in thread main java.awt.AWTError: Cant connect to X11 window server这个问题一般只出现在没有图形界面的环境里或者你通过SSH远程执行了启动命令。jmavsim是一个图形程序必须在有X Server的环境中运行。物理机上直接跑到这一步一般不会出问题但WSL1/WSL2或者纯SSH终端里就会报这个错。如果你用的是WSL2可以通过安装WSLg来支持图形界面或者用export DISPLAY:0指定Windows侧的X Server。如果你只是想跑无头仿真不需要看画面可以改用make px4_sitl gazebo-classic或者用Headless模式——不过那是另一篇博文的范畴了。我个人的经验是PX4仿真调试之初GUI还是有用的尤其是你要验证起飞降落逻辑看桨叶转向和姿态变化。等到后面做自动化测试、跑回归用例了再换无头模式。4.5 启动很慢甚至卡在[init] creating helios界面很多朋友以为卡住了其实不是jmavsim首次启动时要加载大量纹理和模型资源加上Java JIT编译需要预热等个三四十秒很正常。如果你的目录里有旧版缓存反而会拖慢启动速度。另外注意看终端里的进度提示如果出现[ERR] Could not load texture: ...之类的纹理加载错误通常是因为资源路径不对。可以在启动前手动指定jmavsim的资源路径export PX4_HOME_LAT47.397742 export PX4_HOME_LON8.545594 export PX4_HOME_ALT488这组经纬度坐标是苏黎世联邦理工学院的默认起飞点也是PX4官方示例常用的。设置后仿真器会在指定位置生成无人机避免因为默认坐标缺失而加载异常。5. 一些更隐蔽的坑缓存、网络与权限问题5.1 编译缓存导致的“改了代码却不生效”PX4和cmake都使用缓存机制来加速增量编译。但如果你的源码或子模块更新了而缓存还残留着旧的文件路径就会出现改了代码却不生效、或者报奇怪的“No such file”错误。我常用的三连清make clean rm -rf build/px4_sitl_default rm -rf ~/.cache/ccache然后重新编译。这一步能解决大约三成“莫名其妙”的编译错误。代价是编译时间变长但胜在干净。5.2 网络代理对子模块和依赖下载的影响我知道不少朋友为了下载GitHub代码会配置各种代理工具。这本身没有问题但代理设置不当反而会让PX4的依赖下载失败。PX4编译时有一步会通过git拉取mavlink子模块的更新如果代理不稳定这步会一直卡着或者反复失败。建议在编译前先测试一下网络git ls-remote https://github.com/mavlink/mavlink.git HEAD如果这条命令能正常返回结果说明git访问正常。如果返回超时或连接失败先解决网络问题再继续编译。这里也提醒一下PX4的Tools/setup/ubuntu.sh脚本在执行时会调用apt-get update如果你的apt源配置的是国外源速度会非常慢。建议把apt源换成国内镜像这个操作在桌面上打开“软件和更新”即可配置命令行下也可以直接改/etc/apt/sources.list。注意修改后执行sudo apt update5.3 文件权限问题导致的无法写入如果你不是用当前用户克隆的PX4源码而是在/opt下或者其他需要root权限的目录里执行的git clone那么后续编译时大概率会遇到Permission denied的报错。PX4官方不建议用sudo make来编译因为这样生成的缓存文件全属于root用户之后切换回普通用户会有各种麻烦。如果你的源码已经在/opt下了最省事的办法是更改目录归属权sudo chown -R $USER:$USER /opt/PX4-Autopilot或者直接把项目克隆到家目录下重新编译。不要偷懒用sudo make后面你会十倍时间偿还。5.4px4命令找不到或版本不对如果你希望之后在终端里直接使用px4命令而不是每次都要进源码目录执行make需要把编译生成的工具目录加到PATH里。常见做法export PATH$PATH:$HOME/PX4-Autopilot/build/px4_sitl_default/rootfs但更常用的其实是直接使用源码目录下的Tools/setup/px4_setup_gui.sh或以下命令来初始化环境cd PX4-Autopilot source Tools/setup/ubuntu.sh需要注意的是每次新开终端都要重新执行source你也可以把这行加到~/.bashrc里省得每次手动敲。不过我不太建议这么做因为如果同时开发多个PX4版本环境变量会互相干扰。6. 从报错中建立自己的排查方法论写到这里我不太想再堆砌更多“报错-解法”的条目了因为实际遇到的报错千变万化总会有一个是你搜不到答案的。比起逐个记答案更重要的是掌握一套排查秩序。我个人的排查流程如下第一步看终端最后30行日志。不要从中间开始看也不要只看最上面。多数编译错误最终的失败原因在最后几行里都有明确提示比如error:之后的内容。有时候一个error:消除了后面的error:也会跟着消失。第二步判断报错属于哪个阶段。是CMake配置阶段、make编译阶段、链接阶段还是Java启动阶段阶段不同排查方向完全不同。CMake阶段多查依赖和路径编译阶段多查语法和头文件链接阶段多查符号和库路径Java启动阶段多查JVM参数和图形环境。第三步用“最小化复现”的方式验证。比如编译报错时试着只编译PX4固件部分不启动jmavsimmake px4_sitl如果固件部分编译通过说明问题出在jmavsim相关的Java工具链上如果固件部分也报错说明是基础的C工具链有问题。这种二分法能帮你快速缩小范围不用一股脑把所有报错都堆到网上求答案。第四步善用搜索引擎但别盲目复制。搜索时报错信息要抓关键行不要复制整段大日志。比如error: ‘mavlink_...’ was not declared in this scope这类C语法报错如果搜不到完全一致的结果试着把变量名去掉再搜通常能定位到是某个头文件没有#include导致。我见过太多人一遇到报错就慌了其实90%的编译问题本质就是“某个工具没装、某个依赖版本不对、某个路径没配对”这三种情况。把这三个方向检查一遍大多数问题都能迎刃而解。最后再说一个心态上的建议PX4环境搭建不是一次性的任务它会随着你更新代码、切换分支、重装系统而反复出现。与其每次踩坑都要重新搜寻解决方案不如自己建一个笔记文档把你遇到过的报错、报错的最后三行日志、当时的解决方案都记下来。后面你会发现很多东西都是换汤不换药——比如某个头文件缺失今天缺的是rapidjson明天缺的是yaml-cpp但解决思路完全一致。把这个方法论建立起来你就再也不怕环境问题了。
返回列表