vakue determined for int variable in a function but returns 0

Here is part of a sketch i wrote to determine a number to analogWrite() to set the speed of a DC motor. I am using NodeMCU (esp8266) so the PCM range is 0-1023. Following the code segment is debug out put from the Serial monitor to demonstrate the issue. The carSpeed int is assigned value in the function and those values are shown on the debug output but by the end processing in the function it has a reported value of 0. Can anyone explain to me why the variable ends up 0 and how I can fix it?
Thanks, Richard

//functions
BLYNK_WRITE(V1)
{
int x = param[0].asInt();
int y = param[1].asInt();

Serial.println(" y is: " + String(y) + " x is: " + String(x)); //DEBUG

int carSpeed = calculateSpeed(x , y);
Serial.println("AFTER CALC Speed " + String(carSpeed) ); //DEBUG

turnSpeed = .5 * carSpeed;
moveControl(x, y, carSpeed, turnSpeed);

//Serial.println("AFTER MOVE Speed " + String(carSpeed) ); //BEGUG
Serial.println();
}
/*
1 2 3 4 5 6
int speedRange[] = {252, 378, 507, 517, 640, 765}; DEBUG

// set speed based speed tier above and below midRange */
int calculateSpeed(int x, int y)
{
Serial.println("In calculateSpeed function y " + String(y) + " x " + String(x)); //DEBUG

// base tier +- 5 from midRange..speed 0
if ( y < speedRange[3] || y > speedRange[4])
{ // 507 to 517
carSpeed = 0;
Serial.println("in if 507 to 517 carSpeed " + String(carSpeed)); //DEBUG
}

//in first tier upper or lower range .. speed 40%
if (y < speedRange[3] && y > speedRange[4])
{ //<507 or >517
carSpeed = .40 * speedMax ; //409
Serial.println("in if <507 or <517 carSpeed " + String(carSpeed)); //DEBUG
}

// in second tier upper or lower range .. up speed to 75%
if (y < speedRange[2] || y > speedRange[5] )
{ // <378 or >640
carSpeed = .75 * speedMax; //767
Serial.println("in if <378 or >640 carSpeed " + String(carSpeed)); // DEGUG
}

//in third tier upper and lower ranges...up speed to 100%
if (y < speedRange[1] || y > speedRange[6] )
{ // < 252 or > 765
carSpeed = speedMax; //1023
Serial.println("in < 252 or > 765 carSpeed " + String(carSpeed)); //DEBUG
}

//if not moving forward or back but want to turn
if (carSpeed = 0 && (x < speedRange[3] || x > speedRange[4]))
{ // 507 517
carSpeed = .40 * speedMax; //409

Serial.println("in carspeed 0, 507>x<517 " + String(carSpeed)); //DEBUG
}

Serial.println(" carSpeed val just before calc function return " + String(carSpeed)); //DEBUG

return carSpeed;
} 

From Serial Monitor

y is: 1006 x is: 418
In calculateSpeed function y 1006 x 418
in if 507 to 517 carSpeed 0
in if <378 or >640 carSpeed 767
carSpeed val just before calc function return 0
AFTER CALC Speed 0

y is: 1024 x is: 431
In calculateSpeed function y 1024 x 431
in if 507 to 517 carSpeed 0
in if <378 or >640 carSpeed 767
in < 252 or > 765 carSpeed 1023
carSpeed val just before calc function return 0
AFTER CALC Speed 0

Post the rest of your code. Have you also got some global variable with that same name?

Try googling “C++ scope” and see if the things there are enlightening.

carSpeed is a global variable.

This is the entire sketch:

#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

#define RightMotorSpeed 5
#define RightMotorDir 0
#define LeftMotorSpeed 4
#define LeftMotorDir 2

// mid range of joystick travel
int midRange = 512;

int carSpeed;
int turnSpeed;
int speedMax = 1023; //PWM range for esp8266 0-1023 arduino 0-255

// vary speed based on y position
int speedRange[] = {252, 378, 507, 517, 640, 765};

// Blynk and Wifi connection info
char auth[] = "";
char ssid[] = "";
char pass[] = "";

void setup()
{
Serial.begin(9600);
Blynk.begin(auth, ssid, pass);

pinMode(RightMotorSpeed, OUTPUT); //not necessary for pin used for PWM
pinMode(LeftMotorSpeed, OUTPUT); // ie; values post with analogWrite()
pinMode(RightMotorDir, OUTPUT);
pinMode(LeftMotorDir, OUTPUT);

//set initial speed to 0
analogWrite(RightMotorSpeed, 0);
analogWrite(LeftMotorSpeed, 0);

}

void loop()
{
Blynk.run();
}

//functions
BLYNK_WRITE(V1)
{
int x = param[0].asInt();
int y = param[1].asInt();

Serial.println(" y is: " + String(y) + " x is: " + String(x)); //DEBUG

int carSpeed = calculateSpeed(x , y);
Serial.println("AFTER CALC Speed " + String(carSpeed) ); //DEBUG

turnSpeed = .5 * carSpeed;
moveControl(x, y, carSpeed, turnSpeed);

//Serial.println("AFTER MOVE Speed " + String(carSpeed) ); //BEGUG
Serial.println();
}
/*
1 2 3 4 5 6
int speedRange[] = {252, 378, 507, 517, 640, 765}; DEBUG

// set speed based speed tier above and below midRange */
int calculateSpeed(int x, int y)
{
Serial.println("In calculateSpeed function y " + String(y) + " x " + String(x)); //DEBUG

// base tier +- 5 from midRange..speed 0
if ( y < speedRange[3] || y > speedRange[4])
{ // 507 to 517
carSpeed = 0;
Serial.println("in if 507 to 517 carSpeed " + String(carSpeed)); //DEBUG
}

//in first tier upper or lower range .. speed 40%
if (y < speedRange[3] && y > speedRange[4])
{ //<507 or >517
carSpeed = .40 * speedMax ; //409
Serial.println("in if <507 or <517 carSpeed " + String(carSpeed)); //DEBUG
}

// in second tier upper or lower range .. up speed to 75%
if (y < speedRange[2] || y > speedRange[5] )
{ // <378 or >640
carSpeed = .75 * speedMax; //767
Serial.println("in if <378 or >640 carSpeed " + String(carSpeed)); // DEGUG
}

//in third tier upper and lower ranges...up speed to 100%
if (y < speedRange[1] || y > speedRange[6] )
{ // < 252 or > 765
carSpeed = speedMax; //1023
Serial.println("in < 252 or > 765 carSpeed " + String(carSpeed)); //DEBUG
}

//if not moving forward or back but want to turn
if (carSpeed = 0 && (x < speedRange[3] || x > speedRange[4]))
{ // 507 517
carSpeed = .40 * speedMax; //409

Serial.println("in carspeed 0, 507>x<517 " + String(carSpeed)); //DEBUG
}

Serial.println(" carSpeed val just before calc function return " + String(carSpeed)); //DEBUG

return carSpeed;
}

// post direction and speed
void moveControl(int x, int y, int carSpeed, int turnSpeed)
{
//Serial.println("In moveControl function y " + String(y) + " x " + String(x)); //DEBUGM char carMotion("");
//initilize debug string variables
char carMotion[] = " ";
char stringPrint[40];

// above midRange = forward HIGH else reverse LOW
if (y > midRange) {
digitalWrite(RightMotorDir, HIGH);
digitalWrite(LeftMotorDir, HIGH);

strcpy(carMotion, " Forward "); //DEBUG
}
else if ( y < midRange) {
digitalWrite(RightMotorDir, LOW);
digitalWrite(LeftMotorDir, LOW);

strcpy(carMotion, " Backwards "); //DEBUG
}

// turn off motor speed when x at md
if ( x == midRange && y == midRange) {
analogWrite(RightMotorSpeed, 0);
analogWrite(LeftMotorSpeed, 0);

strcpy(carMotion, " Stopped "); //DEBUG
}
// moving straight FORWARD or BACK if x is not more that =-5 from midRange both motor same speed
else if ( x > (midRange - 5) && x > (midRange + 5))
{ // 507 < x < 517
analogWrite(RightMotorSpeed, carSpeed);
analogWrite(LeftMotorSpeed, carSpeed);

strcat(carMotion, " No Turn "); //DEBUG
}
// move front or back end of robot to right if x more than +5 inits from center center
else if ( x > (midRange + 5) )
{ //x >517
analogWrite(RightMotorSpeed, turnSpeed);
analogWrite(LeftMotorSpeed, carSpeed);

strcat(carMotion, " Right Turn "); //DEBUG
}
// move front or back of robot to left if x is more than -5 from midRange
else if (x < (midRange - 5) )
{ // x < 507
analogWrite(RightMotorSpeed, carSpeed);
analogWrite(LeftMotorSpeed, turnSpeed);

strcat(carMotion, " Left Turn "); //DEBUG

}
//Serial.println(carMotion); //DEBUG
}

One obvious error, array elements are numbered starting with 0, not 1, and the last element would be speedRange[5], not speedRange[6].

/*
                      1    2    3    4    5    6
  int speedRange[] = {252, 378, 507, 517, 640, 765};  DEBUG

  // set speed based speed tier above and below midRange */

Please read the How to use this forum post and pay particular attention to the part about how to properly post your code. It will go a long way to help us help you.

If carSpeed is a global variable then there is no need to return anything. Instead of creating a new variable (what happens when you put the “int” or whatever other type there) use the global variable in the function. And then the function can return void. You don’t have to return global variables.

Then google “C++ scope” and read if you want to understand the why.

Please edit your posts to add code tags ("</>" button).

Please use blockquotes as shown in "How to ask a programming question on this forum"

You may have compile warnings that you haven't fixed. You defined the variable carSpeed three times. Once in globals, once in loop() and again in moveControl().

It may compile OK, but it is really confusing what carSpeed do you want to use?

I suspect that your problem is that you are modifying a global value in calculateSpeed() and returning it from your function:

int carSpeed = calculateSpeed(x , y);

You don't need to return a global from a function. It's redundant and really hard to read.

I could be wrong here, but when you redefine a global variable in a function, you now have two distinctly different variables.

Right you are on the array numbering David.... I was asleep at the switch on that one.... a condition i experience all to often unfortunately.

I don't have any compile errors... the sketch runs.

I added 'int' to carSpeed with every use in the calculateSpeed function trying to cure the no value outcome at the end of the function.

The values calculated at each level are decimal numbers and I was testing to see if the rounding process was a factor in the 0 value.

I have tried defining a different variable to hold the speed number calculated at each tier. That variable was 0 at the end too.

I rewrote the calcSpeed function. The prior version specifically defining the range in each tier. The if logic got kind of complex. I used if , else if statements in that version and ended up calculating carSpeed only once. carSpeed had 0 value when control was returned to the call until i made it return a value. Then it worked. I rewrote the function because the debug printout said it was not getting the carSpeed value in the correct if statement. I see now that it was doing what I told it to do... I was using the wrong number for the speedRange element numbers.

Still.... I cannot understand why the carSpeed variable ends up 0 at the end of the current, more concise calculateSpeed function.

I added 'int' to carSpeed with every use in the calculateSpeed function trying to cure the no value outcome at the end of the function.

OK, well that wasn't the right fix. Maybe let's take a look at that error instead.

Still.... I cannot understand why the carSpeed variable ends up 0 at the end of the current, more concise calculateSpeed function.

Did you google what I told you to google yet?

Basically, because the carSpeed variable that you're looking at in the rest of the code never got modified. It was 0 all along. The second variable with the same name that you created that was local to that function got calculated, but got destroyed when the function exited.

Having two variables with the same name in the same scope is a really confusing thing. You shouldn't do that.

I'm not kidding, if you want to understand then google "C++ scope" and do a little reading. It will all become clear pretty quick.

Yes I did googe and scan the C++ scope chapter .

I have gone through the code and deleted all the 'int' I added. Now I only have one declared int carSpeed.

I declared the two functions in Set Up where before they were kind of declared in BLYNK_WRITE ...i guess it is a function too. Arduino says don't declare a function inside a function.

I changed all the erroneous reference to the speedRange array so at least the tiers are named right now.

I am kind of spent at this point and will pick up tomorrow to see if anything I did changed anything.

I sincerely appreciate the time and expertise you have given me!!!
Richard

This is where you set ‘carSpeed’ to zero, shortly before returning it:

 if (carSpeed = 0 && (x < speedRange[3] || x > speedRange[4]))

You probably meant:

 if (carSpeed == 0 && (x < speedRange[3] || x > speedRange[4]))

OMG.... johnwasser ....you are right on the money! I would never have guessed you could assign a value to a variable as a condition in an if statement. I would have thought the condition would be ignored or maybe flagged. Great catch...THANKS!

MisterRPH:
I would never have guessed you could assign a value to a variable as a condition in an if statement. I would have thought the condition would be ignored or maybe flagged. Great catch...THANKS!

If your warning level is set high enough in "Arduino->Preferences...->Compiler warnings," you will see a warning for what you did:

sketch_sep14a.ino:41:9: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
   if (a = 1 && isInByteList(t.hour, OnHour, sizeof OnHour) && isInByteList(t.min, OnMin, sizeof OnMin))
       ~~^

That is one of the many reasons I recommend that EVERYONE set their warning level to "All". You may see a bunch of warnings from libraries (from lazy programmers) but only when the libraries are compiled. The second time you verify that sketch you will only see the warnings for your sketch.