Facing unsteady delay time when motor is reversed

Background about the project:
I am making a automatic egg incubator tray. for that i am using 2 limit switches, 1 L298n motor driver and arduino leonardo. I am making the egg tray in a way that it would tilt 45 degrees on both sides. and i want to introduce a delay off time in this code. so that whenever the tray touches the switch it turns off the motor for one hour, reverse the direction and repeat

Main Question:
I have programmed it in such a way that it stops for a certain amount of before it goes in the other direction. that works. well kinda. i have found out that if i set the interval time to 10 seconds and let the motor run for about 5 mins and then press the switch to reverse it. the off time is very different than when i let the motor run for 1 min and then reverse it.

CODE:

If you want to visit the link and check the code out. it's your choice. i don't know if this is allowed. if not let me know and i will delete the link.

unsigned long currentMillis;
unsigned long previousMillis;
const long onInterval = 10000; 
const byte in1 = 3;
const byte in2 = 4; 
const byte sw1 = 6;  //this is left switch
const byte sw2 = 5;  //this is right switch
boolean sw1Status;
boolean sw2Status;
int stateMachine;

void setup() {
  // put your setup code here, to run once:
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(sw1, INPUT);
  pinMode(sw2, INPUT);
  Serial.begin(9600);
  millis();

}

void loop() {
  // put your main code here, to run repeatedly:
  currentMillis = millis();
  sw1Status = digitalRead(sw1);
  sw2Status = digitalRead(sw2);
  Serial.println("This is another process");

 switch (stateMachine) {
    case 0: //motor stop/ reset
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    if(sw1Status == HIGH && sw2Status == LOW)  //tray is tilted to the left 
    {
      stateMachine = 1; 
    } else if (sw1Status == LOW && sw2Status == HIGH) {  //try is tilted to the right
      stateMachine = 2; 
    }
    break;  //erase the break see what happens

    case 1:  //go right
    if(sw2Status == LOW) {   //go right until the right switch is high
      if(currentMillis - previousMillis >= onInterval) {
        digitalWrite(in1, HIGH);
        digitalWrite(in2, LOW);
        previousMillis = currentMillis;
      } else if (sw2Status == HIGH ) {
        stateMachine = 0;   // go to reset
      }
    } else if (sw2Status == HIGH) {
      stateMachine = 0;  // go to reset
    }
    break;

    case 2:  //go left
    if(sw1Status == LOW) { //go left until it touches left switch
      if(currentMillis - previousMillis >= onInterval) {
        digitalWrite(in1, LOW);   //go right mechanism
        digitalWrite(in2, HIGH);
        previousMillis = currentMillis;
      } else if (sw1Status == HIGH) {  //if it touches left switch
        stateMachine = 0;  //go to reset
      }
    } else if (sw1Status == HIGH) {
      stateMachine = 0;
    }
    break;

   
  }

In this piece of code

if(sw2Status == LOW) {   //go right until the right switch is high
      if(currentMillis - previousMillis >= onInterval) {
        digitalWrite(in1, HIGH);
        digitalWrite(in2, LOW);
        previousMillis = currentMillis;
      } 
      else if (sw2Status == HIGH ) {
        stateMachine = 0;   // go to reset
      }
    }

sw2Status can never be HIGH. Might that be part of the problem?

I'm not clear what is intended to happen during the onInterval?

Should there also be an offInterval?

...R

Robin2:
sw2Status can never be HIGH. Might that be part of the problem?

I'm not clear what is intended to happen during the onInterval?

Should there also be an offInterval?

...R

That code works something like this.

when the tray is tilted towards left. means sw1 is high and sw2 is low. then keep going right until sw2 becomes high(the tray presses the right switch) or in other words that condition of 'sw1 == low' becomes false.

the oninterval is supposed to be the delay whenever a switch becomes high or the tray tilts, then until the interval has elapsed (1 hour for example ) it will not move. as soon as it elapses the motor starts.

i thought about incorporating another offinterval but i just don't know how to fit it in here. i mean my requirement is that the motor should stay in stopped state normally and only start moving when interval has elapsed and stop when another switch is pressed and repeat. so i believe i have no use for another interval. and even if i have to add it in the code. i dont know how that would play out with the rest of the code.

Sorry for the messy explanation. if you want i can try explaining again.

Does your Arduino have other tasks to do? If not, delay() might work for you:

const byte in1 = 3;
const byte in2 = 4;


const byte LeftLimitSwitchPin = 6;  //this is left switch
const byte RightLimitSwitchPin = 5;  //this is right switch

void setup()
{
  Serial.begin(9600);


  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(LeftLimitSwitchPin, INPUT);
  pinMode(RightLimitSwitchPin, INPUT);
}


void loop()
{
  // Go right
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);


  // Until right limit switch is reached
  while (digitalRead(RightLimitSwitchPin) == LOW)
  {
    /*Do Nothing Else*/
  }


  // Stop the motor
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);


  // Wait an hour
  delay(60UL * 60UL * 1000UL);


  // Go left
  digitalWrite(in1, LOW);   //go right mechanism
  digitalWrite(in2, HIGH);


  // Until right limit switch is reached
  while (digitalRead(LeftLimitSwitchPin) == LOW)
  {
    /*Do Nothing Else*/
  }


  // Stop the motor
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);


  // Wait an hour
  delay(60UL * 60UL * 1000UL);
}

If you have other tasks to run, a state machine is an excellent choice. Use an "enumeration" to assign meaningful names to each state. If a state has code you DON'T want to run each time through the loop when that state is active, make it a separate state.

const byte in1 = 3;
const byte in2 = 4;


const byte LeftLimitSwitchPin = 6;  //this is left switch
const byte RightLimitSwitchPin = 5;  //this is right switch

void setup()
{
  Serial.begin(9600);


  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(LeftLimitSwitchPin, INPUT);
  pinMode(RightLimitSwitchPin, INPUT);
}


void loop()
{
  static unsigned long waitStartTime;
  const unsigned long waitInterval = 60UL * 60UL * 1000UL;  // One Hour
// const unsigned long waitInterval = 30000;  // 30-second version, for testing


  enum states {GoRight, WaitForRightLimit, WaitOnRight, GoLeft, WaitForLeftLimit, WaitOnLeft};
  static byte state = GoRight;


  switch (state)
  {
    case GoRight:
      digitalWrite(in1, HIGH);
      digitalWrite(in2, LOW);
      state = WaitForRightLimit;
      break;


    case WaitForRightLimit:
      if (digitalRead(RightLimitSwitchPin) == HIGH)
      {
        // Stop the motor
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
        waitStartTime = millis();
        state = WaitOnRight;
      }
      break;


    case WaitOnRight:
      if (millis() - waitStartTime >= waitInterval)
      {
        state = GoLeft;
      }
      break;


    case GoLeft:
      digitalWrite(in1, LOW);   //go right mechanism
      digitalWrite(in2, HIGH);
      state = WaitForLeftLimit;


    case WaitForLeftLimit:
      if (digitalRead(LeftLimitSwitchPin) == HIGH)
      {
        // Stop the motor
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
        waitStartTime = millis();
        state = WaitOnLeft;
      }
      break;


    case WaitOnLeft:
      if (millis() - waitStartTime >= waitInterval)
      {
        state = GoRight;
      }
      break;
  }
}

Manhoosbilli123456:
That code works something like this.

Is that how it actually works, or how you would like it to work - I suspect the latter. And my comments were aimed at getting you to think about possible changes.

...R

enum State {
  LEFT, MOVING_RIGHT, RIGHT, MOVING_LEFT
} state;

uint32_t timer;

void setup() {
  if(the left limit switch is closed) {
    timer = millis();
    state = LEFT;
  }
  else {
    turn on the move_left motor;
    state = MOVING_LEFT;
  }
}


void loop() {
  switch(state) {
    case LEFT:
      if(milis() - timer >= 60L*60L*1000L) {
        turn on the moving right motor;
        state = MOVING_RIGHT;
      }
      break;

    case MOVING_RIGHT:
      if(the right limit switcvh is closed) {
        turn off the moving right motor;
        timer = millis();
        state = RIGHT;
      }
      break;

    case RIGHT:
      if(milis() - timer >= 60L*60L*1000L) {
        turn on the moving left motor;
        state = MOVING_LEFT;
      }
      break;

    case MOVING_LEFT:
      if(the left limit switch is closed) {
        turn off the moving left motor;
        timer = millis();
        state = LEFT;
      }
      break;

  }
}

Robin2:
Is that how it actually works, or how you would like it to work - I suspect the latter. And my comments were aimed at getting you to think about possible changes.

...R

Oh i thought my code was unclear. well yes, ofc it's the latter. And you have been very helpful. i am not a programmer so i am kinda stuck with this code. i have been trying for weeks now and this is what i have come up with. you can assume my knowledge is limited to this.

johnwasser:
If you have other tasks to run, a state machine is an excellent choice. Use an "enumeration" to assign meaningful names to each state. If a state has code you DON'T want to run each time through the loop when that state is active, make it a separate state.

Yes. i have other tasks to run. And i really appreciate you writing that code for me. it looks promising and i will try it. i was not really familiar with enumeration concept since im a newbie but now i realise when we use enumeration we just assign names to the cases instead of 0 1 2... i am hopeful that this will solve the timing issue.

PaulMurrayCbr:

    case MOVING_LEFT:

if(the left limit switch is closed) {
       turn off the moving left motor;
       timer = millis();
       state = LEFT;
     }
     break;

}
}

could you explain why you started the timer within the loop and just before the motor stars and turn it on again in this moving left case? i don't really understand.

johnwasser:
If you have other tasks to run, a state machine is an excellent choice. Use an "enumeration" to assign meaningful names to each state. If a state has code you DON'T want to run each time through the loop when that state is active, make it a separate state.

Just tried this code. made some changes and ran it.
Result: the wait time is nowhere to be found. it just reverses immediately when i press the opposite switch.

const byte in1 = 3;
const byte in2 = 4;
const byte LeftLimitSwitchPin = 6;  //this is left switch
const byte RightLimitSwitchPin = 5;  //this is right switch

void setup()
{
  Serial.begin(9600);


  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(LeftLimitSwitchPin, INPUT);
  pinMode(RightLimitSwitchPin, INPUT);
}


void loop()
{
 unsigned long waitStartTime;
 // const unsigned long waitInterval = 60UL * 60UL * 1000UL;  // One Hour
 const unsigned long waitInterval = 10000;  // 30-second version, for testing


  enum state {CalculateReversal, GoRight, WaitForRightLimit, WaitOnRight, GoLeft, WaitForLeftLimit, WaitOnLeft};
  static byte state = CalculateReversal;


  switch (state)
  {
    case CalculateReversal:
    if(digitalRead(LeftLimitSwitchPin)== HIGH && digitalRead(RightLimitSwitchPin)==LOW){
     //means motor is towards left so go right
     state = GoRight;
    } else if (digitalRead(LeftLimitSwitchPin) == LOW && digitalRead(RightLimitSwitchPin)== HIGH){
    //means motor is towards right so go left.
      state = GoLeft;
    }
    break;
    
    case GoRight:
      digitalWrite(in1, HIGH);
      digitalWrite(in2, LOW);
      state = WaitForRightLimit;
      break;


    case WaitForRightLimit:
      if (digitalRead(RightLimitSwitchPin) == HIGH)
      {
        // Stop the motor
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
        waitStartTime = millis();
        state = WaitOnRight;
      }
      break;


    case WaitOnRight:
      if (millis() - waitStartTime >= waitInterval)
      {
        state = GoLeft;
        waitStartTime = millis();
      }
      break;


    case GoLeft:
      digitalWrite(in1, LOW);   //go right mechanism
      digitalWrite(in2, HIGH);
      state = WaitForLeftLimit;
      break;


    case WaitForLeftLimit:
      if (digitalRead(LeftLimitSwitchPin) == HIGH)
      {
        // Stop the motor
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
        waitStartTime = millis();
        state = WaitOnLeft;
      }
      break;


    case WaitOnLeft:
      if (millis() - waitStartTime >= waitInterval)
      {
        state = GoRight;
        waitStartTime = millis();
      }
      break;
  }
}

Manhoosbilli123456:
Just tried this code. made some changes and ran it.
Result: the wait time is nowhere to be found. it just reverses immediately when i press the opposite switch.

void loop()

{
unsigned long waitStartTime;

That's probably because one of the 'changes' you made was to remove the 'static' keyword from the declaration of waitStartTime.

Another problem with your 'changes': If the position is between limits when you start the sketch, it will sit in the CalculateReversal state forever and never move.

johnwasser:
That's probably because one of the 'changes' you made was to remove the 'static' keyword from the declaration of waitStartTime.

Another problem with your 'changes': If the position is between limits when you start the sketch, it will sit in the CalculateReversal state forever and never move.

Umm i see. i'll try to run it as it is and see if it works. As i said i am a newbie. i thought i was supposed to change it.

I have been thinking. everyone suggests that i use delay() since i cannot afford to do that because i have other processes running. to solve that issue i remembered i had an attiny85 lying around and thought if i use that as a standalone timer and programme it with the delay() it wont affect the main arduino. do you think it would work?

johnwasser:
Does your Arduino have other tasks to do? If not, delay() might work for you:

const byte in1 = 3;

const byte in2 = 4;

const byte LeftLimitSwitchPin = 6;  //this is left switch
const byte RightLimitSwitchPin = 5;  //this is right switch

void setup()
{
  Serial.begin(9600);

pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(LeftLimitSwitchPin, INPUT);
  pinMode(RightLimitSwitchPin, INPUT);
}

void loop()
{
  // Go right
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);

// Until right limit switch is reached
  while (digitalRead(RightLimitSwitchPin) == LOW)
  {
    /Do Nothing Else/
  }

// Stop the motor
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);

// Wait an hour
  delay(60UL * 60UL * 1000UL);

// Go left
  digitalWrite(in1, LOW);  //go right mechanism
  digitalWrite(in2, HIGH);

// Until right limit switch is reached
  while (digitalRead(LeftLimitSwitchPin) == LOW)
  {
    /Do Nothing Else/
  }

// Stop the motor
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);

// Wait an hour
  delay(60UL * 60UL * 1000UL);
}

johnwasser:
Does your Arduino have other tasks to do? If not, delay() might work for you:

const byte in1 = 3;

const byte in2 = 4;

const byte LeftLimitSwitchPin = 6;  //this is left switch
const byte RightLimitSwitchPin = 5;  //this is right switch

void setup()
{
  Serial.begin(9600);

pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(LeftLimitSwitchPin, INPUT);
  pinMode(RightLimitSwitchPin, INPUT);
}

void loop()
{
  // Go right
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);

// Until right limit switch is reached
  while (digitalRead(RightLimitSwitchPin) == LOW)
  {
    /Do Nothing Else/
  }

// Stop the motor
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);

// Wait an hour
  delay(60UL * 60UL * 1000UL);

// Go left
  digitalWrite(in1, LOW);  //go right mechanism
  digitalWrite(in2, HIGH);

// Until right limit switch is reached
  while (digitalRead(LeftLimitSwitchPin) == LOW)
  {
    /Do Nothing Else/
  }

// Stop the motor
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);

// Wait an hour
  delay(60UL * 60UL * 1000UL);
}

johnwasser:
Does your Arduino have other tasks to do? If not, delay() might work for you:

const byte in1 = 3;

const byte in2 = 4;

const byte LeftLimitSwitchPin = 6;  //this is left switch
const byte RightLimitSwitchPin = 5;  //this is right switch

void setup()
{
  Serial.begin(9600);

pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(LeftLimitSwitchPin, INPUT);
  pinMode(RightLimitSwitchPin, INPUT);
}

void loop()
{
  // Go right
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);

// Until right limit switch is reached
  while (digitalRead(RightLimitSwitchPin) == LOW)
  {
    /Do Nothing Else/
  }

// Stop the motor
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);

// Wait an hour
  delay(60UL * 60UL * 1000UL);

// Go left
  digitalWrite(in1, LOW);  //go right mechanism
  digitalWrite(in2, HIGH);

// Until right limit switch is reached
  while (digitalRead(LeftLimitSwitchPin) == LOW)
  {
    /Do Nothing Else/
  }

// Stop the motor
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);

// Wait an hour
  delay(60UL * 60UL * 1000UL);
}

I hope this code could be helpful if i programme attiny85 with it and run that as a standalone timer. i guess that is the only option for me now. i will update the post once i do that

@Manhoosbilli123456, it would help if you take the time to gather your thoughts before making a post with a question and then waiting until you get a reply rather than posting a Reply every time you have the next new thought. I can't figure where you have got to at this stage or what sort of advice would be appropriate.

...R

Robin2:
@Manhoosbilli123456, it would help if you take the time to gather your thoughts before making a post with a question and then waiting until you get a reply rather than posting a Reply every time you have the next new thought. I can't figure where you have got to at this stage or what sort of advice would be appropriate.

...R

I understand. i apologise for jumping around from idea to idea. but you need to understand that i have been stuck because of this motor for about a month now. for some reason i couldn't sign in to the arduino forum. no matter who i asked they couldn't give me a satisfying answer instead would say just use delay(). you could imagine someones impatience who has been locked out for a month with no supervisor or teacher. this forum was my last hope. when professionals such as you replied with 'i don't understand what's supposed to happen' and 'use delay' it got me thinking that maybe i have wasted all this time and my code is so bad that they cannot even understand it. which is why i accepted the fact that i should use delay and that is why i asked if i should just move on to attiny85 and programme that as separate timer.

I am sorry if it felt like i am wasting your time.

believe it or not. i am so desperate for help that i keep refreshing the page after every 5 mins.

sorry for this dramatic reply. i am just tired of trying and trying. and when im so close i have to change my plans all over.

Maybe you can get everything focused by posting the latest version of your program, telling us in detail what it actually does and telling us what you want it to do that is different.

...R