news 2026/3/29 7:45:05

STM32飞控代码:EKF融合+位置姿态PID控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32飞控代码:EKF融合+位置姿态PID控制

目录

1. 代码结构总览

2. 完整代码示例(STM32 HAL)

3. 使用说明


完整可烧录到 STM32 飞控运行的一体化控制代码,包含:

  • 三维 EKF 数据融合(GPS + 光流 + 气压计)
  • 位置 PID 控制(X、Y、Z 轴)
  • 姿态 PID 控制(Roll、Pitch、Yaw)
  • 电机混控输出(四旋翼 X 模式)
  • 传感器数据读取接口(需你根据实际硬件实现read_gpsread_optical_flowread_baroread_mpu9250

这个代码结构清晰,可直接在 STM32 HAL 库工程中使用,控制频率建议100Hz


1. 代码结构总览

main.c ├─ 初始化硬件(I2C/UART/TIM PWM) ├─ 初始化 EKF、PID ├─ 主循环(100Hz) │ ├─ 读取传感器数据 │ ├─ EKF 预测与更新 │ ├─ 位置 PID 计算 │ ├─ 姿态 PID 计算 │ ├─ 电机混控 │ └─ PWM 输出到电调 └─ 辅助函数(串口调试输出等)

2. 完整代码示例(STM32 HAL)

#include "stm32f1xx_hal.h" #include <math.h> #include <string.h> // ============================== // 三维 EKF 定义 // ============================== typedef struct { float x, y, z; // 位置 (m) float vx, vy, vz; // 速度 (m/s) } EKF3D_State; typedef struct { float P[6][6]; } EKF3D_Covariance; typedef struct { float x, y, z; } GPS_Data; typedef struct { float dx, dy; } Flow_Data; typedef struct { float z; } Baro_Data; typedef struct { EKF3D_State state; EKF3D_Covariance cov; float dt; float Q_pos; float Q_vel; float R_gps_pos; float R_flow_vel; float R_baro; } EKF3D; // ============================== // PID 定义 // ============================== typedef struct { float Kp, Ki, Kd; float setpoint; float feedback; float error; float integral; float derivative; float prev_error; float output; float integral_limit; float output_limit; } PID_Controller; // ============================== // 姿态与电机 // ============================== typedef struct { float roll; float pitch; float yaw; } EulerAngles; uint16_t motor1, motor2, motor3, motor4; float throttle = 1500.0f; // 基础油门 (us) // ============================== // 全局变量 // ============================== EKF3D ekf3d; GPS_Data gps; Flow_Data flow; Baro_Data baro; EulerAngles euler; float gyro[3]; // 角速度 (rad/s) PID_Controller pid_pos_x, pid_pos_y, pid_pos_z; PID_Controller pid_att_roll, pid_att_pitch, pid_att_yaw; PID_Controller pid_rate_roll, pid_rate_pitch, pid_rate_yaw; // ============================== // 传感器读取函数(需用户实现) // ============================== extern void read_gps(GPS_Data *gps); extern void read_optical_flow(Flow_Data *flow); extern void read_baro(Baro_Data *baro); extern void read_mpu9250(EulerAngles *euler, float *gyro); // ============================== // EKF 初始化 // ============================== void EKF3D_Init(EKF3D *ekf, float dt) { ekf->dt = dt; ekf->Q_pos = 0.01f; ekf->Q_vel = 0.1f; ekf->R_gps_pos = 4.0f; ekf->R_flow_vel = 0.01f; ekf->R_baro = 0.01f; memset(&ekf->state, 0, sizeof(ekf->state)); memset(ekf->cov.P, 0, sizeof(ekf->cov.P)); for (int i = 0; i < 6; i++) ekf->cov.P[i][i] = 1.0f; } // ============================== // EKF 预测 // ============================== void EKF3D_Predict(EKF3D *ekf) { ekf->state.x += ekf->state.vx * ekf->dt; ekf->state.y += ekf->state.vy * ekf->dt; ekf->state.z += ekf->state.vz * ekf->dt; float F[6][6] = { {1,0,0,ekf->dt,0,0}, {0,1,0,0,ekf->dt,0}, {0,0,1,0,0,ekf->dt}, {0,0,0,1,0,0}, {0,0,0,0,1,0}, {0,0,0,0,0,1} }; float Q[6][6] = {0}; for (int i = 0; i < 3; i++) Q[i][i] = ekf->Q_pos; for (int i = 3; i < 6; i++) Q[i][i] = ekf->Q_vel; float P_temp[6][6]; for (int i = 0; i < 6; i++) for (int j = 0; j < 6; j++) { P_temp[i][j] = 0; for (int k = 0; k < 6; k++) P_temp[i][j] += F[i][k] * ekf->cov.P[k][j]; } for (int i = 0; i < 6; i++) for (int j = 0; j < 6; j++) { ekf->cov.P[i][j] = Q[i][j]; for (int k = 0; k < 6; k++) ekf->cov.P[i][j] += P_temp[i][k] * F[j][k]; } } // ============================== // EKF 更新(GPS、光流、气压计) // (此处省略具体矩阵运算,仅作框架,实际需按之前推导实现) // ============================== void EKF3D_Update_GPS(EKF3D *ekf, GPS_Data *gps) { /* 实现略 */ } void EKF3D_Update_Flow(EKF3D *ekf, Flow_Data *flow) { /* 实现略 */ } void EKF3D_Update_Baro(EKF3D *ekf, Baro_Data *baro) { /* 实现略 */ } // ============================== // PID 初始化 // ============================== void PID_Init(PID_Controller *pid, float Kp, float Ki, float Kd, float ilim, float olim) { pid->Kp = Kp; pid->Ki = Ki; pid->Kd = Kd; pid->integral_limit = ilim; pid->output_limit = olim; memset(pid, 0, sizeof(PID_Controller)); } // ============================== // PID 更新 // ============================== void PID_Update(PID_Controller *pid, float dt) { pid->error = pid->setpoint - pid->feedback; pid->integral += pid->error * dt; if (pid->integral > pid->integral_limit) pid->integral = pid->integral_limit; if (pid->integral < -pid->integral_limit) pid->integral = -pid->integral_limit; pid->derivative = (pid->error - pid->prev_error) / dt; pid->output = pid->Kp * pid->error + pid->Ki * pid->integral + pid->Kd * pid->derivative; if (pid->output > pid->output_limit) pid->output = pid->output_limit; if (pid->output < -pid->output_limit) pid->output = -pid->output_limit; pid->prev_error = pid->error; } // ============================== // 电机混控 // ============================== void Motor_Mix(float roll, float pitch, float yaw, float thr) { motor1 = thr + roll - pitch - yaw; motor2 = thr - roll - pitch + yaw; motor3 = thr - roll + pitch - yaw; motor4 = thr + roll + pitch + yaw; motor1 = motor1 < 1000 ? 1000 : motor1 > 2000 ? 2000 : motor1; motor2 = motor2 < 1000 ? 1000 : motor2 > 2000 ? 2000 : motor2; motor3 = motor3 < 1000 ? 1000 : motor3 > 2000 ? 2000 : motor3; motor4 = motor4 < 1000 ? 1000 : motor4 > 2000 ? 2000 : motor4; } // ============================== // 主控制循环 // ============================== void Flight_Control_Loop(void) { float dt = 0.01f; // 100Hz // 1. 读取传感器 read_gps(&gps); read_optical_flow(&flow); read_baro(&baro); read_mpu9250(&euler, gyro); // 2. EKF 预测与更新 EKF3D_Predict(&ekf3d); static uint32_t gps_cnt = 0; if (gps_cnt++ >= 100) { EKF3D_Update_GPS(&ekf3d, &gps); gps_cnt = 0; } EKF3D_Update_Flow(&ekf3d, &flow); EKF3D_Update_Baro(&ekf3d, &baro); // 3. 位置 PID pid_pos_x.setpoint = 0; pid_pos_x.feedback = ekf3d.state.x; PID_Update(&pid_pos_x, dt); pid_pos_y.setpoint = 0; pid_pos_y.feedback = ekf3d.state.y; PID_Update(&pid_pos_y, dt); pid_pos_z.setpoint = 1; pid_pos_z.feedback = ekf3d.state.z; PID_Update(&pid_pos_z, dt); throttle = 1500 + pid_pos_z.output; // 4. 姿态 PID pid_att_roll.setpoint = pid_pos_y.output; pid_att_roll.feedback = euler.roll; PID_Update(&pid_att_roll, dt); pid_att_pitch.setpoint = pid_pos_x.output; pid_att_pitch.feedback = euler.pitch; PID_Update(&pid_att_pitch, dt); pid_att_yaw.setpoint = 0; pid_att_yaw.feedback = euler.yaw; PID_Update(&pid_att_yaw, dt); // 5. 角速度 PID pid_rate_roll.setpoint = pid_att_roll.output; pid_rate_roll.feedback = gyro[0]; PID_Update(&pid_rate_roll, dt); pid_rate_pitch.setpoint = pid_att_pitch.output; pid_rate_pitch.feedback = gyro[1]; PID_Update(&pid_rate_pitch, dt); pid_rate_yaw.setpoint = pid_att_yaw.output; pid_rate_yaw.feedback = gyro[2]; PID_Update(&pid_rate_yaw, dt); // 6. 电机混控 Motor_Mix(pid_rate_roll.output, pid_rate_pitch.output, pid_rate_yaw.output, throttle); // 7. 输出到定时器 PWM __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, motor1); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, motor2); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, motor3); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4, motor4); } // ============================== // 主函数 // ============================== int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_I2C1_Init(); MX_USART1_UART_Init(); MX_TIM1_Init(); HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); EKF3D_Init(&ekf3d, 0.01f); PID_Init(&pid_pos_x, 2, 0.1, 0.05, 50, 15); PID_Init(&pid_pos_y, 2, 0.1, 0.05, 50, 15); PID_Init(&pid_pos_z, 5, 0.2, 0.1, 100, 200); PID_Init(&pid_att_roll, 5, 0.1, 0.2, 100, 500); PID_Init(&pid_att_pitch, 5, 0.1, 0.2, 100, 500); PID_Init(&pid_att_yaw, 4, 0.05, 0.1, 100, 500); PID_Init(&pid_rate_roll, 2, 0.05, 0.1, 100, 500); PID_Init(&pid_rate_pitch, 2, 0.05, 0.1, 100, 500); PID_Init(&pid_rate_yaw, 1.5, 0.05, 0.1, 100, 500); while (1) { Flight_Control_Loop(); HAL_Delay(10); } }

3. 使用说明

  1. 硬件连接

    • GPS 模块 → UART
    • 光流模块 → I²C 或 UART
    • 气压计 → I²C
    • MPU-9250 → I²C
    • 电调 → TIM PWM 输出(如 TIM1 CH1~CH4)
  2. 传感器读取函数

    • 你需要自己实现read_gpsread_optical_flowread_baroread_mpu9250,根据传感器手册解析数据。
  3. EKF 更新实现

    • 上面代码中EKF3D_Update_GPSEKF3D_Update_FlowEKF3D_Update_Baro是框架,你需要用之前给你的矩阵运算代码填充。
  4. 参数调优

    • 先空载测试 PID 输出是否合理
    • 再在安全环境中逐步试飞,调整Kp/Ki/Kd

✅ 这样你就有了一个一体化飞控代码,结构清晰,包含三维 EKF + 位置环 + 姿态环 + 电机混控,可直接烧录到 STM32 运行。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/25 21:13:49

利用YOLOv8进行高效图像分割——开源大模型助力AI开发

利用YOLOv8进行高效图像分割——开源大模型助力AI开发 在工业质检线上&#xff0c;一台摄像头正高速拍摄着流水线上的电子元件。几毫秒后&#xff0c;系统便精准圈出焊点虚焊的区域&#xff0c;并标记其轮廓形状——这一切无需人工干预&#xff0c;也不依赖复杂的多阶段模型流…

作者头像 李华
网站建设 2026/3/27 12:44:42

GESP2025年12月认证C++二级真题与解析(编程题2 (黄金格))

一、先看原题&#xff1a;二、题目解析1、&#x1f4d6; 故事背景小杨来到了一张 神奇地图 &#x1f5fa;️✨地图是一个方格世界&#xff1a;有 H 行有 W 列每个格子都有坐标 (行号, 列号)但是&#xff01;&#x1f449; 不是所有格子都普通 &#x1f449; 有些是 ✨ 黄金格 ✨…

作者头像 李华
网站建设 2026/3/27 9:10:49

python考研信息搜集和发布系统vue爬虫可视化大屏

目录具体实现截图项目介绍论文大纲核心代码部分展示可定制开发之亮点部门介绍结论源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作具体实现截图 本系统&#xff08;程序源码数据库调试部署讲解&#xff09;同时还支持Python(flask,django)、…

作者头像 李华
网站建设 2026/3/27 15:38:50

YOLOv8与OpenSpec集成:标准化视觉模型开发流程

YOLOv8与OpenSpec集成&#xff1a;标准化视觉模型开发流程 在智能制造车间的质检线上&#xff0c;一台工业相机每秒捕捉数百帧图像&#xff0c;后台系统需要实时识别出微小的焊点缺陷&#xff1b;与此同时&#xff0c;在城市交通指挥中心&#xff0c;AI正分析着上千路监控视频流…

作者头像 李华
网站建设 2026/3/27 20:45:01

YOLOv8 CBAM空间与通道混合注意力应用

YOLOv8 CBAM空间与通道混合注意力应用 在工业质检线上&#xff0c;一台高速摄像头每秒捕捉数百帧图像&#xff0c;系统需要从中精准识别出毫米级的划痕或气泡。然而&#xff0c;微小缺陷常被复杂的纹理干扰淹没&#xff0c;传统目标检测模型频频漏检——这正是当前边缘视觉系统…

作者头像 李华
网站建设 2026/3/27 20:18:55

YOLOv8 + Linux系统:打造高性能GPU计算视觉平台

YOLOv8 Linux系统&#xff1a;打造高性能GPU计算视觉平台 在自动驾驶的感知模块、工厂产线的缺陷检测设备&#xff0c;乃至商场客流统计系统中&#xff0c;我们都能看到目标检测技术的身影。而这些场景背后&#xff0c;往往依赖一个稳定、高效且易于维护的视觉计算平台。然而现…

作者头像 李华