1. 从零认识 FMT 与它的“左膀右臂”
如果你刚接触无人机飞控开发,面对 PX4、ArduPilot 这些庞然大物,可能会觉得门槛有点高,代码结构复杂,想动点东西都无从下手。我第一次接触 FMT(Firmament)开源飞控时,感觉像是发现了一个新大陆。它给我的第一印象是“清爽”——代码结构清晰,文档(虽然当时还不算特别完善)努力在讲人话,最关键的是,它选择的技术栈非常有意思:RT-Thread 操作系统和 SCons 构建系统。
简单来说,FMT 是一个基于**模型设计(MBD)**理念打造的开源自驾仪平台。你可以把它想象成一个乐高积木套装。它的核心框架(FMT-Firmware)提供了标准的接口和模块化的结构,而具体的算法,比如怎么让飞机保持平衡(控制算法)、怎么知道飞机现在的位置和姿态(导航算法),都可以用 Simulink 像搭积木一样画出来,然后一键生成 C 代码,“咔哒”一声嵌入到框架里。这种方式特别适合算法工程师和需要快速迭代验证的团队,能把更多精力放在算法本身,而不是纠结于底层驱动和系统调度。
那 RT-Thread 和 SCons 在这其中扮演什么角色呢?你可以把 RT-Thread 看作是飞控这个“机器”的“神经系统”和“调度中心”。它是一个国产的、开源实时的操作系统,负责管理飞控软件里所有的任务(比如读取传感器、计算控制指令、记录日志、通信等),确保它们能在正确的时间、以确定的优先级被执行,这对于飞行安全至关重要。我之前用过一些裸机或者简单调度器的飞控,当任务多起来的时候,管理和调试简直就是噩梦,而 RT-Thread 提供了线程、信号量、消息队列这些标准组件,让多任务开发变得规范很多。
SCons 呢,则是这个项目的“高级建筑工程师”兼“自动化流水线”。我们平常写 C 项目,可能用一个简单的 Makefile,但当项目像 FMT 这样庞大,有几十上百个源文件,依赖关系复杂,还要为不同硬件(比如 ICF5、Pixhawk)生成不同配置的固件时,手写和维护 Makefile 就非常痛苦了。SCons 基于 Python,你用 Python 脚本描述构建规则,它就能智能地分析文件依赖,只编译改动过的文件,极大提升编译效率。在 FMT 项目里,SCons 不仅仅是调用编译器,它还承担了系统配置解析、组件裁剪、链接脚本生成等一系列繁重工作。可以说,理解了 SCons 在 FMT 中的运作,你就掌握了定制和移植 FMT 飞控的钥匙。
2. 揭秘 SCons:不止于“替代 Makefile”
很多人刚看到 SCons,觉得它就是另一个构建工具,和 CMake、Make 差不多。我在最初移植 FMT 到新硬件平台时,也是这么想的,结果踩了不少坑。后来才发现,SCons 在 FMT 项目里被用到了极致,它深度参与了构建、配置、裁剪的整个生命周期。
2.1 SCons 构建的核心逻辑
FMT 的代码根目录下,你会找到一个 SConstruct 文件,这是 SCons 的“总入口”。它不像 Makefile 那样写一堆晦涩的规则,而是像一段 Python 程序。我们来看一段简化后的逻辑:
# 导入必要的模块和工具
import os
from building import *
# 1. 加载构建选项和配置
env = DefaultEnvironment()
opts = Variables('config/defconfig.py')
env.Append(ENV = os.environ)
# 2. 处理命令行参数,比如指定目标硬件
AddOptions(opts)
target = ARGUMENTS.get('target', 'icf5')
print('Building for target: %s' % target)
# 3. 根据目标加载对应的硬件描述(BSP)目录
bsp_path = os.path.join('target', target)
SConscript(os.path.join(bsp_path, 'SConscript'), exports='env', duplicate=0)
# 4. 加载飞控核心框架的构建脚本
SConscript('src/SConscript', exports='env', duplicate=0)
这个过程很有意思。当你执行 scons target=icf5 时,SCons 会先解析总控脚本,然后通过 SConscript 函数“递归”地进入各个子目录(比如 target/icf5/ 和 src/)。每个子目录里也有自己的 SConscript 文件,负责收集本目录下的源文件、设置特有的编译选项。最后,所有信息汇总回顶层,生成最终的编译命令。
这种“递归式”的构建描述,非常契合飞控的模块化设计。传感器驱动、通信模块、算法模型,每个都是独立的目录,有自己的构建脚本,互不干扰。你想添加一个新模块?很简单,在对应的 SConscript 里加几行,告诉 SCons 这个新模块的源文件在哪、依赖谁就行。
2.2 依赖分析与增量编译的威力
SCons 一个让我爱不释手的功能是它强大的依赖分析。它不光看源文件(.c)和头文件(.h)的修改时间,还会分析 #include 语句。这意味着,如果你只修改了一个头文件的内容,所有包含了这个头文件的源文件都会被自动识别为“需要重新编译”。这避免了手动清理再编译的麻烦,也杜绝了因头文件更新未触发重编导致的诡异 bug。
在实际开发中,我经常一边改代码一边测试。用传统的 Makefile,有时忘了 make clean,跑出来的结果不对,排查半天才发现是旧的目标文件在作祟。用 SCons 后,几乎没再遇到过这个问题。执行 scons -j8(-j8 表示用8个线程并行编译),它总能精准地只编译必要的部分,编译速度非常快。对于 FMT 这种规模的项目,全量编译可能需要一两分钟,但增量编译往往几秒


1387

被折叠的 条评论
为什么被折叠?



