Automatic Servo with Manual Override (delay problems)

landis:
I want the first code to become a timer. When this the total time - the time from when the button was last pressed is greater or equal to 3secs I want the code to pan automatically.

So you have the conditional part down, but if the condition fires, all you do is break out of the code to just go right back into it. How does that break statement make "the code pan automatically"?

My overall idea with the conditionally breaks is that if the code reads that the leftbutton is being pushed it should rotate left and stay left once the button is not pushed. However, if either of the buttons are pushed again, I want it to restart the case and essentially restart the "delay" time.

Think about this part:

if (digitalRead(leftbutton))
        {
        casenum = 2;
        break;
        }

casenum is already 2, since you're still within the "case 2:" part of the switch statement, so this entire piece of code does nothing for you.

Okay that lightens up the code content, thank you. But the problem is still with the delay. It will not stop for me, it just keeps panning.

Updated code? (the whole sketch, not snippits)

CODE:

#include <Servo.h> 
 
Servo myservo;
const int leftbutton = 2;  //variable to represent the pin that the left button is on
const int rightbutton = 4;  //variable to represent the pin that the right button is on
int casenum = 0;  //case number to tell the servo which case to run
int pos = 0;  //position
int delaytime = 20;  // increasing this slows down the servo movement
unsigned long LastTimeButtonWasPressed; // last time update
long interval = 3000UL; // interval at which to do something (milliseconds)
 
void setup()
{   
  
  
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
  
  pinMode(leftbutton, INPUT);  // the buttons are the inputs
  pinMode(rightbutton, INPUT);

} 

void loop()
{
  unsigned long StartVoidLoopTime = millis();
  if (digitalRead(leftbutton))  //checks to see if each button is being pressed
        {
          casenum = 2;  //if so it switches the casenum
        }
        if (digitalRead(rightbutton))
        {
          casenum = 3;
        }
  
  switch (casenum)  //switch switches the case based on the value of casenum
  {
    case 0:
    for (pos = pos; pos < 180; pos += 1)  // pan right
      {
        
        myservo.write(pos);  // Move to next position
        delay(delaytime);  // Short pause to allow it to move
        if (digitalRead(leftbutton))  //checks to see if each button is being pressed
        {
          casenum = 2;  //if so it switches the casenum
          break;
        }
        if (digitalRead(rightbutton))
        {
          casenum = 3;
          break;
        }
      }

    casenum = 1;  //if none of the buttons are pressed then it goes to pan left
    break;
   
    case 1:
    for(pos = pos; pos >= 0; pos -= 1)  // pan left
      {
     
        myservo.write(pos);  // Move to next position
        delay(delaytime);  // Short pause to allow it to move
        if (digitalRead(leftbutton))  //checks to see if each button is being pressed
        {
          casenum = 2;  //if so it switches the casenum
          break;
        }
        if (digitalRead(rightbutton))
        {
          casenum = 3;
         break;
        }
        
      }
    casenum = 0;
    break;

    case 2:
    while (digitalRead(leftbutton))  //while the button is being pressed
    {
        myservo.write(pos);  //rotates servo to its current positon
        delay(delaytime);
        pos-=1;  //position becomes one less
        LastTimeButtonWasPressed = millis();
    }
        
        if(StartVoidLoopTime - LastTimeButtonWasPressed >= interval)  //if the total time - the start time is greater than 3 sec 
        {    
          myservo.write(pos);      
          casenum = 0;  //this is where the code goes wrong, it seems like it reads this if statement 
                        //and immedietly say thinks its true
          //LastTimeButtonWasPressed = millis();
          LastTimeButtonWasPressed = StartVoidLoopTime;
          break;
        }
        if (digitalRead(rightbutton))
        {
        casenum = 3;
        break;
        }
      
      
    case 3: 
    while (digitalRead(4))
        {
          myservo.write(pos);
          delay(delaytime);
          pos +=1;
          LastTimeButtonWasPressed = millis();
        }
        myservo.write(pos);
        if(StartVoidLoopTime - LastTimeButtonWasPressed >= interval)  //if the total time - the start time is greater than 3 sec 
        {          
          casenum = 1;  //this is where the code goes wrong, it seems like it reads this if statement 
                       //and immedietly say thinks its true
          //previousmillis = currentmillis;
          break;
        }
        if (digitalRead(leftbutton))
        {
        casenum = 2;
        break;
        }
                
       default:
       casenum = 0;
       break;
  }  
}
LastTimeButtonWasPressed = StartVoidLoopTime;

You're clinging to hard to Blink Without Delay example here. LastTimeButtonWasPressed shouldn't be set while the button is not pressed (If it was pressed, it would still be in the while loop).

You're problem is still with your understanding of the break statements. Unless you know exactly what you are doing, you should be using an UNCONDITIONAL break at the end of every case statement. Since none of your break conditions are met in case 2 or case 3, as soon as the left button is released, it will fall through all the way to the default section, which sets the casenum to 0.

Okay,its making more sense. So because my if statement for the "delay" is not being accomplished in the first pass it is jumping out and going to the default case? How do I make it reloop to accomplish that if statement?

I don't know a way to get rid of the conditional breaks.

landis:
Okay,its making more sense. So because my if statement for the "delay" is not being accomplished in the first pass it is jumping out and going to the default case?

Jumping out isn't the right phrase. More like it's failling through. A break statement says "I'm done executing code in this switch statement, proceed to the end of the switch statement, skipping all the code between here and there"

How do I make it reloop to accomplish that if statement?

It already loops by virtue of being within the loop() function. What you need it to do is only execute the code within the case 2: section of your code. To stop it from doing that, you need an unconditional break.

I don't know a way to get rid of the conditional breaks.

With your delete key.

I need it to only do the code in case 2, then in order to stop it I need an unconditional break? okay, sorry but I need some more advice on that.

So, are you saying that once it gets to case 2 I should only do that code. or case 2 should be the only code.

And then how would I make it keep running case 2?

And I knew what the delete key was thank you haha. Are you saying get rid of the conditional breaks within cases 2 & 3?

landis:
I need it to only do the code in case 2, then in order to stop it I need an unconditional break? okay, sorry but I need some more advice on that.

This is what a typical switch statement looks like:

int someState = 0;

void loop()
{
  // Do some stuff
  switch (someState)
  {
    case 0:
      // Do some stuff for case 0
      break;
    case 2:
      // Do some stuff for case 2
      break;
    case 3:
      // Do some stuff for case 3
      break;
  }
  // Do some more stuff
}
So, are you saying that once it gets to case 2 I should only do that code. or case 2 should be the only code.

When in case 2, the only code in the switch statement that should run is the code in case 2. Any code outside the switch statement will still run without issue.

And then how would I make it keep running case 2?

I already answered that:

It already loops by virtue of being within the loop() function.

And I knew what the delete key was thank you haha. Are you saying get rid of the conditional breaks within cases 2 & 3?

Yes, get rid of the conditional loops and add an unconditional one.

Am I getting closer, because this still reads when the button is pressed, but I'm not sure how to set it up for the delay. Its still jumping into case 1 immediately.

When you make changes, you post the updated code.

Sorry about that, this is an example for case 3

    case 3: 
    while (digitalRead(4))
        {
          myservo.write(pos);
          delay(delaytime);
          pos +=1;
          LastTimeButtonWasPressed = millis();
        }
        myservo.write(pos);
        (StartVoidLoopTime - LastTimeButtonWasPressed >= interval);  //if the total time - the start time is greater than 3 sec 
                  
          casenum = 1;  //this is where the code goes wrong, it seems like it reads this if statement 
                       //and immedietly say thinks its true
          //previousmillis = currentmillis;
          break;
        
            
                
       default:
       casenum = 0;
       break;

as you can see I'm a little confused on the what I need to code there to act as the timer

Why did you remove the if and make the 2nd line after your while statement pointless?

I was getting rid of the conditional break. But now I think I get it.

 case 3: 
    while (digitalRead(4))
        {
          myservo.write(pos);
          delay(delaytime);
          pos +=1;
          LastTimeButtonWasPressed = millis();
        }
        myservo.write(pos);
        if (StartVoidLoopTime - LastTimeButtonWasPressed >= interval);  //if the total time - the start time is greater than 3 sec 
           {       
          casenum = 1;  //this is where the code goes wrong, it seems like it reads this if statement 
                       //and immedietly say thinks its true
    
           }
            break;

but it still doesn't delay

Full code

#include <Servo.h> 
 
Servo myservo;
const int leftbutton = 2;  //variable to represent the pin that the left button is on
const int rightbutton = 4;  //variable to represent the pin that the right button is on
int casenum = 0;  //case number to tell the servo which case to run
int pos = 0;  //position
int delaytime = 20;  // increasing this slows down the servo movement
unsigned long LastTimeButtonWasPressed; // last time update
long interval = 3000UL; // interval at which to do something (milliseconds)
 
void setup()
{   
  
  
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
  
  pinMode(leftbutton, INPUT);  // the buttons are the inputs
  pinMode(rightbutton, INPUT);

} 

void loop()
{
  unsigned long StartVoidLoopTime = millis();
  if (digitalRead(leftbutton))  //checks to see if each button is being pressed
        {
          casenum = 2;  //if so it switches the casenum
        }
        if (digitalRead(rightbutton))
        {
          casenum = 3;
        }
  
  switch (casenum)  //switch switches the case based on the value of casenum
  {
    case 0:
    for (pos = pos; pos < 180; pos += 1)  // pan right
      {
        
        myservo.write(pos);  // Move to next position
        delay(delaytime);  // Short pause to allow it to move
        if (digitalRead(leftbutton))  //checks to see if each button is being pressed
        {
          casenum = 2;  //if so it switches the casenum
          break;
        }
        if (digitalRead(rightbutton))
        {
          casenum = 3;
          break;
        }
      }

    casenum = 1;  //if none of the buttons are pressed then it goes to pan left
    break;
   
    case 1:
    for(pos = pos; pos >= 0; pos -= 1)  // pan left
      {
     
        myservo.write(pos);  // Move to next position
        delay(delaytime);  // Short pause to allow it to move
        if (digitalRead(leftbutton))  //checks to see if each button is being pressed
        {
          casenum = 2;  //if so it switches the casenum
          break;
        }
        if (digitalRead(rightbutton))
        {
          casenum = 3;
         break;
        }
        
      }
    casenum = 0;
    break;

    case 2:
    while (digitalRead(leftbutton))  //while the button is being pressed
    {
        myservo.write(pos);  //rotates servo to its current positon
        delay(delaytime);
        pos-=1;  //position becomes one less
        LastTimeButtonWasPressed = millis();
    }
        myservo.write(pos);
        if(StartVoidLoopTime - LastTimeButtonWasPressed >= interval)  //if the total time - the start time is greater than 3 sec 
        {         
          //casenum = 1;  //this is where the code goes wrong, it seems like it reads this if statement 
                        //and immedietly say thinks its true
          //LastTimeButtonWasPressed = millis();
          //LastTimeButtonWasPressed = StartVoidLoopTime;
          break;
        }
      
      
    case 3: 
    while (digitalRead(4))
        {
          myservo.write(pos);
          delay(delaytime);
          pos +=1;
          LastTimeButtonWasPressed = millis();
        }
        myservo.write(pos);
        if (StartVoidLoopTime - LastTimeButtonWasPressed >= interval);  //if the total time - the start time is greater than 3 sec 
           {       
          casenum = 1;  //this is where the code goes wrong, it seems like it reads this if statement 
                       //and immedietly say thinks its true
    
           }
            break;
          
        
            
                
       default:
       casenum = 0;
       break;
  }  
}

Starting in the loop here:

unsigned long StartVoidLoopTime = millis();

Let's say the result from millis() is 2 seconds. The button is pressed for say 8 seconds, so you're in this loop for that long:

while (digitalRead(4))
        {
          myservo.write(pos);
          delay(delaytime);
          pos +=1;
          LastTimeButtonWasPressed = millis();
        }

That means the last call to millis() will be 10 seconds (2 form when you started the loop + 8 in the loop).

if(StartVoidLoopTime - LastTimeButtonWasPressed >= interval)  //if the total time - the start time is greater than 3 sec

So what is 2 - 10 seconds? In unsigned subtraction, it's a really big number, which will most certainly be bigger than 3 seconds. You should be subtracting LastTimeButtonWasPressed from the current time, not some time you set an arbitrarily amount of time ago.

        if (StartVoidLoopTime - LastTimeButtonWasPressed >= interval);  //if the total time - the start time is greater than 3 sec

That semicolon on the end forms the body of the if statement. A ; by itself is valid code - it is a no-op statement. Therefore, if the condition is true, nothing happens. There being no else statement with this if statement, nothing happens if the condition is not true. The whole point of the if statement - with that semicolon on the end - is what? It achieves nothing.

Here is a modified version of your code that I reformatted and made some significant changes to. I have not tested it, but it should be significantly easier to read, understand, and troubleshoot:

#include <Servo.h> 
 
Servo myservo;
const int leftButton  = 2;     //variable to represent the pin that the left button is on
const int rightButton = 4;     //variable to represent the pin that the right button is on
int caseNum = 0;               //case number to tell the servo which case to run
int pos = 0;                   //position
int delayTime = 20;            // increasing this slows down the servo movement
unsigned long lastPress = 0;   // last time update
long interval = 3000UL;        // interval at which to do something (milliseconds)
 
void setup() {   
  myservo.attach(9);           // attaches the servo on pin 9 to the servo object 
  pinMode(leftButton, INPUT ); // the buttons are the inputs
  pinMode(rightButton, INPUT);

} 

void loop() {
  if (digitalRead(leftButton)) {         //check if left button pressed
    caseNum = 2;                         //if so it switches the caseNum
  } else if (digitalRead(rightButton)) { //checks right button (else skips if left is pressed)
    caseNum = 3;
  }
  
  switch (caseNum) {
    case 0:
      while( pos < 180 ) {   // pan right until 180 degrees
        myservo.write(pos);  // Move to next position
        delay(delayTime);    // Short pause to allow it to move
        pos++;               // increment
        if (digitalRead(leftButton) || digitalRead(rightButton))  // checks to see if either button is down
          break;             // break out of subloop to check inputs
      }
      caseNum = 1;  // if no buttons pressed, default to pan left
      break;
    case 1:
      while(pos > 0) {       // pan right until 0 degrees
        myservo.write(pos);  // Move to next position
        delay(delayTime);    // Short pause to allow it to move
        if (digitalRead(leftButton) || digitalRead(rightButton))  // checks to see if either button is down
          break;             // break out of subloop to check inputs
      }
      caseNum = 0;  // if no buttons pressed, default to pan right
      break;
    case 2:
      while (digitalRead(leftButton)) { //while the button is being pressed
        pos-=1;                         //position becomes one less
        if( pos < 0 ) pos = 0;          // only necessary if you want to restrict motion to 180
        myservo.write(pos);             //rotates servo to its current positon
        delay(delayTime);
        lastPress = millis();
      }
      if(millis() - lastPress >= interval)  // if it has been interval since last press
        caseNum = 0;                        // return to expected pan sequence
      break;      
    case 3: 
      while (digitalRead(4)) {
          pos+=1;                         // position becomes one greater
          if( pos > 180 ) pos = 180;      // only necessary if you want to restrict motion to 180
          myservo.write(pos);
          delay(delayTime);
          lastPress = millis();
      }
      if ( millis() - lastPress >= interval)  // if it has been interval since last press 
        caseNum = 1;
      break;
    default:
      caseNum = 0;
  }
}