请教一个关于PID的知识

目前,我想写的一个pid用来控制正反转,我写了一个pid程序。他正转可以实现、但是翻转却疯转了。pid控制中正反转不应该是一致的吗。(我的电机正反转是用高低电平来控制的)
我尝试了把预期值和反馈量都变为正,结果还是和一开始的一样。请教一下,我到底是哪里出了问题QAQ

初始化

int want_speed_x[4];
int encoder_errorall_x[4];
int encoder_store_x[4];
float encoder_error_x[4];
float encoder_speed_x[4];
float last_encoder_error_x[4];

float encoder_kp0=0.045;
float encoder_ki0=0;
float encoder_kd0=0;

float encoder_kp1=0.045;
float encoder_ki1=0;
float encoder_kd1=0;

float encoder_kp2=0.045;
float encoder_ki2=0;
float encoder_kd2=0;

float encoder_kp3=0.045;
float encoder_ki3=0.0;
float encoder_kd3=0.0;

pid

int pid_x(int a)
{

              want_speed_x[0]=-500;  
              want_speed_x[1]=-500; 
              want_speed_x[2]=-500; 
              want_speed_x[3]=-500;   

    encoder_error_x[0] = want_speed_x[0] - encoder_data[0];
    encoder_errorall_x[0]+=encoder_error_x[0];
    encoder_store_x[0] += (int)(encoder_kp0*encoder_error_x[0] +encoder_ki0*encoder_errorall_x[0]+ encoder_kd0*(encoder_error_x[0] - last_encoder_error_x[0]));
    last_encoder_error_x[0] = encoder_error_x[0];
    
    encoder_error_x[1] = want_speed_x[1] - encoder_data[1];
    encoder_errorall_x[1]+=encoder_error_x[1];
    encoder_store_x[1] += (int)(encoder_kp1*encoder_error_x[1] +encoder_ki1*encoder_errorall_x[1] +encoder_kd1*(encoder_error_x[1] - last_encoder_error_x[1]));
    last_encoder_error_x[1] = encoder_error_x[1];
    
    encoder_error_x[2] = want_speed_x[2] - encoder_data[2];
    encoder_errorall_x[2]+=encoder_error_x[2];
    encoder_store_x[2] += (int)(encoder_kp2*encoder_error_x[2] +encoder_ki2*encoder_errorall_x[2]+encoder_kd2*(encoder_error_x[2] - last_encoder_error_x[2]));
    last_encoder_error_x[2] = encoder_error_x[2];
    
    encoder_error_x[3] = want_speed_x[3] - encoder_data[3];
    encoder_errorall_x[3]+=encoder_error_x[3];
    encoder_store_x[3] += (int)(encoder_kp3*encoder_error_x[3] +encoder_ki3*encoder_errorall_x[3]+ encoder_kd3*(encoder_error_x[3] - last_encoder_error_x[3]));
    last_encoder_error_x[3] = encoder_error_x[3];
       
  motor(a,encoder_store_x[0],encoder_store_x[1],encoder_store_x[2],encoder_store_x[3]); 
   PRINTF("%d,%d,%d,%d,%d,%d,%d,%d\n",encoder_data[0],encoder_data[1],encoder_data[2],encoder_data[3],encoder_store_x[0],encoder_store_x[1],encoder_store_x[2],encoder_store_x[3]);

 return 0;

}

电机控制

void motor(int move,int a,int b,int c,int d)
{
  
  
  int A;int B;int C;int D;
  A=abs(a); B=abs(b); C=abs(c); D=abs(d); 

     //move     0==前进  1==后    2==左 3==右
        
        if (move==0)
        {
         
          gpio_set(D14,1);
          gpio_set(D15,1);
          gpio_set(D0,1);
          gpio_set(D1,1);
          pwm_duty(PWM2_MODULE3_CHB_D3,A);
          pwm_duty(PWM2_MODULE3_CHA_D2,B);
          pwm_duty(PWM1_MODULE0_CHB_D13,C);
          pwm_duty(PWM1_MODULE0_CHA_D12,D);

        }

        if (move==1)
        {
          
          gpio_set(D14,0);
          gpio_set(D15,0);
          gpio_set(D0,0);
          gpio_set(D1,0);
          pwm_duty(PWM2_MODULE3_CHB_D3,A);
          pwm_duty(PWM2_MODULE3_CHA_D2,B);
          pwm_duty(PWM1_MODULE0_CHB_D13,C);
          pwm_duty(PWM1_MODULE0_CHA_D12,D);
        }

}

你的gpio是控制电机方向的吧 你考虑过没有 一但转速超过了目标速度你的pid结果可能需要改变方向(例如你给定的速度是负一,结果电机跑到了负二,那么新的电机给定速度方向可能会变成正的,但你的电机方向却是gpio给定的,结果就造成越差越多 越多越差 就转疯了

PID的参数只针对一种运行条件的,正转调好的参数,并不适用于反转,运行条件不一样,参数就不一样了,你需要建立两套PID参数,分别对应正反转运行,调出各自的参数。正转有正转的参数,反转有反转的参数才行。这里可以参考下:
https://blog.csdn.net/qq_19979629/article/details/123451333
Codesys使用ST语言实现离散PID模型的仿真

不能只用一个PID