02-03-01 无人机飞控系统原理

1. 核心概念

1.1 飞控系统概述

飞控系统(Flight Control System)是无人机的"大脑",负责处理传感器数据、执行飞行控制算法、驱动电机,实现稳定飞行和自主导航。

核心特点

  • 实时性:控制周期<10ms
  • 高可靠性:故障检测与容错
  • 多传感器融合:IMU + GPS + 气压计 + 磁力计
  • 自主控制:姿态稳定、高度保持、位置控制
  • 扩展性:支持多种飞行器构型

1.2 飞行器构型

四旋翼(Quadcopter)

              前
        M1(CW)  M2(CCW)
            ╲  ╱
             ╳
            ╱  ╲
       M4(CCW)  M3(CW)

X型布局:
- M1/M3:顺时针(CW)
- M2/M4:逆时针(CCW)
- 优点:结构简单、成本低
- 应用:消费级无人机

六旋翼(Hexacopter)

       M1    M2
         ╲  ╱
      M6  ╳  M3
         ╱  ╲
       M5    M4

- 冗余设计(单电机故障仍可飞行)
- 载重能力强
- 应用:专业航拍、物流

固定翼

       ───────
      │       │
   ───┴───────┴───
      │电机    │
      └────────┘

- 巡航效率高
- 续航时间长
- 应用:测绘、巡检

1.3 坐标系定义

机体坐标系(Body Frame)

     X(前)
      ↑
      │
      │
      └────→ Y(右)
     ╱
    ╱
   Z(下)

俯仰(Pitch):绕Y轴旋转
横滚(Roll):绕X轴旋转
偏航(Yaw):绕Z轴旋转

地理坐标系(NED Frame)

North-East-Down:
- X:指向北
- Y:指向东
- Z:指向地心

2. 技术原理

2.1 四旋翼飞行原理

升力产生

电机转速 → 螺旋桨旋转 → 空气向下加速 → 产生升力

升力公式:
F = ½ × ρ × A × V² × CL

其中:
- ρ:空气密度(1.225 kg/m³)
- A:旋翼面积
- V:气流速度
- CL:升力系数

实际简化:
F ≈ k × ω²

其中:
- k:电机/螺旋桨常数
- ω:电机角速度(rad/s)

六自由度控制

俯仰(Pitch Forward):
M1↑ M4↑ > M2↓ M3↓
→ 机头下压,前飞

横滚(Roll Right):
M1↑ M2↑ > M3↓ M4↓
→ 右倾,右飞

偏航(Yaw Right):
M1↑ M3↑ > M2↓ M4↓
→ 顺时针旋转

油门(Throttle Up):
M1↑ M2↑ M3↑ M4↑
→ 整体升力增加

悬停(Hover):
M1 = M2 = M3 = M4
→ 升力 = 重力

2.2 传感器系统

IMU(惯性测量单元)

加速度计(Accelerometer):
- 测量:三轴加速度
- 用途:计算姿态角(静态)
- 频率:1kHz
- 精度:±0.5°

陀螺仪(Gyroscope):
- 测量:三轴角速度
- 用途:姿态解算(动态)
- 频率:1kHz
- 精度:0.01°/s

磁力计(Magnetometer):
- 测量:地磁场方向
- 用途:偏航角校准
- 频率:100Hz
- 精度:±2°

气压计(Barometer)

测量:大气压力
用途:高度估计
频率:50Hz

高度计算:
h = 44330 × (1 - (P/P0)^0.1903)

其中:
- P:当前气压
- P0:海平面气压(1013.25 hPa)
- h:高度(米)

精度:±0.5m(室外)

2.3 姿态解算算法

互补滤波(Complementary Filter)

// 简单互补滤波
float alpha = 0.98;  // 高通滤波系数

void complementary_filter(float dt) {
    // 陀螺仪积分(高频)
    float angle_gyro = angle + gyro_rate * dt;

    // 加速度计计算(低频)
    float angle_acc = atan2(acc_y, acc_z) * RAD_TO_DEG;

    // 互补滤波融合
    angle = alpha * angle_gyro + (1 - alpha) * angle_acc;
}

卡尔曼滤波(Kalman Filter)

// 卡尔曼滤波姿态解算
typedef struct {
    float angle;          // 角度估计
    float bias;           // 陀螺仪偏差
    float P[2][2];        // 误差协方差矩阵
} kalman_t;

float kalman_update(kalman_t* k, float gyro_rate, float acc_angle, float dt) {
    // 预测
    k->angle += (gyro_rate - k->bias) * dt;
    k->P[0][0] += dt * (dt * k->P[1][1] - k->P[0][1] - k->P[1][0] + Q_angle);
    k->P[0][1] -= dt * k->P[1][1];
    k->P[1][0] -= dt * k->P[1][1];
    k->P[1][1] += Q_bias * dt;

    // 更新
    float S = k->P[0][0] + R_measure;
    float K[2];
    K[0] = k->P[0][0] / S;
    K[1] = k->P[1][0] / S;

    float y = acc_angle - k->angle;
    k->angle += K[0] * y;
    k->bias += K[1] * y;

    float P00_temp = k->P[0][0];
    float P01_temp = k->P[0][1];

    k->P[0][0] -= K[0] * P00_temp;
    k->P[0][1] -= K[0] * P01_temp;
    k->P[1][0] -= K[1] * P00_temp;
    k->P[1][1] -= K[1] * P01_temp;

    return k->angle;
}

3. 代码实现

3.1 姿态解算实现(C)

// attitude.c - 姿态解算模块

#include <math.h>
#include "attitude.h"

#define RAD_TO_DEG 57.29578f
#define DEG_TO_RAD 0.0174533f

// 姿态结构体
typedef struct {
    float roll;      // 横滚角
    float pitch;     // 俯仰角
    float yaw;       // 偏航角
} attitude_t;

// IMU数据结构体
typedef struct {
    float acc_x, acc_y, acc_z;      // 加速度(m/s²)
    float gyro_x, gyro_y, gyro_z;   // 角速度(rad/s)
    float mag_x, mag_y, mag_z;      // 磁力计(μT)
} imu_data_t;

// 互补滤波参数
static float alpha = 0.98f;
static attitude_t attitude = {0, 0, 0};

/**
 * 姿态解算 - 互补滤波
 */
void attitude_update_complementary(imu_data_t* imu, float dt) {
    // 陀螺仪积分
    float gyro_roll = attitude.roll + imu->gyro_x * dt * RAD_TO_DEG;
    float gyro_pitch = attitude.pitch + imu->gyro_y * dt * RAD_TO_DEG;

    // 加速度计计算角度
    float acc_roll = atan2f(imu->acc_y, imu->acc_z) * RAD_TO_DEG;
    float acc_pitch = atan2f(-imu->acc_x,
                             sqrtf(imu->acc_y * imu->acc_y +
                                   imu->acc_z * imu->acc_z)) * RAD_TO_DEG;

    // 互补滤波融合
    attitude.roll = alpha * gyro_roll + (1 - alpha) * acc_roll;
    attitude.pitch = alpha * gyro_pitch + (1 - alpha) * acc_pitch;

    // 偏航角(磁力计)
    float mag_x_h = imu->mag_x * cosf(attitude.pitch * DEG_TO_RAD) +
                    imu->mag_z * sinf(attitude.pitch * DEG_TO_RAD);
    float mag_y_h = imu->mag_x * sinf(attitude.roll * DEG_TO_RAD) *
                    sinf(attitude.pitch * DEG_TO_RAD) +
                    imu->mag_y * cosf(attitude.roll * DEG_TO_RAD) -
                    imu->mag_z * sinf(attitude.roll * DEG_TO_RAD) *
                    cosf(attitude.pitch * DEG_TO_RAD);

    attitude.yaw = atan2f(-mag_y_h, mag_x_h) * RAD_TO_DEG;
}

/**
 * 获取姿态角
 */
void attitude_get(attitude_t* out) {
    *out = attitude;
}

3.2 PID控制器实现

// pid.c - PID控制器

typedef struct {
    float kp;           // 比例系数
    float ki;           // 积分系数
    float kd;           // 微分系数
    float integral;     // 积分累积
    float prev_error;   // 上次误差
    float output_min;   // 输出下限
    float output_max;   // 输出上限
} pid_t;

/**
 * PID控制器更新
 */
float pid_update(pid_t* pid, float setpoint, float measurement, float dt) {
    // 计算误差
    float error = setpoint - measurement;

    // 积分项
    pid->integral += error * dt;

    // 积分限幅(防止积分饱和)
    if (pid->integral > 100.0f) pid->integral = 100.0f;
    if (pid->integral < -100.0f) pid->integral = -100.0f;

    // 微分项
    float derivative = (error - pid->prev_error) / dt;

    // PID输出
    float output = pid->kp * error +
                   pid->ki * pid->integral +
                   pid->kd * derivative;

    // 输出限幅
    if (output > pid->output_max) output = pid->output_max;
    if (output < pid->output_min) output = pid->output_min;

    // 保存当前误差
    pid->prev_error = error;

    return output;
}

/**
 * 三环PID控制(角速度环 + 角度环 + 位置环)
 */
typedef struct {
    pid_t angle_pid;       // 角度环PID
    pid_t rate_pid;        // 角速度环PID
} cascade_pid_t;

float cascade_pid_update(cascade_pid_t* cpid,
                         float angle_setpoint,
                         float angle_measurement,
                         float rate_measurement,
                         float dt) {
    // 外环:角度控制
    float rate_setpoint = pid_update(&cpid->angle_pid,
                                     angle_setpoint,
                                     angle_measurement,
                                     dt);

    // 内环:角速度控制
    float output = pid_update(&cpid->rate_pid,
                             rate_setpoint,
                             rate_measurement,
                             dt);

    return output;
}

3.3 电机混控(Motor Mixing)

// motor_mixing.c - 电机混控

// 四旋翼X型布局混控矩阵
void motor_mixing_quad_x(float throttle, float roll, float pitch, float yaw,
                         float* motor) {
    /*
     * 混控矩阵:
     *        油门  横滚  俯仰  偏航
     * M1:    +1    -1    +1    -1
     * M2:    +1    +1    +1    +1
     * M3:    +1    +1    -1    -1
     * M4:    +1    -1    -1    +1
     */

    motor[0] = throttle - roll + pitch - yaw;  // M1 (左前)
    motor[1] = throttle + roll + pitch + yaw;  // M2 (右前)
    motor[2] = throttle + roll - pitch - yaw;  // M3 (右后)
    motor[3] = throttle - roll - pitch + yaw;  // M4 (左后)

    // 油门限幅(0-100%)
    for (int i = 0; i < 4; i++) {
        if (motor[i] > 100.0f) motor[i] = 100.0f;
        if (motor[i] < 0.0f) motor[i] = 0.0f;
    }
}

// 六旋翼混控
void motor_mixing_hexa_x(float throttle, float roll, float pitch, float yaw,
                         float* motor) {
    /*
     *        油门  横滚  俯仰  偏航
     * M1:    +1    0     +1    -1
     * M2:    +1    +0.87 +0.5  +1
     * M3:    +1    +0.87 -0.5  -1
     * M4:    +1    0     -1    +1
     * M5:    +1    -0.87 -0.5  -1
     * M6:    +1    -0.87 +0.5  +1
     */

    motor[0] = throttle + pitch - yaw;
    motor[1] = throttle + 0.87f * roll + 0.5f * pitch + yaw;
    motor[2] = throttle + 0.87f * roll - 0.5f * pitch - yaw;
    motor[3] = throttle - pitch + yaw;
    motor[4] = throttle - 0.87f * roll - 0.5f * pitch - yaw;
    motor[5] = throttle - 0.87f * roll + 0.5f * pitch + yaw;

    // 限幅
    for (int i = 0; i < 6; i++) {
        if (motor[i] > 100.0f) motor[i] = 100.0f;
        if (motor[i] < 0.0f) motor[i] = 0.0f;
    }
}

3.4 飞控主循环(Python示例)

from dataclasses import dataclass

@dataclass
class IMUData:
    """IMU数据"""
    acc: np.ndarray  # 加速度 [x, y, z]
    gyro: np.ndarray  # 角速度 [x, y, z]
    mag: np.ndarray  # 磁力计 [x, y, z]

@dataclass
class Attitude:
    """姿态角"""
    roll: float
    pitch: float
    yaw: float

class FlightController:
    """飞控主控制器"""

    def __init__(self):
        self.attitude = Attitude(0, 0, 0)

        # PID控制器
        self.roll_pid = PIDController(kp=4.0, ki=0.05, kd=0.5)
        self.pitch_pid = PIDController(kp=4.0, ki=0.05, kd=0.5)
        self.yaw_pid = PIDController(kp=2.0, ki=0.0, kd=0.3)

        self.loop_rate = 400  # 400Hz控制频率
        self.dt = 1.0 / self.loop_rate

    def update(self, imu: IMUData, rc_input: dict):
        """
        飞控主循环更新

        Args:
            imu: IMU数据
            rc_input: 遥控器输入 {'throttle', 'roll', 'pitch', 'yaw'}
        """
        # 1. 姿态解算
        self.attitude_update(imu)

        # 2. PID控制
        roll_output = self.roll_pid.update(
            setpoint=rc_input['roll'],
            measurement=self.attitude.roll,
            dt=self.dt
        )

        pitch_output = self.pitch_pid.update(
            setpoint=rc_input['pitch'],
            measurement=self.attitude.pitch,
            dt=self.dt
        )

        yaw_output = self.yaw_pid.update(
            setpoint=rc_input['yaw'],
            measurement=self.attitude.yaw,
            dt=self.dt
        )

        # 3. 电机混控
        motors = self.motor_mixing(
            throttle=rc_input['throttle'],
            roll=roll_output,
            pitch=pitch_output,
            yaw=yaw_output
        )

        return motors

    def attitude_update(self, imu: IMUData):
        """姿态解算(互补滤波)"""
        alpha = 0.98

        # 陀螺仪积分
        gyro_roll = self.attitude.roll + imu.gyro[0] * self.dt * 57.3
        gyro_pitch = self.attitude.pitch + imu.gyro[1] * self.dt * 57.3

        # 加速度计计算
        acc_roll = np.arctan2(imu.acc[1], imu.acc[2]) * 57.3
        acc_pitch = np.arctan2(-imu.acc[0],
                               np.sqrt(imu.acc[1]**2 + imu.acc[2]**2)) * 57.3

        # 融合
        self.attitude.roll = alpha * gyro_roll + (1 - alpha) * acc_roll
        self.attitude.pitch = alpha * gyro_pitch + (1 - alpha) * acc_pitch

        # 偏航角(磁力计)
        self.attitude.yaw = np.arctan2(-imu.mag[1], imu.mag[0]) * 57.3

    def motor_mixing(self, throttle, roll, pitch, yaw):
        """四旋翼X型混控"""
        motors = np.array([
            throttle - roll + pitch - yaw,  # M1
            throttle + roll + pitch + yaw,  # M2
            throttle + roll - pitch - yaw,  # M3
            throttle - roll - pitch + yaw   # M4
        ])

        # 限幅
        motors = np.clip(motors, 0, 100)

        return motors

class PIDController:
    """PID控制器"""

    def __init__(self, kp, ki, kd):
        self.kp = kp
        self.ki = ki
        self.kd = kd
        self.integral = 0
        self.prev_error = 0

    def update(self, setpoint, measurement, dt):
        """PID更新"""
        error = setpoint - measurement

        self.integral += error * dt
        self.integral = np.clip(self.integral, -100, 100)

        derivative = (error - self.prev_error) / dt

        output = self.kp * error + self.ki * self.integral + self.kd * derivative

        self.prev_error = error

        return np.clip(output, -100, 100)

# 使用示例
if __name__ == '__main__':
    fc = FlightController()

    # 模拟飞行
    for i in range(1000):
        # 读取IMU数据(模拟)
        imu = IMUData(
            acc=np.array([0, 0, 9.8]),
            gyro=np.array([0.01, -0.02, 0.005]),
            mag=np.array([25, -5, 40])
        )

        # 遥控器输入
        rc_input = {
            'throttle': 50,
            'roll': 0,
            'pitch': 0,
            'yaw': 0
        }

        # 更新飞控
        motors = fc.update(imu, rc_input)

        print(f"姿态: Roll={fc.attitude.roll:.2f}° "
              f"Pitch={fc.attitude.pitch:.2f}° "
              f"Yaw={fc.attitude.yaw:.2f}°")
        print(f"电机: {motors}")

        time.sleep(0.0025)  # 400Hz

4. 行业案例

案例1:DJI Phantom系列

飞控架构

  • 处理器:STM32F427(168MHz ARM Cortex-M4)
  • IMU:MPU6000(加速度计+陀螺仪)+ HMC5883L(磁力计)
  • 气压计:MS5611
  • 控制频率:400Hz
  • 传感器融合:扩展卡尔曼滤波(EKF)

实施效果

  • 悬停精度:垂直±0.5m,水平±1.5m
  • 姿态控制精度:±0.02°
  • 最大抗风:10m/s(5级风)

案例2:PX4开源飞控

技术特点

  • 平台:Pixhawk硬件
  • RTOS:NuttX实时操作系统
  • 算法:级联PID + EKF2状态估计
  • 通信:MAVLink协议

实施效果

  • 支持多种飞行器构型
  • 开源社区活跃
  • 商业应用广泛

5. 性能优化

5.1 控制频率优化

多速率控制

// 400Hz主循环
void main_loop_400hz() {
    // 高频:姿态控制
    attitude_control();
    motor_output();
}

// 100Hz循环
void loop_100hz() {
    // 中频:高度/位置控制
    altitude_control();
    position_control();
}

// 10Hz循环
void loop_10hz() {
    // 低频:任务管理
    mission_update();
    telemetry_send();
}

5.2 传感器校准

加速度计校准(六面法)

def calibrate_accelerometer():
    """六面法校准加速度计"""
    samples = []

    print("将飞机放置在6个面,每个面采集100个样本")
    for face in ['上', '下', '左', '右', '前', '后']:
        input(f"按Enter开始采集{face}面...")
        face_samples = []

        for _ in range(100):
            acc = read_accelerometer()
            face_samples.append(acc)
            time.sleep(0.01)

        samples.append(np.mean(face_samples, axis=0))

    # 计算偏移和缩放
    offset = (samples[0] + samples[1]) / 2
    scale_z = 9.8 / ((samples[0][2] - samples[1][2]) / 2)

    print(f"偏移: {offset}")
    print(f"缩放: {scale_z}")

    return offset, scale_z

6. 协议对比

飞控协议对比

协议开发者开源应用
MAVLinkDroneCodePX4/Ardupilot
MSPMultiWii/Betaflight穿越机
ULogPX4日志记录
DJI SDKDJIDJI无人机
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐