Total mystery to me

Hey,

I am having a little problem that I just can't seem to fix or find any information on. I am reading from 8 sensors and saving the data in a 2D array. Then I am doing some calculations on the data. My problem is that when I do my smoothing operation I get a wierd jump in the smoothed curve. It does not happen in the first round of the loop, but in all the others. The jump is one position long in the first point and 8 positions long at point 126. I appreciate any help I can get.

Thanks!

image

#include <Controllino.h>  // Usage of CONTROLLINO library allows you to use CONTROLLINO_xx aliases in your sketch. //


volatile int count = 0;       //sets the variable count to zero. A variable should be declared volatile whenever its value
volatile int countzero = 0;  //can be changed by something beyond the control of the code section in which it appears, such as a concurrently executing
//thread. In the Arduino, the only place that this is likely to occur is in sections of code associated with interrupts, called an interrupt service routine
int switchstate = 0;

int Gauss = 0;

int testArray[8][365];   //defines array for hall sensor 1


int result = 1;   //Result for strength   0 = ok, 1 =NOK
int result1 = 1;   //Result for angel error  0 for OK 1 for NOK
int approved = 1;
int tt = 0;
void setup() {

  Serial.begin(9600);  //Sets the data rate in bits per second (baud) for serial data transmission

  pinMode(CONTROLLINO_R0, OUTPUT);  //Configures the specified pin to behave either as an input or an output
  //R0 is a relay that Will start the motor
  pinMode(CONTROLLINO_D0, OUTPUT);  //output signal to robot if parts are ok
  pinMode(CONTROLLINO_D1, OUTPUT);  //output signal to robot parts NOK
  pinMode(CONTROLLINO_D2, OUTPUT);  //Temperary output for test

  pinMode(CONTROLLINO_IN0, INPUT);    //IN0 is an interupt and will read the pulse from the refernce point

  pinMode(CONTROLLINO_A0, INPUT);     //pin for the start switch

  pinMode(CONTROLLINO_A1, INPUT);     //pin for the hall sensor 1

  pinMode(CONTROLLINO_A2, INPUT);     //pin for hall sensor 2
  pinMode(CONTROLLINO_A3, INPUT);     //pin for hall sensor 3
  pinMode(CONTROLLINO_A4, INPUT);     //pin for hall sensor 4
  pinMode(CONTROLLINO_A10, INPUT);    //pin for hall sensor 5
  pinMode(CONTROLLINO_A9, INPUT);     //pin for hall sensor 6
  pinMode(CONTROLLINO_A7, INPUT);     //pin for hall sensor 7
  pinMode(CONTROLLINO_A8, INPUT);     //pin for hall sensor 8

  //allows external interrupts
  attachInterrupt(digitalPinToInterrupt(CONTROLLINO_IN0), zero, RISING);   //attachInterrupt(digitalPinToInterrupt(pin), ISR, mode) (recommended)   pin: the Arduino pin number.
  //ISR: the ISR to call when the.  mode: defines when the interrupt should be triggered. interrupt occurs

}

void loop() {

  switchstate = digitalRead(CONTROLLINO_A0);

  result = 1;
  result1 = 1;

  if (switchstate == HIGH)                     //Read from robot that it is time to start a measruement
  {


    digitalWrite(CONTROLLINO_R0, HIGH);        //Start motor

    delay(3500);


    for (int work = 0; work < 8; work++)       //Evaluation loop
    {
      tt += 1;
      approved = Eval1();

      if (approved == 1)
      {
        work = 0;
        break;
      }
      //Serial.println(approved);
    }


    if (approved == 0)
    {
      //digitalWrite(CONTROLLINO_D0, HIGH);
      Serial.println("OK");
    }
    else
    {
      //digitalWrite(CONTROLLINO_D1, HIGH);
      Serial.println("NOK");
    }

  }

  delay(30);
  countzero = 0;
  tt = 0;
}


//**********************************************************************Function: Count zero pulse************************************************************************

void zero()
{

  countzero += 1;   //add one to the count of zero pulses
  int x = countzero - 1;

  testArray[0][x] = analogRead(CONTROLLINO_A1) ;
  testArray[1][x] = analogRead(CONTROLLINO_A2) ;
  testArray[2][x] = analogRead(CONTROLLINO_A3) ;
  testArray[3][x] = analogRead(CONTROLLINO_A4) ;
  testArray[4][x] = analogRead(CONTROLLINO_A10);
  testArray[5][x] = analogRead(CONTROLLINO_A7) ;
  testArray[6][x] = analogRead(CONTROLLINO_A8) ;
  testArray[7][x] = analogRead(CONTROLLINO_A9) ;

  if (x == 360)
  {
    digitalWrite(CONTROLLINO_R0, LOW);

    for (int i = 0; i < 365; i++) {
      Serial.println(testArray[0][i]);

    }
    Serial.println("done testArray");
  }
}




//*************************************************************************Function: Evaluate testArray*********************************************************
//**************************************************************************************************************************************************************

int Eval1()
{

  float calcArray[180];
  float tempA = 0;
  float maxMin = 0;
  float C = 0.00;

  for (int ty = 0; ty < 180; ty++)
  {
    calcArray[ty] = 0.00;
  }

  //Serial.print(tt);
  // Serial.println("tt");

  //--------------------------------------------------------------------------------Smooth the values---------------------------------
  for (int t = 0; t < 180; t++)
  {
    if (tt == 1)      //calibration for sensor placement
    {
      C = 1.35;
    }

    if (tt == 2)
    {
      C = 2.31;
    }
    if (tt == 3)
    {
      C = 3.15;
    }

    if (tt == 4)
    {
      C = 1.00;
    }

    if (tt == 5)
    {
      C = 1.34;
    }

    if (tt == 6)
    {
      C = 1.00;
    }
    if (tt == 7)
    {
      C = 1.34;
    }

    if (tt == 8)
    {
      C = 1.52;
    }

    calcArray[t] = ((testArray[tt - 1][(t + 2) * 2] + testArray[tt - 1][((t + 2) * 2) + 1]) / 2.00) * C;
  }

  //delay(50);
  // for (int i = 0; i < 180; i++) {
  // Serial.println(calcArray[i]);

  //}
  //Serial.println("done smoooth");

  //-----------------------------------------------------------------------find max, min and amplitude--------------------------------
  float maxTemp = calcArray[0];                           //max value place holder
  float minTemp = calcArray[0];                           //min value place holder

  for (int u = 1; u < 180; u++)
  {
    if (calcArray[u] > maxTemp)                           //find the maximum in the array.
    {
      maxTemp = calcArray[u];
    }

    if (calcArray[u] < minTemp)                           //find the minimum in the array.
    {
      minTemp = calcArray[u];
    }
  }

  maxMin = (maxTemp - minTemp) / 2.00;   //evaluate amplitude

  //Serial.println(maxMin);
  //Serial.println("next");

  //-----------------------------------------------------------------------convert to cos'---------------------------------------
  for (int v = 0; v < 180; v++)
  {
    calcArray[v] = (calcArray[v] - (maxTemp - maxMin)) / maxMin;
  }

  // for (int i = 0; i < 180; i++) {
  //   Serial.println(calcArray[i]);

  // }
  // Serial.println("Done cos'");

  //---------------------------------------------------------------------arctan2 plus conversion to degrees-----------------------------------------

  float calcArraycopy[44];
  for (int hi = 0; hi < 44; hi++)
  {
    calcArraycopy[hi] = calcArray[hi];
  }
  //for (int i = 0; i < 44; i++)
  //   {
  //   Serial.println(calcArraycopy[i]);

  //}
  //Serial.println("done angle");

  for (int w = 0; w < 180; w++)
  {
    int nn = w + 44;

    if (nn > 179)
    {
      calcArray[w] = atan2(calcArray[w], calcArraycopy[w - 136]) * 180.00 / 3.1415;
    }
    else
    {
      calcArray[w] = atan2(calcArray[w], calcArray[nn]) * 180.00 / 3.1415;
    }
  }
  //for (int i = 0; i < 180; i++) {
  //Serial.println(calcArray[i]);

  //}
  //Serial.println("done angle");

  //----------------------------------------------------------------------shift array so that 180 degrees is first--------------------------------------------------------------------
  for (int z = 1; z < 180; z++)
  {
    if (calcArray[0] > -178.50)
    {

      float temp = calcArray[0];                        // save x[0] in temporary

      for (int from = 1; from < 180; from++)            // shift remaining values to the front of the array
      { int to = from - 1;
        calcArray[to] = calcArray[from];
      }

      calcArray[179] = temp;                            // put x[0] saved in temp into last entry
    }
  }

  float temp = calcArray[0];                        // save x[0] in temporary



  //for (int i = 0; i < 180; i++) {
  //Serial.println(calcArray[i]);

  //}
  //Serial.println("done shift");

  //-------------------------------------------------------------------------check delta angle------------------------------------------------------------------------


  tempA = 0;
  for (int pp = 0; pp < 180; pp++)
  {
    float delta = calcArray[pp] - (-180.00 + (pp * 2));

    if (abs(delta) > tempA)
    {
      tempA = abs(delta);
    }
  }
  //Serial.println(tempA);
  // Serial.println("done");
  //--------------------------------------------------------------------------Ok eller NOK parts----------------------------------------------------------------
  if (maxMin < 15)                                    //part not ok
  {
    // Serial.println(maxMin);
    result = 1;
  }
  else {
    result = 0;
  }
  if (tempA > 400.00)                                     //part not ok
  {
    //Serial.println(tempA);
    result1 = 1;
  }
  else
  {
    result1 = 0;
  }

  if (result == 1 || result1 == 1)
  {
    return (1);

  }
  else
  {
    return (0);
  }
}

What’s your Arduino ? Any memory issue? (You have large arrays including some transient on the stack that the compiler won’t warn you about).

Seems you have an array of 365x8 values but you stop at 360 and then print 365 data points

Also reading quickly across the analog input might return faulty data if there is a big difference between them. Usually one would read the value, throw it away and then read again and keep the second one.

There are a lot of questions about your code.
The zero() function. Why is a function that reads the values ​​of eight sensors called zero()?

Why do that

countzero += 1;
int x = countzero - 1;

Couldn't it be more clear

int x = countzero;
countzero += 1;

Where do you control the maximum value of countzero and x?
What happens if countzero and x are 365, 366, 367, etc.?
When you execute code

if (x == 360)
  {
    digitalWrite (CONTROLLINO_R0, LOW);
    for (int i = 0; i <365; i ++) {
      Serial.println (testArray [0] [i]);
    }
    Serial.println ("done testArray");
  }

what are testArray [0] [361], testArray [0] [362], testArray [0] [363] ...?
Why is countzero = 0 in a completely different function?
At what point of time does this happen?
What does delay (3500) do in the loop() function?

Hey,

@ J-M-L: Sorry I forgot to put what type of board I have. I am using a Controllino Maxi which has an ATmega 2560 board.

I was printing extra data points so that I could start at position 4 in the array. I thought that I was reading bad data at the start of my cycle but that was not the case.

As seen in the pictures that I added the read from my sensors looks good. It is only in the loop that it gets shifted.

@Boffin: The function is called zero() since when I started this project I was using a different angle sensor and I was only reading the zero point. Now I am reading 360 pulses per revolution.

Yes, it would be clearer if I had:

int x=countzero;
countzero +=1

Thanks for the tip.

I don't know how to control the maximum value of countzero. It is an interupt that reads from an angle sensor. Even when I have reached x=360 there is a little overshoot and I get extra values. That is why the array is 365 and not 360. I didn' know what would happen if there wasn't space in the array for the overshoot.

The extra array places are just for the overshoot.
Countzero=0 is in another function since I was sloppy with my global vs. local variables. This is my first program so I am learning on the way.
The delay(3500) is so that nothing else is happening when I do my interrupt reads. I didn't want anything else running that could disturb the sensor reads. Plus, the entire program is based on the array that is created from the interrupt reads. If there is a better way to do this I would love to see what it is.

This is never an issue if the analog signals are 10k impedance or lower, only if the impedance is substantially higher would you get visible cross-talk. The problem is best solved in hardware, not software anyway.

Hi,
What is the application?
Do you have each of the Hall Effect devices bypassed at their pins?

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

You have not written how often interruptions occur and how long one revolution takes.

You must have a variable like measuringState, which is responsible for the measurement state (0/1 or false / true). When you start measuring, set x = 0 and measuringState = 1/
When x = 360 do either measuringState = 0 and measurements are finished, or x = 0 and a new measurement cycle begins. Control your x (countzero) in one place, inside zero().
The variable x must always be between 0 and 359.
Do your evaluation of data when measuring is finished.

You aren't synchronizing to the interrupt routine - you are reading and printing the data in the testArray while interrupts are active, no wonder they change under your feet! I think you need a volatile bool to control whether sampling is active.

You are using Serial inside the ISR - this can deadlock the system.

Your ISR will be taking a long time - this may break millis(), delay() and micros(). analogRead takes 110us or so, so the ISR is perhaps 0.9ms to run.

Hej TomGeorge,

I am evaluating magnets for amplitude and anger error.

I am not sure what you mean by bypassed. You can see my connection below.

Hey,

@Boffin: The interrupt occurs every 1 degree. This comes in the form of a pulse from the angle encoder. A full revolution, 360 degress, takes just under 3 seconds.

Hi,

bypass

Tom... :smiley: :+1: :coffee: :australia:

Indeed

Very correct comments from @MarkT. Remove Serial.println() from ISR, it should be as fast as possible.
Enter a global variable that is responsible for the measurement state. Set this variable at the beginning of measurements and reset at the end.
Start processing the dataset when the measurement is complete. Start a new measurement when the entire dataset has been processed.

Hey,

The serial print was just there for debugging and I forgot to comment it away again. I wanted to see how my read data looked.

I have done as you have advised and set a new variable inside zero() that starts and stops the read. This fixed the problem and now everything is running just like it should.

I really appreciate all the help. I sat almost 5 hours yesterday banging my head over this and you all fixed it almost directly!

Good, glad that worked out.