I'm new both to this forum and to Arduino. My robot is comprised of Arduino Uno with Arduino Motor Shield, 12V DC gear motor, and two limit switches. The robot supposed to move endlessly on rails between the two walls back-and-forth. I have it all wired up and am able to switch the directions of the motor's rotation by pushing the limit switches. However, I also want to have a pause between switching of directions:
... Robot moving forward ...
If front limit switch is pushed
Stop motor
Pause 2 seconds
Run motor CCW
... Robot moving backwards ...
If rear limit switch is pushed
Stop motor
Pause 2 seconds
Run motor CW
... Robot moving forward ...
Simple delay(2000)
doesn't work as the limit switch remains pushed against the wall. I've been trying out millis()
approach but the fact that limit switch remains pushed (HIGH
) I can never produce a difference in time needed to trigger an action. I learned about State Machine but not sure if and how this could help my case?
Can anyone please help me in implementing a two second pause between the switching of the motor's direction?
Below is the code that momentarily switches the motor's direction when robot reaches the wall and limit switch is pushed.
int switchFront_State = 0;
int switchRear_State = 0;
const int ledYellow = 6;
const int ledGreen = 5;
const int switchFront = 4;
const int switchRear = 2;
const int motorDirection = 12;
const int motorBreak = 9;
const int motorPWM = 3;
void setup() {
Serial.begin (9600);
pinMode(switchFront, INPUT_PULLUP); // Front switch
pinMode(switchRear, INPUT_PULLUP); // Rear switch
pinMode(ledYellow, OUTPUT);
pinMode(ledGreen, OUTPUT);
// Setup Channel A
pinMode(motorDirection, OUTPUT); // Motor direction pin
pinMode(motorBreak, OUTPUT); // Motor break pin
pinMode(motorPWM, OUTPUT); // Motor PWM pin
}
void runMotorBackward(){ // Motor moving backward
digitalWrite(motorDirection, LOW);
digitalWrite(motorBreak, LOW);
digitalWrite(motorPWM, 128);
}
void motorStop(){ // Stop motor
digitalWrite(motorBreak, HIGH);
digitalWrite(motorPWM, 0);
}
void runMotorForward(){ // Motor moving forward
digitalWrite(motorDirection, HIGH);
digitalWrite(motorBreak, LOW);
digitalWrite(motorPWM, 128);
}
void loop(){
switchFront_State = digitalRead (switchFront);
switchRear_State = digitalRead (switchRear);
if (switchFront_State == HIGH){ // If front switch is pressed
digitalWrite(ledYellow, HIGH); // Yellow LED
motorStop();
runMotorBackward();
} else {
digitalWrite(ledYellow, LOW);
}
if (switchRear_State == HIGH){ // If rear switch is pressed
digitalWrite(ledGreen, HIGH); // Green LED
motorStop();
runMotorForward();
} else {
digitalWrite(ledGreen, LOW);
}
}
-
Have you considered using a full state machine rather than just sensing the states of the switches?Ignacio Vazquez-Abrams– Ignacio Vazquez-Abrams11/11/2016 11:34:21Commented Nov 11, 2016 at 11:34
-
I don't get why delay(2000) does work?Gerben– Gerben11/11/2016 14:35:44Commented Nov 11, 2016 at 14:35
-
Gerben, delay(2000) works but it requires limit switch to be in LOW position in order for motor to run again. Originally, I tried placing delay(2000) between motorStop() and runMotorForward() / runMotorBackward() which worked but not in the useful way for me. In other words, the delay would be fired if the limit switch is pushed (HIGH) but the motor wouldn't start running again till the limit switch is released again (LOW).Dragan Miletic– Dragan Miletic11/11/2016 22:40:07Commented Nov 11, 2016 at 22:40
-
Ignacio Vazquez-Abrams, I'm not sure what do you mean by "full state machine?" As I suggested, I'm new to Arduino and programming in general.Dragan Miletic– Dragan Miletic11/11/2016 22:41:14Commented Nov 11, 2016 at 22:41
2 Answers 2
I think the problem is because there is no delay time after your motor switch its direction, so the robot is stay on position where the switch is pressed. I don't know if this gonna work, but perhaps you can add delay after the direction changed.
But based on your code, I can't find a condition to run if no switch is pressed. For alternative, you can try this
int direction_state = 1; //state where robot moves forward
void loop(){
/*notes that here I assume while robot moving forward,
*the rear switch is impossible to pressed, so does while
*robot moving backward, the front switch is impossible to
*pressed.
*/
while ((digitalRead (switchRear)==LOW) && (digitalRead (switchFront)==LOW))
//no switch pressed, loop will break if any switch pressed
{
if (direction_state == 1) runMotorForward(); else
runMotorBackward();
}
//indicator which switch is pressed and start of 2s motor stops
if (direction_state==1) digitalWrite(ledYellow,HIGH);
else digitalWrite(ledGreen,HIGH);
motorStop(); //stop the motor
delay(2000);
//indicator 2s motor stops finished
if (direction_state==1) digitalWrite(ledYellow,LOW); //indicator front switch is pressed
else digitalWrite(ledGreen,LOW);
direction_state = -direction_state //toggle the state
if (direction_state == 1) runMotorForward(); else
runMotorBackward();
delay(2000);
}
Feel free to ask if it's not works
-
Well, your suggestion above is exactly what doesn't work, adding i.e. delay(2000); after runMotorForward() / runMotorBackward() is not firing at all. Originally, I tried placing delay(2000) between motorStop() and runMotorForward() / runMotorBackward() which worked but not in the useful way for me. In other words, the delay would be fired if the limit switch is pushed (HIGH) but the motor wouldn't start running again till the limit switch is released again (LOW). As I described above, this is not an option as robot will get stuck first time it reaches a wall. The 2nd code doesn't have pause?Dragan Miletic– Dragan Miletic11/11/2016 22:39:25Commented Nov 11, 2016 at 22:39
-
dpw, if you look at my code you'll realize that pressing on either limit switch (by hand) will set the robot in motion. I power the robot, it's not moving, then i press say the front limit switch and robot immediately starts to move backwards, hits the rear wall, changes the direction, runs towards the front wall, hits the front wall, changes the direction... endlessly, or as long as it is powered. All I want is that the robot pauses for two seconds when it hits the wall instead of just "bouncing" off of it.Dragan Miletic– Dragan Miletic11/11/2016 22:50:29Commented Nov 11, 2016 at 22:50
-
1Hi Dragan, I've edited the answers. Perhaps you can try itduck– duck11/13/2016 03:01:25Commented Nov 13, 2016 at 3:01
-
1Hi dpw, thank you sooooo very much for the corrected code. I uploaded it and it works EXACTLY the way I want!!! BTW, would it be possible to make switchRear to only switch motor to run forward and similarly that switchFront only switches motor to run backward. As of now, the directions could be confused if a "wrong" switch is pressed by accident.Dragan Miletic– Dragan Miletic11/14/2016 11:16:30Commented Nov 14, 2016 at 11:16
-
Sure it can, you can modify the "while" condition. Happy I can help, and good luck to your projectduck– duck11/14/2016 12:27:37Commented Nov 14, 2016 at 12:27
You need to make your switch logic edge sensitive rather than state sensitive. (That's the digital electronics term for it.) That means that you need to react to the change from switch off to switch on, not to the switch being on. (Since you're using INPUT_PULLUP mode, a switch on = LOW.
So:
In your loop, don't use
switchFront_State = digitalRead (switchFront);
instead, use code like below to detect a switch press:
int newSwitchState = digitalRead (switchFront);
if (newSwitchState == LOW && newSwitchState != switchFront_State) {
switchFront_State = newSwitchState;
//Code to handle the limit switch being pressed
} else if (newSwitchState == HIGH && newSwitchState != switchFront_State) {
switchFront_State = newSwitchState;
//Code to handle switch changing to the off state
}
You'll probably also need to use millis() to add some debouncing to your switch. (Ignore switch changes unless 10-20 milliseconds has passed, to avoid the switch jittering on and off when it is initially pressed or released.)