3、PX4固件烧录:从地面站到命令行,再到安全签名

固件烧录,说白了就是把编译好的二进制文件写进飞控的Flash里。这一步看似简单,但坑不少。我见过不少开发者在地面站里点一下“烧录”就完事了,结果飞控死活连不上,或者飞着飞着突然重启——嗯,多半是Bootloader出了问题。

这一章,我会把PX4固件烧录的几种主流方式都过一遍。从最常用的QGroundControl图形化烧录,到命令行下的J-Link/SWD调试器烧录,再到Bootloader的原理和升级,最后聊聊固件签名与安全。这些都是我在实际项目中踩过坑、填过土的经验。

核心要点:烧录不是简单的“复制粘贴”,它涉及Bootloader、硬件接口、协议栈和签名验证。任何一个环节出问题,飞控都可能变砖。

3.1 QGroundControl地面站烧录

QGroundControl(简称QGC)是PX4官方推荐的地面站软件。它集成了固件烧录功能,操作起来非常直观。我个人习惯在原型验证阶段用QGC烧录,因为快,而且能看到实时日志。

3.1.1 准备工作

  • 硬件:飞控板(如Pixhawk 4、CUAV V5+)、USB数据线(注意:有些飞控需要Micro USB,有些是USB-C)
  • 软件:QGC最新版(Windows/macOS/Linux均可)
  • 固件:PX4编译好的二进制文件(.px4或.bin格式)

3.1.2 烧录步骤

  1. 用USB线连接飞控和电脑。飞控上的LED灯应该会亮起。
  2. 打开QGC,点击左上角的“Q”图标,进入应用设置。
  3. 选择“固件”选项卡。QGC会自动检测飞控型号。
  4. 点击“高级设置”,勾选“自定义固件文件”。
  5. 选择你编译好的.px4文件,点击“烧录”。
  6. 等待进度条走完。飞控会自动重启。

小技巧:如果QGC检测不到飞控,试试换一根USB线。我曾经被一根劣质线坑了整整一下午——飞控供电不稳,烧录到一半就断连。

3.1.3 常见问题

问题 原因 解决方法
飞控无法识别 驱动未安装或USB线有问题 安装驱动(Windows需装WinUSB驱动),换线
烧录中途失败 供电不足或USB带宽不够 使用独立供电的USB Hub
烧录后飞控无反应 固件版本不匹配或Bootloader损坏 重新烧录Bootloader

3.2 命令行烧录:J-Link/SWD

QGC虽然方便,但在批量生产或调试底层时,命令行烧录才是王道。你想想看,生产线上一百块飞控,总不能一块一块地插USB点鼠标吧?

J-Link是SEGGER公司的调试器,支持SWD(Serial Wire Debug)接口。SWD只需要两根线(SWDIO和SWCLK),比传统的JTAG少很多引脚,非常适合飞控这种小尺寸板子。

3.2.1 硬件连接

把J-Link的SWD接口连接到飞控的调试端口。以Pixhawk 4为例,调试端口定义如下:

引脚 信号 说明
1 VCC (3.3V) 目标板供电(可选)
2 SWDIO 数据线
3 SWCLK 时钟线
4 GND 地线

警告:千万不要接反VCC和GND!我见过有人把3.3V接到GND上,飞控直接冒烟。嗯,那块板子后来成了我们的“教学标本”。

3.2.2 使用J-Link Commander烧录

J-Link Commander是SEGGER提供的命令行工具。以下是一个典型的烧录脚本:

# 连接J-Link
JLinkExe -device STM32F765 -if SWD -speed 4000 -autoconnect 1

# 解锁Flash(如果之前锁了)
unlock Kinetics

# 擦除整个Flash
erase

# 加载固件到Flash
loadfile px4_fmu-v5_default.px4

# 重置并运行
r
g

# 退出
exit

这里要注意:-device参数必须指定正确的芯片型号。PX4常用的芯片有STM32F427、STM32F765、STM32H743等。搞错了型号,烧录会失败。

3.2.3 使用OpenOCD烧录

如果你不想用SEGGER的收费工具,OpenOCD是个不错的开源替代。我个人在Linux下用得比较多:

# 启动OpenOCD,连接ST-Link(兼容SWD)
openocd -f interface/stlink.cfg -f target/stm32f7x.cfg

# 在另一个终端中,通过telnet连接
telnet localhost 4444

# 烧录命令
reset halt
flash write_image erase px4_fmu-v5_default.px4 0x08000000
reset run

避坑指南:我曾经在烧录时忘记指定起始地址0x08000000,结果固件写到了错误的位置,飞控直接变砖。后来我养成了一个习惯:每次烧录前都先读一下芯片的Flash起始地址。

3.3 Bootloader原理与升级

Bootloader是飞控上电后第一个运行的程序。它的职责很简单:检查Flash里有没有有效的固件,有就跳转过去执行,没有就进入烧录模式等待新固件。

PX4的Bootloader通常放在Flash的起始扇区(0x08000000 ~ 0x0800FFFF,共64KB)。应用程序则从0x08010000开始。

3.3.1 Bootloader的工作流程

我画了一张流程图,帮你理清Bootloader的执行逻辑:

PX4 Bootloader工作流程 PX4 Bootloader 工作流程 上电复位 初始化硬件 检查固件签名 签名无效 → 进入烧录模式 签名有效 → 跳转应用程序 等待USB/串口固件 运行PX4应用程序 Bootloader 只负责引导,不参与飞行控制。它的核心任务是验证签名并跳转。

3.3.2 升级Bootloader

有时候,飞控出厂自带的Bootloader版本太旧,不支持新固件的签名算法。这时候就需要升级Bootloader。

升级方法有两种:

  • 通过J-Link直接烧录:把Bootloader的二进制文件(如px4_bootloader.bin)烧录到0x08000000地址。
  • 通过应用程序升级:有些飞控支持在应用程序中触发Bootloader升级。这需要固件本身支持。

警告:升级Bootloader有风险。如果中途断电或烧录错误,飞控将无法启动。我建议你在升级前先备份原版Bootloader。

3.4 固件签名与安全

为什么需要固件签名?你想想看,如果一架无人机飞在天上,突然被人注入了恶意固件,后果不堪设想。固件签名就是为了防止这种情况。

PX4从v1.11版本开始引入了固件签名机制。Bootloader在启动时会验证固件的数字签名,只有签名合法的固件才会被执行。

3.4.1 签名原理

签名过程其实不复杂:

  1. 开发者用私钥对固件哈希值进行加密,生成签名。
  2. 签名被附加在固件文件的末尾。
  3. Bootloader用公钥解密签名,得到哈希值A。
  4. Bootloader计算固件本身的哈希值B。
  5. 如果A == B,说明固件未被篡改,签名有效。

3.4.2 生成密钥对

你可以使用OpenSSL生成RSA密钥对:

# 生成私钥
openssl genrsa -out px4_private.pem 2048

# 提取公钥
openssl rsa -in px4_private.pem -pubout -out px4_public.pem

3.4.3 对固件签名

PX4提供了签名工具px4_sign:

# 对固件签名
python3 px4_sign.py --private-key px4_private.pem --firmware px4_fmu-v5_default.px4

签名后的固件文件会变大,因为末尾多了一段签名数据。

3.4.4 将公钥烧录到Bootloader

公钥需要提前烧录到Bootloader的特定位置。PX4的Bootloader源码中有一个public_keys.c文件,你需要把公钥放进去,然后重新编译Bootloader。

// public_keys.c 示例
const uint8_t public_key[] = {
    0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
    // ... 公钥数据
};

避坑指南:我曾经在生成密钥对时忘了保存私钥,结果签名后的固件无法被验证。嗯,那次我不得不重新编译Bootloader,把新的公钥烧进去。所以,私钥一定要妥善保管!

3.4.5 安全建议

建议 说明
私钥离线存储 不要将私钥放在联网的电脑上,使用离线机器或硬件安全模块(HSM)
定期更换密钥 建议每6个月更换一次密钥对,旧密钥用于兼容旧固件
多级签名 对于高安全场景,可以使用多级签名(如Bootloader签名、应用程序签名)
禁用不安全接口 量产时禁用SWD/JTAG接口,防止物理攻击

3.5 本章小结

固件烧录是PX4部署的第一步,也是最重要的一步。从QGC的图形化操作,到命令行的精确控制,再到Bootloader的原理和签名安全,每一步都有它的门道。

我个人建议:在开发阶段用QGC烧录,方便快捷;在批量生产或调试底层时,用命令行烧录,可控性强;在安全敏感场景下,一定要启用固件签名。

嗯,这一章的内容就到这里。记住:烧录不是终点,安全才是。