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.