1. 为什么需要滤波与PID结合

在四旋翼或云台系统中,角度传感器(如MPU6050)输出的原始数据包含高频噪声和机械振动。直接使用这些数据驱动PID,会导致控制量剧烈波动,舵机或电机发热、抖动,甚至失控。因此,必须对传感器数据进行低通滤波,去除高频分量,再送入PID控制器。

一阶低通滤波(LPF)因其计算量小、实时性强,成为嵌入式控制中最常用的滤波方法。其本质是:

output = alpha * input + (1 - alpha) * output_prev;

其中 alpha 为滤波系数,取值范围0~1。alpha 越小,滤波越强,但响应越慢;alpha 越大,滤波越弱,响应越快。

2. 一阶低通滤波原理与参数选择

2.1 数学原理

一阶低通滤波的传递函数为:

H(s) = 1 / (τs + 1)

离散化后得到差分方程:

y[k] = a * x[k] + (1 - a) * y[k-1]

其中 a = T / (τ + T)T 为采样周期,τ 为时间常数。

2.2 参数选择

  • 采样周期 T:通常取控制周期,如1ms(1000Hz)。
  • 时间常数 τ:根据系统带宽需求。若云台带宽要求20Hz,则 τ ≈ 1/(2π*20) ≈ 8ms,则 a ≈ 0.111
  • 实际调试中,可先设置 a=0.2,观察响应,再微调。

3. PID控制器设计

3.1 位置式PID

对于角度环,常用位置式PID:

float pid_update(PID_t *pid, float setpoint, float measurement) {
    float error = setpoint - measurement;
    pid->integral += error;
    // 抗积分饱和
    if (pid->integral > pid->integral_max) pid->integral = pid->integral_max;
    if (pid->integral < -pid->integral_max) pid->integral = -pid->integral_max;
    float derivative = error - pid->prev_error;
    pid->prev_error = error;
    return pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative;
}

3.2 微分先行与低通滤波

纯微分项会放大噪声,因此通常对微分项进行低通滤波,或采用“微分先行”结构(只对测量值微分)。推荐使用:

float derivative = (measurement - pid->prev_measurement) / dt;
pid->prev_measurement = measurement;
// 对derivative再低通滤波
pid->deriv_lpf = alpha_d * derivative + (1 - alpha_d) * pid->deriv_lpf;

4. 完整代码示例(STM32平台)

以下代码在STM32F103上实现,使用定时器1ms中断调用控制函数。

// pid.h
#ifndef __PID_H
#define __PID_H

typedef struct {
    float Kp, Ki, Kd;
    float integral;
    float prev_error;
    float prev_measurement;
    float deriv_lpf;
    float integral_max;
    float deriv_alpha;  // 微分低通系数
} PID_t;

void pid_init(PID_t *pid, float kp, float ki, float kd, float integral_max, float deriv_alpha);
float pid_update(PID_t *pid, float setpoint, float measurement, float dt);

#endif
// pid.c
#include "pid.h"

void pid_init(PID_t *pid, float kp, float ki, float kd, float integral_max, float deriv_alpha) {
    pid->Kp = kp;
    pid->Ki = ki;
    pid->Kd = kd;
    pid->integral = 0;
    pid->prev_error = 0;
    pid->prev_measurement = 0;
    pid->deriv_lpf = 0;
    pid->integral_max = integral_max;
    pid->deriv_alpha = deriv_alpha;
}

float pid_update(PID_t *pid, float setpoint, float measurement, float dt) {
    float error = setpoint - measurement;
    // 积分项(带限幅)
    pid->integral += error * dt;
    if (pid->integral > pid->integral_max) pid->integral = pid->integral_max;
    if (pid->integral < -pid->integral_max) pid->integral = -pid->integral_max;
    // 微分项(对测量值微分,并低通滤波)
    float derivative = (measurement - pid->prev_measurement) / dt;
    pid->deriv_lpf = pid->deriv_alpha * derivative + (1 - pid->deriv_alpha) * pid->deriv_lpf;
    pid->prev_measurement = measurement;
    // 输出
    float output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * pid->deriv_lpf;
    return output;
}
// main.c 示例
#include "pid.h"
#include "mpu6050.h" // 假设有MPU6050驱动

PID_t pid_roll, pid_pitch;
float target_angle = 0.0f;
float measured_angle;

void TIM1_UP_IRQHandler(void) {
    if (TIM_GetITStatus(TIM1, TIM_IT_Update)) {
        // 读取传感器(已滤波)
        measured_angle = mpu6050_get_angle();
        // 一阶低通滤波(alpha=0.15)
        static float filtered_angle = 0;
        filtered_angle = 0.15f * measured_angle + 0.85f * filtered_angle;
        // PID计算
        float output = pid_update(&pid_roll, target_angle, filtered_angle, 0.001f);
        // 输出到舵机或电机(PWM)
        set_servo_pwm(output);
        TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
    }
}

int main(void) {
    // 初始化硬件...
    pid_init(&pid_roll, 2.0f, 0.1f, 0.05f, 100.0f, 0.2f);
    // 启动定时器...
    while(1) {}
}

5. 调试步骤与注意事项

5.1 调试步骤

  1. 先调滤波:单独观察滤波后的角度曲线,确保噪声明显减小,且延迟可接受。
  2. 整定P:只加P,从小到大,直到系统出现等幅振荡,然后取当前值的60%作为P。
  3. 加I:缓慢增加I,消除稳态误差,注意积分限幅防止超调。
  4. 加D:增加D,抑制超调,但D过大会引入噪声,需配合微分滤波。
  5. 联合调试:在真实负载下微调,观察阶跃响应。

5.2 注意事项

  • 采样时间一致性:PID和滤波的dt必须与实际中断周期一致,否则参数失效。
  • 抗积分饱和:积分限幅要合理,否则系统会长时间饱和。
  • 滤波系数调整alpha 过小会导致响应迟钝,过大则滤波效果差。建议从0.1~0.3开始。
  • 舵机死区:如果输出变化很小,舵机可能不响应,可添加死区处理。
  • 测试环境:在固定台架上测试,避免飞行器振动影响判断。

6. 总结

本文详细介绍了四旋翼/云台角度控制中PID与一阶低通滤波的结合方法。通过合理选择滤波系数和PID参数,可以有效抑制噪声,提高控制稳定性。实际工程中,还需根据具体硬件特性反复调试,才能达到最佳性能。希望本文能为你的嵌入式控制开发提供实用参考。