ARTICLE DETAIL

资讯详情

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

Ubuntu下ArduPilot源码编译:从环境搭建到固件烧录全指南

Ubuntu下ArduPilot源码编译:从环境搭建到固件烧录全指南 简介面向在Ubuntu下开展ArduPilot飞控开发与固件编译的工程师这份于2024年7月5日更新的源码包省去了联网克隆仓库时的卡顿与失败风险解压后即可在Ubuntu系统中配置编译环境直接生成APM或PX4两类固件。包内目录完整保留原始仓库层级包含AP_AHRS、AP_InertialSensor、AC_AttitudeControl、AP_RangeFinder等核心飞行控制与传感器模块也提供AP_Common、AP_Math、AP_SerialManager等基础库支持Copter、Plane、Rover等多机型适配并兼容Pixhawk系列硬件及LTM遥测、KDECAN、SmartRTL、Soaring等外围设备适合二次开发、参数调试、传感器适配和ESC遥测集成。资源文件共3个以html、inscode、gitignore等类型为主其中html便于在线预览说明inscode可作为代码片段配置参考gitignore用于管理版本控制范围压缩包大小为3KB体量极小、便于快速下载核对版本。目前已有16人学习下载推荐给需要稳定获取最新源码、快速搭建Ubuntu编译环境并进行后续开发的飞控开发者从源码获取到固件编译全流程覆盖目录结构清晰方便按需提取对应模块。 拿到这份2024年7月5日快照的ArduPilot源码包时我的第一反应是松了口气。过去几年在Ubuntu下编译ArduPilot最让人上火的从来不是代码本身而是源码拉下来之后没完没了的子模块补齐、依赖冲突、工具链版本对不上。你照着ArduPilot官网的Building教程一步步来系统装的是Ubuntu 22.04git、python、gcc全都齐了结果./waf configure一跑就报错这种体验我太熟悉了。这篇文章不打算重复官方文档只围绕这份“可直接编译”的源码包从解压、环境准备、编译配置到固件产出和烧录验证讲清楚完整流程和那些真正值得注意的坑。适合手头有Ubuntu机器、想把ArduPilot源码跑起来做二次开发或者自己编译固件的朋友不管你是刚接触飞控源码的初学者还是被编译问题折磨过的老油条里面都有能直接抄作业的内容。1. 为什么需要“可直接编译”的ArduPilot源码包1.1 ArduPilot的版本机制与快照源码的价值ArduPilot的开发和绝大多数开源飞控项目一样采用Git分布式工作流。主分支master上的代码是社区实时提交的结果每天都有大量功能合并、重构和修复。这带来两个问题第一master分支的代码时刻在变今天能编译通过明天可能因为某人提交了一个未完成的接口重构就编不过第二官方文档推荐的依赖版本和编译流程会跟随master更新你看到的教程可能已经过时了。正式版本通常以四段式版本号发布比如Copter-4.5.7这些稳定版本在Release分支上维护比如release/4.5分支。稳定分支的特点是有明确的维护策略只接受bug修复和安全补丁不引入大规模功能变动因此编译环境相对稳定出问题的概率小得多。但即便是在稳定分支上直接clone的仓库仍然面临一个隐患ArduPilot的源码里有一个重量级目录modules里面存放MAVLink协议库、gtest测试框架等子模块这些子模块通过git submodule机制挂在主仓库下面。如果你只是git clone主仓库而没有同步子模块编译到一半必然报头文件找不到的错误。这份2024.07.05的源码包本质上就是基于当时的稳定维护分支打的一个快照并且已经完成了子模块的初始化和同步。它把“版本一致性”和“依赖完整性”两个最容易出问题的变量提前处理掉了所以标题才敢叫“可直接编译”。这一点对新手尤其重要因为子模块问题报错时往往让人一头雾水你根本不知道mavlink.h这种头文件为什么就是找不到。1.2 这份源码包解决了哪些“不能直接编译”的问题我把这类源码包的价值拆开看主要解决了三个层面的问题。第一子模块完整性。不带--recurse-submodules参数clone下来的ArduPilot仓库modules/MAVLink和modules/gtest都是空目录。编译时只要代码里引用了MAVLink协议相关的头文件编译就会立刻中断。这个源码包拿到手子模块已经就位省掉了最麻烦的一步。第二依赖版本锁定。ArduPilot的编译依赖一套Python工具链和ARM交叉编译器这些组件都有版本兼容性的讲究。比如Python接口模块empy某些较新版本会和ArduPilot的waf构建脚本不兼容导致编译时出现诡异的empy错误。直接编译的源码包通常对应一个已知可用的工具链组合你在使用说明里看到的推荐依赖版本就是这个快照实际测试过的版本组合。第三源码完整性与可追溯性。快照包不是一个随随便便压缩的文件夹它有明确的时间节点对应Git仓库里特定的commit。拿到后可以通过git log和git describe确认版本这给后续排查问题提供了重要锚点遇到问题时可以明确说“我编译的是2024年7月5日这个版本”而不是笼统地说“我编的是最新版”这对我排查问题的帮助非常大。1.3 直接clone master与使用快照包的差异实测我曾经试过直接clone master来编译那是一个让人印象深刻的经历。第一次编译时一切正常一周后重新拉取代码再编编译过程中突然冒出一堆variant相关的错误查了GitHub issues才发现是有人在重构参数定义框架中间状态没有保持可编译。这种“半成品代码”在master上非常常见。快照包就不一样它选的是稳定分支上经过验证的节点代码是自洽的不会出现“模块A已经切换到新接口模块B还在用旧接口”的错位。所以对于绝大多数场景——包括学习、教学、二次开发甚至小批量生产——快照包比跟踪master更为可靠。这也是我为什么拿到这份源码包后愿意花时间把完整流程整理出来的原因它值得推荐。2. Ubuntu编译环境的完整搭建与避坑2.1 系统版本选择与硬件底线编译ArduPilot对Ubuntu版本不算挑剔但我实测下来Ubuntu 22.04 LTS是最省心的选择。20.04也能用只是Python版本偏旧个别依赖需要手动处理24.04虽然新但官方工具链脚本对它的适配在2024年仍然不算完善可能会出现一些Python包名称或者依赖版本的小问题。如果你不是有特殊原因就用22.04这点我踩过坑不会骗你。硬件方面一个容易被人忽视的点是内存。编译ArduPilot的C代码使用GCC进行交叉编译虽然单个编译单元的复杂度不算夸张但并行编译时内存消耗会直线上升。我的经验是8GB内存是底线16GB是舒适区。如果你用的是虚拟机比如VMware里跑Ubuntu分配内存时千万不要只给4GB否则编译到一半会看到g: internal compiler error: Killed这种让人绝望的提示那是系统OOM把编译器进程杀掉的信号。磁盘空间至少预留20GB源码加编译产物加工具链空间消耗比想象中快得多。2.2 依赖安装的正确姿势别自己一个个装很多人习惯从网上找一堆apt install命令然后照着敲一遍。这个做法在ArduPilot上行不通或者说效率低下。因为ArduPilot的依赖不仅仅包括系统层面的编译工具还包括特定版本的Python包和ARM工具链这些需要精确定位。ArduPilot官方在源码的Tools/environment_install/目录下提供了环境安装脚本install-prereqs-ubuntu.sh这才是正确的打开方式。我拿到这份源码包后的第一步先给脚本加上执行权限再运行cd ardupilot Tools/environment_install/install-prereqs-ubuntu.sh -y这个脚本会做几件事安装build-essential、git、libtool、autoconf、automake、cmake等基础编译工具安装gcc-arm-none-eabi交叉编译器通过pip安装ArduPilot编译需要的Python模块包括future、lxml、pexpect、pyserial、empy等。脚本执行完成后还会把ArduPilot的工具目录写入~/.profile保证arm-none-eabi-g等命令可以在后续终端中直接使用。这里有一个非常常见的坑脚本执行完后当前终端环境变量不会自动更新。你需要执行source ~/.profile或者干脆关掉终端重新打开不然./waf configure还是会报找不到arm-none-eabi-g。这个问题让很多人在环境配置这一步卡了半天其实只是忘了刷新环境变量。2.3 ARM工具链版本一个隐形的地雷ArduPilot对ARM工具链的版本有明确要求。官方长期使用ARM官方发布的GCC工具链版本相对固定。Ubuntu 22.04的软件源里虽然也有gcc-arm-none-eabi包但版本可能和ArduPilot预期的不完全一致这会导致一个非常隐蔽的问题编译时不会直接失败但生成的固件在飞控板上运行时可能出现莫名其妙的行为异常。install-prereqs-ubuntu.sh脚本在安装ARM工具链时会从ARM官方获取指定版本并安装到/usr/bin或者ArduPilot工具目录。脚本设计上已经做了版本适配所以只要用官方脚本安装版本就不会出问题。我见过有人为了“更新”擅自升级了gcc-arm-none-eabi结果编译过程中出现unrecognized command-line option之类的报错最后不得不降级回来。这个环境的冗余度没有想象中那么大不要自作聪明去升级组件。另外提醒一句如果你在编译时遇到/usr/bin/arm-none-eabi-g: No such file or directory这类报错大概率是脚本没有安装成功或者安装路径不在PATH中。先用which arm-none-eabi-g确认工具链是否可用再检查~/.profile里的路径配置这是最快定位问题的方式。3. 源码包解压、目录结构与版本校验3.1 解压后先看这几个关键目录拿到源码包后我习惯先看一眼目录结构再动手而不是急着编译。ArduPilot的源码目录乍一看有点乱但核心区域其实很清晰ArduCopter/多旋翼飞控的主程序目录进入ArduCopter后直接./waf build编译产物就是arducopter固件。ArduPlane/固定翼飞控主程序编译产物是arduplane。Rover/地面车辆载具的实现对应ardurover。Sub/水下机器人的飞控实现。libraries/所有公共代码库包括传感器驱动、姿态解算、导航算法、控制律等这里是二次开发的主要阵地。Tools/各种辅助工具和脚本包括环境安装、日志解析、参数转换等。modules/子模块目录MAVLink子模块在这下面编译时不可缺少。build/编译输出的根目录第一次跑完./waf build后各个板卡的固件会按build/board/bin/的路径生成。如果是初次接触ArduPilot源码我建议花点时间在libraries/AP_Math和libraries/AP_AHRS目录下翻一翻这两个是理解飞控姿态解算核心逻辑的入口。源码包的解压路径尽量不要包含中文或空格因为waf对路径处理时可能会因为特殊字符出问题这是一个被很多人忽略的小细节。3.2 确认版本与子模块状态的正确方法源码包标题写的是2024.07.05但源码里面到底是什么版本需要用Git自己确认。在源码根目录执行git log -1 --format%H %ci git describe --tags git submodule status第一条命令输出当前HEAD对应的完整commit哈希和提交日期第二条输出距离最近的标签名称第三条列出所有子模块的当前commit状态。正常情况下三个输出应该都是正常的不会出现-dirty标记。如果git submodule status中某一项以-开头说明这个子模块没有被正确初始化如果以开头说明子模块的commit和主仓库记录的版本不一致。对于“可直接编译”的源码包来说正常情况下所有子模块的状态都是开头不带符号的这种情况下编译环境才算真正就绪。我建议编译前花30秒做一下这个检查能省掉后面排查问题的大量时间。3.3 编译前的Python环境自检ArduPilot的waf构建系统是Python写的因此Python环境必须正常。系统层面Ubuntu 22.04自带Python 3.10满足要求。需要注意的是一些Python包的兼容性。可以先在源码根目录执行一下python3 -c import empy, future, lxml, pexpect, pyserial如果某个模块报错就用pip install补装。关键点是empy的版本ArduPilot对empy的版本要求比较特殊某些新版本在生成编译配置时会有兼容性问题。官方脚本安装的是经过测试的版本如果你之前手动装过别的版本出现Error: empy is not the correct version之类的提示不要犹豫直接用pip uninstall empy卸掉再重新安装脚本指定的版本即可。这段自检流程虽然看起来多花几分钟但能避免后面编译跑到一半才被Python环境问题打断。编译失败不可怕可怕的是编译到80%才失败前面的时间全浪费了。4. 编译全流程从configure到固件产出4.1 为什么ArduPilot用waf而不是CMake第一次接触ArduPilot的人都会问为什么这个项目不用CMake这是一个合理的问题。CMake是当前C项目的主流构建工具生态成熟资料也多。但ArduPilot选择waf有它的历史原因和技术考量waf是一个基于Python的构建工具构建脚本可以充分利用Python的灵活性而ArduPilot的编译系统里有大量复杂的参数配置、板卡适配和代码生成逻辑用Python写这套流程比CMake的DSL更顺手。另一个现实原因是ArduPilot的构建系统高度定制化从硬件抽象层的选择到自动代码生成再到固件打包脚本形成了一个完整的工具链。迁移到CMake意味着重写整个构建系统成本极高风险极大。所以在可预见的未来ArduPilot仍然会使用waf。理解了这一点你就知道为什么编译ArduPilot不能直接用cmake make而是必须用./waf命令。4.2 选择board并执行configurewaf构建流程的第一步是配置编译目标。ArduPilot把不同飞控硬件板称为board每个板卡对应一个配置文件。执行配置的命令格式是./waf configure --board board名常见的board名包括板卡硬件board参数适用场景Pixhawk 1Pixhawk1经典飞控板资料最多Pixhawk 4Pixhawk4新一代Pixhawk系列性能更强Cube BlackCubeBlack工业级飞控可靠性高Cube OrangeCubeOrange高端飞控多冗余设计SITLsitl纯软件仿真不涉及硬件如果你是第一次编译又没有特定硬件在手我强烈建议先编译SITL目标。SITL是全软件仿真环境不需要任何飞控硬件编译成本低而且能跑通完整的飞控逻辑适合理解整个编译和运行流程。命令是./waf configure --board sitl ./waf build如果目标是真实飞控硬件比如Pixhawk 1就是./waf configure --board Pixhawk1 ./waf buildconfigure阶段waf会检查工具链、Python依赖、编译器版本并生成一套以板卡名命名的构建配置。看到Configuration is complete之类的输出说明配置成功如果中途报错大多和工具链缺失或者Python依赖有关先回到第2、3章检查环境。4.3 编译输出与二进制文件的正确理解执行./waf build后waf会根据configure阶段选择的板卡将源码编译为对应架构的二进制文件。如果configure时选了Pixhawk1编译产物会出现在build/Pixhawk1/bin/目录下。第一次编译需要的时间取决于机器性能我实测在8核16线程的机器上Copter固件大概需要10到15分钟如果机器比较老或者内存不足时间可能翻倍。编译过程中屏幕上会滚动大量编译信息这是正常的。真正需要关注的是最后是否出现build complete类似的提示以及bin目录下是否生成了固件文件。关于固件文件ArduPilot会生成多种格式.apj带bootloader的固件包地面站直接加载这个文件烧录即可。.px4Pixhawk系列原生固件格式用于地面站烧录。.bin纯二进制格式通常用于bootloader配合烧录。不带扩展名的文件例如arducopter是ELF格式的原始可执行文件主要用于调试。如果编译SITL目标build/sitl/bin/下生成的arducopter是一个Linux下的可执行文件直接运行就能启动一个软件在环仿真飞控。5. 编译高频报错的完整排查链路5.1 找不到ARM交叉编译器报错特征./waf configure时提示找不到arm-none-eabi-g或者编译过程中提示/bin/sh: 1: arm-none-eabi-g: not found。排查链路先在终端执行which arm-none-eabi-g如果没有任何输出说明工具链没有安装或安装路径不在PATH中。确认是否执行过Tools/environment_install/install-prereqs-ubuntu.sh如果执行过但没有生效检查一下~/.profile里是否添加了ArduPilot工具目录。加入后执行source ~/.profile再重试。如果which命令能找到工具链但还是报编译错误可能是工具链权限问题执行ls -l /usr/bin/arm-none-eabi-g看是否有可执行权限。这三个步骤能覆盖大多数工具链缺失的情况。5.2 Python模块empy版本冲突报错特征configure过程中提示Python module empy is not installed或者empy version is not supported。排查链路ArduPilot对empy的版本有严格要求在2024年的环境中官方脚本安装的是empy3.3.4。如果你之前手动装过其他版本比如empy4.x就会触发这个报错。解决办法是先卸载pip uninstall empy再重新安装指定版本pip install empy3.3.4。这里有一个细节如果你使用了虚拟环境一定要激活虚拟环境后操作否则卸载的是系统Python的包而waf用的是虚拟环境的包问题不会解决。5.3 编译中段进程被杀死报错特征编译跑到一半屏幕突然出现g: internal compiler error: Killed然后编译中断。排查链路这个报错几乎可以确定是内存不足导致的操作系统OOM Kill。用free -h查看内存使用情况如果剩余内存很少说明并行编译的进程数超出内存承载能力。解决办法有两个方向一是增加物理内存或虚拟机分配的内存二是降低并行编译的进程数waf通过-j参数控制./waf build -j2在内存有限的机器上-j2比默认并行度慢不了多少但编译稳定得多。这是我在8GB内存笔记本上实测出来的经验与其反复被Killed不如一开始就限制并行度。5.4 子模块缺失导致头文件找不到报错特征编译时提示fatal error: modules/MAVLink/mavlink.h: No such file or directory。排查链路这个报错在直接clone官方仓库时很常见但在“可直接编译”的源码包里出现频率较低如果出现了说明子模块状态异常。执行git submodule status检查看到任何子模块状态前有-前缀说明该子模块没有初始化。运行git submodule update --init --recursive同步完成后重新编译。这个错误本身很好解决但定位时需要一点耐心因为头文件路径在报错信息中可能只显示一部分如果没头绪的人可能会错怪代码本身实际上完全是构建环境的问题。6. 固件验证、烧录与后续玩法6.1 编译产物的校验与确认编译完成后不要急着烧录先做几步验证。用ls -lh build/Pixhawk1/bin/查看固件文件大小正常Copter固件应该在1MB到2MB之间如果只有几十KB说明编译过程可能出了问题。再用sha256sum计算固件的哈希值记录这个值烧录后可以通过比对校验固件是否完整上传。如果你有飞控板在手建议先连上地面站读取一下当前板上固件的版本和参数做好备份再烧录新固件。这样如果新固件有问题可以随时刷回旧版本。6.2 USB烧录实操与常用工具烧录ArduPilot固件最常用的地面站是Mission Planner和QGroundControl。Mission Planner在Windows下支持最好功能和固件烧录流程最完善QGroundControl则跨平台做得更好在Linux下运行稳定。在Ubuntu下用QGroundControl烧录时一个容易踩的坑是USB权限问题。飞控板通过USB连接到电脑如果系统没有给当前用户分配对应串口设备的权限QGroundControl会显示设备连接失败。解决办法是把用户加入dialout组sudo usermod -a -G dialout $USER执行后注销并重新登录再插上飞控板这时ls /dev/ttyACM0或者/dev/ttyUSB0能看到设备节点QGroundControl也能正常识别飞控。如果不喜欢图形界面ArduPilot还提供了命令行烧录脚本Tools/scripts/upgrade_firmware.py在编译出.apj固件之后可以执行python3 Tools/scripts/upgrade_firmware.py --port /dev/ttyACM0 --baudrate 115200 build/Pixhawk1/bin/arducopter.apj这种方式在自动化测试和生产场景下更实用。6.3 后续扩展SITL仿真与二次开发方向编译成功只是起点真正的玩法在后面。如果你编译的是SITL目标可以直接在命令行运行./build/sitl/bin/arducopter -I 0启动一个软件在环仿真飞控然后用MAVProxy连接mavproxy.py --master tcp:127.0.0.1:5760 --out 127.0.0.1:14550或者用QGroundControl直接连接UDP端口。SITL环境下飞控完全模拟真实硬件的行为你可以在完全不碰实体飞机的情况下测试自驾逻辑、调参策略、航线规划等这是学习飞控原理最高效的方式。再往后ArduPilot和ROS2生态的融合是当前社区的一个热点方向通过SITL加Gazebo等仿真环境可以在虚拟世界里完成无人机全流程的仿真测试代码验证成熟后再迁移到真实硬件这能大幅降低试错成本。如果你有心继续深入这个方向值得好好研究。从我个人的经验来看ArduPilot的编译体系虽然初看起来有些另类但它一旦跑通整个流程异常稳定和规整。你只要记住几个关键点环境脚本优先、板卡选择明确、并行度量力而行、子模块常检查后面就很少会再被编译问题卡住。我还喜欢把常用的编译命令写成一个shell别名比如alias copter-build./waf configure --board CubeBlack ./waf build -j4一条命令搞定配置和编译省心很多。希望你也能顺利编出属于自己的固件跑通这条完整的工具链。本文还有配套的精品资源点击获取
返回列表