Comparing PID_v1.h in Arduino to PID(z) in Simulink

Discussion about events, resources, or any topic not related to one of the project forums below.
zhuzhu
Posts: 1
Joined: Tue Dec 19, 2017 10:22 pm

Comparing PID_v1.h in Arduino to PID(z) in Simulink

Postby zhuzhu » Tue Dec 19, 2017 10:45 pm

Hi to all, there are some problems I met if had any good ideas, please suggest, thank you so much. :arrow: I am trying to implement model-based controllers in Arduino. I have explored several control systems in Simulink and now I want to see if I can replicate those simulations in Arduino.

For instance, I have a discrete model, H(z) that takes the form of:

0.02926
----------
z - 0.9512
The open-loop step response is a characteristic over-damped system. Using the method provided by Marko (sorry, I can't link more than 2 links) I was able to simulate the system, along with any other discrete transfer function, in Arduino perfectly. Now I want to implement a closed-loop PID control in Arduino and compare the simulation to Simulink. I expect to have an error of 0, as I did when implementing the discrete model.

To do this, I used the PID_v1 library to implement closed-loop control in Arduino. Here a snippet of code that shows this:

#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;
}
}
In Simulink, the system looks like this. When executing the simulations and comparing the closed-loop response of both PID systems (Arduino and Simulink) they are muchdifferent. I kept the gains of both PIDs systems (in Arduino and Simulink) the same as well as the sampling time.

My question is, how can I setup the Simulink PID(z) block in Simulink to mimic the PID Arduino library? I am relatively weak in Simulink and there are so many parameters that can get manipulated to achieve specific performance. I'd rather use the PID block versus writing my own code.

EDIT: Doing some more testing. I replaced the PID block in Simulink with a gain of 1, and then Kp = 1 with Ki = 0 and Kd = 0 in Arduino. There is a tiny difference with the model output. I believe my problem has something to do with data types/precision in floating point numbers.
Thanks all!

Return to “General Discussion”

Who is online

Users browsing this forum: No registered users and 2 guests