第一章:PX4与I2C基础

大家好,我是你们的讲师。今天咱们正式开始《PX4驱动I2C设备开发全流程》的第一章。

这一章说白了就是打地基。地基不牢,后面写驱动代码的时候你会各种踩坑。我个人习惯是,不管多简单的协议,都得先把框架摸清楚再动手。你想想看,飞控上挂个传感器,要是I2C时序没搞对,数据读出来全是乱的,那飞机能稳吗?

1.1 PX4飞控架构简介

先聊聊PX4的整体架构。PX4不是那种「大而全」的 monolithic 系统,它更像一个模块化的乐高积木。

核心架构分三层:

  • 应用层:你写的飞行模式、导航算法、传感器融合都在这一层。说白了就是「脑子」。
  • 中间层:uORB消息总线。这是PX4的灵魂。所有模块之间通过uORB发布和订阅消息来通信。我刚开始接触时觉得这玩意儿多此一举,后来发现它让模块解耦做得非常干净。
  • 硬件抽象层:也就是驱动层。I2C、SPI、UART这些外设的驱动都在这里。我们今天要搞的I2C驱动,就属于这一层。

嗯,这里要注意:PX4的驱动不是直接操作寄存器,而是通过一个叫 Device 的抽象类来管理。你写I2C驱动时,实际上是在继承这个基类,然后实现它的几个虚函数。

核心要点:PX4驱动开发 = 继承Device类 + 实现probe/init/read/write + 注册到uORB。

1.2 I2C总线协议基础

I2C协议,说白了就是两根线(SCL时钟线 + SDA数据线)搞定多个设备通信。我当年在学校做第一个I2C项目时,觉得这协议太简单了,结果被ACK/NACK坑了一整天。

几个关键点你必须记住:

  • 起始条件:SCL高电平时,SDA从高变低。
  • 停止条件:SCL高电平时,SDA从低变高。
  • 地址+读写位:7位地址 + 1位读写标志(0写1读)。
  • ACK/NACK:每发送一个字节,接收方必须拉低SDA表示应答。我曾经遇到一个传感器,它的ACK时序比标准慢了半拍,导致PX4一直报错。排查了整整两天。

为什么I2C在飞控上这么流行?因为它只需要两个引脚,而且支持多主机。但缺点也很明显——速度慢(标准模式100kHz,快速模式400kHz)。所以像IMU这种高频数据,一般走SPI。而温湿度计、气压计这类低频传感器,用I2C就够用了。

避坑指南:我曾经在STM32F4上调试一个I2C气压计,发现数据偶尔会卡死。后来用逻辑分析仪一看,是SDA线被从设备一直拉低。原因是主设备发送停止条件时,SCL时钟没给够。解决办法是在停止条件前加一个额外的SCL脉冲。

1.3 PX4中I2C驱动框架概述

PX4的I2C驱动框架,其实就三个核心文件:

文件 作用
I2C.hpp I2C总线抽象类,封装了读写时序、地址管理等底层操作
I2C.cpp 实现文件,包含probe、transfer等核心函数
device/Device.hpp 设备基类,所有驱动都要继承它

你写一个I2C传感器驱动时,流程大概是这样的:

  1. 创建一个类,继承 I2CDevice
  2. 实现 probe() 函数:检测设备是否存在(通常读WHO_AM_I寄存器)。
  3. 实现 init() 函数:配置传感器寄存器。
  4. 实现 read() 函数:读取传感器数据。
  5. cycle() 函数中周期性调用 read(),并通过uORB发布数据。

我个人习惯是,先写一个最简单的probe函数,确保I2C通信通了,再慢慢加功能。别一上来就搞全套,否则出了问题你都不知道是硬件还是软件的问题。

重要提醒:PX4的I2C驱动默认使用100kHz速率。如果你的传感器支持400kHz,记得在 init() 里调用 set_bus_frequency() 修改。但别盲目改快,我曾经在一块长线缆的飞控板上跑400kHz,结果数据全是乱码。后来降到100kHz就稳了。

1.4 开发环境搭建(Ubuntu + PX4 Toolchain)

环境搭建这块,我踩过的坑比写过的代码还多。直接上干货。

第一步:安装Ubuntu

推荐Ubuntu 20.04或22.04 LTS。别用最新版,PX4的依赖库有时候跟不上。我有个同事用Ubuntu 24.04,结果编译时一堆库版本冲突,折腾了两天。

第二步:安装PX4 Toolchain

官方推荐用 ubuntu.sh 脚本一键安装。但我不建议你直接跑,因为脚本会装很多你用不到的东西。我习惯手动装核心组件:

# 安装基础工具
sudo apt update
sudo apt install git zip cmake build-essential genromfs ninja-build

# 安装交叉编译工具链
sudo apt install gcc-arm-none-eabi gdb-arm-none-eabi

# 安装PX4依赖
sudo apt install python3-pip
pip3 install --user kconfiglib pyelftools

# 克隆PX4源码
git clone https://github.com/PX4/PX4-Autopilot.git --recursive
cd PX4-Autopilot
make px4_fmu-v5_default

嗯,这里要注意:--recursive 参数不能少,否则子模块拉不下来。我第一次克隆时忘了加,编译到一半报错说找不到 uavcan 库,气得我直接删了重来。

第三步:验证环境

编译成功后,你会看到类似这样的输出:

-- Build files have been written to: /home/user/PX4-Autopilot/build/px4_fmu-v5_default
[100%] Built target px4_fmu-v5_default

看到 [100%] 就说明环境搭好了。如果报错,多半是网络问题(子模块下载失败)或Python版本问题。我建议用Python 3.8-3.10,太新或太旧都可能出幺蛾子。

小技巧:如果你在公司内网(需要代理),记得配置git代理:git config --global http.proxy http://proxy:port。否则子模块下载会卡死。我曾经因为这个浪费了一整个下午。

本章知识体系

下面这张图,是我手绘的本章知识结构。你可以把它当作一个「地图」,后面写代码时随时回来对照。

第一章:PX4与I2C基础 - 知识体系 PX4飞控架构 应用层(uORB) 中间层(消息总线) 硬件抽象层(驱动) ← 我们在这里 I2C总线协议 SCL + SDA 两根线 起始/停止条件 7位地址 + 读写位 ACK/NACK 应答 PX4 I2C驱动框架 I2C.hpp(总线抽象) Device.hpp(设备基类) probe → init → read → uORB发布 开发环境搭建 Ubuntu 20.04/22.04 ARM交叉编译工具链 PX4源码克隆 make编译验证 本章核心逻辑 理解PX4架构 → 掌握I2C协议 → 熟悉驱动框架 → 搭建开发环境 下一章:我们将基于这个框架,手写一个真实的I2C传感器驱动 公众号:蓝海资料掘金营,微信deep3321

好了,第一章的内容就到这里。环境搭好了,框架理清了,下一章我们就可以开始动手写真正的I2C驱动代码了。记住,别急着跳步,基础打牢了,后面写代码会顺很多。

课后作业:按照1.4节的步骤,在你的Ubuntu上搭建好PX4开发环境,并成功编译一次 px4_fmu-v5_default 目标。如果遇到问题,先检查网络和Python版本,这是最常见的两个坑。


公众号:蓝海资料掘金营,微信deep3321