Motor won't shut off!

Hi Guys,

I am using a UNO R3 with relay to start and stop a motor. When a momentary contact push button is pressed, I would like the motor to run for 5 seconds and then stop.

The code below only works if I add a 1 ms delay in the checkStartSwitch() function (3rd line from the bottom). If I remove the 1ms delay, the motor starts when the push button is pressed, but it does not stop. It tries to stop every 5 seconds (ie. I can hear the relay click like it is trying to stop) but the motor just keeps on going.

It doesn't make sense to me. Any ideas why I can't remove the delay?

Don

const int startSwitch = A0;
const int mainInclineMotor = 4;

enum startButtonStates{IS_PRESSED = 0, IS_RELEASED = 1};
enum motorControlStates{ON = 0, OFF = 1};
   
// set the time limit to 5 seconds and the current time to 0.

const long timeLimit = 5000;
unsigned long currentTime = 0;

void setup() {
pinMode(startSwitch, INPUT_PULLUP);
pinMode(mainInclineMotor, OUTPUT);

         
//turn off all motors off during setup (note that the output pins are "active" low)

digitalWrite(mainInclineMotor, OFF);

//initialize serial communication with terminal 
Serial.begin(9600);
} 
  
     
//main program loop runs continuously over and over again.

void loop(){
checkStartSwitch ();
}

void checkStartSwitch(){

// this function turns on the mainInclineMotor when the startSwitch is pressed
// and turns off the mainInclineMotor when the timer is complete.
  
if (digitalRead(startSwitch) == IS_PRESSED) {   

// If it is the first time through this function, set the currentTime to millis and turn on the mainInclineMotor.
// On subsequent passes, this skip these two steps.  
   
    if (currentTime == 0) {
    currentTime = millis();
    digitalWrite(mainInclineMotor, ON);
   }
}  

// If the timer is finished, then turn off the mainInclineMotor and reset the currentTime back to "0"
  
  if (millis() - currentTime >= timeLimit) {
  digitalWrite(mainInclineMotor, OFF);
  currentTime = 0;
 delay (1);
  }
}

First step would be to change the type of your timeLimit to const unsigned long.

Switches do bounce although a bounce time of 5 seconds would be very extreme (and a delay of 1ms should not improve that situation).

You can do a search for debounce examples if you want to solve it in code or place a small capacitor over the pin A0 (to ground).

In the code you posted, the setup() function never ends. You're missing a }

Anyway, I could think of 2 things:

1 - Electrical induction from the motor spinning down causes power fluctuations that make your input pin read LOW for under a millisecond.

2 - Physical vibration from switching the relay/motor causes your button to close.

sterretje:
First step would be to change the type of your timeLimit to const unsigned long.

Thanks sterretje. I changed timeLimit type to const unsigned long. Same symptoms.

sterretje:
Switches do bounce although a bounce time of 5 seconds would be very extreme (and a delay of 1ms should not improve that situation).

You can do a search for debounce examples if you want to solve it in code or place a small capacitor over the pin A0 (to ground).

The switch is not bouncing after 5 seconds. Just to check, I wrote the value of the switch to the terminal. Teh switch is "high" when the code misbehaves. See below.

Jobi-Wan:
In the code you posted, the setup() function never ends. You're missing a }

Jobi-Wan. Thanks for your response. The missing } is a cut and paste error. My bad. I abbreviated the code when posting to the forum. The bracket was in my code.

Jobi-Wan:
Anyway, I could think of 2 things:

1 - Electrical induction from the motor spinning down causes power fluctuations that make your input pin read LOW for under a millisecond.

2 - Physical vibration from switching the relay/motor causes your button to close.

I think you are on to something here. The motor is a small 110VAC gear motor, and I noticed my monitor sometimes flickered when the motor shut off. To test this out, I changed to a small 12VDC motor. The monitor flicker is gone but the problem persists.

Just to further test, I wrote the state of the switch to terminal. See post below for results.

Here is the revised function with the 1 millisecond delay included...

void checkStartSwitch(){
// this function turns on the track1BrakeRunMotor when the startSwitch is pressed
// and turns off the track1BrakeRunMotor when the timer is complete.
  if (digitalRead(startSwitch) == IS_PRESSED) {  
// If it is the first time through this function, set the currentTime to millis and turn on the mainInclineMotor.
// On subsequent passes, this skip these two steps.  
    if (currentTime == 0) {
    currentTime = millis();
    Serial.print("startSwitch=");
    Serial.print(digitalRead(startSwitch));
    Serial.print(" ");
    digitalWrite(track1BrakeRunMotor, ON);
    Serial.println("MOTOR ON");
 }
}
// If the timer is finished, then turn off the track1BrakeRunMotor and reset the currentTime back to "0"
  
    if (millis() - currentTime >= timeLimit) {
    digitalWrite(track1BrakeRunMotor, OFF);
    Serial.println("MOTOR OFF");
    currentTime = 0;
    delay(1);
  }
 }

When I press the switch and release, the motor runs for 5 seconds and shuts off as it is supposed to. Here is what gets printed to the terminal... Totally makes sense!

startSwitch=0 MOTOR ON
MOTOR OFF
MOTOR OFF
MOTOR OFF
MOTOR OFF
MOTOR OFF
MOTOR OFF
MOTOR OFF
MOTOR OFF
MOTOR OFF
MOTOR OFF
MOTOR OFF

Now, here is revised function with the 1 millisecond delay removed....

void checkStartSwitch(){
// this function turns on the track1BrakeRunMotor when the startSwitch is pressed
// and turns off the track1BrakeRunMotor when the timer is complete.
  if (digitalRead(startSwitch) == IS_PRESSED) {  
// If it is the first time through this function, set the currentTime to millis and turn on the mainInclineMotor.
// On subsequent passes, this skip these two steps.  
    if (currentTime == 0) {
    currentTime = millis();
    Serial.print("startSwitch=");
    Serial.print(digitalRead(startSwitch));
    Serial.print(" ");
    digitalWrite(track1BrakeRunMotor, ON);
    Serial.println("MOTOR ON");
 }
}
// If the timer is finished, then turn off the track1BrakeRunMotor and reset the currentTime back to "0"
  
    if (millis() - currentTime >= timeLimit) {
    digitalWrite(track1BrakeRunMotor, OFF);
    currentTime = 0;
  }
 }

Now, when I press the switch and release it, the motor runs continuously. Every 5 seconds, the relay flickers as if the motor is trying to turn off, but the motor keeps on running. Here is what is printed to the terminal... It is really bizarre!

startSwitch=0 MOTOR ON
startSwitch=1 MOTOR ON
startSwitch=1 MOTOR ON
startSwitch=1 MOTOR ON
startSwitch=1 MOTOR ON

With the value of the startSwitch =1, how can the Arduino possibly reach the Serial.println("MOTOR ON") command????

dz63:
With the value of the startSwitch =1, how can the Arduino possibly reach the Serial.println("MOTOR ON") command?

I don't really know, but...

You're not really testing the same value twice. You're reading it again.
Try reading the startSwitch pin only once, and use that value twice.

 // If the timer is finished, then turn off the track1BrakeRunMotor and reset the currentTime back to "0"
  if (millis() - currentTime >= timeLimit)
  {

^^ This is also true when currentTime is already zero. So you constantly switch the motor off.

This is probably it:

You use an analog pin. Are you sure you can use INPUT_PULLUP on those?
Try this in your setup():

pinMode(startSwitch,INPUT); // Instead of INPUT_PULLUP, and then ..
digitalWrite(startSwitch,HIGH);  // .. this to enable pullup on analog pin

(See here: https://www.arduino.cc/en/Tutorial/AnalogInputPins)

JobiWan - thanks for the suggestions. I appreciate your help.

Jobi-Wan:
So you constantly switch the motor off.

I added another if statement to eliminate this.

Jobi-Wan:
You use an analog pin. Are you sure you can use INPUT_PULLUP on those?
Try this in your setup():

pinMode(startSwitch,INPUT); // Instead of INPUT_PULLUP, and then ..

digitalWrite(startSwitch,HIGH);  // .. this to enable pullup on analog pin

Not sure if using INPUT_PULLUP on analog pins is legal. I changed to the method above and it did not solve the problem, so I don't think this was the issue.

With a 1ms delay, the motor stops 99% of the times, but I observed a few times where it did not stop. It leads me to believe it is something to do with back EMF when the motor is stopped. So, I bumped the delay up to 10ms and it works well now.

Here is the revised function...

void checkStartSwitch(){
// this function turns on the track1BrakeRunMotor when the startSwitch is pressed
// and turns off the track1BrakeRunMotor when the timer is complete.
  if (digitalRead(startSwitch) == IS_PRESSED) {  
// If it is the first time through this function, set the currentTime to millis and turn on the mainInclineMotor.
// On subsequent passes, this skip these two steps.  
    if (currentTime == 0) {
    currentTime = millis();
    Serial.print("startSwitch=");
    Serial.print(digitalRead(startSwitch));
    Serial.print(" ");
    digitalWrite(track1BrakeRunMotor, ON);
    Serial.println("MOTOR ON");
  }
}
// If the timer is finished, then turn off the track1BrakeRunMotor and reset the currentTime back to "0"
  
    if (currentTime != 0) {  // prevent the motor from repeatedly shutting off
    if (millis() - currentTime >= timeLimit) {
    digitalWrite(track1BrakeRunMotor, OFF);
    Serial.print("startSwitch=");
    Serial.print(digitalRead(startSwitch));
    Serial.print(" ");
    Serial.println("MOTOR OFF");
    currentTime = 0;
    delay(10);  //delay required to eliminate switch bounce due to motor shutting off
    }
   }
 }

And here is the output to the terminal for one depression of the switch.

startSwitch=0 MOTOR ON
startSwitch=1 MOTOR OFF

Not sure if using INPUT_PULLUP on analog pins is legal.

The "analog" pins are also digital pins. Using the internal pullup resistors, when using the pin as a digital pin is perfectly legal. Using them when the pin is used as an analog pin is perfectly silly.

PaulS:
The "analog" pins are also digital pins. Using the internal pullup resistors, when using the pin as a digital pin is perfectly legal. Using them when the pin is used as an analog pin is perfectly silly.

But that all depends - you might want to avoid noise on inputs that are not connected - if the sensor has low
impedance outputs the input pull-ups have no effect on the readings. Its hard for software to tell the
difference between an unconnected floating input and one with a genuine signal, its easy to spot an
input that reads (near) 1023 all the time.

Consider detecting a hardware fault - it a cable is broken or shorted using pull-ups enables you to spot this
when the sensor normally outputs a signal based around mid-rail.