Failing to use a simple switch

I’m close to hair-tearing stage so would appreciate some help please.

I’ve heavily commented my code for posting here. And in my testing I’ve used many Serial.begin commands. But I still cannot see why it fails.

All the servo stuff (and LED) was working fine until this attempt to add a switch using pin D4. I either get ‘videoLength’ was not declared in this scope or, if I try other options for placing int videoLength, its value does not get used in loop mode, being replaced by zero!

My aim is simply to set it to either 5s or 30s in setup mode, so that is then used in loop mode. I’m guessing that I’m breaking the rules about when and where to define variables?

// Testing currently with 328 #09
// All was working fine until I tried to add a switch to
// set value of videoLength
// #include <Servo.h> // Uses code from the Arduino library
#include <VarSpeedServo.h> // Uses the VarSpeedServo library

//  Servo myservo;  // "Create servo object to control a servo"
// VarSpeedServo myServo;
VarSpeedServo myservo;

int outPos = 17;
int inPos = 5; // So rotation is 12 degs
const int triggerPin = 5; // Thursday 11 June 2020, 2031, was 6
const int delayPeriod = 250; // Delay between press/release simulations
// int videoLength = 5000; // Set length of video recording to 5 s
int waitBeforeRelease = 200;
const int redledPin = 8; // (Blue LED on bb)
const int switchPin = 4;
// int videoLength;
// With the above int commented out, sketch does not compile.
// Error = 'videoLength' was not declared in this scope'
// But it's not meant to be a GLOBAL variable, and is defined
// in setup mode.

void setup()
{
  Serial.begin(9600);
  Serial.println("Program now in setup");
  Serial.println("SKETCH: CUBE-ServoPlusLED-SwitchD4");
  Serial.print("videoLength = ");
  Serial.println(videoLength);

  myservo.attach(9);
  pinMode(switchPin, INPUT_PULLUP);
  pinMode(triggerPin, INPUT_PULLUP);
  pinMode(redledPin, OUTPUT);
  myservo.write(outPos); // Rotates to the 'Out' position.

  // Test D4 to choose value of videolength
  if (digitalRead(switchPin) == HIGH)
  {
    int videoLength = 30;
    Serial.print("videoLength in IF = ");
    Serial.println(videoLength);
  }
  else
  {
    int videoLength = 5;
    Serial.print("videoLength in ELSE = ");
    Serial.println(videoLength);
  }

  Serial.print("videoLength after IF/ELSE= ");
  Serial.println(videoLength); // Expected 5 or 30 but this
  // shows videoLength = 0 ??
  // **************************************************

}
// Servo arm is now close to face of button.

void loop()
{

  // The loop will be run only when a LOW is detected
  if (digitalRead(triggerPin) == LOW)
  {
    myservo.write(inPos);
    delay(3100); // Press for > 3s to power up
    myservo.write(outPos);
    delay(100); // Delay before starting video

    myservo.write(inPos); // 1st of 2 presses
    delay(waitBeforeRelease);
    myservo.write(outPos);
    delay(200);

    myservo.write(inPos); // 2nd of 2 presses
    delay(waitBeforeRelease);
    myservo.write(outPos);
    // Video is now running. Stop it after videoLength.
    digitalWrite(redledPin , HIGH) ;

    //    Serial.println("Program now in loop mode");
    //    Serial.print("videoLength = ");
    //    Serial.println(videoLength); // Correctly shows 5 or 30

    delay(videoLength); // So I just see the 200 mS flash
    // Not the 5 or 30 s that I expected
    // ******************************************************
    myservo.write(inPos);
    delay(waitBeforeRelease);
    myservo.write(outPos);
    digitalWrite(redledPin , LOW) ;
    delay(200); // Delay before powering off

    myservo.write(inPos); // Power off with >3s press
    delay(3100);
    myservo.write(outPos);
  }
}

With this line of code in setup()

Serial.println(videoLength);

you are referring to videoLength before you define it inside setup()

...R

Thanks, but that was one of the several options I had tried in vain. With the variable defined at the very start of setup mode I get the same error, so guess there’s something else wrong.

Here’s the edited code:

// Testing currently with 328 #09
// All was working fine until I tried to add a switch to
// set value of videoLength
// #include <Servo.h> // Uses code from the Arduino library
#include <VarSpeedServo.h> // Uses the VarSpeedServo library

//  Servo myservo;  // "Create servo object to control a servo"
// VarSpeedServo myServo;
VarSpeedServo myservo;

int outPos = 17;
int inPos = 5; // So rotation is 12 degs
const int triggerPin = 5; // Thursday 11 June 2020, 2031, was 6
const int delayPeriod = 250; // Delay between press/release simulations
// int videoLength = 5000; // Set length of video recording to 5 s
int waitBeforeRelease = 200;
const int redledPin = 8; // (Blue LED on bb)
const int switchPin = 4;
// int videoLength;
// With the above int commented out, sketch does not compile.
// Error = 'videoLength' was not declared in this scope'
// But it's not meant to be a GLOBAL variable, and is defined
// in setup mode.

void setup()
{
  int videoLength;
  Serial.begin(9600);
  Serial.println("Program now in setup");
  Serial.println("SKETCH: CUBE-ServoPlusLED-SwitchD4");
  Serial.print("videoLength = ");
  Serial.println(videoLength);

  myservo.attach(9);
  pinMode(switchPin, INPUT_PULLUP);
  pinMode(triggerPin, INPUT_PULLUP);
  pinMode(redledPin, OUTPUT);
  myservo.write(outPos); // Rotates to the 'Out' position.

  // Test D4 to choose value of videolength
  if (digitalRead(switchPin) == HIGH)
  {
    int videoLength = 30;
    Serial.print("videoLength in IF = ");
    Serial.println(videoLength);
  }
  else
  {
    int videoLength = 5;
    Serial.print("videoLength in ELSE = ");
    Serial.println(videoLength);
  }

  Serial.print("videoLength after IF/ELSE= ");
  Serial.println(videoLength); // Expected 5 or 30 but this
  // shows videoLength = 0 ??
  // **************************************************

}
// Servo arm is now close to face of button.

void loop()
{

  // The loop will be run only when a LOW is detected
  if (digitalRead(triggerPin) == LOW)
  {
    myservo.write(inPos);
    delay(3100); // Press for > 3s to power up
    myservo.write(outPos);
    delay(100); // Delay before starting video

    myservo.write(inPos); // 1st of 2 presses
    delay(waitBeforeRelease);
    myservo.write(outPos);
    delay(200);

    myservo.write(inPos); // 2nd of 2 presses
    delay(waitBeforeRelease);
    myservo.write(outPos);
    // Video is now running. Stop it after videoLength.
    digitalWrite(redledPin , HIGH) ;

    //    Serial.println("Program now in loop mode");
    //    Serial.print("videoLength = ");
    //    Serial.println(videoLength); // Correctly shows 5 or 30

    delay(videoLength); // So I just see the 200 mS flash
    // Not the 5 or 30 s that I expected
    // ******************************************************
    myservo.write(inPos);
    delay(waitBeforeRelease);
    myservo.write(outPos);
    digitalWrite(redledPin , LOW) ;
    delay(200); // Delay before powering off

    myservo.write(inPos); // Power off with >3s press
    delay(3100);
    myservo.write(outPos);
  }
}

If you have a variable that you want to use in both setup() and loop() it needs to be global. But currently you have two different versions of videoLength defined in setup() and two more commented out at global scope. You need just ONE of the global ones and the take the int from in front of the uses in setup(). That's all.

Steve

This is a variable declaration...

int videoLength;

It declares a new variable called "videoLength" of type int.
It's "scope" (where it can be seen and used) is within the { } brackets where it is declared, nowhere else.
If you declare it at the top of your program it is "global" and it's "scope" is everywhere.

This is a variable assignment...

videoLength = 5;

It assigns the value 5 to a previously declared variable called "videoLength".

This is a variable definition and an assignment all in one go...

int videoLength = 5;

It is C shorthand and you don't have to use it, but it makes your code look neater if you do.

However crucially, if you have a another variable "videoLength" at a higher level of scope (or global), and you then write...

int videoLength;

or

int videoLength = 5;

You have now declared a completely new variable also called "videoLength".
It replaces any reference to any another variable with the same name, but at a higher level of scope.

This is the coding equivalent of having two children and calling them both "Bob". Perfectly legal, and you can do it, but you'd be stupid to try: To easy to get your two "Bob's" confused.

Edit: TL;DR
You basic mistake is assuming that in order to assign value "5" to variable "videoLength" you need to precede the statement with the keyword "int":

int videoLength = 5;

This is incorrect. Doing that introduces a new declaration of an entirely new variable, the scope of which is only within the { } where it is declared. After that "videoLength" goes back to whatever was declared at the higher level of scope (or it is undeclared if not declared previously).

(deleted)

Thanks Steve, but that was one of the options I mentioned that resulted in "... its value does not get used in loop mode, being replaced by zero!"

Have to leave for a short while but on return I'll add a few more serial commands and re-post the code to show you what I mean. In short, instead of the LED on D8 being displayed for 5 or 30 s, it blinks once, presumably for 200 ms.

Terry

Terrypin:
Thanks Steve, but that was one of the options I mentioned that resulted in "... its value does not get used in loop mode, being replaced by zero!"

I don't think it is.

Please read my post #4 again.

Your problem is "scope" and the fact that you think in order to assign to a variable you need to prefix the variable with the key word "int".

That is incorrect. prefixing a variable assignment "videoLength = 5" with the keyword int "int videoLength = 5" declares an entirely new version of the variable. That new version exists (is "in scope") only within the { } where it is defined. After that it goes back to the global version.

This is why you think "the variable does not get used in loop mode". The global variable is ZERO (or whatever you assigned to it when you declared the global).

// Global variable videoLength
int videoLength = 0; // Set length of video recording to 0 s

void setup()
{
  // Test D4 to choose value of videolength
  if (digitalRead(switchPin) == HIGH)
  {
    // NEW local variable declared with same name as global (because you precede it with "int")
    // Local variable replaces all references to global within this "scope"
    // Scope is delcared by the enclosing { }
    int videoLength = 30;
    Serial.print("videoLength in IF = ");
    Serial.println(videoLength);
    // End of scope of local videoLength, references to videoLength now reference the global again
  }
  else
  {
    // ANOTHER NEW local variable with the same name (again because you precede it with "int")
    // This one is different from the global, and different from the other LOCAL one above
    int videoLength = 5;
    Serial.print("videoLength in ELSE = ");
    Serial.println(videoLength);
    // End of scope of local videoLength, references to videoLength now reference the global again
  }

  Serial.print("videoLength after IF/ELSE= ");
  // Yes, it's back referencing the global again
  // The local variables above are "out of scope"
  Serial.println(videoLength); // Expected 5 or 30 but this shows videoLength = 0 ??

}

Note that spycatcher2k code above does NOT declare new copies of variable "videoLength" all over the shop because it does NOT precede them with the declaration type "int".

You set videoLength to the values 5 or 30 then you use it in delay()...that take MILLISECONDS not SECONDS. 30 ms is a very short time.

Steve

slipstick:
You set videoLength to the values 5 or 30 then you use it in delay()…that take MILLISECONDS not SECONDS. 30 ms is a very short time.

Steve

Thanks a bunch, the seegar is yours, you’re a star! No wonder everything I tried failed.

With that (now embarrassingly obvious!) correction made the sketch runs perfectly.

Anyway, for completness, here’s the latest heavily annotated code I was about to post before seeing your latest. It shows the conclusion I’d come to, reflecting pcbbc’s post. But wrongly assuming that the void loop() was ignoring the value set immediately beforehand in void setup(), instead using the global value (zero in this case).

// Testing currently with 328 #09
// All was working fine until I tried to add a switch to
// set value of videoLength
// #include <Servo.h> // Uses code from the Arduino library
#include <VarSpeedServo.h> // Uses the VarSpeedServo library

//  Servo myservo;  // "Create servo object to control a servo"
// VarSpeedServo myServo;
VarSpeedServo myservo;

int outPos = 17;
int inPos = 5; // So rotation is 12 degs
const int triggerPin = 5; // Thursday 11 June 2020, 2031, was 6
const int delayPeriod = 250; // Delay between press/release simulations
int waitBeforeRelease = 200;
const int redledPin = 8; // (Blue LED on bb)
const int switchPin = 4;
// int videoLength = 10000; // Set length of video recording to 10 s
// **** WHEN USED IN LOOP MODE, THIS VALUE OVERRIDES
// **** THAT SET IN SETUP MODE ****
// **** YET LEAVING IT 'UNASSIGNED' APPARENTLY SETS IT TO ZERO
int videoLength;

void setup()
{
  Serial.begin(9600);
  Serial.println("Program now in setup");
  Serial.println("SKETCH: CUBE-ServoPlusLED-SwitchD4-EDIT");
  Serial.print("videoLength = ");
  Serial.println(videoLength);

  myservo.attach(9);
  pinMode(switchPin, INPUT_PULLUP);
  pinMode(triggerPin, INPUT_PULLUP);
  pinMode(redledPin, OUTPUT);
  myservo.write(outPos); // Rotates to the 'Out' position.

  // Test D4 to choose value of videolength
  if (digitalRead(switchPin) == HIGH)
  {
    videoLength = 30000;
  }
  else
  {
    videoLength = 5000;
  }
  Serial.print("switch value after IF/ELSE= ");
  Serial.println(digitalRead(switchPin));
  Serial.print("videoLength after IF/ELSE= ");
  Serial.println(videoLength); // **** Reports videoLength = 0 ****
  // **** WHICH MUST BE WHY VOID LOOP FAILS ****
}

void loop()
{

  // The loop will be run only when a LOW is detected
  if (digitalRead(triggerPin) == LOW)
  {
    myservo.write(inPos);
    delay(3100); // Press for > 3s to power up
    myservo.write(outPos);
    delay(100); // Delay before starting video

    myservo.write(inPos); // 1st of 2 presses
    delay(waitBeforeRelease);
    myservo.write(outPos);
    delay(200);

    myservo.write(inPos); // 2nd of 2 presses
    delay(waitBeforeRelease);
    myservo.write(outPos);
    // Video is now running. Stop it after videoLength.
    digitalWrite(redledPin , HIGH) ;

    Serial.println("Program now in loop mode");
    Serial.print("videoLength = ");
    Serial.println(videoLength); // Correctly shows 5 or 30

    delay(videoLength); // So I just see the 200 mS flash
    // Not the 5 or 30 s that I expected
    // ******************************************************
    myservo.write(inPos);
    delay(waitBeforeRelease);
    myservo.write(outPos);
    digitalWrite(redledPin , LOW) ;
    delay(200); // Delay before powering off

    myservo.write(inPos); // Power off with >3s press
    delay(3100);
    myservo.write(outPos);
  }
}
// int videoLength = 10000; // Set length of video recording to 10 s
// **** WHEN USED IN LOOP MODE, THIS VALUE OVERRIDES
// **** THAT SET IN SETUP MODE ****
// **** YET LEAVING IT 'UNASSIGNED' APPARENTLY SETS IT TO ZERO
int videoLength;

You are correct the default is zero.

But you can set any value you like here as an initial value. You are wrong in your understanding that the value "overrides" any value set in the setup function.

The reason that was apparently happening was because you had this in setup...

void setup()
{
  ....
  int videoLength = xxxx;
  ....
}

And not this...

void setup()
{
  ....
  videoLength = xxxx;
  ....
}

That word "int" in the first example makes a whole load of difference as to what the code does. The int keyword says you want to declare a new variable, instead of assigning to an existing one (e.g. the global).

Edit: So your problems were a combination of...
a) Not understanding scope and...
b) Thinking the parameter for delay() is seconds and not milliseconds

Thanks pcbbc, understood.

I actually got rid of the invalid 'ints' quite soon (that was just one of many variations I tried before posting) but remained deceived for the next hour or so by the units error!