SOLVED!!! A Servo and 3 Buttons

Good day great minds.

I am a bit new with programming Arduino. Though I already had few projects made, all of which do have simple and basic sketches. Now, I am trying to move forward, but got stuck with probably a simple logic. I had been doing some trial and errors with my sketch but still no luck, thus, will ask for your help.

My goal is to have 3 momentary normally open buttons control 1 continuous servo.

The first button will signal the arduino to commence the sequence of blinking an LED and rotate. While the other two will determine the direction (clockwise or counter clockwise) of the rotation and stop the sequence at the same time.

For example, at a momentary press of the first button, the LED will blink and rotate the servo clockwise for 1000ms. Unless the button that corresponds the counter clockwise direction is pressed, the sequence will loop indefinitely. But once the counter clockwise button is pressed, it should stop the sequence and define the next direction should be counter clockwise and wait for the first button to be pressed again and start with the sequence.

Your help will be highly appreciated.

Below is the code (with my limited knowledge):

#include <Servo.h>

Servo myservo;

const int START_SEQ = 7;
const int RIGHT_SW = 2;
const int LEFT_SW = 4;
const int LED_PIN = 13;

int runState = 0;
int rotDir = 0;

void setup()
{
  myservo.attach(9);
  pinMode(START_SEQ, INPUT);
  pinMode(LEFT_SW, INPUT);
  pinMode(RIGHT_SW, INPUT);
  pinMode(LED_PIN, OUTPUT);
}

void loop()
{
  runState = digitalRead(LEFT_SW) || digitalRead(RIGHT_SW);
  {
    if (digitalRead(LEFT_SW) == HIGH)
     {
       rotDir = 45;
     }
     else if (digitalRead(RIGHT_SW) == HIGH)
     {
       rotDir = 135;
     }
    if (runState == HIGH)
    {
      myservo.write(89);
    }
    else if (digitalRead(START_SEQ) == HIGH)
    {
      Blink_Rotate();
    }
  }
}
void Blink_Rotate()
{
  digitalWrite(LED_PIN, HIGH);
  delay(100);
  digitalWrite(LED_PIN, LOW);
  delay(100);
  myservo.write(rotDir);
  delay(1000);
  myservo.write(89);
  delay(500);
}

You are using delay() in the blinkRotate function (it is "blocking"). The switches are not being tested while in that function is executing.
The blink without delay example in the IDE shows how to time things and still read buttons.

You are using delay() in the blinkRotate function (it is "blocking"). The switches are not being tested while in that function is executing.
The blind without delay example in the IDE shows how to time things and still read buttons.

Thank you for that info groundfungus. That point is useful, specially if I would need to interrupt the sequence at the time the button is pressed.

I meant blink without delay. It can be found in the IDE menus by File, Examples, Digital. In my opinion, it is one of the most important concepts to learn with Arduino.

Let me illustrate this a little farther.

The servo is actually controlling a platform that move either towards left or right. Once the said platform reaches the end of the rail, it pushes a button so it will be the signal for arduino to stop the sequence and at the same time, tells arduino that the next time it runs the sequence, it should rotate the opposite direction.

With my sketch, when the platform reaches and pushes the button, it stops the sequence and tells the servo to rotate the opposite direction next time. But the problem is, since it keeps the button pressed and will be able to depress only when it starts to rotate the other direction, pushing the first button cannot initiate the sequence since the direction/stop button is also pressed from the last sequence.

If only there's a code that ignores the pressed button, that might do the trick.

I'll point you to another example. The state change detection example. Using that concept you would stop and reverse only on a transition say low to high. You can have it ignore LOW, HIGH states and the other transition.

groundfungus:
I'll point you to another example. The state change detection example. Using that concept you would stop and reverse only on a transition say low to high. You can have it ignore LOW, HIGH states and the other transition.

That might work.

I got to try to understand and apply this.

Thanks again for the help groundfungus. :slight_smile:

About those switches. It seems that you have them pulled low and they are high if actuated. Is that right? If so I would suggest that you wire them like the attached schematic. There are 2 advantages to this scheme. You can use the internal pullup resistors instead of any external resistor and with the addition of the cap, debounce most momentary switches. Enable the internal pullups on an input with
pinMode(pin, INPUT_PULLUP);.

groundfungus:
About those switches. It seems that you have them pulled low and they are high if actuated. Is that right? If so I would suggest that you wire them like the attached schematic. There are 2 advantages to this scheme. You can use the internal pullup resistors instead of any external resistor and with the addition of the cap, debounce most momentary switches. Enable the internal pullups on an input with
pinMode(pin, INPUT_PULLUP);.

WHOA!!!

With a bonus.

Thanks again. Very much appreciated.

close, but not close enough.

the change state idea is almost there.

my problem is, in the loop, it will always check for difference in state from current compared to the last state and will only execute when state is not the same.

i need something that disables the command of one button when the other is pressed.

i have seen before something like mode = STANDBY; and mode = ACTIVE; which i can assign the first button to change the mode into ACTIVE and run the loop into infinity and will only stop when either of the other 2 buttons are pressed which changes the mode into STANDBY.

i just don't know how to use that logic though. i tried, but no luck.

Another concept. The state machine. There are many tutorials that can explain better than me.

arcQuisumbing:
close, but not close enough.

the change state idea is almost there.

my problem is, in the loop, it will always check for difference in state from current compared to the last state and will only execute when state is not the same.

i need something that disables the command of one button when the other is pressed.

i have seen before something like mode = STANDBY; and mode = ACTIVE; which i can assign the first button to change the mode into ACTIVE and run the loop into infinity and will only stop when either of the other 2 buttons are pressed which changes the mode into STANDBY.

i just don't know how to use that logic though. i tried, but no luck.

look at something like this and jettison those blocking delays...

#include <Servo.h>

Servo myservo;

const int START_SEQ = 7;
const int RIGHT_SW = 2;
const int LEFT_SW = 4;
const int LED_PIN = 13;

int runState = 0;
int rotDir = 0;
int rightSwitchOldState, leftSwitchOldState, startSwitchOldState;

void setup()
{
  myservo.attach(9);
  pinMode(START_SEQ, INPUT);
  pinMode(LEFT_SW, INPUT);
  pinMode(RIGHT_SW, INPUT);
  pinMode(LED_PIN, OUTPUT);
}

void loop()
{
  int leftSwitchState = digitalRead(LEFT_SW); // test this switch
  if (leftSwitchState==HIGH) 
  {
    if (leftSwitchOldState ==LOW)//state change !!!
    {
      // Do your desired work for this button for  LEFT_SW
    }
  }
  leftSwitchOldState = leftSwitchState;
  //
  int rightSwitchState = digitalRead(RIGHT_SW); // test this switch
  if (rightSwitchState==HIGH) 
  {
    if (rightSwitchOldState ==LOW)//state change !!!
    {
      // Do your desired work for this button for  RIGHT_SW
    }
  }
  rightSwitchOldState = rightSwitchState;
  //
  int startSwitchState = digitalRead(START_SEQ); // test this switch
  if (startSwitchState==HIGH) 
  {
    if (startSwitchOldState ==LOW)//state change !!!
    {
      // Do your desired work for this button for  START_SEQ
      Blink_Rotate();
    }
  }
  startSwitchOldState = startSwitchState;
  /*
  runState = digitalRead(LEFT_SW) || digitalRead(RIGHT_SW);
  {
    if (digitalRead(LEFT_SW) == HIGH)
    {
      rotDir = 45;
    }
    else if (digitalRead(RIGHT_SW) == HIGH)
    {
      rotDir = 135;
    }
    if (runState == HIGH)
    {
      myservo.write(89);
    }
    else if (digitalRead(START_SEQ) == HIGH)
    {
      Blink_Rotate();
    }
  }
  */
}
void Blink_Rotate()
{
  digitalWrite(LED_PIN, HIGH);
  delay(100);
  digitalWrite(LED_PIN, LOW);
  delay(100);
  myservo.write(rotDir);
  delay(1000);
  myservo.write(89);
  delay(500);
}

FINALLY!!!!

Got what I am looking for. Thank you groundfungus for the direction and BulldogLowell for the elaboration and sample.

Below is my final sketch.

#include <Servo.h>
#define STANDBY 0
#define ACTIVE 1

Servo myservo;

const int START_SEQ = 7;
const int RIGHT_SW = 2;
const int LEFT_SW = 4;
const int LED_PIN = 13;

int runState = 0;
int rotDir = 0;
int mode = STANDBY;
int rightSwitchOldState, leftSwitchOldState, startSwitchOldState;

void setup()
{
  Serial.begin(9600);
  myservo.attach(9);
  pinMode(START_SEQ, INPUT_PULLUP);
  pinMode(LEFT_SW, INPUT_PULLUP);
  pinMode(RIGHT_SW, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
}

void loop()
{
  int startSwitchState = digitalRead(START_SEQ); // test this switch
  int leftSwitchState = digitalRead(LEFT_SW); // test this switch
  int rightSwitchState = digitalRead(RIGHT_SW); // test this switch
  if (leftSwitchState==LOW)
  {
    rotDir = 45;
  }
  if (rightSwitchState==LOW)
  {
    rotDir = 135;
  }
  if (leftSwitchState==LOW || rightSwitchState==LOW)
  {
    mode = STANDBY;
  }
  if (startSwitchState==LOW)
  {
    if (mode==STANDBY)
    {
      myservo.write(rotDir);
      delay(1500);
      Serial.println("Releasing switch.");
      mode = ACTIVE;
      Blink_Rotate();
    }
    else
    {
      Serial.println("Start sequence.");
      mode = ACTIVE;
    }
  }
  Blink_Rotate();
}


void Blink_Rotate()
{
  if (mode == ACTIVE){
    digitalWrite(LED_PIN, HIGH);
    Serial.println("LED ON.");
    delay(100);
    Serial.println("LED OFF.");
    digitalWrite(LED_PIN, LOW);
    delay(100);
    Serial.print("Rotating ");
    Serial.print(rotDir);
    Serial.println(".");
    myservo.write(rotDir);
    delay(1000);
    myservo.write(89);
    delay(500);
    mode = ACTIVE;
  }
}

great that you got it working... I'd have been happier if you were able to get rid of this dang delay()s!!! :cold_sweat:

great job!!!

BulldogLowell:
great that you got it working... I'd have been happier if you were able to get rid of this dang delay()s!!! :cold_sweat:

great job!!!

thanks and thanks again. :slight_smile:

for this particular purpose, i really don't mind the delay() as it is an integral part of the sequence. each step have to be executed and should not abruptly stop upon left/right button signal.