Arduino stops sending data after 3 minutes and needs to be reseted to work again

Hello,

I’m working on a program which will publish 1 float data (3 floating points) for every each 10 ms (approximately) to the Serial Monitor. Everything is working well, but after 3 minutes, the Serial Monitor stops publishing the data. Moreover, I notice that about 10 last data published on the Serial Monitor are not correct (For example, my correct value is 1.212, and it publishes 0.053). I tried Serial.flush() but it doesn’t get much better. When I change to lower baudrate, Arduino can send data for a longer period but still stops after a while.

Here is my Arduino code (it is quite long but just ignore how I process my data value):

#include <Math.h>

uint8_t temp;
uint8_t i, j = 0;
unsigned long previous = 0;
int mod_11k = 12; 
int mod_17k = 13; 
int16_t data_toSend[6]={0,0,0,0,0,0};
float s1_11k;
float s2_11k;
float s1_17k;
float s2_17k;

float P1[4];float P2[4];float P3[4]; float P4[4];float P5[4];float P6[4];
float xprec1[2];float xprec2[2];float xprec3[2];float xprec4[2];float xprec5[2];float xprec6[2];
float *sol1;float *sol2;float *sol3; float *sol4;float *sol5;float *sol6;
float *sf_11k;
float *sf_17k;
float Te;
float Tbeg;
float temp_var1;
float temp_var2;
float temp_var;
float height;

void setup() { 
  pinMode(mod_11k,OUTPUT);  
  pinMode(mod_17k,OUTPUT);
  digitalWrite(mod_11k,LOW);
  digitalWrite(mod_17k,LOW);
 
  Serial.begin(9600);

//---------------------------------------------------Initialize Kalman Filter---------------------------------//
float qkf = 0.0005;

 P1[0] = qkf; P1[1] =0; P1[2] =0; P1[3] = qkf;
 P2[0] = qkf; P2[1] =0; P2[2] =0; P2[3] = qkf;
 P3[0] = qkf; P3[1] =0; P3[2] =0; P3[3] = qkf;
 P4[0] = qkf; P4[1] =0; P4[2] =0; P4[3] = qkf;
 P5[0] = qkf; P5[1] =0; P5[2] =0; P5[3] = qkf;
 P6[0] = qkf; P6[1] =0; P6[2] =0; P6[3] = qkf;
 xprec1[0] =0; xprec1[1] =0;
 xprec2[0] =0; xprec2[1] =0;
 xprec3[0] =0; xprec3[1] =0;
 xprec4[0] =0; xprec4[1] =0;
 xprec5[0] =0; xprec5[1] =0;
 xprec6[0] =0; xprec6[1] =0;

Tbeg = millis();

//Get raw ANALOG DATA
digitalWrite(mod_11k,HIGH);
delayMicroseconds(4000);
data_toSend[0] = analogRead(0);  
data_toSend[1] = analogRead(1);
data_toSend[2] = analogRead(2);
digitalWrite(mod_11k,LOW);
delayMicroseconds(200);
digitalWrite(mod_17k,HIGH);
delayMicroseconds(4000);
data_toSend[3] = analogRead(0);
data_toSend[4] = analogRead(1);
data_toSend[5] = analogRead(2);
digitalWrite(mod_17k,LOW);
delayMicroseconds(200);

//Save raw ANALOG data
xprec1[0] = data_toSend[0];
xprec2[0] = data_toSend[1]; 
xprec3[0] = data_toSend[2];
xprec4[0] = data_toSend[3];
xprec5[0] = data_toSend[4]; 
xprec6[0] = data_toSend[5];

//Filter with Kalman
Te = (millis() - Tbeg)/1000;
sol1 = Fkalman(xprec1,data_toSend[0],P1,Te);
sol2 = Fkalman(xprec2,data_toSend[1],P2,Te);
sol3 = Fkalman(xprec3,data_toSend[2],P3,Te);
sol4 = Fkalman(xprec4,data_toSend[3],P4,Te);
sol5 = Fkalman(xprec5,data_toSend[4],P5,Te);
sol6 = Fkalman(xprec6,data_toSend[5],P6,Te);
Tbeg= millis();
}


void loop()
{
    tick();
}


void tick() {
   
    P1[0] =sol1[2]; P1[1] =sol1[3]; P1[2] =sol1[4]; P1[3] =sol1[5];
    P2[0] =sol2[2]; P2[1] =sol2[3]; P2[2] =sol2[4]; P2[3] =sol2[5];
    P3[0] =sol3[2]; P3[1] =sol3[3]; P3[2] =sol3[4]; P3[3] =sol3[5];
    P4[0] =sol4[2]; P4[1] =sol4[3]; P4[2] =sol4[4]; P4[3] =sol4[5];
    P5[0] =sol5[2]; P5[1] =sol5[3]; P5[2] =sol5[4]; P5[3] =sol5[5];
    P6[0] =sol6[2]; P6[1] =sol6[3]; P6[2] =sol6[4]; P6[3] =sol6[5];
    xprec1[0] =sol1[0]; xprec1[1] =sol1[1];
    xprec2[0] =sol2[0]; xprec2[1] =sol2[1];
    xprec3[0] =sol3[0]; xprec3[1] =sol3[1];
    xprec4[0] =sol4[0]; xprec4[1] =sol4[1];
    xprec5[0] =sol5[0]; xprec5[1] =sol5[1];
    xprec6[0] =sol6[0]; xprec6[1] =sol6[1];
    free(sol1);                                        // Free the stocking space of KalmanFilter function variable
    free(sol2);
    free(sol3);
    free(sol4);                                        // Free the stocking space of KalmanFilter function variable
    free(sol5);
    free(sol6);

    //Get raw ANALOG data
    digitalWrite(mod_11k,HIGH);
    delayMicroseconds(4000);
    data_toSend[0] = analogRead(0);   //phi1 11k
    data_toSend[1] = analogRead(1); //phi2 11k
    data_toSend[2] = analogRead(2);
    digitalWrite(mod_11k,LOW);
    delayMicroseconds(200);
    digitalWrite(mod_17k,HIGH);
    delayMicroseconds(4000);
    data_toSend[3] = analogRead(0);
    data_toSend[4] = analogRead(1);
    data_toSend[5] = analogRead(2);
    digitalWrite(mod_17k,LOW);
    delayMicroseconds(200);
    Te = (millis() - Tbeg)/1000;
    
    //Kalman Filter
    sol1 = Fkalman(xprec1,data_toSend[0],P1,Te);           // Filtrage des mesures led1
    sol2 = Fkalman(xprec2,data_toSend[1],P2,Te);
    sol3 = Fkalman(xprec3,data_toSend[2],P3,Te);
    sol4 = Fkalman(xprec4,data_toSend[3],P4,Te);           // Filtrage des mesures led2
    sol5 = Fkalman(xprec5,data_toSend[4],P5,Te);
    sol6 = Fkalman(xprec6,data_toSend[5],P6,Te);
    Tbeg= millis();
    
    data_toSend[0] = sol1[0];
    data_toSend[1] = sol2[0];
    data_toSend[2] = sol3[0];
    data_toSend[3] = sol4[0];
    data_toSend[4] = sol5[0];
    data_toSend[5] = sol6[0];

    //Processing filtered analog data
    sf_11k = traitement1(data_toSend[0],data_toSend[1],data_toSend[2]);
    sf_17k = traitement1(data_toSend[3],data_toSend[4],data_toSend[5]);
    s1_11k = sf_11k[0];
    s2_11k = sf_11k[1];
    s1_17k = sf_17k[0];
    s2_17k = sf_17k[1];
    temp_var1 = -24.946*((tan(s1_11k)-tan(s1_17k))*(tan(s1_11k)-tan(s1_17k)))+7.9023*(tan(s1_11k)-tan(s1_17k))-0.3583;
    temp_var2 = -8.0096*((tan(s2_11k)-tan(s2_17k))*(tan(s2_11k)-tan(s2_17k)))+0.4445*(tan(s2_11k)-tan(s2_17k))-0.1195;
    temp_var = sqrt(temp_var1*temp_var1+temp_var2*temp_var2);
    height = 0.2/temp_var;

   //Send height value to Serial
    Serial.print(height,3);
    Serial.print('\n');
}


float *Fkalman(float xprec[2],float ymes,float P[4],float Te){ 
    float *sol = NULL ;
    sol = (float*) malloc (sizeof(float) * 6);
    float xpred[2];
    float Ppred[4] ;
    float Kf[2] ;
    float q = 0.0005;
    float r = 30;

    //x prediction
    xpred[0] = xprec[0] + Te*xprec[1];
    xpred[1] = xprec[1]; 

    //P_pred = F.P.F'+Q
    Ppred[0] = q + P[0]+ Te*(P[2] +P[1]+Te*P[3]);
    Ppred[1] = P[1] + Te*P[3];
    Ppred[2] = P[2] + Te*P[3] ;
    Ppred[3] = q+ P[3];

    //Kf = (P_pred.C').inv(C.P_pred.C'+R)
    Kf[0]  = (Ppred[0]/(r+Ppred[0]));
    Kf[1]  = (Ppred[2]/(r+Ppred[0]));

    //X_est  
    sol[0] = xpred[0] + Kf[0]*(ymes-xpred[0]);
    sol[1] = xprec[1] + Kf[1]*(ymes-xprec[0]);

    //P_est = (I-Kf*C)*P_pred
    sol[2] = Ppred[0]*(1-Kf[0]);
    sol[3] = Ppred[1]*(1-Kf[0]);
    sol[4] = -Kf[1]*Ppred[0]+Ppred[2];
    sol[5] = -Kf[1]*Ppred[1]+Ppred[3];
    return sol;
  }

    float *traitement1(float mes1,float mes2,float mes3)
  {
    float *sol11 = NULL ;
    sol11 = (float*) malloc (sizeof(float) * 2);
    sol11[0] = (mes1-mes2)/(mes1+mes2);
    sol11[1] = (((mes1+mes2)/2)-mes3)/(((mes1+mes2)/2)+mes3);
    return sol11;
  }

Does anyone have some idea about this problem? I guess the memory or buffer are filling due to some variables?

Thank you

Since you're doing tons of memory allocation/de-allocation, you probably have a leak. I would add print statements that display the free memory on each pass of loop(), and I bet you see the number ticking down to near zero before the crash.

Regards,
Ray L.

And if you have only 2k of SRAM allocating and deallocating memory is a bit like playing with petrol (gasoline) on Guy Fawkes night.

...R

Every time you call tick(), you allocate memory for sf_11k and sf_17k, which are NEVER freed!

And if you have only 2k of SRAM allocating and deallocating memory is a bit like playing with petrol (gasoline) on Guy Fawkes night.

That is just paranoid nonsense. If the memory is allocated and freed properly with a well understood pattern, and worst-case memory usage is well understood, there is NO reason for this to be a problem, even with much less than 2K of RAM. Proper use of malloc/new/free is perfectly safe, even with small memory systems. In this case, the pattern is clear, the worst-case usage (not counting the obvious bugs in the code at present) is also very clear. Once the bugs are corrected, it should work perfectly for indefinite periods of time.

Regards,
Ray L.

RayLivingston:
Proper use of malloc/new/free is perfectly safe, even with small memory systems.

Indeed. But that does not seem to be the case here.

And there are many examples of memory leaks causing problems on PCs with gigabytes of memory and professional programmers.

...R

RayLivingston:
Every time you call tick(), you allocate memory for sf_11k and sf_17k, which are NEVER freed!

That is just paranoid nonsense. If the memory is allocated and freed properly with a well understood pattern, and worst-case memory usage is well understood, there is NO reason for this to be a problem, even with much less than 2K of RAM. Proper use of malloc/new/free is perfectly safe, even with small memory systems. In this case, the pattern is clear, the worst-case usage (not counting the obvious bugs in the code at present) is also very clear. Once the bugs are corrected, it should work perfectly for indefinite periods of time.

Regards,
Ray L.

Yes, and if you really know what you are doing, then playing with gasoline around a fire is perfectly safe. I think the point is about folks doing so when they have absolutely no clue.

What's not clear in this code is why there needs to be ANY dynamic allocation at all. It's tossed, re-allocated, then used on every pass of loop. There isn't a reason in the world I can see that it couldn't be static-allocated. Seems like someone just decided to complicate the code for no good reason.

Regards,
Ray L.