2. 飞控系统架构:从传感器到电机,PID在飞控链路中的位置

做飞控这么多年,我经常被问到同一个问题:“PID到底在飞控里扮演什么角色?”

很多人一上来就调PID,结果越调越乱。为什么?因为你不清楚整个飞控链路是怎么跑的。传感器数据从哪来,经过哪些处理,最后怎么变成电机的转速——这些搞不明白,调参就是瞎蒙。

今天我就带你走一遍这条链路。说白了,就是搞清楚“谁在干活,活是怎么干的”

2.1 飞控系统的“五层架构”

我习惯把飞控系统拆成五层。你想想看,一架四旋翼飞起来,从你推油门到它真的往上窜,中间经历了什么?

  1. 传感器层:感知物理世界(IMU、磁力计、GPS、气压计)
  2. 状态估计层:把传感器数据融合成姿态、位置、速度
  3. 控制层:计算期望姿态/位置与实际值的偏差,输出控制量
  4. 混控层:把控制量分配到各个电机
  5. 执行层:电机响应,产生力和力矩

嗯,这里要注意:PID就住在第三层——控制层。它既不是最底层,也不是最顶层。

核心认知:PID不是飞控的全部,它只是控制层里的一个“计算单元”。但它是整个链路里最容易被调崩的一环。

2.2 一张图看懂飞控链路

我画了一张图,把整个链路串起来。你看完就明白PID到底在哪了。

飞控系统架构:从传感器到电机 第1层:传感器层 IMU(加速度计+陀螺仪) | 磁力计 | GPS | 气压计 | 光流 第2层:状态估计层 卡尔曼滤波 / 互补滤波 → 姿态角、位置、速度 第3层:控制层 ← PID就在这里! 外环(位置/速度PID)→ 内环(姿态角PID)→ 角速率PID 期望值 vs 实际值 → 计算偏差 → PID输出控制量 第4层:混控层 将控制量(油门、横滚、俯仰、偏航)映射到4个电机 第5层:执行层 → 电机转动,无人机飞起来 反馈回路(传感器数据更新)

这张图我画了好几次才满意。你看,PID控制层是整个链路的“大脑”——它接收状态估计层算出来的姿态和位置,跟遥控器给的期望值做比较,然后算出该给电机多少力。

2.3 PID在控制层里的具体位置

控制层内部其实还有讲究。我见过不少新手,以为PID就是一层。实际上,飞控里通常是串级PID

什么叫串级?就是外环套内环。拿四旋翼的横滚控制举个例子:

  • 外环(位置环):期望横滚角 vs 实际横滚角 → 输出期望角速率
  • 内环(角速率环):期望角速率 vs 实际角速率 → 输出电机控制量

为什么会这样设计?因为角速率环响应更快,能先把飞机的“抖动”压住,外环再慢慢把角度调准。我在项目里遇到过,如果只用单环PID,飞机稍微受点风就晃得跟筛子似的。

实战经验:调参时永远先调内环(角速率环),再调外环(角度环)。内环稳了,外环才有意义。我曾经有一次把顺序搞反了,结果飞机在地上疯狂抽搐,差点把桨打碎。

2.4 传感器数据是怎么“喂”给PID的?

你可能会问:PID怎么知道飞机当前的角度?答案是——它不知道,它只负责算

传感器数据经过状态估计层处理后,变成了PID能理解的“实际值”。这个过程我简单说一下:

传感器 原始数据 状态估计输出 PID使用
陀螺仪 角速度(°/s) 滤波后的角速度 内环PID输入
加速度计 三轴加速度(m/s²) 姿态角(横滚、俯仰) 外环PID输入
磁力计 磁场强度 偏航角 偏航外环PID
GPS 经纬度、高度 位置、速度 位置/速度PID

说白了,PID就是个“比较器+计算器”。它不关心数据怎么来的,只关心“期望值 - 实际值 = 偏差”,然后根据偏差算输出。

2.5 一个典型的控制循环代码

我写一段伪代码,你看完就明白PID在循环里是怎么跑的:

// 飞控主循环(400Hz,每2.5ms执行一次)
while(flight_armed) {
    // 1. 读取传感器原始数据
    raw_gyro = read_gyroscope();
    raw_accel = read_accelerometer();
    
    // 2. 状态估计(卡尔曼滤波)
    attitude = kalman_filter(raw_gyro, raw_accel);
    angular_rate = lowpass_filter(raw_gyro);
    
    // 3. PID控制(串级)
    // 外环:角度PID
    angle_error = target_roll - attitude.roll;
    target_rate = angle_pid.update(angle_error);
    
    // 内环:角速率PID
    rate_error = target_rate - angular_rate.roll;
    control_output = rate_pid.update(rate_error);
    
    // 4. 混控:分配到4个电机
    motor_pwm = mixer(control_output, throttle);
    
    // 5. 输出PWM给电调
    write_pwm(motor_pwm);
    
    // 6. 等待下一个控制周期
    wait_for_next_cycle();
}

你看,PID在整个循环里只占了两步。但就是这两步,决定了飞机是稳如磐石还是乱晃乱抖

避坑指南:我曾经在调试一架大四旋翼时,发现PID输出一直在震荡。查了半天,结果是传感器数据更新频率跟控制频率不匹配——传感器100Hz,控制跑400Hz,PID每次算的都是旧数据。后来我把控制频率降到跟传感器同步,问题就解决了。

2.6 为什么PID调参会影响到整个链路?

这个问题很关键。你调PID的时候,其实是在调整整个控制链路的“响应特性”

  • P太大:控制量过冲,飞机来回晃
  • D太大:对噪声敏感,电机高频抖动
  • I太大:积分饱和,飞机反应迟钝

但你知道吗?有时候问题不在PID本身。我遇到过好几次,用户说“PID调不好”,结果一看——传感器安装有振动,IMU数据本身就带噪声,PID再努力也白搭。

所以我的建议是:调参之前,先确认传感器数据是干净的。你可以在飞控的日志里看看角速度曲线,如果毛刺很多,先解决减震问题,再来调PID。

2.7 小结:记住这三句话

这一章的内容,你只需要记住三句话:

  1. PID在控制层,控制层在飞控链路的中间——前面是传感器和状态估计,后面是混控和电机
  2. 串级PID是标配——内环管角速率,外环管角度/位置,调参先内后外
  3. PID不是万能的——传感器数据质量、控制频率、混控逻辑都会影响最终效果

下一章,我会带你深入PID的三个参数——P、I、D到底在干什么,以及它们各自对飞行的影响。嗯,到时候我会拿我踩过的坑给你当反面教材。


专注资料整理