Max-Min values of forced oscillation using MPU6050

I am going round in circles! I want to find the Max and Min values of repeated forced oscillations. I am using an MPU6050 with an Uno. The code does not work all the time and sometimes the Min value gets missed.
Also, It does not always record the maximum but the next reading (maybe the condition for separation of values : cmx-pmx && cmx - lmx is not met until further values tested). And I get some missed Min values or delayed recording in the serial monitor.
Why do I get missed Min values and why are some readings delayed in the serial printing?
Can I use 2 arrays: How to fill an array with x angle values then stop the array when back to neutral - 195 degrees - and find max value in first array and min value in second array?
The forced oscillation is slow : about 1 oscillation per second but does vary and may stop.
Do I even need an array? (just correct my faulty code!)
Thanks in advance. C

#include<Wire.h>

const int MPU_addr=0x68; 
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;

int minVal=265; 
int maxVal=402;


int cmx = 1960;                //initialise current max angle variable
int cmn = 1950;                //initialise current min angle variable 
int pmx = 1960;                //initialise previous max angle variable
int pmn = 1950;                //initialise previous min angle variable
int lmx = 1960;                //initialise a variable to store the old previous max value 
int lmn = 1950;                //initialise a variable to store the old previous min value 


int count_max;                //initialise count for max angles 
int count_min;                //initialise count for min angles 

double x;
double y; 
double z;


void setup() { 
  Wire.begin(); 
  Wire.beginTransmission(MPU_addr); 
  Wire.write(0x6B); 
  Wire.write(0); 
  Wire.endTransmission(true); 
  Serial.begin(115200);
} 
void loop(){ 
  Wire.beginTransmission(MPU_addr); 
  Wire.write(0x3B); 
  Wire.endTransmission(false); 
  Wire.requestFrom(MPU_addr,14,true); 
  AcX=Wire.read()<<8|Wire.read(); 
  AcY=Wire.read()<<8|Wire.read(); 
  AcZ=Wire.read()<<8|Wire.read(); 
  int xAng = map(AcX,minVal,maxVal,-90,90); 
  int yAng = map(AcY,minVal,maxVal,-90,90); 
  int zAng = map(AcZ,minVal,maxVal,-90,90);

x= RAD_TO_DEG * (atan2(-yAng, -zAng)+PI);          //calculation of x angle (double)

if (x > 196){                                      //checking for angle over neutral angle (180 degrees) 
cmx = x*10;                                        //converting x angle (double) into current angle integer with one decimal place of accuracy 
 if (pmx - cmx > 20 && lmx - cmx > 40){            //checking current angle against previous angle and last previous angle 
                             
  Serial.print ("Osc_max   ");                    //printing maximum oscillation
  Serial.println (lmx); 

  lmx = 1960;                                      //reset these previous angles so as to try to avoid printing a second (but lesser) max value 
  pmx = 1960;
  count_max++;                                     //printing count for number of max values
  Serial.print ("Count.Max   ");
  Serial.println (count_max); 
 
 }
                                                   //equivalent of small array to provide conditions to find max oscillation
 lmx = pmx;                                        //storing the old previous max value as last max value 
 pmx = cmx;                                        //storing the old current max value as previous max value 


}
else if (x<195){                                    //checking for angle under 180 degrees
cmn = x*10;                                         //converting x angle (double) into current angle
  if (cmn - pmn > 20 && cmn - lmn > 40 ){           //checking current angle against previous angle and last previous angle
                         
    Serial.print ("Osc_min   ");                   //printing minimum oscillation
    Serial.println (lmn);

    lmn = 1950;                                     //reseting these previous min angles so as to try to avoid printing other values
    pmn = 1950;
    count_min++;                                    //printing count for number of min values
    Serial.print ("Count.Min   ");
    Serial.println (count_min);

  }
                                                    //equivalent of small array to provide conditions to find max oscillation    
  lmn = pmn;                                        //storing the old previous min value as last prepvious value
  pmn = cmn;                                        //storing the old current min value as previous min value 

}
                                          
Serial.print("AngleX= ");                           //printing actual angle to check validity of max and min printed values 
Serial.println(x);
 
Serial.println("-----------------------------------------"); 
delay(250);                                         //setting sampling rate for x angle 
} 

Hey the answer is on line 76 of your code. That at least is what my crystal ball says. It might be a bit wonky so follow the advice here.

how to get the best out of this forum

Ah-Ha ... I used another guess : copy for forum and then cmdV for post
Now code in my post as it should be..Yes . ( could not find a # to add code )

If you are measuring tilt angles, replace all of this (which is wrong)

  int xAng = map(AcX,minVal,maxVal,-90,90); 
  int yAng = map(AcY,minVal,maxVal,-90,90); 
  int zAng = map(AcZ,minVal,maxVal,-90,90);

x= RAD_TO_DEG * (atan2(-yAng, -zAng)+PI);          //calculation of x angle (double)

with this:

  float x_T = AcX;
  float y_T = AcY;
  float z_T = AcZ;
  roll = atan2(y_T , z_T) * 57.3;
  pitch = atan2((- x_T) , sqrt(y_T * y_T + z_T * z_T)) * 57.3;

For an explanation of the formulas, see How_to_Use_a_Three-Axis_Accelerometer_for_Tilt_Sensing-DFRobot

Is a problem why do you do this. It makes the whole code just stop for a quarter of a second. During which time your pendulum keeps on moving.

Why so long, this only slows things down and prevents you from reading data?

Thanks I will replace and see what happens and I will look at your link for tilt sensing
I've jumped into coding and probably out of my depth .... willing to learn thou'

The delay was just to slow the sampling down so I could see what was going on
The Oscillation is forced and slow
And, I took the code from an example / tutorial so I will comment out this - actually remove it as see the outcome
Thanks

A lot of which you find and copy off the web is just plain wrong.

The code you found and posted will print numbers vaguely related to some tilt angle, but would be useless for measuring anything. So beware!

Thanks. Have just swapped out the code as you suggested and adjusted the remaining code.
It has changed the axis that responds to the calculated tilt; but will print out angles. Have scanned the content for the link you provided: Needs re-reading but interesting to see a Bosch sensor BMA220 to work with. Page not found for the 'tilt sensing using 3 axis accelerometer' so I guess I will contact Bosch for relevant software unless the arduino coding will work.
I am still worried about finding the max and min angles - if I remove the 'delay' the sampling will be increased and the 'if' statement will not work, I think. Would an 'array' work? or is there another handy way to find a max and min angle of a continuing oscillation?

The posted code is very strange. To find the minimum and maximum values of a series, I use something like this. The sampling rate is irrelevant.

float max = -10000.0;   //global variables
float min = 10000.0;
...
//in loop()
if (max < angle) max = angle;
if (min > angle) min = angle;

At some point, stop the sampling and print the max and min values.

Thanks for the last post .... I have been unwell and not able to do anything .... now I'm better I have re-done the code and I get max and min angles as suggested and I've used a condition to stop printing extra angles; but why do I often get a delayed printed max or min angle. I have included code to print the sampled angles so I can check all the angles. These keep printing fine but the defined max or min angles get printed out of sequence with these.....
Does anyone know why ?

here's the code :

#include<Wire.h>

const int MPU_addr=0x68; 
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;

int minVal=265; 
int maxVal=402;


int cmx = 5;                //initialise current max angle variable
int cmn = 3;                //initialise current min angle variable 
int pmx = 5;                //initialise previous max angle variable
int pmn = 3;                //initialise previous min angle variable
//int lmx = 5;                //initialise a variable to store the old previous max value 
//int lmn = 3;                //initialise a variable to store the old previous min value 


int count_max;                //initialise count for max angles 
int count_min;                //initialise count for min angles 

double x;
double y; 
double z;

bool neutral;                 //condit. to check neurtal position 


void setup() { 
  Wire.begin(); 
  Wire.beginTransmission(MPU_addr); 
  Wire.write(0x6B); 
  Wire.write(0); 
  Wire.endTransmission(true); 
  Serial.begin(115200);
} 
void loop(){ 
  Wire.beginTransmission(MPU_addr); 
  Wire.write(0x3B); 
  Wire.endTransmission(false); 
  Wire.requestFrom(MPU_addr,14,true); 
  float AcX=Wire.read()<<8|Wire.read(); 
  float AcY=Wire.read()<<8|Wire.read(); 
  float AcZ=Wire.read()<<8|Wire.read(); 
  float x_T = AcX;
  float y_T = AcY;
  float z_T = AcZ;
  y = atan2(y_T , z_T) * 57.3;
  x = atan2((- x_T) , sqrt(y_T * y_T + z_T * z_T)) * 57.3;

if (x > 3 && x < 6){                              //checking neutral position
  neutral = true;
}
 if (x > 7){                                      //checking for angle greater than neutral position 
  cmx = x*10;                                     //converting x angle (double) into current angle to one decimal place accuracy
  
  if (cmx < pmx && neutral == true){              //checking current angle against previous angle  
                             
  Serial.print ("Tilt_max   ");                   //printing maximum tilt
  Serial.println (pmx); 

//  lmx = 5;                                      //reset these previous angles so as to try to avoid printing a second (but lesser) max value 
  pmx = 5;
  cmx = 5;
  
  count_max++;                                    //printing count for number of max values
  Serial.print ("Count.Max   ");
  Serial.println (count_max); 
  neutral = false;                                //stop printing any further angles
 
 }
 
// lmx = pmx;  
 pmx = cmx;                                       //storing the old current max value as previous value 


}
else if (x < 2){                                  //checking for angle less than neutral position
cmn = x*10;                                       //converting x angle (double) into current angle to one decimal place
  if (cmn > pmn && neutral == true){              //checking current angle against previous angle 
                         
    Serial.print ("Tilt_min   ");                 //printing minimum tilt
    Serial.println (pmn);

//    lmn = 3;                                    //reseting these previous min angles so as to try to avoid printing other values
    pmn = 3; 
    cmn = 3;
    
    count_min++;                                  //printing count for number of min values
    Serial.print ("Count.Min   ");
    Serial.println (count_min);
    neutral  = false;                             //stop printing further angles

  }
                                                         
//  lmn = pmn;                                        //storing the old previous min value as last prepvious value
  pmn = cmn;                                      //storing the old current min value as previous value 

}
                                          
Serial.print("AngleX= ");                         //printing actual angle to check validity of max and min printed values 
Serial.println(x);
 
//Serial.println("-----------------------------------------"); 
delay(50); 
} 

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.