How can I program a servo to move to a position once then be controlled manually

I need a servo to move to 30 degrees upon a switched being flipped on, then while the switch is still on be able to control the servo manually without going back to 30 degrees automatically for the rest of the time the program is running.

Basically what I want to code is:

while (switch is flipped on && boolean value == false){

slowly rotate servo to 30 degrees
set boolean value to true so code segment will not run again

}

After this bit of code executes the switch will remain switched on and manual control of the servo will resume.

I have written the code in this way and many others but every time the servo rotates to 30 degrees upon the switch being flipped on the switch needs to be flipped off and back on again before the servo can be controlled manually.

Not sure if this is relevant but upon the switch being flipped off the servo is programmed to rotate to 90 degrees.

I’ve attached the working code without my attempt at coding the bit that would bring the servo to 30 degrees as it would probably just make things more confusing.

The switch in question is assigned to pin 6 which is defined as DEF.

Any help would be greatly appreciated, thanks.

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

int angle =90;    // initial angle  for servo
int angleStep =5;


#define UP 12   // pin 12 is connected to UP button
#define DOWN  2  // pin 2 is connected to DOWN button
#define DEF 6  // pin 6 is connected to switch

void setup() {
  Serial.begin(9600);          //  setup serial
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  pinMode(UP,INPUT_PULLUP); // assign pin 12 as input for UP button
  pinMode(DOWN,INPUT_PULLUP);
  pinMode(DEF,INPUT_PULLUP);
}


void loop() {
  
  while(digitalRead(DOWN) == LOW){

    if (angle > 0 && angle <= 180) {
      angle = angle - angleStep;
       if(angle < 0){
        angle = 0;
       }else{
      myservo.write(angle); // move the servo to desired angle
       }
    }
    
  delay(80); // waits for the servo to get there
  }// while
 

  while(digitalRead(UP) == LOW){

    if (angle >= 0 && angle <= 180) {
      angle = angle + angleStep;
      if(angle >180){
        angle =180;
       }else{
      myservo.write(angle); 
       }
    }
    
  delay(80); 
  }
 

 while(digitalRead(DEF) == HIGH){

if (angle < 90) {
      angle = angle + angleStep;
      if(angle >90){
        angle =90;
       }else{
      myservo.write(angle); 
       }
    }
    
  if (angle > 90) {
      angle = angle - angleStep;
       if(angle < 90){
        angle = 90;
       }else{
      myservo.write(angle); 
       }
    }
    
  delay(80); 

 }  
 
}

Please explain in detail what you are doing to "manually" control the servo.

Paul

Paul_KD7HB:
Please explain in detail what you are doing to “manually” control the servo.

Paul

Hi Paul,

I’ve attached the code which allows manual control of the servo.

If pin 2 (assigned to DOWN) is LOW (ie the button connecting ground to pin 2 is in the on position), the servo moves in one direction.

If pin 12 (assigned to UP) is LOW (ie button is on), the servo moves in the opposite direction.

while(digitalRead(DOWN) == LOW){

    if (angle > 0 && angle <= 180) {
      angle = angle - angleStep;
       if(angle < 0){
        angle = 0;
       }else{
      myservo.write(angle); // move the servo to desired angle
       }
    }
    
  delay(80); // waits for the servo to get there
  }// while
 


  while(digitalRead(UP) == LOW){

    if (angle >= 0 && angle <= 180) {
      angle = angle + angleStep;
      if(angle >180){
        angle =180;
       }else{
      myservo.write(angle); 
       }
    }
    
  delay(80); 
  }

Maybe this will do what you want? The servo goes to 90 initially. The servo cannot move until the first time the DEF switch goes from OPEN/OFF to CLOSED/ON. Then the servo moves to 30 and manual controls are enabled.

#include <Servo.h>
Servo myservo;  // create servo object to control a servo

int angle = 90;   // initial angle  for servo
const int angleStep = 5;

const byte UPPin = 12;   // pin 12 is connected to UP button
const byte DOWNPin = 2;  // pin 2 is connected to DOWN button
const byte DEFPin = 6;  // pin 6 is connected to switch

void setup()
{
  Serial.begin(9600);          //  setup serial
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  pinMode(UPPin, INPUT_PULLUP); // assign pin 12 as input for UP button
  pinMode(DOWNPin, INPUT_PULLUP);
  pinMode(DEFPin, INPUT_PULLUP);
}

void loop()
{
  boolean downPressed = digitalRead(DOWNPin) == LOW;  // Active Low
  boolean upPressed = digitalRead(UPPin) == LOW;  // Active Low
  boolean defIsClosed = digitalRead(DEFPin) == LOW;  // Active Low
  static boolean defWasClosed = false;
  static boolean manualControl = false;

  if (manualControl)
  {
    if (downPressed)
      angle -= angleStep;

    if (upPressed)
      angle += angleStep;

    angle = constrain(angle, 0, 180);
    myservo.write(angle); // move the servo to desired angle
    delay(80); // waits for the servo to get there
  }
  else if (defIsClosed != defWasClosed) // Switch position changed
  {
    defWasClosed = defIsClosed;
    if (defIsClosed) // Switch jst closed
    {
      angle = 30;
      myservo.write(angle); // move the servo to desired angle
      delay(80); // waits for the servo to get there
      manualControl = true;
    }
  }
}

johnwasser:
Maybe this will do what you want? The servo goes to 90 initially. The servo cannot move until the first time the DEF switch goes from OPEN/OFF to CLOSED/ON. Then the servo moves to 30 and manual controls are enabled.

Thank you so much! This does almost exactly what I've been trying to do. The only thing it doesn't do (which I didn't mention in the original post because I thought I could easily add it in later) is rotate slowly to 30 degrees. Right now the servo zips right to 30 and I don't want to give the thing the servo is attached to a quick jerk like that. I've been attempting to do this all day and can't seem to find a way to make it work.
I'm very new to Arduino and only have some coding experience and would appreciate any further help you could give me.
Additionally I want to fully understand the code you posted and am a little confused by this line:

boolean downPressed = digitalRead(DOWNPin) == LOW;  // Active Low

Is it setting the boolean downPressed to true when the switch is in the on position?

Thanks,
Aaron

whiteaa:
boolean downPressed = digitalRead(DOWNPin) == LOW;  // Active LowIs it setting the boolean downPressed to true when the switch is in the on position?

Yes. A switch or button connects two things when it is closed and disconnects them when open. If nothing is connected to an input pin, the pin starts acting like an antenna. The voltage on the pin can randomly go high enough that the pin reads as HIGH and low enough for the pin to read as LOW. To keep the pin from floating you have to have a pull-up resistor between the pin and a HIGH signal (+5V) or a pull-down resistor between the pin and a LOW signal (Ground/0V). The processor has an internal pull-up resistor that you can enable by using pinMode INPUT_PULLUP. That saves you from having to add an external resistor. When you use a pull-up, the switch/button is connected between the pin and Ground. The pin will read as HIGH until the switch/button is closed.

Some people find it confusing to have a LOW represent 'pressed' and a HIGH represent 'unpressed'. Also, on some Arduino models, the values HIGH and LOW can't be used as true/false values at all. By writing:
boolean xxxxPressed = digitalRead(xxxxPin) == LOW;  // Active Lowyou get a nice clean boolean that is true only when the button is pressed.

For state change detection I like to use the boolean variables xxxxIsPressed and xxxxWasPressed.