Comparando PID_v1.h en Arduino con PID (z) en Simulink

0

Estoy intentando implementar controladores basados en modelos en Arduino. He explorado varios sistemas de control en Simulink y ahora quiero ver si puedo replicar esas simulaciones en Arduino.

Por ejemplo, tengo un modelo discreto, H (z) que toma la forma de:

  0.02926
  ----------
  z - 0.9512

La respuesta escalonada de bucle abierto es un sistema con amortiguación característica. Usando el método provisto por Marko (lo siento, no puedo enlazar más de 2 enlaces) pude simular el sistema, junto con cualquier otra función de transferencia discreta, en Arduino perfectamente. Ahora quiero implementar un control PID de ciclo cerrado en Arduino y comparar la simulación con Simulink. Espero tener un error de 0, como lo hice cuando implementé el modelo discreto.

Para hacer esto, usé la infame biblioteca PID_v1 para implementar el control de ciclo cerrado en Arduino. Aquí un fragmento de código que muestra esto:

#include <PID_v1.h>

double Setpoint = 25;
double Input = 0;
double Output = 0;

double Kp = 20;
double Ki = 10;
double Kd = 0;

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

const double T = 0.05;

const double a = 0;
const double b = 0.02926;
const double c = 0;
const double d = 1;
const double e = -0.9512;
const double f = 0;

const double A_D = a/d;
const double B_D = b/d;
const double C_D = c/d;
const double E_D = e/d;
const double F_D = f/d;

double y0 = 0; // y[n]
double y1 = 0; // y[n - 1]
double y2 = 0; // y[n - 2]
double x0 = 0; // x[n]
double x1 = 0; // x[n - 1]
double x2 = 0; // x[n - 2]

double model_output = 0;

double elapsedTime = 0;
volatile bool interrupt_flag = true;
int timer1_counter;

void setup() {
  Serial.begin(115200);

  // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;

  // Set timer1_counter to the correct value for our interrupt interval
//  timer1_counter = 64286;   // preload timer 65536-16MHz/256/50Hz (20 ms)
  timer1_counter = 62411;   // preload timer 65536-16MHz/256/20Hz (50 ms)
//  timer1_counter = 3036;   // preload timer 65536-16MHz/256/1Hz (1000 ms)

  TCNT1 = timer1_counter;   // preload timer
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts

  myPID.SetSampleTime(T*1000);
  myPID.SetMode(AUTOMATIC);
}

ISR(TIMER1_OVF_vect) {        // ISR 
  TCNT1 = timer1_counter;   // preload timer
  interrupt_flag = true;
}

double sys(double x0) {
  y0 = (A_D * x0) + (B_D * x1) + (C_D * x2) - (E_D * y1)  - (F_D * y2);
  x2 = x1;
  x1 = x0;
  y2 = y1;  
  y1 = y0;
  return y0;
}

void loop() {
  myPID.Compute();
  if (interrupt_flag) {
    interrupt_flag = false;
    model_output = sys(Output);
    Input = model_output;
    Serial.print(elapsedTime);
    Serial.print('\t');
    Serial.println(model_output, 4);
    elapsedTime += T;
  }
}

En Simulink, el sistema se parece a this . Al ejecutar las simulaciones y comparar la respuesta en bucle cerrado de ambos sistemas PID (Arduino y Simulink), son muy diferentes . Mantuve las ganancias de ambos sistemas PID (en Arduino y Simulink) al igual que el tiempo de muestreo.

Mi pregunta es, ¿cómo puedo configurar el bloque Simulink PID (z) en Simulink para imitar la biblioteca PID Arduino? Soy relativamente débil en Simulink y hay muchos parámetros que pueden manipularse para lograr un rendimiento específico. Prefiero usar el bloque PID en lugar de escribir mi propio código.

EDITAR: Haciendo algunas pruebas más. Reemplacé el bloque PID en Simulink con una ganancia de 1, y luego Kp = 1 con Ki = 0 y Kd = 0 en Arduino. Hay una pequeña diferencia con la salida del modelo. Creo que mi problema tiene algo que ver con los tipos de datos / precisión en los números de punto flotante.

    
pregunta Danny Gelman

0 respuestas

Lea otras preguntas en las etiquetas