Problems with while loop on MPU6050 application

Hello and Happy new Year to all!
I am trying to build an arm with the self-balance function using the MPU6050 Gyro and an Arduino Uno. While writing the sketch, i ran into a problem regarding the while loops, actually I cannot exit the loop once it starts to execute. And i can't seem to figure out what I missed.
Regardless how I move the gyro, eaven when the position is reversed, there is no change on the serial monitor.
Also search on the forum for clues and same story. Bellow is the sketch and a prinscreen of the serial monitor. Any help is highly appreciated.
Thank you all!

L.E. - I updated the code, fix syntax errors, same story.

#include <Wire.h>

const int MPU_addr=0x68;
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
 
int minVal=265;
int maxVal=402;
 
double x;
double y;
double z;

int xdeg;  //angle to be converted from 360 degrees to +/-180 degrees on X axys
int ydeg;  //angle to be converted from 360 degrees to +/-180 degrees on Y axys

double offsetp = 20;  //positive angular tolerance in respect to the horizontal line
double offsetm = -20; //negative angular tolerance in respect to the horizontal line





void setup(){
  
Wire.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
Serial.begin(9600);

}
void loop(){

boolean validatorx1;
boolean validatorx2;
boolean xalign = false;
 
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);
y= RAD_TO_DEG * (atan2(-xAng, -zAng)+PI);
z= RAD_TO_DEG * (atan2(-yAng, -xAng)+PI);

// convert the X axis angles from 360 degrees to +/- 180 degrees format
if (x < 180) {
  xdeg = x;
}

if (x > 180) {
  xdeg = 180 - 1;
}
// convert the Y axis angles from 360 degrees to +/- 180 degrees format
if (y < 180 ){
  ydeg = y;
}

if (y > 180 ) {
  ydeg = 180 - y;
}


Serial.print("X Angle = ");
Serial.println(xdeg);
 
Serial.print("Y Angle= ");
Serial.println(ydeg);
 

Serial.println("-----------------------------------------");

if (xdeg > offsetp)  { //check the positive deviation on X axis
  validatorx1 == false;
}

if (xdeg < offsetm) { //check the negative deviation on Y axis
  validatorx2 == false;
}

while (validatorx1 == false) {                 //if on the X axis the deviation is positive then engage one servo motor in order to lift then plate until  
  Serial.println ("Lifting Right");            // the angle is between 0 and offsetp value
  Serial.println ("Angle difference is ");     // here it starts the loop, but regardless how I rotate the MPU6050, eaven if the conditions to exit the loop
  Serial.print (xdeg-offsetp);                 // are fulfilled, it never does. 
 
 if (xdeg < offsetp)  {
  break;
 }
}

while (validatorx2 == false) {                 //if on the Y axis the deviation is positive then engage another servo motor in order to lift then plate until  
  Serial.println ("Lifting Left");             // the angle is between 0 and offsetp value
  Serial.println ("Angle difference is ");     // here it starts the loop, but regardless how I rotate the MPU6050, eaven if the conditions to exit the loop
  Serial.print (offsetm + xdeg);               // are fulfilled, it never does. 
  delay (1000);
  validatorx2 == true;
}

if ((validatorx1) and (validatorx2)) {                           //after the plate is alligned to X axis, the alignment moves to y axis
  Serial.println ("X axis is alligned - moving to Y axis");    //never reach to test this loop because of the other two that are not exiting
  xalign == true;
}


delay (1000);
}

Arduino MPU6050.PNG

Arduino MPU6050.PNG

This while loop is your problem:

  while (validatorx1 == false)                   //if on the X axis the deviation is positive then engage one servo motor in order to lift then plate until
  {
    Serial.println ("Lifting Right");            // the angle is between 0 and offsetp value
    Serial.println ("Angle difference is ");     // here it starts the loop, but regardless how I rotate the MPU6050, eaven if the conditions to exit the loop
    Serial.print (xdeg - offsetp);               // are fulfilled, it never does.
    if (xdeg < offsetp)
    {
      break;
    }
  }

It loops forever if validatorx1 is false, which it is - there is nothing anywhere in your code to set it true.
You can break the loop if xdeg < offsetp, but apparently it isn't, so it loops forever, as you observe.

It appears from the comments that you are expecting xdeg to change during the while loop. It won't. xdeg is set earlier in your loop function but that code won't be executed again until your while loop exits, which will never happen.

You have a (common) fundamental misunderstanding of how and when variables change in code.

These equations for tilt angles are mostly nonsense, but the results will change as the actual tilt angles change.

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);
y= RAD_TO_DEG * (atan2(-xAng, -zAng)+PI);
z= RAD_TO_DEG * (atan2(-yAng, -xAng)+PI);

If you are interested in measuring the pitch and roll angles, the correct approach is here: How_to_Use_a_Three-Axis_Accelerometer_for_Tilt_Sensing-DFRobot

Here is the code for the MPU-6050

// minimal MPU-6050 tilt and roll (sjr)
// works perfectly with GY-521, pitch and roll signs agree with arrows on sensor module 7/2019
// tested with eBay Pro Mini, **no external pullups on SDA and SCL** (works with internal pullups)
// A4 = SDA, A5 = SCL

#include<Wire.h>
const int MPU_addr1 = 0x68;
float xa, ya, za, roll, pitch;

void setup() {

  Wire.begin();                                      //begin the wire communication
  Wire.beginTransmission(MPU_addr1);                 //begin, send the slave adress (in this case 68)
  Wire.write(0x6B);                                  //make the reset (place a 0 into the 6B register)
  Wire.write(0);
  Wire.endTransmission(true);                        //end the transmission
  Serial.begin(9600);
}

void loop() {

  Wire.beginTransmission(MPU_addr1);
  Wire.write(0x3B);  //send starting register address, accelerometer high byte
  Wire.endTransmission(false); //restart for read
  Wire.requestFrom(MPU_addr1, 6, true); //get six bytes accelerometer data
  int t = Wire.read();
  xa = (t << 8) | Wire.read();
  t = Wire.read();
  ya = (t << 8) | Wire.read();
  t = Wire.read();
  za = (t << 8) | Wire.read();
// formula from https://wiki.dfrobot.com/How_to_Use_a_Three-Axis_Accelerometer_for_Tilt_Sensing
  roll = atan2(ya , za) * 180.0 / PI;
  pitch = atan2(-xa , sqrt(ya * ya + za * za)) * 180.0 / PI; //account for roll already applied

  Serial.print("roll = ");
  Serial.print(roll,1);
  Serial.print(", pitch = ");
  Serial.println(pitch,1);
  delay(400);
}

wildbill:
This while loop is your problem:

  while (validatorx1 == false)                   //if on the X axis the deviation is positive then engage one servo motor in order to lift then plate until

{
    Serial.println ("Lifting Right");            // the angle is between 0 and offsetp value
    Serial.println ("Angle difference is ");    // here it starts the loop, but regardless how I rotate the MPU6050, eaven if the conditions to exit the loop
    Serial.print (xdeg - offsetp);              // are fulfilled, it never does.
    if (xdeg < offsetp)
    {
      break;
    }
  }




It loops forever if validatorx1 is false, which it is - there is nothing anywhere in your code to set it true.
You can break the loop if xdeg < offsetp, but apparently it isn't, so it loops forever, as you observe.

It appears from the comments that you are expecting xdeg to change during the while loop. It won't. xdeg is set earlier in your loop function but that code won't be executed again until your while loop exits, which will never happen.

You have a (common) fundamental misunderstanding of how and when variables change in code.

The condition xdeg<offsetp is achieved by tilting the sensor by hand for the moment. Anyway, I tilted the sensor way more than necessary to achieve the condition, but the while loop continued displaying same values over and over again. Also the same condition should turn the value of validatorx1 to true

You're missing the point. You have a bunch of code at the start of the loop function that sets xdeg based on what you read from your MPU.

Having read it, you run your while loop. There is nothing in your while loop that changes xdeg, so if it doesn't exit on the first iteration, it never will. You can wave the MPU around as much as you like, but nothing is reading it.

So the problem was solved. I needed to rewrite the while loops, to work as intented. Also I missed to init the MPU6050 inside every while loop. Just as bonus, I re-wrote the entire scetch using the functions. Now the while loops look like this:

void balance_right() {
  while ((varx1 == 0) && (varx2 == 1)) {  //these are established in a previous validation function.
    mpu.Execute();                        //this is the sensor init
    Serial.println ("Lifting right cylinder");
    if (angx <= refn) {                  //checking the conditions
      angx = mpu.GetAngX();
      Serial.println ("Actual X angle");
      Serial.println (angx);
    }
    else if (angx > refn) {
      Serial.println ("Condition fulfilled");
      Serial.println (angx);
      angx = 0;
    }
  }
}

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