El motor codificador de desaceleración CC PID incremental secreto que Arduino hace que el automóvil vaya recto

PID incremental para motorreductor DC Versión fácil de entender

Para un estudiante de pregrado que se especializa en electrónica en mi escuela doble africana y que nunca ha asistido al autocontrol, esto es realmente demasiado difícil. Estudié un conductor A4950 antes, que es barato, alta capacidad de conducción, alta seguridad y gran comodidad. Las palabras son más fáciles de usar que L298N. Después de que terminé de escribir, lo envié. Después de leerlo, uno de mis maestros dijo que no lo vio. Debería obtener un control PID. Está bien. Lo haré. ¿Por qué es fácil entender la versión? Esto, porque no lo entiendo muy profundamente. Si hay un error, espero que el tipo grande lo señale a Haihan. Creo que debería ser suficiente para la mayoría de los estudiantes. Este artículo se trata de un motor. Este artículo se investiga en el hogar del automóvil de equilibrio

1. Breve introducción al principio del control de bucle cerrado PID incremental del motor de CC

Generalmente dividimos PID en dos tipos, uno se llama PID de posición y el otro es PID de velocidad. El PID de posición se usa generalmente para péndulo invertido, carro de equilibrio, etc., para hacer que un parámetro alcance con precisión un estado estático específico, como hacer un motor preciso Gire 90 grados, y el PID incremental se usa para mantener una variable dinámica lo más estable posible en un determinado valor objetivo, por lo que queremos que el automóvil conduzca a una velocidad uniforme con la mayor precisión posible, que es para hacer que la velocidad de cada rueda se estabiliza en un objetivo El valor, ¿cómo se logra? Lo dividí en cuatro pasos. Para
Inserte la descripción de la imagen aquí
comprender este diagrama de flujo, debe al menos conocer:
(1) El principio básico del motor de codificación, el codificador del motor de codificación, la velocidad correspondiente será diferente dentro del mismo tiempo. Salida de pulsos diferentes
(2) El microordenador de un solo chip obtiene la velocidad leyendo el borde ascendente o descendente, o el borde ascendente y el borde descendente del pulso emitido por el codificador (a pulso continuo es una onda cuadrada)
Bien, explicaremos este diagrama a continuación
Paso 1: El microordenador de un solo chip obtiene la velocidad a través del codificador del motorreductor DC, y obtiene el error entre la velocidad actual y la velocidad objetivo.
Paso 2: De acuerdo con el error, el controlador PI calculará un valor PWM para ajustar el motorreductor de CC a la velocidad objetivo
. Paso 3: Envíe el valor PWM calculado al motor de CC y ajuste la velocidad del motor de CC.
Paso 4: Lea la velocidad del motor de CC nuevamente y envíela al microcontrolador

Controlador PI: una función, la entrada es el error entre la velocidad actual y la velocidad objetivo, y la salida es el valor PWM necesario para ajustar la velocidad

A continuación, permítanme presentarles un hada viviente con una velocidad uniforme del automóvil, fórmula PID discreta

PWM + =Kp× [e (k) -e (k-1)] +Ki× e (k) +Kd× [e (k) -2e (k-1) + e (k-2)]

¡Mira la fórmula y marea !? No te vayas, no te vayas, no usaremos esta fórmula complicada al final.
Permíteme primero presentarte lo que representan sus parámetros.

PWM: el incremento de salida es el valor de salida

Los tres parámetros de Kp, Ki y Kd deben ajustarse en consecuencia. De acuerdo con la prueba y el ajuste continuos, se puede obtener un conjunto de valores óptimos. ¿¡Qué !? Las cuatro palabras son superficiales? No vayas, don ' Ve, habrá ejemplos Bueno, debes entender, debes entender

e (k): este error de tiempo

e (k-1): Último error

e (k-2): último error

Los antepasados ​​de la fórmula que vamos a usar están terminados, la fórmula que usamos realmente se puede simplificar a

PWM + =Kp× [e (k) -e (k-1)] +Ki× e (k)

Esta sencilla y corta fórmula es la clave para desbloquear el tesoro del coche a una velocidad constante

El código de implementación del lenguaje C es el siguiente

int Incremental_PI (int Encoder,int Target)
{
    
      
   static float Bias,PWM,Last_bias;
   Bias=Target-Encoder;                                  //计算偏差
   PWM+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias;   //增量式PI控制器
   Last_bias=Bias;                                       //保存上一次偏差 
   return PWM;                                           //增量输出
}

Expliquemos en detalle línea por línea

int Incremental_PI (int Encoder,int Target)

Defina una función cuyo valor de retorno sea un entero llamadoIncremental_PILa entrada son dos variables enteras Codificador, Objetivo (El codificador representa la velocidad actual, el Objetivo representa la velocidad objetivo)

Bias=Target-Encoder; 

Calcular el valor objetivo de desviación menos el valor actual

static float Bias,PWM,Last_bias;

Defina tres variables estáticas de punto flotante globales, Bias (esta desviación), PWM (incremento de salida), Last_bias (último error)

PWM+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias;

Calcule el valor de PWM necesario para ajustar la desviación

Last_bias=Bias;   

Desviación primaria en almacenamiento

return PWM;

Devuelve el valor PWM que se emitirá

2. Preparación del experimento

1.
Fuente de alimentación Arduino mega 2560 2.12V, una que uso es una batería de modelo de avión
3. Unidad de motor DC
Enlace A4950 : Explicación detallada de la unidad A4950
4. Motor de codificación
5. Placa de pruebas
6. Varias líneas Dupont El
diagrama de cableado es el siguiente:

mega 2560 pierna de tiro Pines periféricos
2 Codificador Fase A
50 Codificador Fase B
5 Controlador A4950 AIN1
6 Controlador A4950 AIN2
5V Protoboard +
GND Tablero de circuitos-
Pin del motor de codificación Pin conectado
Línea de motor ﹢ A4950 impulsa AOUT1
Cable del motor A4950 impulsa AOUT2
Codificador 5v Protoboard +
Codificador GND Tablero de circuitos-
Codificador Fase A mega2560 pin 2
Codificador Fase B mega2560 pin 50
Driver A4950 Pin conectado
VCC Protoboard ﹢
GND Tablero de circuitos-
VM Unidad de fuente de alimentación de 12V +
AIN1 mega2560 pin 5
AIN2 mega2560 pin 6
AOUT1 Codificación de la línea del motor del motor +
AOUT2 Codificación de la línea del motor del motor
Potencia de accionamiento de 12 V Pin conectado
electrodo positivo A4950VM
GND Tablero de circuitos-

3. Conocimientos preliminares experimentales

1. Fase AB del codificador
La fase A y la fase B del codificador emiten dos pulsos con diferencia de fase, que en realidad son dos ondas cuadradas. Entonces, ¿cómo emitimos ondas cuadradas del codificador? La fase A y la fase B distinguenLo que creemosPros y contras

Por ejemplo, nuestro contador cuenta detectando el borde ascendente de la onda cuadrada de salida de la fase A. Cuando detectamos el borde ascendente de la salida de la fase A, encontramos que si la salida de la fase B es alta en este momento, entonces podemos asumimos que el motor está girando hacia adelante en este momento. Cuando se detecta el flanco ascendente de la fase A, si la salida de la fase B es baja, entonces podemos determinar que el motor está en reversa

Si solo detectamos el número de ocurrencias de un borde de una fase en una unidad de tiempo, llamamos a este método de medición de velocidad el método de medición de velocidad M. Si detectamos los bordes ascendente y descendente de la fase AB, puede alcanzar cuatro veces La precisión. Se llama medición de velocidad de cuatro frecuencias, pero el Arduino mega 2560 tiene solo 6 puertos IO de interrupción, y también hay puertos IO compartidos con el puerto de comunicación I2C y el puerto serie Serial1, por lo que solo usamos cuatro puertos IO de interrupción para cada puerto de interrupción IO. Correspondiente al codificador de un motor, pero podemos detectar los flancos ascendentes y descendentes de la fase A usando dos mediciones de velocidad por división de frecuencia Inserte la descripción de la imagen aquí
2. Interrupción interna de temporización
Si desea utilizar Arduino como un carro PID de cuatro ruedas , necesita al menos cuatro puertos IO de interrupción. En términos generales, todos usamos Mega2560. El siguiente es el número de pin correspondiente y el número de interrupción de la MCU de la serie arduino
Inserte la descripción de la imagen aquí
. Los flancos ascendentes y descendentes del pulso dentro del tiempo establecido deben contarse , y sin ocupar la CPU, necesitamos usar la interrupción interna de temporización Por supuesto, la mayor ventaja de arduino es la conveniencia. No necesitamos configurar muchos registros y muchos modos como usar 32. Usamos el mega2560 biblioteca de temporizadores internos escrita para nosotros por un tipo extranjero.

#include <FlexiTimer2.h>        //定时中断

La configuración también es muy simple, simplemente escribe dos líneas en setup ().

  FlexiTimer2::set(5, control); //5毫秒定时中断函数,每5s执行一次control函数
  FlexiTimer2::start ();      //中断使能 

Es como si entendieras lo básico, entonces comenzamos

4. Código experimental

La función del siguiente código es ingresar una velocidad objetivo Velocidad desde el puerto serie, de modo que la velocidad del motor se pueda mantener en el valor objetivo con la mayor precisión posible. La velocidad representa el número de flancos ascendentes y descendentes dentro de un tiempo especificado . El tiempo establecido en la interrupción de tiempo interna, también conocido como período de muestreo

unsigned int Motor_AIN1=5;       //控制A电机的PWM引脚  一定改成自己用的
unsigned int Motor_AIN2=6;        
String Target_Value;             //串口获取的速度字符串变量
int value;                       //用于存储通过PI控制器计算得到的用于调整电机转速的PWM值的整形变量 
#include <FlexiTimer2.h>         //定时中断头文件库
/***********编码器引脚************/
#define ENCODER_A 2              //编码器A相引脚
#define ENCODER_B 50             //编码器B相引脚
int Velocity,Count=0;            //Count计数变量 Velocity存储设定时间内A相上升沿和下降沿的个数
float Velocity_KP =7.2, Velocity_KI =0.68,Target=0;//Velocity_KP,Velocity_KI.PI参数  Target目标值
/*********** 限幅************
*以下两个参与让输出的PWM在一个合理区间
*当输出的PWM小于40时电机不转 所以要设置一个启始PWM
*arduino mega 2560 单片机的PWM不能超过255 所以 PWM_Restrict 起到限制上限的作用
*****************************/
int startPWM=40;                 //初始PWM
int PWM_Restrict=215;            //startPW+PWM_Restric=255<256
void setup() 
{
    
    
  Serial.begin(9600);            //打开串口
  Serial.println("/*****开始驱动*****/");
  pinMode(ENCODER_A,INPUT);     //设置两个相线为输入模式
  pinMode(ENCODER_B,INPUT);
  pinMode(Motor_AIN1,OUTPUT);   //设置两个驱动引脚为输出模式
  pinMode(Motor_AIN2,OUTPUT); 
  FlexiTimer2::set(5, control); //5毫秒定时中断函数
  FlexiTimer2::start ();        //中断使能 
  attachInterrupt(0, READ_ENCODER_A, CHANGE);      //开启对应2号引脚的0号外部中断,触发方式为CHANGE 即上升沿和下降沿都触发,触发的中断函数为 READ_ENCODER_A 
}

void loop() 
{
    
    
  while(Serial.available()>0)          //检测串口是否接收到了数据
  {
    
    
    Target_Value=Serial.readString();  //读取串口字符串
    Target=Target_Value.toFloat();     //将字符串转换为浮点型,并将其赋给目标值
    Serial.print("目标转速频率:");      //串口打印出设定的目标转速
    Serial.println(Target);


  }
}
/**********外部中断触发计数器函数************
*根据转速的方向不同我们将计数器累计为正值或者负值(计数器累计为正值为负值为计数器方向)
*只有方向累计正确了才可以实现正确的调整,否则会出现逆方向满速旋转
*
*※※※※※※超级重点※※※※※※
*
*所谓累计在正确的方向即
*(1)计数器方向
*(2)电机输出方向(控制电机转速方向的接线是正着接还是反着接)
*(3)PI 控制器 里面的误差(Basi)运算是目标值减当前值(Target-Encoder),还是当前值减目标值(Encoder-Target)
*三个方向只有对应上才会有效果否则你接上就是使劲的朝着一个方向(一般来说是反方向)满速旋转

我例子里是我自己对应好的,如果其他驱动单片机在自己尝试的时候出现满速旋转就是三个方向没对应上

下列函数中由于在A相线上升沿触发时,B相是低电平,和A相线下降沿触发时B是高电平是一个方向,在这种触发方式下,我们将count累计为正,另一种情况将count累计为负
********************************************/
void READ_ENCODER_A() 
{
    
    
    
    if (digitalRead(ENCODER_A) == HIGH) 
    {
    
         
     if (digitalRead(ENCODER_B) == LOW)      
       Count++;  //根据另外一相电平判定方向
     else      
       Count--;
    }
    
    else 
    {
    
        
     if (digitalRead(ENCODER_B) == LOW)      
     Count--; //根据另外一相电平判定方向
     else      
     Count++;
    }
    
}
/**********定时器中断触发函数*********/
void control()
{
    
         

        Velocity=Count;    //把采用周期(内部定时中断周期)所累计的脉冲上升沿和下降沿的个数,赋值给速度
        Count=0;           //并清零
        value=Incremental_PI_A(Velocity,Target);  //通过目标值和当前值在这个函数下算出我们需要调整用的PWM值
        Set_PWM(value);    //将算好的值输出给电机
        
}
/***********PI控制器****************/
int Incremental_PI_A (int Encoder,int Target)
{
    
      
   static float Bias,PWM,Last_bias;                      //定义全局静态浮点型变量 PWM,Bias(本次偏差),Last_bias(上次偏差)
   Bias=Target-Encoder;                                  //计算偏差,目标值减去当前值
   PWM+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias;   //增量式PI控制计算
   
   if(PWM>PWM_Restrict)
   PWM=PWM_Restrict;                                     //限幅
   
   if(PWM<-PWM_Restrict)
   PWM=-PWM_Restrict;                                    //限幅  
   
   Last_bias=Bias;                                       //保存上一次偏差 
   return PWM;                                           //增量输出
}
/**********实际控制函数*********/
void Set_PWM(int motora)                        
{
    
     
  if (motora > 0)                                  //如果算出的PWM为正
  {
    
    
    analogWrite(Motor_AIN1, motora+startPWM);      //让PWM在设定正转方向(我们认为的正转方向)正向输出调整
    analogWrite(Motor_AIN2, 0); 
  }
  else if(motora == 0)                             //如果PWM为0停车
  {
    
    
    analogWrite(Motor_AIN2, 0);
    analogWrite(Motor_AIN1, 0);   
  }
  else if (motora < 0)                              //如果算出的PWM为负
  {
    
    
    analogWrite(Motor_AIN2, -motora+startPWM);      //让PWM在设定反转方向反向输出调整
    analogWrite(Motor_AIN1, 0);
  }
}

El efecto de cargar el código es el siguiente
Inserte la descripción de la imagen aquí
. ¿Cómo se sabe si es una velocidad uniforme?
Si no tiene un osciloscopio de computadora host,
puede imprimir Volocity en el puerto serie. Es una
tontería, pero se puede usar.

void loop() 
{
    
    
  while(Serial.available()>0)
  {
    
    
    Target_Value=Serial.readString();
    Target=Target_Value.toFloat();
    Serial.print("目标转速频率:");
    Serial.println(Target);
  }
  Serial.println(Velocity);     //这句是新加的
}

Por ejemplo, si ingreso un 10, puedo ver que la velocidad de salida fluctuará alrededor de 10. Corto una imagen que está temblando. De hecho, la velocidad de salida permanece en 10 la mayor parte del tiempo, y la velocidad de salida no excederá [9.11]. Flotará en este rango, que es 1 hacia arriba y hacia abajo.
Inserte la descripción de la imagen aquí
Si tiene un osciloscopio de computadora host, será más cómodo de ver. La
línea amarilla es el valor PWM para ajustar la salida de velocidad, la línea blanca es el valor real y la línea roja es el valor objetivo. La
línea roja coincide básicamente con la línea blanca. No puedo verla.
Inserte la descripción de la imagen aquí
Echemos un vistazo más de cerca a la desviación entre la línea blanca y la línea roja, que no no exceda 1. Las cuatro ruedas están ajustadas a este nivel. El efecto real es bastante bueno. Creo que es suficiente. Por supuesto, puedes ajustarlo.
Inserte la descripción de la imagen aquí

5.Kp, ajuste de parámetros Ki

Bien, entonces la pregunta clave es cómo ajustar los parámetros de Kp y Ki.
De hecho, debido a que solo usamos dos parámetros, es mejor ajustar
1. En términos generales, el primer parámetro Kp mantiene el valor real en un punto flotante estable . El efecto de un valor fijo hacia arriba y hacia abajo. El tamaño del parámetro Kp está relacionado con la capacidad del variador del motor y el valor de voltaje de la fuente de alimentación del variador. Cuanto más fuerte sea la capacidad del variador, mayor será el Kp. La situación es diverso. Solo sigue intentando ver qué parámetro tiene el mayor efecto. Bueno, la amplitud de oscilación es la más pequeña y el número de oscilaciones es el menor.
Personalmente, siento que el método de ajuste es diferente de la posición PID. No quiero hago demasiadas explicaciones complicadas.
Pero aún puedo darle algunas sugerencias. Tome los parámetros de mi ejemplo como ejemplo, yo utilizo Es A4950, fuente de alimentación de 12 V, el parámetro utilizado es Velocity_KP = 7.2, si usa una combinación de variador que es más fuerte que el mío (el módulo de accionamiento es mejor que el mío, y el voltaje de accionamiento es más alto que el mío), entonces puedes usar los parámetros de mi ejemplo Empezar a probar poco a poco, por cierto, la capacidad de conducción de L298N es similar al de A4950.

2. El segundo parámetro Ki desempeña el papel de convertir este valor fijo en el valor objetivo. Se utiliza para eliminar el error de estado estable, también conocido como error estático. ¿Cómo funciona específicamente?
Usé los parámetros en el ejemplo anterior .

Velocity_KP =7.2, Velocity_KI =0.68

Luego cambié Ki a 0

// An highlighted block
Velocity_KP =7.2, Velocity_KI =0

Habrá la siguiente situación. Aunque la línea blanca también fluctúa en un valor fijo, este valor fijo obviamente se desvía de nuestro valor objetivo, es decir, la línea roja. Si no comprende este principio, puede buscar el Error de estado estable, comenzando desde Ki Esto es para eliminar el efecto del error de estado estable.
Inserte la descripción de la imagen aquí
Asignemos Velocity_KI a 0.68 nuevamente.
Puede ver que las líneas rojas y blancas comienzan a "enredarse" nuevamente.
Inserte la descripción de la imagen aquí
En el ejemplo de control PI donde el coche quiere estar a una velocidad constante, este Ki no necesita ser demasiado grande.

6. Posdata

En el último ajuste de parámetros, he leído mucho antes, este artículo sobre ajuste de parámetros, hay muchas fórmulas y así sucesivamente, personalmente siento que no es muy fácil de entender, y básicamente se usa para el primer tipo de posición PID Sí, y luego no me siento tan feliz como si lo hubiera intentado directamente. Probablemente primero ajusté Kp para estabilizar el sistema, y ​​luego Ki dejó que el sistema eliminara el error estático y lo estabilizara en el valor estable. La primera vez que escribí el PID, estaba un poco asustado, asustado de mí mismo. Qué parte de entendimiento no está en su lugar, engaña a todos, si hay algo mal en la escritura, espero que pueda criticarlo y corregirlo, y espero ayudar Uds

Supongo que te gusta

Origin blog.csdn.net/chrnhao/article/details/112639533
Recomendado
Clasificación