Arduino not calculating correct straight line gradient?

Hey Guys,

I have a problem with my code!

For some reason the Arduino can’t work out the gradient (or the gradient doesn’t change). This leads to the setpoint jumping around and not proportionally changing from 1 setpoint in the array to the next!

Any ideas what I did wrong or how I can fix this?

Thanks in advance :slight_smile:

Omar

// The following are dummy arrays used for testing;
const int SetpointArray [] = {0, 2, 7, 4, 4, 15, 0, 0};
const int SetpointTimeArray [] = {0, 4000, 6000, 8000, 10000, 12000, 14000, 16000};
int j; // The term number in the arrays;
// Variables used to change the setpoint;
double Setpoint; 
double SetpointInterval = (SetpointArray [j+1] - SetpointArray [j]);
double TimeInterval = (SetpointTimeArray [j+1] - SetpointTimeArray [j]);


void setup() {
Serial.begin(19200);
}

void loop()
{
  
int DataPoints = (((sizeof(SetpointTimeArray)) / 4) - 1); // Counts the number of data points inside the time array. The sizeof function give the number of bits inside the array;
double  t = (millis()); // Initalise timing;

if (SetpointTimeArray [j+1] > SetpointTimeArray [j] && j < DataPoints) { // This loop will run if the time in the time array is increasing and j is smaller than the number of data points;
  if (t <= SetpointTimeArray[j+1]) {
    if (SetpointArray [j+1] > SetpointArray [j]) {  
      Setpoint = (((SetpointInterval / TimeInterval)*(t - SetpointTimeArray [j+1])) + SetpointArray [j+1]);
    }
    else if (SetpointArray [j+1] < SetpointArray [j]){
      Setpoint = ((-(SetpointInterval / TimeInterval)*(t - SetpointTimeArray [j+1])) + SetpointArray [j+1]);
    }
    else {
      Setpoint = SetpointArray [j];
    }
  }
  else {
    j = j+1;
  }
  Serial.print (" Time (Sec) ");
  Serial.print (t);
  Serial.print (" Setpoint ");
  Serial.print (Setpoint); 
  Serial.print (" j = ");
  Serial.println (j);
}
else {
  if (j >= DataPoints) {
    Serial.println (" Task Completed ");
    Setpoint = 0;
  }
  else {
    Serial.println (" Error Encountered, Program Terminated ");  
    Setpoint = 0;
  }
}
}

omario93: Any ideas what I did wrong or how I can fix this?

Are you mixing up integers and floating point values in your maths?

...R

have a problem with my code!

So have we, it's not in code tags! You could have read the documentation for this part of the forum. There is say Read this before posting .....

  1. Try reading the documentation for sizeof.

Mark

(SetpointInterval / TimeInterval)

That's integer division. Integer division gives wrong results since the result is truncated to an integer. 5 / 2 gives 2.

Declare SetpointInterval as float and it'll work.

That's integer division.

No, it isn't. SetpointInterval and TimeInterval were declared "double", so that is not the problem.

@omario93: The following declaration may not be doing what you expect. Did you intend to declare SetpointInterval and TimeInterval as functions of j? If so, the #define macro can accomplish that.

As defined below, SetpointInterval and TimeInterval are initialized to 2.0 and 4000.0 and will not change thereafter.

int j; // The term number in the arrays;
// Variables used to change the setpoint;
double Setpoint;
double SetpointInterval = (SetpointArray [j+1] - SetpointArray [j]);
double TimeInterval = (SetpointTimeArray [j+1] - SetpointTimeArray [j]);
int DataPoints = (((sizeof(SetpointTimeArray)) / 4) - 1); // Counts the number of data points inside the time array. The sizeof function give the number of bits inside the array;

The SetpointTimeArray array type is int, so why are you dividing by 4?

Why does SerpointTimeArray need "Array" in the name? Aren't the [] enough to remind you that it is an array?

Why are you subtracting 1?

The way I see it, sizeof(SetpointTimeArray) will return 16, so DataPoints will be 3. I fail to see how 3 is a useful number, given that there are 8 values in the array.

Hi Guys,

Really sorry for the late reply, I had set the forum to notify me by email when I get a response but I never received anything.

Thank you for your replies however. I am going to try to answer all your questions so hopefully we can reach a solution.

Robin2:
Are you mixing up integers and floating point values in your maths?

…R

I tried to do it both ways, it still Doesn’t seem to work. What happens is… say the setpoint is 2 and the next setpoint is 3. In this case, the program works nicely and proportionally increases with time to 3 (using the straight line equation). However, if the setpoint is 2 and the next is 4. The program skip from 2 to 3, then proportionally increases from 3 to 4 in a straight line, rather than increasing from 2 to 4 within the time gap.

The next problem is, the gradient should automatically become negative as the setpoint decreases, however that doesnt work and I needed to add the same equation again with a - in front.

holmes4:

  1. So have we, it’s not in code tags! You could have read the documentation for this part of the forum. There is say Read this before posting …

  2. Try reading the documentation for sizeof.

Mark

  1. Sorry about that Mark, I have just noticed that. I will change it.

  2. The sizeof is not the problem, that part of the code does the job required and counts the number of data points inside the array correctly. However, maybe it is the problem… are you seeing something I am not?

MarkT:

(SetpointInterval / TimeInterval)

That’s integer division. Integer division gives wrong results since the result is truncated
to an integer. 5 / 2 gives 2.

Declare SetpointInterval as float and it’ll work.

Tried it mate, still not working as I expect it to.

jremington:
No, it isn’t. SetpointInterval and TimeInterval were declared “double”, so that is not the problem.

@omario93: The following declaration may not be doing what you expect. Did you intend to declare SetpointInterval and TimeInterval as functions of j? If so, the #define macro can accomplish that.

As defined below, SetpointInterval and TimeInterval are initialized to 2.0 and 4000.0 and will not change thereafter.

int j; // The term number in the arrays;

// Variables used to change the setpoint;
double Setpoint;
double SetpointInterval = (SetpointArray [j+1] - SetpointArray [j]);
double TimeInterval = (SetpointTimeArray [j+1] - SetpointTimeArray [j]);

Yes I think you are right! :D… this is the most reasonable explanation as I have noticed that the gradient and time interval do not change! I am going to look at how to incorporate the #Define function… but I will also post a simplified version of the code and you can show me where you add it if you have time.

PaulS:

int DataPoints = (((sizeof(SetpointTimeArray)) / 4) - 1); // Counts the number of data points inside the time array. The sizeof function give the number of bits inside the array;

The SetpointTimeArray array type is int, so why are you dividing by 4?

Why does SerpointTimeArray need “Array” in the name? Aren’t the enough to remind you that it is an array?

Why are you subtracting 1?

The way I see it, sizeof(SetpointTimeArray) will return 16, so DataPoints will be 3. I fail to see how 3 is a useful number, given that there are 8 values in the array.

I am dividing by 4 because in the array each data point adds 4 to the overall output the sizeof function. So if I have 7 data points the sizeof function will return 28.
So, I divide by 4 that gives me 7. I then subtract by 1 because the first value counts as 0 in the array… so when j = 6, this refers to the 7th value.

I hope that helps.

As for why I put array in the name of an array, good question lol… I am not writing this code for myself but for a supervisor and future research assistants. We are working on a tensile testing machine that will be used in medical hospitals to check the condition of living tissue.

Kind regards and many thanks,

Omar

Here is the Code in its simplest form

// The following are dummy arrays used for testing;
double SetpointArray [] = {0, 2, 7, 4, 4, 15, 0, 0};
double SetpointTimeArray [] = {0, 4000, 6000, 8000, 10000, 12000, 14000, 16000};
int j; // The term number in the arrays;
// Variables used to change the setpoint;
double Setpoint; 
double SetpointInterval = (SetpointArray [j+1] - SetpointArray [j]);
double TimeInterval = (SetpointTimeArray [j+1] - SetpointTimeArray [j]);

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

void loop()
{
  
int DataPoints = (((sizeof(SetpointTimeArray)) / 4) - 1); // Counts the number of data points inside the time array. The sizeof function give the number of bits inside the array, deviding by 4 and subtracting the overall number by 1 gives the number of terms in the array;

if (SetpointTimeArray [j+1] > SetpointTimeArray [j] && j < DataPoints) { // This loop will run if the time in the time array is increasing and j is smaller than the number of data points;
  double  t = millis(); // Initalise timing;
  if (t <= SetpointTimeArray[j+1]) {
    Setpoint = (((SetpointInterval / TimeInterval)*(t - SetpointTimeArray [j+1])) + SetpointArray [j+1]);
  }
  else {
    j = j+1;
  }
   Serial.print (" Time (Sec) ");
   Serial.print (t);
   Serial.print (" Setpoint ");
   Serial.print (Setpoint); 
   Serial.print (" j = ");
   Serial.println (j);
}
else {
  if (j >= DataPoints) {
    Serial.println (" Task Completed ");
    Setpoint = 0;
  }
  else {
    Serial.println (" Error Encountered, Program Terminated ");  
    Setpoint = 0;
  }
}
}

Moderator edit: Code tags corrected

The sizeof function give the number of bits inside the array, deviding by 4 and subtracting the overall number by 1 gives the number of terms in the array

Such a short sentence; so many wrong things.

double  t = millis(); // Initalise timing;

“millis” returns . . . a double?

I am dividing by 4 because in the array each data point adds 4 to the overall output.

I think you need to do some checking of this assumption. Integer values only occupy 2 bytes each.

Edit: OK. I notice you've now changed setPointTimeArray to double.

KenF: Integer values only occupy 2 bytes each.

Edit: OK, I still think you need to do some checking of this assumption. ;)

Hint: "char", "long", "long long"

Ok,

Finally managed to get it to work!

@jremington you are awsome man, thanks for the help.

AWOL:
Such a short sentence; so many wrong things.

double  t = millis(); // Initalise timing;

“millis” returns . . . a double?

I have only been programming for 2 weeks using arduino. I do not have a strong grasp of all the functions yet. However, we are all students in life. If you have something you want to explain to me or correct me on then I am your student.

here is the final code

// The following are dummy arrays used for testing;
double ArrayType [] = {1, 1, 1, 1, 1, 1, 1, 1}; // 0 for Position, 1 for Load - not yet used; 
double SetpointArray [] = {0, 2, 7, 4, 4, 15, 0, 0};
double SetpointTimeArray [] = {0, 4000, 6000, 8000, 10000, 12000, 14000, 16000};
int j; // The term number in the arrays;
// Variables used to change the setpoint;
double Setpoint; 
#define SetpointInterval ((SetpointArray [j+1] - SetpointArray [j]))
#define TimeInterval ((SetpointTimeArray [j+1] - SetpointTimeArray [j]))

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

void loop()
{
  
int DataPoints = (((sizeof(SetpointTimeArray)) / 8) - 1); // Counts the number of data points inside the time array. For Due the value of division need to be 8 bits, and 4 bits for Uno and other boards;
if (SetpointTimeArray [j+1] > SetpointTimeArray [j] && j < DataPoints) { // This loop will run if the time in the time array is increasing and j is smaller than the number of data points;
  int  t = millis(); // Initalise timing;
  if (t <= SetpointTimeArray[j+1]) {
    Setpoint = (((SetpointInterval / TimeInterval)*(t - SetpointTimeArray [j+1])) + SetpointArray [j+1]);
  }
  else {
    j = j+1;
  }
   Serial.print (" Data point ");
   Serial.print (DataPoints);
   Serial.print (" Time (Sec) ");
   Serial.print (t);
   Serial.print (" Setpoint ");
   Serial.print (Setpoint); 
   Serial.print (" j = ");
   Serial.println (j);
}
else {
  if (j >= DataPoints) {
    Serial.println (" Task Completed ");
    Setpoint = 0;
  }
  else {
    Serial.println (" Error Encountered, Program Terminated ");  
    Setpoint = 0;
  }
}
}

Edit 1: New Code, Now Fixed… Thanks AWOL!

Thanks for the help everyone

Omar

Edit 2:

So to summertime for my understanding:

I should use the #Define If I have an equation outside the void loop that changes value with each loop.

I should not use int and double or int and float together because of the truncation errors involved.

Kind of still unsure about those two points. Please explain?

I should use the #Define If I have an equation outside the void loop that changes value with each loop.

No. You should get out of the habit of using #define. #define is NOT a substitute for declaring variables.

I think this is what you want in loop()

SetpointInterval = (SetpointArray [j+1] - SetpointArray [j]);
TimeInterval = (SetpointTimeArray [j+1] - SetpointTimeArray [j]);
Setpoint = (((SetpointInterval / TimeInterval)*(t - SetpointTimeArray [j+1])) + SetpointArray [j+1]);

PaulS: No. You should get out of the habit of using #define. #define is NOT a substitute for declaring variables.

Thanks for the heads up, will do. :D

jremington: I think this is what you want in loop()

SetpointInterval = (SetpointArray [j+1] - SetpointArray [j]);
TimeInterval = (SetpointTimeArray [j+1] - SetpointTimeArray [j]);
Setpoint = (((SetpointInterval / TimeInterval)*(t - SetpointTimeArray [j+1])) + SetpointArray [j+1]);

I realized that yeah, at first I had a long equation inside the loop that went like this:

SetpointX = ((((SetpointArrayX [j+1] - SetpointArrayX [j]) / (SetpointTimeArray [j+1] - SetpointTimeArray [j]))*(t - SetpointTimeArray [j+1])) + SetpointArrayX [j+1]);
    SetpointY = ((((SetpointArrayX [j+1] - SetpointArrayX [j]) / (SetpointTimeArray [j+1] - SetpointTimeArray [j]))*(t - SetpointTimeArray [j+1])) + SetpointArrayY [j+1]);

It didnt work for some reason... But now I tried that equation again and it works. I probably had some errors in the code which I wasn't aware of.

Thanks for your help guys!

I probably had some errors in the code which I wasn’t aware of.

The use of intermediate variables makes it easy to debug the code. Complex statements like that are fine if you KNOW that the code is correct, and that you’ll never divide by 0, etc.

Intermediate variables don’t necessarily make the program larger, because, once the code is debugged and the intermediate variables are no longer actually used (by printing), the compile will usually optimize them away.

Determining the type for the intermediate variable often causes you to think about what the code is doing. Choosing the correct type is often half the battle.

PaulS: Determining the type for the intermediate variable often causes you to think about what the code is doing. Choosing the correct type is often half the battle.

Dude you are so right about that! It took me some thinking to figure out what is what. :D

Now the next step for me is to extend this code so that instead of me writing the arrays (dummy test arrays) I want to read the arrays over the serial buffer from the raspberry pi or a PC...

anyone got any hints how I could go about doing that? can I read different arrays via their name over the serial buffer?

If not, I thought about creating a 2D array containing all the arrays I need, what do you guys recommend?

can I read different arrays via their name over the serial buffer?

You can’t read any arrays via the serial port. You read data, and store the data in memory locations. The memory locations may be addressed using scalar variables or they may be addressed using array variables.

Names are non-existent in the hex code. Everything is by address. It is not possible for the Pi to tell the Arduino to store this data in an array named xxx. The Arduino can see the name, xxx, and make decisions to store the data in specific addresses related to that name.

can you write me a small example code please?

omario93: can you write me a small example code please?

To do what?