有关两种PID调参的经验分享——位置式与增量式

2023-12-15 15:24:23

PID是一种用于精确控制的控制算法,通过对比例P,积分I,微分D参数调整以达到最佳的控制效果。
需要注意的是,并不是每一次都三个参数一起出场,有时只需要其中一个或两个就可以达到很好的控制效果。
PID分为位置式与增量式,各有优点,稍后将分别介绍,此处先分别展示,两种PID的公式:

  • 位置式
    位置式PID
    outk 表示 k 时刻的输出值;
    ek 表示 k 时刻偏差量;
    ej 表示 j 时刻的偏差量,这一部分表示自系统开始运行后的误差的累积;
    ek-1显然表示 k 时刻上一时刻的误差。

  • 增量式
    增量式PID
    此处的ek-2表示上上时刻的误差量

位置式PID

参数说明

首先来说 P,他带给系统一个基础的运行能力,使得系统可以往预期的方向发展;这个参数需要适中,如果过大,则会超出目标,并且来回震荡。
积分 I 则起到了补足 P 的作用,他对小幅度的偏差具有明显的调节作用;如果 I 过小则系统存在小幅度偏差时不能回中,过大则会超出目标,且系统表现迟钝。
微分 D 主要起到了限制作用,阻止系统超出预期;过小时会超出目标,过大时则会高频抖动,并且对误差敏感。

调试方法

先调整比例 P,给予系统基础的运行能力,当调整到开始震荡时,减小一点,然后调整积分 I。

积分 I 应当限制他的幅度,这个幅度选定需要根据系统的回复能力决定,可以先自行带入一个设置的阈值,计算后与代表系统回复能力的数值比较,然后得出一个适中的 I,在此基础上进行调整,有时这个值调整完成后就可以发现系统已经可以达到预期,此时可以在根据需要调整微分 D。

微分 D 一般调整到震荡后在减小一些唯宜。

当然,对于 I 与 D 的调整顺序并不是固定的,也可以使 P 过冲,然后调整 D 来限制,之后微调 I 来补足。

当 I 充足后可适当减小P,D 充足后可适当增加 P,此处的增加与减小都不是大踏步行进,而是细微调整。

代码与案例展示

s16 palstance_i_max = 100;      // 角速度环积分限幅
float fly_dt = 0.003;           // 时间

void roll_palstance_c(float target_p_roll, float gyroX)
{
    static float last_offset_rp = 0;                // 上一次的偏差量
    static s16 palstance_i_rp = 0;                  // 积分
    float palstance_offset = gyroX + target_p_roll; // 偏差量

    palstance_i_rp += palstance_offset * fly_dt;

    if (palstance_i_rp > palstance_i_max)
    {
        palstance_i_rp = palstance_i_max;
    }
    else if (palstance_i_rp < -palstance_i_max)
    {
        palstance_i_rp = -palstance_i_max;
    }

    roll_pid_out = (palstance_offset * p_p + palstance_i_rp * p_i + (palstance_offset - last_offset_rp) * p_d / fly_dt);
    // roll_pid_out = limit(roll_pid_out, 200, -200);

    last_offset_rp = palstance_offset;
}

这是一个四轴无人机上角速度环调整的例子,

  • palstance_offset 即为误差,palstance_i_rp 是误差的积分
  • 我为积分限幅为100,因为我发现当达到这个值时就有比较强的回复力
  • 公式中的 fly_dt 表示每 3ms 调整一次,实际并不需要加这个 fly_dt,只有在每次进入计算的时间不等时才需要,此处是为了公式的完整性

增量式PID

参数说明

从公式中增量式的 P 对应着位置式的 D,而 I 又对应着 P。

此处 P 过大会引起系统敏感,高频震荡,过小又不能达到目标。

I 则起到了补足的作用。

调试方法

首先调整 I,给定一个参数后观察是否会收敛,之后尝试增大参数,观察收敛速度,速度加快则增大,速度减慢则减小,当调整到有收敛趋势,且收敛速度适中时,加入参数 P。
P 的作用是一直震荡,给定一个参数后观察震荡幅度是否减小,同理,减小增大,增大减小。
需要注意的是,此处的 I 与 P 不是一劳永逸的,想要或好的效果需要不断调整两个参数,例如当观察到调整 P 的效果不明显时,可以适当减小 I 之后再次调整 P。

  • 对于增量式PID中的 D 来讲,我个人调试时发现作用不大,不管设置的多么不合理的值都不会产生明显的变化。

代码与案例展示

void servo_horizontal_trun(uint16 target_h, uint16 h_x)
{
    error_h = h_x - target_h;					//本次误差
    static sint16 last_error_h = 0;				//上一次的误差
    static sint16 last_last_error_h = 0;		//上上次的误差
    static float last_duty_h = SERVO_MID_H;		//上一次的输出
    static float temp_h = SERVO_MID_H;			//这里是将期望值设为初值

    if (h_x != 0)
    {
        offset_intergral_h += error_h;

        if (offset_intergral_h > horizontal_intergral_max)
        {
            offset_intergral_h = horizontal_intergral_max;
        }
        else if (offset_intergral_h < -horizontal_intergral_max)
        {
            offset_intergral_h = -horizontal_intergral_max;
        }

        temp_h -= (p_h * (error_h - last_error_h) + i_h * error_h + d_h * (error_h - 2 * last_error_h + last_last_error_h));
    }
    else
    {
        temp_h = SERVO_MID_H;
    }
	
	//这部分与pid无关,只是对结果的进一步处理
	//===================================================
    if (abs(error_h) <= 3)
    {
        offset_intergral_h = 0;
    }

    if (temp_h > SERVO_H_MAX)
    {
        temp_h = SERVO_H_MAX;
    }
    else if (temp_h < SERVO_H_MIN)
    {
        temp_h = SERVO_H_MIN;
    }
    //===================================================

    last_duty_h = temp_h;
    duty_h = temp_h;
    pwm_set_duty(servoP_H, duty_h);
    last_last_error_h = last_error_h;
    last_error_h = error_h;
}

后记

设置参数与变量时,数据类型很重要,使用浮点型可以保留更多精度,最好在计算时都使用浮点型,我曾因为想当然的认为输出是整型,而错误的使用整型存储变量,导致丢失的精度,从而做了一整天的无用功。

文章来源:https://blog.csdn.net/d200123zj/article/details/132742532
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。