My Level Displays Negative Zero - Please Help!

Greetings,

I am including a complete function from a program I am writing. I believe that I am providing too much information for some and not enough (never enough;)- for others. This function works as follows: It uses an MPU-6050 to determine the X and Y axes and whether the device is right-side up or upside down. If it is inverted, it does the math to display the same relative answer of negative 90 to 90 degrees.

All of this works fine and most of the included code is just for those who would say "show the rest of your function." The problem is very specific and I just can not see where to apply a test for negative zero, much less why I would have to.

When in use, the level passes zero and displays negative zero on its way to greater negative numbers, doing so in both the Pitch and Roll expressions. When moving from negative to positive numbers, it also passes "-0" and displays it.

Some of this function may be redundant and most of it has nothing to do with the logical problem I am encountering. I would be most grateful if someone can point out my error and help me eliminate "-0" from my display.

The first part of the function is the math for the MPU6050 data extraction and the last part is simply timing code for locking the display or exiting the function. The problem is my "logic" in the mid-section. I believe I am not up to speed on abs() vs. positive and negative and I am lost as to how this function displays a negative zero.

Respectfully - Baran

void FWAYFunction()
{
fway:

 delay(750);
  while (digitalRead(resetButton) == HIGH )
  {

    if (digitalRead(resetButton) == HIGH )
    {

      while (digitalRead(resetButton) == HIGH )
      { static unsigned long _ETimer;
        if ( millis() - _ETimer >= (10)) {
          _ETimer += (10);
          mpuInterrupt = true;
        }

        if (mpuInterrupt ) { // wait for MPU interrupt or extra packet(s) available


          static unsigned long LastGoodPacketTime;
          mpuInterrupt = false;
          FifoAlive = 1;
          fifoCount = mpu.getFIFOCount();
          if ((!fifoCount) || (fifoCount % packetSize)) { // we have failed Reset and wait till next time!
            digitalWrite(LED_PIN, LOW); // lets turn off the blinking light so we can see we are failing.
            mpu.resetFIFO();// clear the buffer and start over
          } else {
            while (fifoCount  >= packetSize) { // Get the packets until we have the latest!
              mpu.getFIFOBytes(fifoBuffer, packetSize); // lets do the magic and get the data
              fifoCount -= packetSize;
            }
            LastGoodPacketTime = millis();


            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            Yaw = (ypr[0] * 180.0 / M_PI);
            Pitch = (ypr[1] *  180.0 / M_PI);
            Roll = (ypr[2] *  180.0 / M_PI);
            Roll = -Roll;
            TCA9548A(1);
            display2.display();
            display2.setTextSize(2);
            display2.setTextColor(WHITE);
            display2.setCursor(0, 0);
            display2.clearDisplay();

  //  The following routine determines if we are inverting the device and display

  
  //      This part handles rightsideup situations
   if (Pitch + Pitch1 <= 90 && Pitch + Pitch1 >= - 90 && Roll + Roll1 >= - 90 && Roll + Roll1 <= 90)
   
  {TCA9548A(0);
  display1.clearDisplay();
  display1.display();
  TCA9548A(1);
  display2.print("Y: ");
  display2.println((Roll + Roll1),0);
  display2.print("X: ");
  display2.println((Pitch + Pitch1),0);

  
  if(Roll + Roll1 >= 0 && Roll + Roll1 < 10)     //  This set of IF statements is used to determine the X-axis location of the
  {display2.drawCircle(58, 3, 3, WHITE);}    //  "degrees" sign based upon the lenth (2 or 3 digits) of the data.
  else if(Roll + Roll1 >= 10 && Roll + Roll1 < 100 || Roll + Roll1 > -10 && Roll + Roll1 < 0 )
  {display2.drawCircle(68, 3, 3, WHITE);}
  else if(Roll + Roll1 >= 100 || Roll + Roll1 > -100 && Roll + Roll1 <= -10 )
  {display2.drawCircle(81, 3, 3, WHITE);}
  else if(Roll + Roll1 <= -100)
  {display2.drawCircle(84, 3, 3, WHITE);}

  if(Pitch + Pitch1 >= 0 && Pitch + Pitch1 < 10)     //  This set of IF statements is used to determine the X-axis location of the
  {display2.drawCircle(58, 19, 3, WHITE);}    //  "degrees" sign based upon the lenth (2 or 3 digits) of the data.
  else if(Pitch + Pitch1 >= 10 && Pitch + Pitch1 < 100 || Pitch + Pitch1 > -10 && Pitch + Pitch1 < 0 )
  {display2.drawCircle(68, 19, 3, WHITE);}
  else if(Pitch + Pitch1 >= 100 || Pitch + Pitch1 > -100 && Pitch + Pitch1 <= -10 )
  {display2.drawCircle(81, 19, 3, WHITE);}
  else if(Pitch + Pitch1 <= -100)
  {display2.drawCircle(84, 19, 3, WHITE);}
  }
  
  
  if (Pitch + Pitch1 > 90 || Pitch + Pitch1 < - 90 || Roll + Roll1 > 90 || Roll + Roll1 < -90)
 //     Some condition (above) qualified so this part handles upsidedown situations
  {
    TCA9548A(1);
    display2.clearDisplay();
    display2.display();
    TCA9548A(0);
    delay(50);
    display1.setTextSize(2);
    display1.setTextColor(WHITE);
    display1.setCursor(0,0);
    display1.display();
    display1.clearDisplay();
    display1.print("Y: ");
    Rolch = 180 - (Roll + Roll1);
    if (Rolch > 180) {Rolch =  - (360 - Rolch);}
    display1.println(Rolch,0);
    display1.print("X: ");
    Patch = 180 - (Pitch + Pitch1);
    if (Patch > 180) {Patch = - (360 - Patch);}
    display1.println(Patch,0);
    if(Rolch >= 0 && Rolch < 10)     //  This set of IF statements is used to determine the X-axis location of the
  {display1.drawCircle(58, 3, 3, WHITE);}    //  "degrees" sign based upon the lenth (2 or 3 digits) of the data.
  else if(Rolch >= 10 && Rolch < 100 || Rolch > -10 && Rolch < 0 )
  {display1.drawCircle(68, 3, 3, WHITE);}
  else if(Rolch >= 100 || Rolch > -100 && Rolch <= -10 )
  {display1.drawCircle(81, 3, 3, WHITE);}
  else if(Rolch <= -100)
  {display1.drawCircle(84, 3, 3, WHITE);}

  if(Patch  >= 0 && Patch < 10)     //  This set of IF statements is used to determine the X-axis location of the
  {display1.drawCircle(58, 19, 3, WHITE);}    //  "degrees" sign based upon the lenth (2 or 3 digits) of the data.
  else if(Patch >= 10 && Patch < 100 || Patch > -10 && Patch < 0 )
  {display1.drawCircle(68, 19, 3, WHITE);}
  else if(Patch >= 100 || Patch > -100 && Patch <= -10 )
  {display1.drawCircle(81, 19, 3, WHITE);}
  else if(Patch <= -100)
  {display1.drawCircle(84, 19, 3, WHITE);}
  }



            digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Blink the Light
          }


        }
      }
    }
  }
  pressLength_milliSeconds = 0;              //  This is used to set a "Zero Point" in the negative location to offset the starting angle between
  while (digitalRead(resetButton) == LOW )   //  the conduit bender and the vertical (0 degree) angle.  The negative angle is added to the data resulting
  { //  in an accurate display of the actual bend angle.
    delay(50);  //if you want more resolution, lower this number
    pressLength_milliSeconds = pressLength_milliSeconds + 50;
  }
  if (pressLength_milliSeconds <= 150)         //  If the button was held down for .15 seconds, or less,return to the top of the submenu.
  { //  This sets the Bender Offset mode, which combines the negative angle from vertical used to engage
    if (Pitch <= 0)                              //   is held for 250ms or less.
    {
      Pitch1 = abs(Pitch);
    }
    else {
      Pitch1 = - Pitch;
    }
    if (Roll <= 0)
    {
      Roll1 = abs(Roll);
    }
    else {
      Roll1 = - Roll;
    }
    goto fway;
  }


  //if (pressLength_milliSeconds <= 250)         //  If the button was held down for less than 1/2 second, copy the data from val into BenDangle.
  //{                                            //  This sets the Bender Offset mode, which combines the negative angle from vertical used to engage
  //                            //  the conduit bender with the vertical offset to accurately gauge the bend angle.
  // goto fway;                              //  Then, return to the bender loop.  If the button was held longer than 1/2 second, jump out of the loop.
  //}                                            //  and start over.
  //if(pressLength_milliSeconds >= 500)        //  If the button is held for longer than one second, return to the menu.
  //{return;}
  while (pressLength_milliSeconds > 250)
  {
    delay(250);
    if (digitalRead(resetButton) == LOW)
    {
      return;
    }
  }
}

There must be some documentation on ABS(). A -0 is perfectly valid in that it tells you how you got to zero.

Could -0 actually be something like -0.00000001 ?

would not the change below perform the same function?

     if (Pitch <= 0)                              //   is held for 250ms or less.
    {
      Pitch1 = abs(Pitch);
    }
    else {
      Pitch1 = - Pitch;
    }

to

Pitch1 = -Pitch

Zero is nonnegative, so what is being displayed is a floating point number that is slightly less that zero (as suggested above).

If you want to print floats as integers, convert to integers, rather than use print(x,0).

1 Like

I haven't studied the code but I don't think negative zero exists in floating point so I'd also guess it's truncated number.

I know negative zero is impossible with regular two's complement integer. That's why with 16-bits you can count from -32,768 to +32,767, with one more count on the negative side.

How about rounding to the nearest integer?

Pitch = round(ypr[1] * 180.0 / M_PI);
Roll = round(ypr[2] * 180.0 / M_PI);

Thank you for the correct answer - You win a virtual toaster!

Following is my (highly simplified) code. The fancy math took care of the inverted display and simply rounding of the pitch and roll eliminated the negative zero from my display.

Thank you to all who made suggestions - Baran

Here is my simplified code:

 //      This part handles right-side up situations
   if (Pitch <= 90 && Pitch >= - 90 && Roll >= - 90 && Roll <= 90)
   
  {TCA9548A(0);
  display1.clearDisplay();
  display1.display();
  TCA9548A(1);
  display2.print("Y: "); 
  Roll = round(Roll);  //  Rounding eliminated the negative zero!
  display2.println(Roll,0);
  display2.print("X: ");
  Pitch = round(Pitch);  //  Rounding eliminated the negative zero!
  display2.println(Pitch,0);


  //     Some condition (above) qualified so this part handles upside down situations
  {
    TCA9548A(1);
    display2.clearDisplay();
    display2.display();
    TCA9548A(0);
    delay(50);
    display1.setTextSize(2);
    display1.setTextColor(WHITE);
    display1.setCursor(0,0);
    display1.display();
    display1.clearDisplay();
    display1.print("Y: ");
    Roll = 180 - Roll;
    if (Roll > 180) {Roll =  - (360 - Roll)-1;}  
    display1.println(Roll,0);
    display1.print("X: ");
    Pitch = 180 - Pitch;
    if (Pitch > 180) {Pitch = - (360 - Pitch)-1;}
    display1.println(Pitch,0);

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