多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

PX4 SITL仿真环境配置与jMAVSim排错指南(Ubuntu 20.04)

PX4 SITL仿真环境配置与jMAVSim排错指南(Ubuntu 20.04) 我是在一个周六下午跟这台Ubuntu 20.04死磕的。屏幕上的编译输出刷了十几分钟make px4_sitl jmavsim的最后一行不是顺利提示而是一段红色Java异常。第一次配PX4仿真环境最容易获得的就是这种“从入门到放弃”的体验Ubuntu20.04、PX4固件、jMAVSim模拟器三个组件单独看都有文档串在一起就是无穷无尽的编译错误和运行时报错。这篇不是去翻译官方文档也不是那种“照着敲一定能成”的运气教程。我把自己在Ubuntu 20.04上配置PX4环境、启动和编译jMAVSim时碰到的问题按类型整理出来哪些是环境依赖没满足哪些是子模块和网络问题哪些是Java版本不对哪些是内存不够把编译器杀了。每个问题我都会给出定位思路和解决命令并且尽量解释背后的原因让你下次换个报错也不至于抓瞎。如果你正准备搭第一套PX4 SITL仿真或者已经被jMAVSim的报错卡了几个小时这篇文章应该能帮你省下不少时间。1. 为什么折腾半天还是要用jMAVSim轻量仿真器的定位与高频翻车点1.1 它是干什么的适合什么场景jMAVSim是PX4自带的轻量级仿真器用Java写的和PX4 SITLSoftware In The Loop配套。所谓SITL就是把飞控固件当成一个普通程序跑在你电脑上由仿真器提供虚拟的传感器数据和3D画面。你不用买任何硬件就能练起飞、降落、姿态控制和简单航线。它最大的优势是轻。和Gazebo那套相比jMAVSim启动更快、依赖更少一个窗口就是一架四旋翼在空地上。我做姿态控制验证、PID调参、跑航线逻辑的时候一般先开jMAVSim看基本行为发现问题的迭代周期短很多。缺点也很明显它没有真实的室内场景、激光雷达/深度相机这些传感器模型所以你要做视觉SLAM或者室内避障直接上Gazebo或者别的仿真器更合适。1.2 最容易出问题的三个环节总结下来我遇到的所有jMAVSim问题都可以归到三类第一类是环境依赖问题包括Java版本、GCC工具链、protobuf等系统库。jMAVSim是Java应用但PX4编译过程中会调用大量C/C工具链所以这里混合了Java和C两套生态的坑。第二类是代码仓库版本和子模块问题。PX4仓库通过submodule管理大量依赖比如mavlink、pyulog这些。如果克隆时不带--recursive参数后面编译到某个中间步骤就会突然报错而且报错内容往往让你完全联想不到是子模块没拉下来。第三类是运行时资源问题。图形环境连不上、端口被占用、内存不够导致编译器被系统杀掉这些在启动和编译阶段非常常见。理解了这三个维度后面排错就有方向了。我从动手前的准备开始说。2. 动手之前先排雷Java版本、交换分区与递归克隆2.1 Java版本是第一个坑jMAVSim跑在JVM上Java版本不对是最容易翻车的点。我在Ubuntu 20.04上第一次装的是系统自带OpenJDK 8启动jMAVSim时一上来就报UnsupportedClassVersionError意思是class文件编译版本比你当前JVM能解析的版本新。我的建议是直接用OpenJDK 11。不是11有多好而是PX4官方的持续集成环境和你当前时期绝大多数教程使用的Java环境都以11为基准踩坑少很多。装法很简单sudo apt update sudo apt install openjdk-11-jdk java -version确认java -version里显示的确实是11.x。注意如果系统里还装了其他版本的Java可以用sudo update-alternatives --config java手动切换默认版本。为什么不建议无脑上Java 17或者更新的版本因为某些新版本Java对模块系统管得更严jMAVSim某些反射调用或者老依赖会触发NoClassDefFoundError这一类问题。不是说一定跑不起来而是你刚接触这套环境的时候没必要给自己加这种不确定性。等仿真环境熟了再去折腾新版本也不迟。2.2 内存不够编译到一半被“Killed”这条是编译期最大的隐性杀手。PX4编译是一个非常吃编译并行的任务如果你机器内存只有8GB甚至更少还没有swap分区cc1plus这种C编译器进程可能直接被OOM Killer杀掉。判断方法其实很简单编译终端如果出现类似cc1plus: fatal error: Killed signal terminated program cc1plus基本就是内存不够了。先看内存状态free -h如果available很小建议先加一个swap文件。别小看它在编译这种突发内存消耗场景里非常管用sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile echo /swapfile none swap sw 0 0 | sudo tee -a /etc/fstab如果fallocate不支持比如文件系统限制用sudo dd if/dev/zero of/swapfile bs1M count4096生成一个4G文件效果一样。另外也可以主动降低编译并发。make px4_sitl jmavsim -j2把并发数控制在2虽然编译慢一点但不容易把内存打爆。我现在在资源紧张的机器上都习惯先free -h看一眼再决定用几路并发。2.3 克隆PX4仓库别忘了递归子模块我看过太多人在这一步省略了--recursive。PX4官方仓库的嵌套依赖很多最典型的就是mavlink和mavlink相关生成代码它们不在主仓库里而是以submodule形式挂载。克隆时不带--recursive看起来仓库也有了但子模块目录是空的。克隆命令建议这样写git clone --recursive https://github.com/PX4/PX4-Autopilot.git如果已经克隆完了才发现子模块没拉全不用重新克隆cd PX4-Autopilot git submodule update --init --recursive后面编译如果报类似No rule to make target ...mavlink/...这种错误99%是子模块问题。先把补拉子模块的命令跑一遍也许问题就解决了比读半天CMake日志高效得多。2.4 官方环境脚本该不该跑PX4仓库里提供了Tools/setup/ubuntu.sh脚本会自动安装一堆构建依赖。我第一次跑的时候没耐心等它跑完就继续编译结果还是缺了包回头查才发现脚本中途有个包的下载超时。所以我的习惯是cd PX4-Autopilot bash Tools/setup/ubuntu.sh --no-nuttx--no-nuttx的意思是跳过NuttX板端交叉编译工具链因为我们只做SITL仿真不涉及把固件烧写到真实飞控硬件。这个参数能省很多下载时间。脚本跑完会提示退出重登或者重新source环境变量照做就行。如果你之后要编译真实固件再单独安装NuttX工具链。3. 启动jMAVSim从X11连不上到端口被占用的完整排查3.1 没有图形环境jMAVSim窗口是起不来的这里先说一个最常见的“启动即死”问题。你在一台Ubuntu服务器上或者通过SSH远程连开发机执行make px4_sitl jmavsim终端抛出来java.awt.AWTError: Cant connect to X11 window server这个报错的含义很直白jMAVSim需要打开一个3D窗口但当前会话没有任何图形显示服务。SSH纯命令行、没有图形桌面的服务器版都可能遇到。解决办法不是去网上找什么“跳过窗口”的黑科技而是确认你确实在图形会话里执行。先看echo $DISPLAY正常情况下桌面环境会输出:0之类如果是空白的说明当前不是图形会话。如果你人在本机直接在完全图形界面下打开终端再跑一次就行。如果你在远程需要用支持X转发的SSH连接方式或者远程桌面方式让仿真器的窗口能显示到你本地。3.2 端口被占用一个完整的排查过程第二种高频启动错误是端口占用。症状有两种一种是第二次启动时jMAVSim直接报java.net.BindException: Address already in use另一种是窗口正常起来了但QGroundControl怎么都连不上。这里的底层逻辑是PX4 SITL默认通过UDP 14550端口对外广播MAVLink消息QGroundControl也通过这个端口接收。如果有一个没退干净的仿真进程占着端口新起的进程自然绑不上就算绑上了QGC也可能收到的是旧进程的数据。我之前遇到过一次排查过程记录下来供参考第一步看看现在到底是谁占着端口ss -tulpn | grep 14550输出里能看到PID和进程名。第二步再配合看进程列表确认是哪个Java程序ps -ef | grep -E java|px4 | grep -v grep第三步确定是自己的旧仿真进程后把它清掉pkill -f jmavsim pkill -f px4注意pkill -f px4会把所有命令行里带px4的进程都杀掉执行前先确认机器上没有别的正在跑的重要进程。清完之后重新执行启动命令端口恢复可用QGC也能正常连接了。3.3 窗口起来但黑屏或者闪退优先怀疑图形加速如果你启动时没报X11错误窗口也弹出来了但画面黑屏、卡死或者几秒后直接闪退这类问题在虚拟机和远程桌面环境下尤其多。jMAVSim的3D渲染依赖本机的图形加速能力虚拟机里如果没开3D加速或者远程桌面环境OpenGL兼容性不好画面就会异常。我推荐按这个顺序排查先确认本机图形加速是否正常比如在Ubuntu桌面环境的终端里跑glxinfo | grep OpenGL renderer如果渲染器显示的是软件渲染Software Rasterizer基本就可以定位是图形加速的问题了。虚拟机场景下尝试在虚拟机的显示设置里开启3D加速物理机场景下检查显卡驱动安装情况。如果驱动实在搞不定jMAVSim还有一些底层渲染参数可调但那不是一般教程会主动提的真到了这一步再考虑。3.4 Java版本导致的UnsupportedClassVersionError回到Java本身。如果你检查完发现是Java版本报错java.lang.UnsupportedClassVersionError: ... has been compiled by a more recent version of the Java Runtime按前面第2章的方法切到OpenJDK 11再试。这个错误本身不难解决难的是你一开始根本想不到往Java版本上想因为报错往往藏在启动脚本的一长串日志中间。我的经验是看到一个长报错先找第一行具体是Exception还是Error再看有没有ClassVersion、BindException、AWTError这种关键词。关键词出来方向就出来了。4. 编译期报错比启动错误更折磨人子模块缺失、编译器被杀与protobuf互搏4.1 No rule to make target先从子模块查起编译期间的第一个高频错误长这样make: *** No rule to make target /home/user/PX4-Autopilot/src/modules/mavlink/mavlink/v2.0/...很多人看到No rule to make target会往Makefile上想但你要知道PX4的构建系统会自动生成很多中间文件而生成这些文件的前提是子模块代码在本地存在。mavlink子模块没拉全构建系统找不到mavlink头文件和生成器就会报这种“没有规则能生成这个目标”的错。解决办法很明确cd ~/PX4-Autopilot git submodule update --init --recursive如果之前克隆用的是浅克隆--depth 1建议老老实实完整克隆一次因为浅克隆加递归子模块在PX4这种大仓库上容易出问题。补完子模块编译再往前推进一大截通常就到了依赖库阶段。我把这个作为完整排查链路来说明现象反馈到“可能是子模块”这个推断只花一分钟但是直接把问题解决掉比在Makefile和CMake日志里翻半天效率高太多。4.2 cc1plus被“Killed”内存与swap的事编译进行到一半屏幕上出现cc1plus: fatal error: Killed signal terminated program cc1plus注意这不是代码写错了是系统在内存不足时把编译器进程杀掉了。C模板展开和STL头文件解析非常吃内存PX4的C代码量又不小多路并发编译时内存会瞬间吃满。解决方法上面已经提过加swap、降低-j并发数。这里再补充一个调参判断如果你的内存是16G-j4一般没问题8G甚至4G就老实-j2。不要盲目追求编译速度我见过有人为了贪快用-j$(nproc)结果笔记本直接卡死最后还得强制重启反而更耽误时间。再强调一次遇到编译崩溃先确认是不是机器资源问题不要一上来就怀疑代码。这个习惯可以帮你省很多时间。4.3 protobuf版本打架Anaconda和ROS的隐藏陷阱第三个编译期顽固问题是protobuf冲突。PX4的mavlink模块在编译过程中会调用protobuf生成C代码如果你的系统里同时存在多个protobuf版本链接阶段就会出现各种undefined reference to google::protobuf::...。Ubuntu 20.04系统仓库默认的protobuf版本是3.6.1和PX4这套链路是匹配的。但很多人为了开发Python环境装了Anaconda为了让命令行能用conda把Anaconda的环境变量加到了.bashrc里其中很可能包含一个LD_LIBRARY_PATH/home/xxx/anaconda3/lib:...。问题来了当你在同一个终端里编译PX4时动态链接器会优先找到Anaconda里的新版libprotobuf而不是系统版本于是C编译器生成的代码和你链接的库版本对不上报出一堆奇怪的重定位错误。我的建议是不要在.bashrc里全局硬写LD_LIBRARY_PATH尤其是Anaconda的路径。要用conda的时候在需要的终端里临时source activate用完退出别污染全局环境。同理装过ROS的机器也要小心ROS自带Python和一堆库经常会和PX4的构建环境互相干扰。装PX4环境之前可以先看一眼echo $LD_LIBRARY_PATH如果里面有Anaconda、ROS之类的路径编译PX4的终端里先unset LD_LIBRARY_PATH或者换个干净终端再跑很多时候问题就消失了。还有一种场景是自己源码编译安装过新版protobuf到/usr/local/lib也会出现类似问题排查思路一样用ldd看看中间文件链接的是哪个so顺藤摸瓜。5. 跑通以后怎样确认仿真真的在工作5.1 看SITL终端的标志性输出编译启动顺利的话终端最后会出现类似下面的日志INFO [commander] Ready for takeoff! INFO [mavlink] mode: Normal, data rate: 4000000 B/s on udp port 14550 remote port 14550 INFO [px4] Startup script: /bin/sh etc/init.d/rcSReady for takeoff!是最关键的标志说明飞控逻辑已经正常初始化等待你解锁和起飞。到这一步jMAVSim窗口里通常能看到一架四旋翼停在跑道上。我见过不少初学者把窗口打开就以为成功了其实真正成功的是SITL终端出现这行日志。窗口只是视觉辅助我们所有判断都应该以终端日志为准。后续切换模式、解锁、起飞终端都会打印对应的状态变化这些日志比窗口画面可靠得多。5.2 用QGroundControl确认数据链路仿真的意义不只是看动画还要和地面站配合。同一台机器上打开QGroundControl正常情况下它会自动发现jMAVSim并弹出连接提示因为PX4 SITL默认向本机的14550 UDP端口发送MAVLink。如果QGC没反应也不要慌。先确认仿真进程里有没有14550端口在监听ss -tulpn | grep 14550没有的话看看是不是初始化时没完全成功有的话大概率是防火墙拦截了UDP。Ubuntu如果自己开了ufw放行即可sudo ufw allow 14550/udp还有一种情况机器上同时跑过多个仿真QGC连到了旧实例。这时候按第3.2节的流程清理进程重新启动一次QGC一般就能连上了。另外如果你是在虚拟机的Ubuntu里跑仿真、QGC装在物理机Windows上记得把虚拟机的网络模式设为桥接或者给虚拟机的UDP 14550做端口转发否则物理机上的QGC根本收不到仿真数据这是很多人容易忽略的跨系统组合场景。5.3 机型选择和参数别照抄错了最后提醒一个容易忽略的坑make px4_sitl jmavsim其实默认编译的是特定机型通常是四旋翼iris。但如果你看了别的教程学着加了PX4_SIM_MODEL之类的环境变量或者改了启动目标名称就必须确保你的PX4固件版本支持这个机型。机型不对的表现往往是编译过了、窗口也出来了但机架在画面里没有出现或者日志里一直报传感器数据无效。我个人的习惯是第一次搭环境时不要加任何花哨参数直接用最原始的命令把全链路跑通然后再去尝试不同机型。先确认基础链路没问题再往上加复杂度这个顺序永远不会错。6. 这套环境我现在的标准操作从零到起飞的最短清单6.1 直接照抄的清单为了避免你看完全文还得回头翻命令我把一套从零开始跑通jMAVSim的操作整理成清单。环境是干净的Ubuntu 20.04桌面版。步骤操作验证方法1sudo apt update sudo apt install -y openjdk-11-jdk git build-essentialjava -version显示112git clone --recursive https://github.com/PX4/PX4-Autopilot.git看到子模块克隆过程3cd PX4-Autopilot bash Tools/setup/ubuntu.sh --no-nuttx脚本正常结束4内存低于8G时加swapfree -h查看5make px4_sitl jmavsim前几次可加-j2出现Ready for takeoff!6打开QGroundControl自动连接看到姿态数据这套流程我在至少三台不同配置的Ubuntu 20.04机器上验证过不能说100%保证一次过因为每个人的网络环境和硬件差异确实很大但按这个顺序排查遇到问题也能快速定位到具体环节。6.2 我的几个操作习惯最后分享几个这些年积累下来的习惯。第一所有编译日志都要留档。我习惯把每次make的输出用tee存到文件里make px4_sitl jmavsim 21 | tee build.log报错时直接在文件里搜索error、fatal、exception比在终端滚动历史里翻效率高多了。第二遇到错误先降低复杂度。默认命令不行就换官方最基础命令加了一堆环境变量和参数的先全部去掉让问题回归最原始状态。第三不要在一个旧版本分支上死磕。如果你用的是好多年前的PX4 release分支在Ubuntu 20.04上遇到Waf和Python版本冲突这类问题与其花几天打补丁不如切到和当前Ubuntu版本匹配的较新稳定tag重新编一次。技术在往前跑环境也在往前跑非要在旧版本上钻牛角尖收益真的很低。
返回列表