Arduino-MATLAB communication using SerialEvent() for PID Loop

Hello,

I have an arduino code for driving a peltier pile to a given set point (TEMP_SP). I am trying to input the set temperature from Matlab GUI (with different protocols, user will enter n temperatures and the time intervals, arduino will implement the PID controller and output the temperature to MATLAB every 1 seconds via serial communication.

I have a serious problem and I would appreciate any help. :confused:

My PID is working with arduino, I can send and receive data to/from matlab/arduino. I am using SerialEvent() to read the messages from matlab and print the responses accordingly.

The problem is that, (maybe because there is a huge delay between matlab and arduino), when I set a temperature from matlab, my peltier temperature jumps up and down crazily. E.g. I set 20 degrees celcius, my peltier jumps up to 35-40 degrees, then toggles around lower temperatures that are not super related to my set temperature. This does not happen when I run the PID on arduino and set the temperature directly from there.

PS: I am reading the temperature using a thermistor. I am changing the voltage using an external DAC and a shifter circuit because I need to both heat up and cool down ( the peltier terminals should change signs)

Algorithm:
-Set temperature (TEMP_SP)
-Read thermistor voltage-->convert to resistance-->convert to temperature (this is current state, T_C_CS)
-Find DAC output from PID
-SerialEvent() runs after every loop() to check if there's message coming from matlab and sets its flag accordingly.
-In each loop, check stringComplete flag and change the set temperature or print the current temperature.

This is my Arduino code:

#include <Wire.h>
#include <Adafruit_MCP4725.h>
#include <PID_v1.h>
Adafruit_MCP4725 dac; // constructor

uint32_t dac_value;

// Thermistor variables
float Rref=10000; //ohms, resistance of thermistor at 25C
float B25=3977;
float TOLB=0.75;
float A=-14.6337;
float B=4791.842;
float C=-115334;
float D=-3.730535E+06;
float A1t=3.354016E-03;
float B1t=2.569850E-04;
float C1t=2.620131E-06;
float D1t=6.383091E-08;
float Vdd=5; //volts
float R_divider=10000;//ohms

//CURRENT STATE
float Vt_CS_val; //current thermistor voltage value
float Vt_CS; //current thermistor voltage
float Rt_CS;//current thermistor resistance
float T_K_CS; //current temperature in K
float T_C_CS; //current temperature in C
float input_CS_val;// current input from the DAC
float input_CS;// current input from the DAC

//SET POINT
float TEMP_SP=20; //desired temperature (celcius)
float TEMP_SP_K; //desired temperature (Kelvin)
float R_SP; //desired resistance for the TEMP_SP_K
float Vt_SP; //desired thermistor voltage

//DAC output
float DAC_val;
float DAC_OUT;//DAC output voltage
//double PID_OUT;

//Custom PID
float der = 0;
float err;
float err_p;
float integral;

//PID set
float Kp=1.0, Ki=0.003, Kd=10.0;
float output;
int state=1;

float read_voltage;
float temp_rec;
float temp_new=20;

String inputString = ""; // a string to hold incoming data

String READ = "R";
boolean stringComplete = false; // whether the string is complete

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

dac.begin(0x62); // The I2C Address: Run the I2C Scanner if you're not sure
DAC_val=2080;//2.54V
dac.setVoltage(DAC_val, false); //819:1V, 3276:4V

// reserve 200 bytes for the inputString:
inputString.reserve(200);

Serial.println('a');
char a = 'b';
while(a != 'a')
{
a = Serial.read();
}
}

void loop() {

Vt_CS_val = analogRead(A1);
Vt_CS=5.0Vt_CS_val/1024.0; //current voltage on thermistor, current temp
Rt_CS=R_divider
Vt_CS/(Vdd-Vt_CS);

//Given R, find T
T_K_CS=pow((A1t+B1tlog(Rt_CS/Rref)+C1tpow((log(Rt_CS/Rref)),2)+D1t*pow((log(Rt_CS/Rref)),3)),-1); //KELVIN
T_C_CS=T_K_CS-273.15; //current Celcius

///////PROCESS SET POINT

TEMP_SP_K=TEMP_SP+273.15; //Celcius to K
//Given T_SP, find R_SP
R_SP=Rref*exp(A+B/TEMP_SP_K+C/pow(TEMP_SP_K,2)+D/pow(TEMP_SP_K,3)); // R_SP

// find Vt_SP

Vt_SP=R_SP*Vdd/(R_SP+R_divider); //Set voltage for thermistor divider. Aim: Vt_SP=Vt_CS

err = Vt_SP - Vt_CS;
integral = integral + err;

output = Kp * err + (Ki * integral) + (Kd * der );
err_p = err;

DAC_OUT = -output + 2.5;

if (DAC_OUT< 1)
DAC_OUT = 1;
if (DAC_OUT > 4)
DAC_OUT = 4;

DAC_val=4096*DAC_OUT/5;

dac.setVoltage((int)DAC_val, false);

// print the answer when message arrives:

if (stringComplete) {

inputString.trim(); //remove newline characters or blanks

if( inputString==READ){

Serial.println(T_C_CS); //print the current temp

}
else //number came, take as temperature
{
temp_new=inputString.toFloat(); //set new temperature

TEMP_SP=temp_new;

Serial.println(TEMP_SP); //send the set temp back

}
inputString = "";
stringComplete = false;
}
}

void serialEvent() {

while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}

Here is my matlab code:

%open serial object (working)

delete(instrfind({'Port'},{'COM11'}));%clear the port
%global ard;
if(~exist('serialFlag','var'))
[ard,serialFlag] = setupSerial('COM11');
end
disp('Connection successful');

isvalid=isvalid(ard);

%send set temperature (I am getting 28.00 back as TEMP_SP, so working)
x=28;
fprintf(ard,num2str(x));
msg=fscanf(ard);
disp(msg);

%read the temperature back every 3 seconds
while(1)

fprintf(ard,'R');
msg=fscanf(ard);
disp(msg);
pause(3);
end

It looks like you have blocking code in your serialEvent() function (using WHILE). My advice is not to use serialEvent() and use, instead, one of the examples (perhaps the second) in Serial Input Basics. Those examples are non-blocking.

...R

If you've got a complete string, then break out of the while(). Otherwise you may get the first few characters of the next string added to the end of the 'complete' string.

@troubled_grad, I forgot to say please modify your post and use the code button </> so your code looks like this and is easy to copy to a text editor. See How to use the Forum

...R