驱动编译与集成:模块化编译方法、将驱动集成到PX4固件、启动脚本编写

好,咱们接着往下走。驱动写完了,测试也通过了,接下来就是把它塞进PX4固件里,让它真正跑起来。这一步,说难不难,说简单也不简单。我见过不少新手,代码写得挺漂亮,结果卡在编译集成这一步,折腾一整天。

今天我就把这块儿掰开了讲。咱们分三块:模块化编译、集成到固件、启动脚本。你跟着我的节奏走,保证一次搞定。

模块化编译方法

先说说编译。PX4的构建系统用的是CMake,这个你应该不陌生。但PX4有自己的模块化编译规则,说白了就是:每个驱动都是一个独立的模块,编译时按需加载。

我个人习惯把驱动放在 src/drivers/ 目录下。比如你写了个气压计驱动,就建个文件夹叫 bmp388。里面放什么呢?至少要有这几个文件:

  • CMakeLists.txt —— 编译规则
  • bmp388.cpp —— 主代码
  • bmp388.hpp —— 头文件

CMakeLists.txt 怎么写?我给你个模板,直接拿去用:

px4_add_module(
  MODULE drivers__bmp388
  MAIN bmp388
  STACK_MAIN 2000
  SRCS
    bmp388.cpp
  DEPENDS
    px4_work_queue
  )

这里要注意几个点:

  • MODULE 的名字,我建议用 drivers__设备名 这种格式,PX4内部就是这么组织的
  • MAIN 就是你的入口函数名,比如 bmp388
  • STACK_MAIN 是栈大小,2000字节一般够用,如果驱动里用了大量局部变量,可以适当调大
小提示: 我曾经遇到过栈溢出导致系统随机重启的坑。排查了两天才发现是局部数组太大。建议你写驱动时,能用静态分配就别用局部大数组。

将驱动集成到PX4固件

模块写好了,怎么让PX4知道它存在?这里有两个步骤。

第一步:注册模块

boards/ 目录下找到你的目标板子配置文件。比如你用 Pixhawk 4,就找 boards/px4/fmu-v5/default.cmake。在里面加上一行:

drivers/bmp388

嗯,就这么简单。PX4的构建系统会自动扫描 src/drivers/ 下的所有模块,你只要在板级配置里声明一下就行。

第二步:编译验证

我个人习惯先单独编译驱动模块,确认没有语法错误:

make px4_fmu-v5_default

如果编译通过,再烧录到板子上测试。这里有个小技巧:你可以用 make px4_fmu-v5_default upload 一步到位,省得手动拷贝固件。

注意: 如果你改了驱动代码,一定要重新编译整个固件。只编译单个模块然后替换,很容易出现版本不一致的问题。我吃过这个亏,调试时发现驱动行为异常,最后发现是固件里的其他模块没同步更新。

启动脚本编写

驱动集成进去了,但系统启动时不会自动加载它。你需要写一个启动脚本。

PX4的启动脚本放在 ROMFS/px4fmu_common/init.d/ 目录下。比如你想让驱动在 rcS 启动时自动运行,就在 rcS 文件里加一行:

bmp388 start

但更规范的做法是单独写一个脚本文件。比如 rc.driver_bmp388

#!/bin/sh
#
# @brief BMP388 barometer driver startup
#

bmp388 start

然后在 rcS 里调用它:

sh /etc/init.d/rc.driver_bmp388

为什么要单独写?因为这样方便调试。你可以随时在终端里手动执行这个脚本,不用重启整个系统。

核心要点: 启动脚本的本质就是告诉系统「什么时候、以什么参数启动你的驱动」。你可以在脚本里传递参数,比如 I2C 总线号、设备地址等。我习惯把参数写在脚本里,而不是硬编码在驱动代码中,这样换硬件平台时只需要改脚本。

知识体系图

下面这张图,是我自己总结的驱动编译与集成流程。你照着这个走,基本不会迷路。

驱动编译与集成流程 1. 编写驱动模块 CMakeLists.txt + 源码 2. 注册到板级配置 boards/xxx/default.cmake 3. 编译固件 make xxx_default 4. 编写启动脚本 ROMFS/px4fmu_common/init.d/rc.driver_xxx 5. 集成到rcS sh /etc/init.d/rc.driver_xxx 6. 烧录并测试 make xxx_default upload 说明:每个步骤都可以独立调试。我建议你按顺序走,不要跳步。 特别是启动脚本,写完后先手动执行一次,确认没问题再集成到rcS。

避坑指南

最后,分享几个我踩过的坑:

  • 编译顺序问题: 如果你改了 CMakeLists.txt,一定要先 make clean 再编译。否则CMake缓存不会更新,你改的东西等于白改。
  • 启动脚本权限: 脚本文件要有可执行权限。我一开始忘了加 chmod +x,结果驱动死活起不来,查了半天才发现是权限问题。
  • 参数传递: 如果你在启动脚本里传了参数,记得在驱动代码里用 param_find()param_get() 来读取。别问我为什么知道,说多了都是泪。

好了,这一章的内容就这些。你按我说的步骤走,驱动编译和集成这块儿基本不会出问题。下一章咱们聊聊更深入的东西。

专注资料整理