I have a program which estimates battery capacity, range as well as runs different control loops on an arduino MEGA2560 to control an eBike. I was using floating points which gave me quite a slow sampling frequency (10Hz). I now changed this to use integers by multiplying everything by at least 1000 so I can still keep a 3 decimal accuracy. However, as soon as the Arduino leaves setup and starts running loop, it crashes and restarts. I have a doubt that this could be due to the fact that my program takes too much RAM. How could I solve this?
Here is my code:
#include <EEPROM.h>
#include <memorysaver.h>
//#include <TFT_HX8357.h> // Hardware-specific library
#include <URTouch.h>
#include <URTouchCD.h>
#include <memorysaver.h>
#include <UTFT.h>
//TFT_HX8357 myGLCD = TFT_HX8357(); // Invoke custom library#include <TFT_HX8357.h> // Hardware-specific library
//
//TFT_HX8357 myGLCD = TFT_HX8357(); // Invoke custom library
UTFT myGLCD(ILI9481,38,39,40,41);
URTouch myTouch(6, 5, 4, 3, 2);
int buttonst, horn=5, throttle=8, powermode=1, alarmsystem=1, xtouch, ytouch, k1=0, k2=0,modechange,ncycles, p=9, divider=12, addresstd=0, kpow[3]={0,0,0}, kcur[3]={25,0,0}, ksp[3]={0,0,0};
long pushed, pushedt, timesp, timespm1, powtimesm, factor, powtimesp, start, elapsed, powtime, powresttime, shuntvoltage, batvoltage, current, power, consumah, capacstore, consumwh, consumbatper, consumbatrange, distance, distanceint, throttlein, throttleout, distancedisp, Totaldist, velocity, Totaldistcheck;
long throttlesmooth, capaccheck, capacactual,consumahstore, errorpower[2], errorpoweri, errorpowerli, errorcuri, errorcurrent[2], errorpowerl[2], diff, errorspeed[2], errorisp, outspeed, outcurrentctl, outspeedctl, elapsedtot, errorsmooth[2];
float internresistance=0.00112;
long batteryspec[6][56]={{4200,4000,3940,3900,3876,3860,3852,3844,3826,3809,3795,3783,3765,3744,3728,3710,3692,3672,3650,3631,3613,3591,3573,3556,3532,3508,3488,3463,3439,3417,3399,3380,3366,3352,3332,3312,3291,3273,3253,3237,3217,3196,3176,3150,3123,3087,3051,2994,2929,2868,2796,2727,2650,5261,2502},//5A discharge 18650GA SPEC
{1,2,15,47,85,133,186,244,309,383,447,506,554,612,681,735,793,852,921,1007,1081,1150,1236,1300,1358,1438,1518,1587,1667,1747,1822,1888,1955,2014,2072,2152,2232,2317,2389,2466,2524,2594,2658,2722,2786,2847,2925,2983,3063,3133,3186,3245,3293,3330,3357,3368},
{4200,4020,3980,3945,3927,3914,3904,3890,3874,3860,3843,3821,3797,3776,3756,3734,3713,3695,3675,3652,3634,3614,3593,3569,3543,3522,3500,3480,3459,3441,3419,3398,3378,3360,3339,3321,3301,3278,3254,3230,3199,3164,3128,3085,3037,2990,2937,2878,2837,2795,2746,2693,2648,2598,2549,2496},
{0,7,33,84,151,223,294,377,457,521,574,646,718,785,851,931,1011,1091,1171,1251,1323,1397,1469,1547,1632,1701,1778,1853,1928,1994,2088,2175,2258,2333,2413,2487,2562,2634,2706,2775,2842,2908,2697,3023,3074,3116,3159,3205,3234,3261,3287,3314,3333,3352,3365,3379},//3A discharge 18650GA SPEC
{4200,4131,4094,4073,4054,4038,4028,4015,4003,3985,3965,3945,3921,3894,3870,3850,3830,3811,3795,3775,3759,3739,3716,3692,3674,3648,3623,3601,3578,3561,3542,3522,3502,3486,3467,3445,3423,3401,3374,3350,3324,3291,3253,3210,3168,3123,3075,3026,2964,2897,2838,2781,2715,2652,2585,2502},
{0,0,36,84,154,223,289,356,420,489,553,620,686,761,838,908,985,1054,1134,1214,1283,1358,1438,1523,1584,1667,1755,1835,1920,2002,2085,2170,2255,2327,2402,2482,2567,2644,2724,2791,2850,2908,2964,3015,3058,3095,3132,3167,3207,3245,3271,3295,3320,3336,3354,3365}}; //1A discharge 18650GA SPEC
long cyclicspec[2][44]={{0,894,7151,16090,26400,37500,50950,61680,74190,85360,96540,107260,118880,130950,142120,154640,168040,182350,194860,208270,219890,234200,246700,262800,276200,291400,303900,317300,3271500,341500,354000,364000,374500,383460,395080,405800,418300,431700,444000,455900,468800,481900,491600,499700},
{3441,3435,3342,3292,3235,3178,3121,3078,3014,2957,2921,2892,2842,2792,2750,2721,2679,2643,2607,2564,2543,2507,2479,2436,2407,2379,2357,2336,2336,2336,2336,2336,2336,2321,2300,2279,2271,2243,2229,2214,2193,2179,2164,2157}};
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];
void EEPROMWritelong(int address, long value)
{
//Decomposition from a long to 4 bytes by using bitshift.
//One = Most significant -> Four = Least significant byte
byte four = (value & 0xFF);
byte three = ((value >> 8) & 0xFF);
byte two = ((value >> 16) & 0xFF);
byte one = ((value >> 24) & 0xFF);
//Write the 4 bytes into the eeprom memory.
EEPROM.write(address, four);
EEPROM.write(address + 1, three);
EEPROM.write(address + 2, two);
EEPROM.write(address + 3, one);
}
long EEPROMReadlong(int address)
{
//Read the 4 bytes from the eeprom memory.
long four = EEPROM.read(address);
long three = EEPROM.read(address + 1);
long two = EEPROM.read(address + 2);
long one = EEPROM.read(address + 3);
//Return the recomposed long by using bitshift.
return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}
long pidcurrent_control() {
long dt, outcurrent=0, outpower=0;
int i=0, descurrent, despower;
i++;
dt=millis()-powtime;
powtime = millis();
if (powermode==1) { //Furo default mode
if (current>40000) {
descurrent=40000;
errorcurrent[1]=descurrent-current;
if (i>=2) {
//Integrate the error
errorcuri+=errorcurrent[1]*dt;
outcurrent=(kcur[0]*errorcurrent[1]+kcur[1]*errorcuri+kcur[2]*((errorcurrent[1]-errorcurrent[0])/dt));
}
errorcurrent[0]=errorcurrent[1];
return outcurrent;
}
if (((batvoltage*current)/1000)>2000000) {
despower=2000000;
errorpower[1]=despower-batvoltage*current/1000;
if (i>=2) {
//Integrate the error
errorpoweri+=errorpower[1]*dt;
outpower=kpow[0]*errorpower[1]+kpow[1]*errorpoweri+kpow[2]*((errorpower[1]-errorpower[0])/dt);
}
errorpower[0]=errorpower[1];
return outpower;
}
}
else { //Eco mode
despower=550000;
errorpowerl[1]=despower-batvoltage*current/1000;
if (i>=2) {
//Integrate the error
errorpowerli+=errorpowerl[1]*dt;
outpower=kpow[0]*errorpowerl[1]+kpow[1]*errorpowerli+kpow[2]*((errorpowerl[1]-errorpowerl[0])/dt);
}
errorpowerl[0]=errorpowerl[1];
return outpower;
}
}
void cyclescaling() {
int j=1;
if (ncycles<=499000) {
while ((ncycles<cyclicspec[0][j-1])||(ncycles>cyclicspec[0][j])){
j++;
}
factor=(cyclicspec[1][j-1]+(ncycles-cyclicspec[0][j-1])*(cyclicspec[1][j]-cyclicspec[1][j-1])/(cyclicspec[0][j]-cyclicspec[0][j-1]))/cyclicspec[1][0];
}
else {
factor=(cyclicspec[1][41]+(ncycles-cyclicspec[0][41])*(cyclicspec[1][42]-cyclicspec[1][41])/(cyclicspec[0][42]-cyclicspec[0][41]))/cyclicspec[1][0];
}
}
long pidspeed_control() {
int isp, dtsp;
isp++;
dtsp=millis()-powtimesp;
powtimesp = millis();
errorspeed[1]=46000-velocity;
if (isp>=2) {
errorisp+=errorspeed[1]*dtsp;
outspeed=(ksp[0]*errorspeed[1]+ksp[1]*errorisp+ksp[2]*((errorspeed[1]-errorspeed[0])/dtsp));
}
errorspeed[0]=errorspeed[1];
return outspeed;
}
void throttlesmoothing() {
int i=0, dtsm;
i++;
long currentmap=map(throttlein,800,3600,0,40000);
dtsm=millis()-powtimesm;
powtimesm = millis();
errorsmooth[1]=currentmap-current;
if (i>=2) {
//Integrate the error
throttlesmooth=kcur[0]*errorsmooth[1];//+kcur[2]*((errorsmooth[1]-errorsmooth[0])/dtsm);
}
errorsmooth[0]=errorsmooth[1];
}
void SOC() {
int currentref=current/p, compbat=batvoltage/14;
int j=1,l=1;
long stateofc1=0, stateofc2=0;
if (currentref<=1000){
while (((compbat)>batteryspec[0][j-1])||((compbat)<batteryspec[0][j])){
j++;
}
capacactual=(batteryspec[1][55]-(batteryspec[1][j-1]+(compbat-batteryspec[0][j-1])*(batteryspec[1][j]-batteryspec[1][j-1])/(batteryspec[0][j]-batteryspec[0][j-1])))*p;
Serial.println("\n");
Serial.println(current);
Serial.println(batvoltage);
Serial.println(batteryspec[1][j-1]);
}
if ((currentref>1000)&&(currentref<=3000)){
while (((compbat)>batteryspec[0][j-1])||((compbat)<batteryspec[0][j])){
j++;
}
stateofc1=(batteryspec[1][55]-(batteryspec[1][j-1]+(compbat-batteryspec[0][j-1])*(batteryspec[1][j]-batteryspec[1][j-1])/(batteryspec[0][j]-batteryspec[0][j-1])))*p;
while (((compbat)>batteryspec[2][l-1])||((compbat)<batteryspec[2][l])){
l++;
}
stateofc2=(batteryspec[3][55]-(batteryspec[3][l-1]+(compbat-batteryspec[2][l-1])*(batteryspec[3][l]-batteryspec[3][l-1])/(batteryspec[2][l]-batteryspec[2][l-1])))*p;
capacactual=stateofc1+(currentref-1)*(stateofc2-stateofc1)/(3000-1000);
}
if ((currentref>3000)&&(currentref<=5000)){
while (((compbat)>batteryspec[2][j-1])||((compbat)<batteryspec[2][j])){
j++;
}
// stateofc1=(batteryspec[3][55]-(batteryspec[3][j-1]+(compbat-batteryspec[2][j-1])*(batteryspec[3][j]-batteryspec[3][j-1])/(batteryspec[2][j]-batteryspec[2][j-1])))*p;
while (((compbat)>batteryspec[2][l-1])||((compbat)<batteryspec[2][l])){
l++;
}
// stateofc2=(batteryspec[3][55]-(batteryspec[3][l-1]+(compbat-batteryspec[2][l-1])*(batteryspec[3][l]-batteryspec[3][l-1])/(batteryspec[2][l]-batteryspec[2][l-1])))*p;
capacactual=(batteryspec[3][55]-(batteryspec[3][j-1]+(compbat-batteryspec[2][j-1])*(batteryspec[3][j]-batteryspec[3][j-1])/(batteryspec[2][j]-batteryspec[2][j-1])))*p+(currentref-1)*((batteryspec[5][55]-(batteryspec[5][l-1]+(compbat-batteryspec[4][l-1])*(batteryspec[5][l]-batteryspec[5][l-1])/(batteryspec[4][l]-batteryspec[4][l-1])))*p-(batteryspec[3][55]-(batteryspec[3][j-1]+(compbat-batteryspec[2][j-1])*(batteryspec[3][j]-batteryspec[3][j-1])/(batteryspec[2][j]-batteryspec[2][j-1])))*p)/(5000-3000);
}
if (currentref>5000) {
while (((compbat)>batteryspec[4][j-1])||((compbat)<batteryspec[4][j])){
j++;
}
capacactual=(batteryspec[5][55]-(batteryspec[5][j-1]+(compbat-batteryspec[4][j-1])*(batteryspec[5][j]-batteryspec[5][j-1])/(batteryspec[4][j]-batteryspec[4][j-1])))*p;
}
}
void autonomy() {
if (modechange==1) {
consumah=0;
}
power=batvoltage*current/1000;
SOC();
if (capacactual!=capaccheck) {
capaccheck=(capacactual+capaccheck)/2;
}
if (abs(capacactual-capacstore)>=100){
EEPROMWritelong(8,roundf(capacactual));
capacstore=capacactual;
}
consumah += 1000*current*elapsed/1000/3600;
capaccheck -= 1000*current*elapsed/1000/3600;
consumwh += 1000*current*elapsed/1000/3600*batvoltage;
elapsedtot += elapsed;
consumbatper = (capaccheck)/(batteryspec[1][55]*p)*100;
if (distance==0) {
switch (powermode) {
case 1: consumbatrange=45*batvoltage*capaccheck/980;
break;
case 2: consumbatrange=35*batvoltage*capaccheck/550;
break;
}
} else {
consumbatrange = distance/consumah*(capaccheck);
}
myGLCD.printNumI(consumbatrange/1000, 2, 350,275);
myGLCD.printNumI(power/1000, 2, 350,205);
myGLCD.printNumI(current/1000, 1, 30,50);
myGLCD.printNumI(ncycles/1000, 1, 30,50+16*2);
myGLCD.printNumI(consumbatper,1,350,50);
myGLCD.printNumI(batvoltage/1000,1,350,50+16*2);
return 0;
}
void speedometer() {
int sense=digitalRead(46);
long sensecst=691150*3;//x1 000 000
if (sense==LOW) {
timesp=millis()-timespm1;
timespm1 = millis();
velocity=3600/1000*sensecst/(timesp);//m/h
if (timesp>1000) {
velocity=0;
}
} else {
if ((millis()-timespm1)>2000) {
velocity=0;
}
}
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
start=millis();
// pinMode(43, OUTPUT);//Speedo power
// pinMode(46, INPUT);//Speedometer
pinMode(A2, INPUT);//Throttle in
pinMode(A7, INPUT);//Battery voltage
pinMode(A4, INPUT);//Shunt
pinMode(throttle, OUTPUT);
pinMode(11, OUTPUT);
pinMode(10, OUTPUT);
pinMode(47, INPUT);
analogWrite(10,255);
analogWrite(11,255);
myGLCD.InitLCD(LANDSCAPE);
myTouch.InitTouch(LANDSCAPE);
myGLCD.fillScr(0,0,0);
myGLCD.setColor(VGA_WHITE);
myGLCD.setBackColor(0,0,0);
myGLCD.setFont(BigFont);
myGLCD.print("FURO SYSTEMS",(480-16*12)/2,16);
myGLCD.print("WELCOME",(480-16*7)/2,(320-16)/2);
myGLCD.setDisplayPage(0);
delay(2000);
myGLCD.clrScr();
myGLCD.print("FURO SYSTEMS",(480-16*12)/2,16);
myGLCD.fillRoundRect((480-3*16-8)/2,320-16*2-4,(480-3*16-8)/2+3*16+6,228);
myGLCD.print("ECO", (480-3*16)/2, 320-16*5);
EEPROMWritelong(4,1000);
ncycles=EEPROMReadlong(4);
cyclescaling();
for (int m=1; m<=5;m+=2) {
for (int n=0; n<=55;n++) {
batteryspec[m][n]*=factor;
}
}
current=analogRead(A4);
current=current/internresistance*5*1000/1023/75;
batvoltage=analogRead(A7);
batvoltage=batvoltage*5*1000*divider/1023;
SOC();
capaccheck=capacactual;
capacstore=EEPROMReadlong(8);
if (capacactual>capacstore) {
ncycles+=1000;
EEPROMWritelong(4,ncycles);
EEPROMWritelong(8,roundf(capacactual));
}
if (capacactual<500) {
powermode=2;
myGLCD.fillRoundRect((480-4*16-8)/2,320-16*2-4,(480-4*16-8)/2+4*16+6,228);
myGLCD.print("FURO", (480-4*16)/2, 320-16*5);
}//3.21V per cell
EEPROMReadlong(addresstd);
Totaldist=EEPROMReadlong(addresstd);
Totaldistcheck=Totaldist;
digitalWrite(43,HIGH);
}
void loop() {
throttlein=analogRead(A2);
throttlein=throttlein*5*1000/1023;
//throttlesmoothing();
throttleout=throttlein/1000*255/5;
analogWrite(8,throttleout);
modechange=0;
if (digitalRead(47)==LOW)
{
if (buttonst==1) {
pushed = millis();
}
buttonst=0;
if ((millis()-pushed)>=2000)
{
distancedisp=0;
}
}
if (digitalRead(47)==HIGH) {
if (buttonst==0) {
modechange=1;
pushedt=millis()-pushed;
if (pushedt<1900){
if (powermode==1)
{ powermode=2;
myGLCD.clrScr();
myGLCD.print("FURO SYSTEMS",(480-16*12)/2,16);
myGLCD.fillRoundRect((480-4*16-8)/2,320-16*2-4,(480-4*16-8)/2+4*16+6,228);
myGLCD.print("FURO", (480-4*16)/2, 320-16*5);
}
else
{
powermode=1;
myGLCD.clrScr();
myGLCD.print("FURO SYSTEMS",(480-16*12)/2,16);
myGLCD.fillRoundRect((480-3*16-8)/2,320-16*2-4,(480-3*16-8)/2+3*16+6,228);
myGLCD.print("ECO", (480-3*16)/2, 320-16*5);
}
}
}
buttonst=1;
}
batvoltage=analogRead(A7);
batvoltage=batvoltage*5*divider*1000/1023;
//speedometer();
current=analogRead(A4);
current=current/internresistance*5*1000/1023/75;
elapsed = millis() - start;
start = millis();
if (modechange==1) {
distance=0;
}
distanceint = (velocity/3600*elapsed/1000);//m
distance += distanceint;
distancedisp += distanceint;
Totaldist += distanceint;
if (abs(Totaldist-Totaldistcheck)>=100) { //later do it upon switch off
EEPROMWritelong(addresstd,round(Totaldist));
Totaldistcheck=Totaldist;
}
autonomy();
if (velocity>45000) {
outspeedctl=pidspeed_control();
outcurrentctl=pidcurrent_control();
long throttleout1=min(outspeedctl,outcurrentctl);
throttleout=min(throttleout1,throttlesmooth);
//analogWrite(throttle, map(throttleout, 0,5,0,255));
} else{
outcurrentctl=pidcurrent_control();
throttleout=min(throttlesmooth,outcurrentctl);
//analogWrite(throttle, map(throttleout, 0,5,0,255));
}
myGLCD.setFont(SevenSegNumFont);
myGLCD.printNumI(velocity, (480-32*3)/2, (320-50)/2);
myGLCD.setFont(BigFont);
myGLCD.printNumF(distancedisp, 1, 30,175);
myGLCD.printNumI(Totaldist, 30,175+2*16);
}
/*
. Please edit the question and post your actual code.