Delay Dilemma

Hi guys,

So I am working on a project that requires a piston to be driven up and down by a DC motor (currently controlled by two relays, will change to a better controller soon but the general coding shouldn't change) between two hall effect sensors that read LOW when the piston (and magnet) are under them.

I have it working great so far, my issue comes with that I need the piston to stop at either end for a predetermined amount of time before returning. For the life of me I cannot get this to happen. Any ideas would be greatly appreciated.

Thanks for the help!

Here's my code so far that works great, just runs "flat out" if you will, and I need a delay at each end without overshooting.

#define forward 7                                         //define pin 7 as forward relay pin
#define back 8                                            //define pin 8 as backward relay pin

const int FrontHallPin = 3;                                //define pin 3 as front hall effect pin       
const int RearHallPin = 2;                                 //define pin 2 as rear hall effect pin

int FrontHallState = 0;                                    //Create FrontHallState variable with 0 initial value
int RearHallState = 0;                                     //Create RearHallState variable with 0 initial value

void setup() {
 pinMode(back, OUTPUT);                                     //Set backward relay pin as output
 pinMode(forward, OUTPUT);                                  //Set forward relay pin as output
 pinMode(FrontHallPin, INPUT);                              //Set front hall signal pin as input
 pinMode(RearHallPin, INPUT);                               //Set rear hall signal pin as input

 if (RearHallState == HIGH or FrontHallState == LOW){       //If piston is anywhere but under
  digitalWrite(back, LOW);                                  //the rear sensor, send it back
  digitalWrite(forward, HIGH);
  }
}

void loop(){
   RearHallState = digitalRead(RearHallPin);                //Create rear hall state variable
   FrontHallState = digitalRead(FrontHallPin);              //Create front hall state variable
  
if (RearHallState == LOW){      //If the piston is under the rear sensor,
    goforward();                //Send it forwards    
    }
if(FrontHallState == LOW){      //If the piston is under the front sensor,
    goback();                   //Send it back
    }
}


void goforward(){                 //Create the function of the piston going forward
  digitalWrite(forward, LOW);
  digitalWrite(back, HIGH);
}

void goback(){                    //Create the function of the piston going backward
  digitalWrite(back, LOW);
  digitalWrite(forward, HIGH);
}

I need the piston to stop at either end for a predetermined amount of time before returning.

Show us your attempt.

Well, let me ask you how are you able to stop a DC motor at a specific position? When you can answer this, you will know how to get your project to do the same.

Oh, you are not able to do this? Perhaps you need to rethink your project. Can you add an electric brake to the motor? Could you replace the motor with a stepper motor that would give precise position control and allow the motor rotation to be stopped at any position? Could you reverse the power to the motor until it stopped? Not a very accurate method.

Are there other options?

Paul

A really simple solution if your code will never do anything else is to add delay() before you reverse the direction.

However, as Paul_KD7HB hints, you may find that the motor 'coasts' to a stop, overshooting the end mark. You may be better getting a motor controller board (dead cheap on eBay, probably cheaper than the relays) that have forward, reverse, stop and brake functions. Look for LM298 or similar ICs, rated for the current into your motors.

If you later intend the code to be doing more, it may pay to switch the coding style to a Finite State Machine and create a delay state that uses the same technique as the BlinkWithoutDelay example to time the passing of the waiting delay without blocking.

This is a job for a State Machine. It's not complex. You want to add a delay when each sensor is triggered but only when it's initially triggered, not when it has been in that position for some time.

So your program needs to remember the state of that sensor the last time it looked at it and then delay when it changes.

void loop(){
   static int PrevRearState = LOW; //initial values correspond to known starting position, set by setup()
   static int PrevFrontState = HIGH;
   RearHallState = digitalRead(RearHallPin);                //Create rear hall state variable
   FrontHallState = digitalRead(FrontHallPin);              //Create front hall state variable

  
   if (RearHallState == LOW){      //If the piston is under the rear sensor,
     if(RearHallState != PrevRearState) {
       //this is the first time we have seen it go LOW
       stop();
       delay(RearDelaytimePeriod);
     } else {
        goforward();                //Send it forwards    
     }
   }
   if(FrontHallState == LOW){      //If the piston is under the front sensor,
     if(FrontHallState != PrevFrontState) {
       //this is the first time we have seen it go LOW
       stop();
       delay(FrontDelayTimePeriod);
     } else {
       goback();                   //Send it back
     }
   }

   PrevFrontState = FrontHallState; //remember for next time
   PrevRearState = RearHallState;
}

Also try this tutorial: State Machine

Here ya go. This is how you do that kind of thing:

enum State {
  MOVING_FWD = 1,
  PAUSING_FRONT = 2,
  MOVING_BACK = 3,
  PAUSING_REAR =4
} state;

uint32_t pauseStartMs;

void setup() {
  // pin setup, etc. You know the drill.

  goforward();
  state = MOVING_FWD;
}

void loop() {
  switch(state) {
    case MOVING_FWD:
      if(digitalRead(FrontHallPin) == LOW) {
        stopmoving();
        pauseStartMs = millis();
        state = PAUSING_FRONT;
      }
      break;

    case PAUSING_FRONT:
      if(millis()-pauseStartMs >= FrontPauseIntervalMs) {
        goback();
        state = MOVING_BACK;
      }
      break;

    case MOVING_BACK:
      if(digitalRead(RearHallPin) == LOW) {
        stopmoving();
        pauseStartMs = millis();
        state = PAUSING_REAR;
      }
      break;

    case PAUSING_REAR:
      if(millis()-pauseStartMs >= RearPauseIntervalMs) {
        goforward();
        state = MOVING_FORWARD;
      }
      break;
  }
}

Don't forget to karma me!