第四章 嵌入式平台搭建:STM32/PX4/ArduPilot平台选择、RTKLIB移植、EKF状态估计器配置、传感器融合框架搭建
各位同学,欢迎来到第四章。这一章,咱们要真刀真枪地干硬件和底层软件了。
说实话,很多做无人机飞控的朋友,一听到「嵌入式平台搭建」就头大。觉得不就是选个板子、刷个固件嘛?其实不然。你想想看,RTK厘米级定位要落地,底层平台选不对,后面全是坑。我当年在做一个农业植保机的项目时,就因为平台选型没想清楚,导致RTK数据融合进去后,EKF直接发散,飞机在天上画八字……嗯,那场面,至今难忘。
所以这一章,我会把三个主流平台——STM32、PX4、ArduPilot——掰开了讲。告诉你哪个场景该用哪个,RTKLIB怎么移植进去,EKF怎么配,传感器融合框架怎么搭。全是实战经验,没有废话。
4.1 平台选型:STM32、PX4、ArduPilot,到底选哪个?
这个问题,几乎每个做RTK融合的人都会问。我的回答很简单:看你的产品定位和团队基因。
咱们先看一张对比表,心里有个底:
| 平台 | 核心优势 | RTK融合难度 | 适合场景 |
|---|---|---|---|
| STM32裸机/FreeRTOS | 完全自主可控,资源占用极低 | 高(需手写EKF) | 定制化飞控、工业级产品 |
| PX4 (NuttX) | 生态成熟,EKF2内置,支持RTK即插即用 | 中(需配置参数) | 科研、快速原型验证 |
| ArduPilot (ChibiOS) | 代码可读性好,传感器驱动丰富 | 中低(有现成RTK插件) | 教育、开源社区项目 |
我个人习惯:如果是做量产产品,我会选STM32+FreeRTOS。为什么?因为PX4和ArduPilot虽然方便,但里面有很多你不需要的模块,占Flash、占RAM,而且出了问题你很难改底层。但如果你是在做科研或者快速验证,PX4的EKF2模块直接支持RTCM数据输入,省事很多。
4.2 RTKLIB移植:从PC到嵌入式
RTKLIB是RTK定位的灵魂。但它的原始代码是跑在PC上的,要移植到STM32这类MCU上,有几个坎必须过。
第一步:裁剪RTKLIB
RTKLIB的源码里,有很多你不需要的东西。比如图形界面、文件读写、TCP通信。我们只需要核心解算引擎。我建议只保留以下模块:
rtkcmn.c— 公共函数rtkpos.c— 定位解算rtknav.c— 导航滤波rtkobs.c— 观测数据处理rtkcmn.h— 头文件
第二步:内存管理改造
RTKLIB在PC上喜欢用malloc动态分配内存。但在STM32上,尤其是实时性要求高的场景,动态分配是大忌。我建议全部改成静态数组,或者使用FreeRTOS的pvPortMalloc。
看一段我实际改过的代码:
// 原版RTKLIB代码
double *obs = (double *)malloc(sizeof(double) * MAXOBS);
// 移植到STM32后的代码
#define MAX_OBS_STATIC 32
static double obs_buf[MAX_OBS_STATIC];
double *obs = obs_buf;
你看,就这么简单。但很多新手会忽略这一步,导致程序跑着跑着就HardFault了。
4.3 EKF状态估计器配置
EKF(扩展卡尔曼滤波)是RTK融合的核心。说白了,它就是把GPS/RTK的位置、IMU的加速度和角速度、磁力计的航向,全部揉在一起,输出一个最靠谱的姿态和位置。
EKF的状态向量,我一般这样定义:
// 22维状态向量
// [0:2] — 位置 (NED坐标系, 米)
// [3:5] — 速度 (NED坐标系, 米/秒)
// [6:8] — 姿态四元数
// [9:11] — 加速度计偏置
// [12:14] — 陀螺仪偏置
// [15:17] — 地磁偏置
// [18:20] — 风速 (如果你做室外飞行)
// [21] — 气压计高度偏移
配置EKF时,有几个关键参数必须调:
- 过程噪声协方差矩阵Q:这个值设大了,EKF会太相信IMU,导致位置漂移;设小了,又跟不上动态变化。我一般先设一个经验值,然后通过实际飞行日志反推。
- 观测噪声协方差矩阵R:RTK的观测噪声,我通常设0.02米(水平)和0.05米(垂直)。注意,RTK的垂直精度天生比水平差,这个要区分开。
- 初始化协方差矩阵P:第一次上电时,P矩阵要设大一点,让EKF快速收敛。我习惯设成单位矩阵乘以100。
4.4 传感器融合框架搭建
框架搭得好,后面写代码就像搭积木。我推荐一个分层架构,大家可以直接复用:
// 伪代码:传感器融合主循环
while(1) {
// 1. 数据采集层
imu_data = read_imu(); // 200Hz
gps_data = read_rtk_uart(); // 10Hz (RTCM数据)
mag_data = read_magnetometer(); // 100Hz
// 2. 时间同步层
// 注意:IMU和GPS的时间戳必须对齐!
sync_data = time_sync(imu_data, gps_data);
// 3. EKF预测步 (IMU驱动)
ekf_predict(sync_data.imu, dt);
// 4. EKF更新步 (观测驱动)
if (new_gps_available) {
ekf_update_gps(sync_data.gps);
}
if (new_mag_available) {
ekf_update_mag(sync_data.mag);
}
// 5. 输出层
output_position(ekf_get_position());
output_attitude(ekf_get_attitude());
}
这个框架,说白了就是「谁有数据谁说话」。IMU负责高频预测,GPS/RTK负责低频修正。磁力计只在航向漂移时拉一把。
关于传感器融合,我再强调三点:
- 时间戳是命根子:IMU和GPS的时间戳必须统一。我习惯用STM32的定时器捕获GPS的PPS脉冲,然后给IMU数据打上硬件时间戳。软件时间戳?误差太大,别用。
- 数据质量要打分:不是所有GPS数据都能进EKF。我会根据RTK的定位状态(单点解、浮点解、固定解)给每个观测值一个权重。固定解的权重最高,单点解直接扔掉。
- 别忘了磁力计校准:硬铁和软铁校准不做,EKF的航向估计会偏到姥姥家。我一般在飞控上电后,让用户拿着飞机转几个「8」字,自动完成校准。
本章知识体系总览
下面这张图,是我用SVG画的本章核心逻辑。你可以把它当成一个「导航图」,随时回来对照:
这张图把本章的四个核心模块串起来了。你从平台选型开始,然后移植RTKLIB,接着配置EKF,最后搭融合框架。每一步都踩实了,厘米级定位自然就出来了。
好了,第四章的内容就到这里。记住,嵌入式开发没有捷径,但有了正确的框架和参数,你能少走很多弯路。下一章,我们会深入RTCM电文的解析与注入,到时候见。