Issue using abs()

Hi,

I want to replace this function and use abs() to find the absolute value.

if (speed < 0)                              
      speed = -speed;

with

speed = abs(speed);

But it's not equivalent for some reason?? Am i using abs() correctly?

How is speed declared ?

DryRun: But it's not equivalent for some reason??

What result do you get? That should be perfectly fine. The only caveat with abs is to remember that it is a macro and not a function so watch out if you have to write an expression in there twice. But in the trivial example you show in your post it should be the same.

Post a complete test code and output that demonstrates your issue.

UKHeliBob: How is speed declared ?

float speed;

From the example given on: https://www.arduino.cc/reference/en/language/functions/math/abs/ I'm wondering if the correct use of abs() should just be:

abs(speed);

instead of

speed = abs(speed);

?

fabs() for floats/doubles

jremington: fabs() for floats/doubles

And that's why it is important to post a complete piece of code and not just the one dumb line you can't tell anything is wrong from.

jremington: fabs() for floats/doubles

And to make things more confusing, Arduino.h defines abs() as

#define abs(x) ((x)>0?(x):-(x))

But there is no mention of fabs() in the Arduino reference docs. https://www.arduino.cc/reference/en/language/functions/math/fabs/ gives an error. Maybe this should be added. Unless it's not officially supported?

Delta_G: And that's why it is important to post a complete piece of code and not just the one dumb line you can't tell anything is wrong from.

My apologies... but i had only started writing the function at that time. I am trying to calculate the speed of rotation of my robot using the encoders on both wheels. I am sending the commands via serial monitor to turn the robot right or left. Here is what i have so far:

int left, right, turnout = 0;   //global variables

//the turn function. It uses the encoder pulse values from both DC motors to calculate current 
//speed of rotation and then based on the user command, turns left or right, and outputs the 
//appropriate PWM value to send to each motor.
void turn()      
{
   
  float turnspeed = 0;
  float rotationratio = 0;
  int turnmin = -5, turnmax = 5; 

  
  if (left == 1 || right == 1)
  {
                                
    turnspeed = (pulseright + pulseleft);  //current turn speed; variables of type int; pulseright and pulseleft have polarities.
    
    turnspeed = abs(turnspeed);     //should return absolute float value of turn speed
    
    rotationratio = 5 / turnspeed;          //set the speed of rotation
    
    if (rotationratio <= 5)
    {
      rotationratio = 0.5;
    }
     
    if (rotationratio > 5)  //this implies that turnspeed < 1
    {
      rotationratio = 5;
    }
  }

  if (left ==1) 
  {
    turnout += rotationratio;
  }
  else if (right == 1 )
  {
    turnout -= rotationratio;
  }
  else turnout = 0;
  
  if (turnout > turnmax)   
    turnout = turnmax;     //the max value setting of amplitude
  if (turnout < turnmin)   
    turnout = turnmin;      //the min value setting of amplitude 
  
  Turn_pwm = turnout;    //PWM value sent to both motors to initiate the rotation of the robot
}

When i tried turnspeed = fabs(turnspeed); it doesn't work, for some reason.

fabs() and abs() don't alter the variable, so you must assign it to something which can be the same variable again if you only want to store an absolute version. So

var = abs(var);
//or
absf(var);

And yeah, some functions that come from standard C libraries are not explicitly documented on Arduino. In this case because (although I hate the implementation), abs() should work just fine.

So, this is the code that i had previously in the function for absolute value of speed and it worked:

if (turnspeed < 0)     //absolute value of current speed
   {
     turnspeed = -turnspeed;

But after i replaced it with the following, it's not working anymore, as there is no PWM output to the motors.

turnspeed = abs(turnspeed);

What do you see if you print turnspeed ?

UKHeliBob: What do you see if you print turnspeed ?

Output from Serial Monitor:

29.00
13.00
0.00
24.00
10.00
34.00
18.00
5.00
29.00
14.00
0.00
24.00
10.00
34.00
20.00
6.00
29.00
14.00
0.00
24.00
10.00
33.00
18.00
4.00
28.00
14.00
0.00
24.00
9.00
33.00
19.00
4.00
28.00
14.00
0.00
24.00
10.00
34.00
20.00
5.00
29.00
15.00
0.00
24.00
10.00
33.00
19.00
5.00
29.00
14.00
0.00
24.00
9.00
32.00
19.00
4.00
28.00
14.00
0.00
24.00
10.00
34.00

So, it's working as expected to output only positive values of the encoder rotation speed. But for some reason, there is no PWM output, meaning that the variable 'turnout' is zero. :confused:

turnspeed = (pulseright + pulseleft);

What are pulseright and pulseleft?

Please, can we have a complete example that we can compile and test that exhibits the problem instead of snippets?

https://snippets-r-us.com/ https://stackoverflow.com/help/minimal-reproducible-example

where do left and right get values?

fabs(turnspeed);     //should return absolute float value of turn speed

It does return the absolute value, but this line is as useless as writing:

27.5;

It doesn't store the value anywhere. It doesn't alter the value of turnspeed.

You need:

turnspeed = fabs(turnspeed);

DryRun: But there is no mention of fabs() in the Arduino reference docs. https://www.arduino.cc/reference/en/language/functions/math/fabs/ gives an error. Maybe this should be added.

We do have adding documentation for this and the many other undocumented math functions on the "to-do" list: https://github.com/arduino/reference-en/issues/522 and some related discussion here: https://github.com/arduino/reference-en/issues/362

There is a weird situation because some cores use the Arduino macro implementation of abs(), which works with any type, while other cores (including Arduino megaAVR Boards, ESP8266, and ESP32) use the standard implementation of abs(), which does not work with float. So it's pretty much a huge mess and the incomplete documentation doesn't help matters.

DryRun: Unless it's not officially supported?

I don't really know what "officially supported" means.