Need help with controlling servos with potentiometer and switch

Hi! I have this problem that when I turn the switch off the servos dont turn slowly to the position the potentiometer is on. When I turn the switch on the servos turn correctly to their position and slowly as planned. What could be my problem? I'm pretty new to arduino.

#include <Servo.h>

Servo myservo1; // create servo 1 object to control a servo
Servo myservo2; // create servo 2 object to control a servo

int potpin = A0;     // analog pin used to connect the potentiometer
unsigned int servoPin[] = {5, 6}; // watch video for details https://youtu.be/QB49Rmc96Ho
int switchPin = 7;   // digital pin used for the switch

int val;                     // variable to read the value from the analog pin
int previousPos1 = 0;        // variable to store previous position of servo 1
int previousPos2 = 0;        // variable to store previous position of servo 2
boolean switchState = false; // current state of the switch
boolean servosMoved = false; // flag to track if the servos have been moved

void setup() {
  Serial.begin(9600);
  Serial.println("Multiple Servo");
  Serial.println("Robojax.com");
  myservo1.attach(servoPin[0]); // attaches the servo 1 to the servo object
  myservo2.attach(servoPin[1]); // attaches the servo 2 to the servo object
  pinMode(switchPin, INPUT_PULLUP);   // sets the switch pin as input    
  digitalWrite(switchPin, HIGH);
  
  myservo1.write(0);
  myservo2.write(0);
  
}

void loop() {
  // Read the state of the switch
  switchState = digitalRead(switchPin);
  previousPos1 = myservo1.read();
  previousPos2 = myservo2.read();

  if (switchState && !servosMoved) {
    // If the switch is on and servos haven't been moved yet
    previousPos1 = 90;
    previousPos2 = 0;
    gradualServoMovement(previousPos1, previousPos2, 2500); // Gradually move servos to new positions over 2 seconds
    servosMoved = true; // Set the flag to indicate that the servos have been moved
  }
  else if (!switchState && servosMoved) {
    // If the switch is off and servos have been moved
    myservo1.write(previousPos1); // Set servo 1 position to previous position
    myservo2.write(previousPos2); // Set servo 2 position to previous position
    gradualServoMovement(previousPos1, previousPos2, 500);
    servosMoved = false; // Reset the flag since the servos are back to their original positions
  }

  if (!switchState) {
    val = analogRead(potpin);   // reads the value of the potentiometer (value between 0 and 1023)
    val = map(val, 0, 1023, 0, 45);   // Scale it to use it with the servo (value between 0 and 45)
    myservo1.write(val);

    val = analogRead(potpin);   // reads the value of the potentiometer (value between 0 and 1023)
    val = map(val, 0, 1023, 90, 45);     // Scale it to use it with the servo (value between 45 and 0)
    myservo2.write(val);
  }

  Serial.print(val);
  Serial.println();

  //delay(10); // waits for the servo to get there
}

// Function for gradually moving servos from current position to target position over a specified duration
void gradualServoMovement(int targetPos1, int targetPos2, unsigned int duration) {
  int startPos1 = myservo1.read(); // Get current position of servo 1
  int startPos2 = myservo2.read(); // Get current position of servo 2
  unsigned long startTime = millis(); // Get the start time
  unsigned long remainingDuration = duration; // Initialize remaining duration

  while (true) {
    unsigned long elapsedTime = millis() - startTime;

    if (elapsedTime >= duration) {
      // Time duration has elapsed, set final position and exit the function
      myservo1.write(targetPos1);
      myservo2.write(targetPos2);
      return;
    }

    // Calculate the current position based on time elapsed
    float progress = elapsedTime / (float)duration;
    int currentPos1 = startPos1 + (targetPos1 - startPos1) * progress;
    int currentPos2 = startPos2 + (targetPos2 - startPos2) * progress;

    // Set the servo positions based on the current position
    myservo1.write(currentPos1);
    myservo2.write(currentPos2);

    // Check if the remaining duration is half of the original duration
    if (elapsedTime >= duration / 2 && remainingDuration == duration) {
      // Double the remaining duration
      remainingDuration = duration * 2;
    }

    // Calculate the delay incrementally for smoother movement
    unsigned long delayIncrement = remainingDuration / 100;
    delay(delayIncrement);
  }
}

it works perfectly fine in the simulator: sketch.ino - Wokwi ESP32, STM32, Arduino Simulator

I built it in tinkercad. Everything works otherwise, but when I turn the switch off the servos wait 0,5 seconds and then move quickly to a new position... They should turn slowly like they do when I turn the switch on.

moving to the pot postion does not use your gradualServoMovement() function. It just writes the value directly to the servo so it will move as fast as possible.

having done this before i know your code is unnecessarily long which makes it more difficult to read, understand and debug for novices as well as experienced coders

please look this over

#include <Servo.h>

const byte PinSwitch   = 7;
const byte PinPot      = A0;
const byte PinServo [] = { 5, 6};
const int  Nservo      = sizeof (PinServo);

Servo myServo [Nservo];
int   pos  [Nservo];
int   targ [Nservo];

void
loop (void)
{
    byte sw = digitalRead (PinSwitch);

    if (sw) {
        int ang = map (analogRead(PinPot), 0, 1023, 0, 45);
        targ [0] = ang;
        targ [1] = 90 - ang;
    }
    else {
        targ [0] = 0;
        targ [1] = 90;
    }

    for (int n = 0; n < Nservo; n++) {
        if (targ [n] == pos [n])
            continue;               // avoid simulation prints of writes

        if (targ [n] < pos [n])
            pos [n]--;
        else if (targ [n] > pos [n])
            pos [n]++;

        myServo [n].write (pos [n]);
    }

    delay (20);
}

void
setup (void)
{
    Serial.begin (9600);

    pinMode (PinSwitch, INPUT_PULLUP);

    for (int n = 0; n < Nservo; n++) {
        myServo [n].attach (PinServo [n]);
    }
}

Make sure when you actually wire this up that you don't power the servos from the Arduino. The servos need to be directly connected to a power supply that can supply the proper voltage and current.

from 3rd thread

So when I power this up the first movement of servos is really fast and I want it to go as slow as the other movements when switch is turned on or off.

at startup there's no easy way to know the position of the servos. one awkward way would be to store the last position in EEPROM and on startup in setup, initialize the servos to that position. of course there's nothing to prevent the servos from being moved while the system is off

considering the use of the switch, it doesn't even make sense to move the servos to some default position in setup() because as soon as loop() is called, they will be moved to the position dictated by the sw and pot.

presumably if you turn the system off and back on, the servos should may jitter a bit but at least return to the position they were already at when the system was turned on

Hi! I got help before on a different problem in this code so I thought I'd ask again if someone would know a solution because I've been struggling. This is my first actual project with arduino. So still learning be kind.

So my problem now is that when I power up the system both of the servos "bounce" to a 90 degree angle from the picture below. After that bounce they start moving nice and slow to either a set position if the switch is on or to a position the potentiometer sets them. I want to eliminate the bounce at the start, but I dont know what is causing it... Thank you so much in advance <3

#include <Servo.h>

Servo myservo1; // create servo 1 object to control a servo
Servo myservo2; // create servo 2 object to control a servo

int potpin = A0;     // analog pin used to connect the potentiometer
unsigned int servoPin[] = {5, 6}; // watch video for details https://youtu.be/QB49Rmc96Ho
int switchPin = 7;   // digital pin used for the switch

int val;  // variable to read the value from the analog pin
int previousPos1 = 0;        // variable to store previous position of servo 1
int previousPos2 = 0;        // variable to store previous position of servo 2
int previousPos3 = 0;        // variable to store previous position of servo 1
int previousPos4 = 0; 
boolean switchState = false; // current state of the switch
boolean servosMoved = false; // flag to track if the servos have been moved

void setup() {
  Serial.begin(9600);
  Serial.println("Multiple Servo");
  Serial.println("Robojax.com");
  myservo1.attach(servoPin[0]); // attaches the servo 1 to the servo object
  myservo2.attach(servoPin[1]); // attaches the servo 2 to the servo object
  pinMode(switchPin, INPUT_PULLUP);   // sets the switch pin as input    
  digitalWrite(switchPin, HIGH);
  previousPos1 = myservo1.read();
  previousPos2 = myservo2.read();
  
  // Read the initial state of the switch
  switchState = digitalRead(switchPin);

  if (!switchState) {
    // If the switch is off during power-up, gradually move the servos to their original positions over 2.5 seconds
    gradualServoMovement(previousPos1, previousPos2, 2500);
    servosMoved = false; // Reset the flag since the servos are back to their original positions
  }
}

void loop() {
  // Read the state of the switch
  switchState = digitalRead(switchPin);

  if (switchState && !servosMoved) {
    // If the switch is on and servos haven't been moved yet
    previousPos1 = 90;
    previousPos2 = 0;
    gradualServoMovement(previousPos1, previousPos2, 3000); // Gradually move servos to new positions over 2.5 seconds
    servosMoved = true; // Set the flag to indicate that the servos have been moved
    Serial.println("switchState && !servosMoved");  
  }
  else if (!switchState && servosMoved) {
    // If the switch is off and servos have been moved
    gradualServoMovement(previousPos3, previousPos4, 3000); // Gradually move servos to original positions over 2.5 seconds
    servosMoved = false; // Reset the flag since the servos are back to their original positions
    Serial.println("!switchState && servosMoved");  
  }

  else if (!switchState) {
    val = analogRead(potpin);   // reads the value of the potentiometer (value between 0 and 1023)
    val = map(val, 0, 1023, 0, 45);   // Scale it to use it with the servo (value between 0 and 45)
    myservo1.write(val);

    val = analogRead(potpin);   // reads the value of the potentiometer (value between 0 and 1023)
    val = map(val, 0, 1023, 90, 45);     // Scale it to use it with the servo (value between 45 and 90)
    myservo2.write(val);
    previousPos3 = myservo1.read();
    previousPos4 = myservo2.read();
    Serial.println("!switchState");
  }

  Serial.print(val);
  Serial.println();

  delay(100); // waits for the servo to get there
}


// Function for gradually moving servos from current position to target position over a specified duration
void gradualServoMovement(int& targetPos1, int& targetPos2, unsigned int duration) {
  float startPos1 = myservo1.read(); // Get current position of servo 1
  float startPos2 = myservo2.read(); // Get current position of servo 2
  unsigned long startTime = millis(); // Get the start time

  while (true) {
    unsigned long elapsedTime = millis() - startTime;

    if (elapsedTime >= duration) {
      // Time duration has elapsed, set final position and exit the function
      myservo1.write(targetPos1);
      myservo2.write(targetPos2);
      return;
    }

    // Calculate the current position based on time elapsed
    float progress = elapsedTime / (float)duration;
    float currentPos1 = startPos1 + (targetPos1 - startPos1) * progress;
    float currentPos2 = startPos2 + (targetPos2 - startPos2) * progress;

    // Set the servo positions based on the current position
    myservo1.write(currentPos1);
    myservo2.write(currentPos2);

    // Check if the switch is turned off and update the target positions
    if (!switchState) {
      targetPos1 = analogRead(potpin);
      targetPos1 = map(targetPos1, 0, 1023, 0, 45);
      
      targetPos2 = analogRead(potpin);
      targetPos2 = map(targetPos2, 0, 1023, 90, 45);
    }

    delay(10); // Delay for smooth movement
  }
}   

write() the initial servo position that you would like to the servo before using attach() and the servo will start in that position instead of its default of 90 degrees

By the way, powering the servos from the Arduino 5V pin is a bad idea because it cannot provide the required current and may damage the Arduino and/or cause other problems

Thanks mate! Works now!

And yes in my real build I have separate power supply.

Hello! I've asked couple questions about this code before and it works almost perfectly now but 1 thing is still bothering me... I know this code is pretty "bad" but this is my first own project and I'm still learning :))

So when I power this up the first movement of servos is really fast and I want it to go as slow as the other movements when switch is turned on or off.
I've tried different solutions but none have worked and have broken something else...

#include <Servo.h>

Servo myservo1; // create servo 1 object to control a servo
Servo myservo2; // create servo 2 object to control a servo

int potpin = A0;     // analog pin used to connect the potentiometer
unsigned int servoPin[] = {5, 6}; // watch video for details https://youtu.be/QB49Rmc96Ho
int switchPin = 7;   // digital pin used for the switch

int val;  // variable to read the value from the analog pin
int previousPos1 = 0;        // variable to store previous position of servo 1
int previousPos2 = 0;        // variable to store previous position of servo 2
int previousPos3 = 0;        // variable to store previous position of servo 1
int previousPos4 = 0;
boolean switchState = false; // current state of the switch
boolean servosMoved = false; // flag to track if the servos have been moved

void setup() {
  Serial.begin(9600);
  Serial.println("Multiple Servo");
  Serial.println("Robojax.com");
 
  myservo1.write(45);
  myservo2.write(45);
 
  myservo1.attach(servoPin[0]); // attaches the servo 1 to the servo object
  myservo2.attach(servoPin[1]); // attaches the servo 2 to the servo object
  pinMode(switchPin, INPUT_PULLUP);   // sets the switch pin as input    
  digitalWrite(switchPin, HIGH);
  previousPos1 = myservo1.read();
  previousPos2 = myservo2.read();
 
  // Read the initial state of the switch
  switchState = digitalRead(switchPin);

  if (!switchState) {
    // If the switch is off during power-up, gradually move the servos to their original positions over 2.5 seconds
    gradualServoMovement(previousPos1, previousPos2, 2500);
    servosMoved = false; // Reset the flag since the servos are back to their original positions
  }
}

void loop() {
  // Read the state of the switch
  switchState = digitalRead(switchPin);

  if (switchState && !servosMoved) {
    // If the switch is on and servos haven't been moved yet
    previousPos1 = 90;
    previousPos2 = 0;
    gradualServoMovement(previousPos1, previousPos2, 3000); // Gradually move servos to new positions over 2.5 seconds
    servosMoved = true; // Set the flag to indicate that the servos have been moved
    Serial.println("switchState && !servosMoved");  
  }
  else if (!switchState && servosMoved) {
    // If the switch is off and servos have been moved
    gradualServoMovement(previousPos3, previousPos4, 3000); // Gradually move servos to original positions over 2.5 seconds
    servosMoved = false; // Reset the flag since the servos are back to their original positions
    Serial.println("!switchState && servosMoved");  
  }

  else if (!switchState) {
    val = analogRead(potpin);   // reads the value of the potentiometer (value between 0 and 1023)
    val = map(val, 0, 1023, 0, 45);   // Scale it to use it with the servo (value between 0 and 45)
    myservo1.write(val);

    val = analogRead(potpin);   // reads the value of the potentiometer (value between 0 and 1023)
    val = map(val, 0, 1023, 90, 45);     // Scale it to use it with the servo (value between 45 and 90)
    myservo2.write(val);
    previousPos3 = myservo1.read();
    previousPos4 = myservo2.read();
    Serial.println("!switchState");
  }

  Serial.print(val);
  Serial.println();

  delay(100); // waits for the servo to get there
}


// Function for gradually moving servos from current position to target position over a specified duration
void gradualServoMovement(int& targetPos1, int& targetPos2, unsigned int duration) {
  float startPos1 = myservo1.read(); // Get current position of servo 1
  float startPos2 = myservo2.read(); // Get current position of servo 2
  unsigned long startTime = millis(); // Get the start time

  while (true) {
    unsigned long elapsedTime = millis() - startTime;

    if (elapsedTime >= duration) {
      // Time duration has elapsed, set final position and exit the function
      myservo1.write(targetPos1);
      myservo2.write(targetPos2);
      return;
    }

    // Calculate the current position based on time elapsed
    float progress = elapsedTime / (float)duration;
    float currentPos1 = startPos1 + (targetPos1 - startPos1) * progress;
    float currentPos2 = startPos2 + (targetPos2 - startPos2) * progress;

    // Set the servo positions based on the current position
    myservo1.write(currentPos1);
    myservo2.write(currentPos2);

    // Check if the switch is turned off and update the target positions
    if (!switchState) {
      targetPos1 = analogRead(potpin);
      targetPos1 = map(targetPos1, 0, 1023, 0, 45);
     
      targetPos2 = analogRead(potpin);
      targetPos2 = map(targetPos2, 0, 1023, 90, 45);
    }

    delay(10); // Delay for smooth movement
  }
}

I don't catch the usage of "servosMoved". If it is needed just for the system start, why you put it in the loop() function? Or, if it is not, why you don't set it on the last "else if (!switchState)"?

Please give more details on what in your mind the program should do (and not only what it does now):

  1. When powered on and the switch is OFF
  2. When powered on and the switch is ON
  3. During the loop, while it is OFF
  4. During the loop, when you set it from OFF to ON
  5. During the loop, while it is ON
  6. During the loop, when you set it from ON to OFF

"servosMoved" dont actually do anything usefull atm... Used it before but not anymore.

  1. When powered on and the switch is OFF
    Servos are being controlled by the potentiometer other one moving between 0 and 45 degrees and the other between 90 and 45 degrees. On start the servos should move nice and slow to a position where the potentiometer is set to.

  2. When powered on and the switch is ON
    Potentiometer doesn't move the servos. Servos should move to set position of 90 and 0 degrees nice and slow.

  3. During the loop, while it is OFF
    Potentiometer moves the servos and the position is recorded by previousPos3 and 4.

  4. During the loop, when you set it from OFF to ON
    Servos move to the set positions of 90 and 0 degrees. Potentiometer stops moving the servos.

  5. During the loop, while it is ON
    Nothing happens. Servos stay in place.

  6. During the loop, when you set it from ON to OFF
    Servos move to a position where potentiometer is set to. Potentiometer takes control of the servos again.

is this the 3rd thread on this topic

https://forum.arduino.cc/t/problem-when-starting-arduino-and-servos/1145509/3

Ugh, you're absolutely right!
And I see HERE the problem has been solved, so for me there's no point on going on, as this thread is next to be closed/deleted...
Have a nice coding, mate.

@polo_vasti, please stop cross-posting. Threads merged.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.