Continuous Rotation Servo Operation with Pushbutton

How would i write some code to run multiple continuous rotation servos in a clockwise direction for a specified amount of time. Each servo would need its own pushbutton.

(essentially, pressing the corresponding button will make the servo rotate clockwise for a specified amount of time)

Take a look at the state change example, and the blink without delay example in the IDE.

what kind of Continuous Rotation Servo ?

Try this on, OP.

Spoiler alert: full working sketch ahead, which OP may not want to read :wink:

Sample serial spew:

setup() ... run servos with buttons forum thread 638602 ....
C:\Users\qwerty\Documents\Arduino\array_of_servos_with_buttons_638602\array_of_servos_with_buttons_638602.ino
Compiler: 4.9.2, Arduino IDE: 10805
Created: 15:11:13, Oct  1 2019
Servo 0 is on pin 8
Servo 1 is on pin 9
Servo 2 is on pin 10
setup() done
Press a button to start its servo....
 
Starting servo 0 at 3323 for 2000ms
Starting servo 1 at 3845 for 3000ms
Starting servo 2 at 4330 for 5000ms
  Stopping servo 0 at 5323
  Stopping servo 1 at 6845
  Stopping servo 2 at 9330
Starting servo 0 at 11612 for 2000ms
  Stopping servo 0 at 13612
Starting servo 1 at 14939 for 3000ms
  Stopping servo 1 at 17939
Starting servo 2 at 18944 for 5000ms
  Stopping servo 2 at 23944

Code:

// https://forum.arduino.cc/index.php?topic=638602

// state change detect on a button array to drive an array of servos
// OP was silent on what happens if button is pressed while servo running
//    so this version just re-starts the clock
// servos' run speed, stop speed (nominally 90) and time it should run are all independent and in arrays
// 1 october 2019

// set the values in the lines marked //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
// run with serial monitor open to read what's happening

// DISCLAIMER... tested on real servos moving to a position, not on continuous "not-really-"servos running at some speed

// BASED ON State change detection (edge detection), changed for INPUT PULLUP https://www.arduino.cc/en/Tutorial/StateChangeDetection
// INCLUDES delay()-less millis()-based bwod pulse pin 13 https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
// SERVO ARRAY idea from PaulS https://forum.arduino.cc/index.php?topic=170597.0

// the buttons
const byte buttonPins[] = {4, 5, 6}; //remember indexed from 0 //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
//                              add as many pins as you can handle servos
//                              the buttons must be wired from pin to ground, pinmodes are input_pullup
const byte howManyButtons(sizeof(buttonPins));
bool buttonStates[howManyButtons];         // current state of the button
bool lastButtonStates[howManyButtons];     // previous state of the button
bool buttonIsNewlyPressed[howManyButtons] = {0, 0, 0};

//the servos
#include <Servo.h>
Servo myServos[howManyButtons]; //number of servos will be same as number of buttons
const int myServoPins[] = {8, 9, 10}; //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoSpeeds[] = {150, 150, 150}; // or whatever //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoStops[] = {90, 90, 90}; //nominally but not necessarily 90 //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoIntervals[] = {2000, 3000, 5000}; //this is how long they run for //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
unsigned long myServoStartedToMoveAt[howManyButtons];
int myServoIsRunning[] = {0, 0, 0}; //this is just to stop the serial print spewing when servo's time is up

//the pulse led
const int pulseLedInterval = 500;
unsigned long previousMillisPulse;
bool pulseState = false;

void setup()
{
  // initialize serial communication:
  Serial.begin(9600); //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
  Serial.print("setup() ... ");
  Serial.println("run servos with buttons forum thread 638602 ....");
  Serial.println(__FILE__);
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);
  
  // initialize the button pins as input with pullup so active low
  //    make sure the button is from pin to ground
  for (int i = 0; i < howManyButtons; i++)
  {
    pinMode(buttonPins[i], INPUT_PULLUP);
    //initialize button states
    buttonStates[i] = digitalRead(buttonPins[i]);
    lastButtonStates[i] = buttonStates[i];
  }
  //initialise pulse led
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, pulseState);

  //attach the servos
  for (int i = 0; i < howManyButtons; i++)
  {
    myServos[i].attach(myServoPins[i]);
    Serial.print("Servo ");
    Serial.print(i);
    Serial.print(" is on pin ");
    Serial.println(myServoPins[i]);
  }

  Serial.println("setup() done");
  Serial.println("Press a button to start its servo....");
  Serial.println(" ");
}

void loop()
{
  pulse(); // to prove nothings blocking
  checkButtons();
  manageServos();
} //loop

void checkButtons()
{
  for (int i = 0; i < howManyButtons; i++)
  {
    buttonStates[i] = digitalRead(buttonPins[i]);
    // compare the buttonState to its previous state
    if (buttonStates[i] != lastButtonStates[i]) // means it changed... but which way?
    {
      if (buttonStates[i] == LOW)  // changed to pressed
      {
        //Serial.print(i);
        //Serial.println(" newly pressed");
        buttonIsNewlyPressed[i] = true;
      }
      // poor man's de-bounce
      delay(50);
    }
    // save the current state as the last state, for next time through the loop
    lastButtonStates[i] = buttonStates[i];
  }
} // checkButtons()

void manageServos()
{
  for (int i = 0; i < howManyButtons; i++)
  {
    if (buttonIsNewlyPressed[i])
    {
      Serial.print("Starting servo ");
      Serial.print(i);
      buttonIsNewlyPressed[i] = false;
      myServos[i].write(myServoSpeeds[i]);
      myServoStartedToMoveAt[i] = millis();
      myServoIsRunning[i] = true;
      Serial.print(" at ");
      Serial.print(myServoStartedToMoveAt[i]);
      Serial.print(" for ");
      Serial.print(myServoIntervals[i]);
      Serial.println("ms");
    }

    if (millis() - myServoStartedToMoveAt[i] >= myServoIntervals[i] && myServoIsRunning[i])
    {
      myServoIsRunning[i] = false;
      myServos[i].write(myServoStops[i]);
      Serial.print("  Stopping servo ");
      Serial.print(i);
      Serial.print(" at ");
      Serial.println(millis());
    }
  }//which button
}//manageServos

void pulse()
{
  if (millis() - previousMillisPulse >= pulseLedInterval)
  {
    previousMillisPulse = millis();
    pulseState = !pulseState;
    digitalWrite(LED_BUILTIN, pulseState);
  }
} //pulse

This code worked perfectly for two servos. However, when i try to introduce another 2 it doesn't seem to work?
i've added the other two in exactly the same way as the first ones. i'm using PWM pins for the servos.
in the serial monitor; i can see that it is continuously spitting out commands for servos 0 and 3 to move at random speed values. Here is the section of this code that i edited:

// the buttons
const byte buttonPins[] = {7, 8, 12, 13}; //remember indexed from 0 //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
// add as many pins as you can handle servos
// the buttons must be wired from pin to ground, pinmodes are input_pullup
const byte howManyButtons(sizeof(buttonPins));
bool buttonStates[howManyButtons]; // current state of the button
bool lastButtonStates[howManyButtons]; // previous state of the button
bool buttonIsNewlyPressed[howManyButtons] = {7, 8, 12, 13};

//the servos
#include <Servo.h>
Servo myServos[howManyButtons]; //number of servos will be same as number of buttons
const int myServoPins[] = {4, 6, 7, 11}; //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoSpeeds[] = {100, 100, 100, 100}; // or whatever //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoStops[] = {90, 90, 90, 90}; //nominally but not necessarily 90 //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoIntervals[] = {3000, 3000, 3000, 3000}; //this is how long they run for //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
unsigned long myServoStartedToMoveAt[howManyButtons];
int myServoIsRunning[] = {0, 0, 0, 0}; //this is just to stop the serial print spewing when servo's time is up

These...

bool buttonIsNewlyPressed[howManyButtons] = {7, 8, 12, 13};

... should be 0.

Not sure if that would have anything to do with the problem, but then I don't actually understand what the problem is.

Can you post a copy of the serial monitor spew, in code tags so it's easier to read, after you change those values to 0?

And please post a full sketch in code tags, not just a part, so I can copy paste the whole thing without having to bolt pieces together.

Code below has 4xservos and 4x buttons, not on your pins though, and gives the following serial spew which looks ok to me. (Not able to test on servos, all packed away...)

Servo 0 is on pin 8
Servo 1 is on pin 9
Servo 2 is on pin 10
Servo 3 is on pin 11
setup() done
Press a button to start its servo....
 
Starting servo 0 at 1306 for 2000ms
  Stopping servo 0 at 3306
Starting servo 1 at 4545 for 3000ms
  Stopping servo 1 at 7545
Starting servo 2 at 9021 for 5000ms
  Stopping servo 2 at 14021
Starting servo 3 at 15481 for 7000ms
  Stopping servo 3 at 22481
// https://forum.arduino.cc/index.php?topic=638602

// state change detect on a button array to drive an array of servos
// OP was silent on what happens if button is pressed while servo running
//    so this version just re-starts the clock
// servos' run speed, stop speed (nominally 90) and time it should run are all independent and in arrays
// 1 october 2019

// set the values in the lines marked //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
// run with serial monitor open to read what's happening

// DISCLAIMER... tested on real servos moving to a position, not on continuous "not-really-"servos running at some speed

// BASED ON State change detection (edge detection), changed for INPUT PULLUP https://www.arduino.cc/en/Tutorial/StateChangeDetection
// INCLUDES delay()-less millis()-based bwod pulse pin 13 https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
// SERVO ARRAY idea from PaulS https://forum.arduino.cc/index.php?topic=170597.0

// the buttons
const byte buttonPins[] = {4, 5, 6, 7}; //remember indexed from 0 //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
//                              add as many pins as you can handle servos
//                              the buttons must be wired from pin to ground, pinmodes are input_pullup
const byte howManyButtons(sizeof(buttonPins));
bool buttonStates[howManyButtons];         // current state of the button
bool lastButtonStates[howManyButtons];     // previous state of the button
bool buttonIsNewlyPressed[howManyButtons] = {0, 0, 0, 0};

//the servos
#include <Servo.h>
Servo myServos[howManyButtons]; //number of servos will be same as number of buttons
const int myServoPins[] = {8, 9, 10, 11}; //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoSpeeds[] = {150, 150, 150, 150}; // or whatever //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoStops[] = {90, 90, 90, 90}; //nominally but not necessarily 90 //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoIntervals[] = {2000, 3000, 5000, 7000}; //this is how long they run for //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
unsigned long myServoStartedToMoveAt[howManyButtons];
int myServoIsRunning[] = {0, 0, 0, 0}; //this is just to stop the serial print spewing when servo's time is up

//the pulse led
const int pulseLedInterval = 500;
unsigned long previousMillisPulse;
bool pulseState = false;

void setup()
{
  // initialize serial communication:
  Serial.begin(9600); //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
  Serial.print("setup() ... ");
  Serial.println("run servos with buttons forum thread 638602 ....");
  Serial.println(__FILE__);
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);

  // initialize the button pins as input with pullup so active low
  //    make sure the button is from pin to ground
  for (int i = 0; i < howManyButtons; i++)
  {
    pinMode(buttonPins[i], INPUT_PULLUP);
    //initialize button states
    buttonStates[i] = digitalRead(buttonPins[i]);
    lastButtonStates[i] = buttonStates[i];
  }
  //initialise pulse led
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, pulseState);

  //attach the servos
  for (int i = 0; i < howManyButtons; i++)
  {
    myServos[i].attach(myServoPins[i]);
    Serial.print("Servo ");
    Serial.print(i);
    Serial.print(" is on pin ");
    Serial.println(myServoPins[i]);
  }

  Serial.println("setup() done");
  Serial.println("Press a button to start its servo....");
  Serial.println(" ");
}

void loop()
{
  pulse(); // to prove nothings blocking
  checkButtons();
  manageServos();
} //loop

void checkButtons()
{
  for (int i = 0; i < howManyButtons; i++)
  {
    buttonStates[i] = digitalRead(buttonPins[i]);
    // compare the buttonState to its previous state
    if (buttonStates[i] != lastButtonStates[i]) // means it changed... but which way?
    {
      if (buttonStates[i] == LOW)  // changed to pressed
      {
        //Serial.print(i);
        //Serial.println(" newly pressed");
        buttonIsNewlyPressed[i] = true;
      }
      // poor man's de-bounce
      delay(50);
    }
    // save the current state as the last state, for next time through the loop
    lastButtonStates[i] = buttonStates[i];
  }
} // checkButtons()

void manageServos()
{
  for (int i = 0; i < howManyButtons; i++)
  {
    if (buttonIsNewlyPressed[i])
    {
      Serial.print("Starting servo ");
      Serial.print(i);
      buttonIsNewlyPressed[i] = false;
      myServos[i].write(myServoSpeeds[i]);
      myServoStartedToMoveAt[i] = millis();
      myServoIsRunning[i] = true;
      Serial.print(" at ");
      Serial.print(myServoStartedToMoveAt[i]);
      Serial.print(" for ");
      Serial.print(myServoIntervals[i]);
      Serial.println("ms");
    }

    if (millis() - myServoStartedToMoveAt[i] >= myServoIntervals[i] && myServoIsRunning[i])
    {
      myServoIsRunning[i] = false;
      myServos[i].write(myServoStops[i]);
      Serial.print("  Stopping servo ");
      Serial.print(i);
      Serial.print(" at ");
      Serial.println(millis());
    }
  }//which button
}//manageServos

void pulse()
{
  if (millis() - previousMillisPulse >= pulseLedInterval)
  {
    previousMillisPulse = millis();
    pulseState = !pulseState;
    digitalWrite(LED_BUILTIN, pulseState);
  }
} //pulse

And you can't use pin 13, it's got the pulse led on it...

Nor can pin 7 be a button and a servo at the same time....

const byte buttonPins[] = {7, 8, 12, 13};
const int myServoPins[] = {4, 6, 7, 11};

(And I think that's your actual problem. Along with making that array all 0's as previous.)

Servos don't need to be on PWM ~ pins btw, and pins are good, even the analog pins Ax.

FEBaily:
And you can't use pin 13, it's got the pulse led on it...

Nor can pin 7 be a button and a servo at the same time....

const byte buttonPins[] = {7, 8, 12, 13};

const int myServoPins[] = {4, 6, 7, 11};




(And I think that's your actual problem. Along with making that array all 0's as previous.)

Servos don't need to be on PWM ~ pins btw, and pins are good, even the analog pins Ax.

i now have the 4 servos connected to pins 8, 9, 10, 11 and the buttons on pins 0, 1, 2, 3
i've updated the code and there is still one rogue servo which is constantly turning clockwise and counter clockwise for about 3 seconds at a time without any input from the corresponding button. (pressing the button does nothing)

// https://forum.arduino.cc/index.php?topic=638602

// state change detect on a button array to drive an array of servos
// OP was silent on what happens if button is pressed while servo running
//    so this version just re-starts the clock
// servos' run speed, stop speed (nominally 90) and time it should run are all independent and in arrays
// 1 october 2019

// set the values in the lines marked //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
// run with serial monitor open to read what's happening

// DISCLAIMER... tested on real servos moving to a position, not on continuous "not-really-"servos running at some speed

// BASED ON State change detection (edge detection), changed for INPUT PULLUP https://www.arduino.cc/en/Tutorial/StateChangeDetection
// INCLUDES delay()-less millis()-based bwod pulse pin 13 https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
// SERVO ARRAY idea from PaulS https://forum.arduino.cc/index.php?topic=170597.0

// the buttons
const byte buttonPins[] = {0, 1, 2, 3}; //remember indexed from 0 //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
//                              add as many pins as you can handle servos
//                              the buttons must be wired from pin to ground, pinmodes are input_pullup
const byte howManyButtons(sizeof(buttonPins));
bool buttonStates[howManyButtons];         // current state of the button
bool lastButtonStates[howManyButtons];     // previous state of the button
bool buttonIsNewlyPressed[howManyButtons] = {0, 0, 0, 0};

//the servos
#include <Servo.h>
Servo myServos[howManyButtons]; //number of servos will be same as number of buttons
const int myServoPins[] = {8, 9, 10, 11}; //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoSpeeds[] = {100, 100, 100, 100}; // or whatever //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoStops[] = {90, 90, 90, 90}; //nominally but not necessarily 90 //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
const int myServoIntervals[] = {3000, 3000, 3000, 3000}; //this is how long they run for //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
unsigned long myServoStartedToMoveAt[howManyButtons];
int myServoIsRunning[] = {0, 0, 0, 0}; //this is just to stop the serial print spewing when servo's time is up

//the pulse led
const int pulseLedInterval = 500;
unsigned long previousMillisPulse;
bool pulseState = false;

void setup()
{
  // initialize serial communication:
  Serial.begin(9600); //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
  Serial.print("setup() ... ");
  Serial.println("run servos with buttons forum thread 638602 ....");
  Serial.println(__FILE__);
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);

  // initialize the button pins as input with pullup so active low
  //    make sure the button is from pin to ground
  for (int i = 0; i < howManyButtons; i++)
  {
    pinMode(buttonPins[i], INPUT_PULLUP);
    //initialize button states
    buttonStates[i] = digitalRead(buttonPins[i]);
    lastButtonStates[i] = buttonStates[i];
  }
  //initialise pulse led
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, pulseState);

  //attach the servos
  for (int i = 0; i < howManyButtons; i++)
  {
    myServos[i].attach(myServoPins[i]);
    Serial.print("Servo ");
    Serial.print(i);
    Serial.print(" is on pin ");
    Serial.println(myServoPins[i]);
  }

  Serial.println("setup() done");
  Serial.println("Press a button to start its servo....");
  Serial.println(" ");
}

void loop()
{
  pulse(); // to prove nothings blocking
  checkButtons();
  manageServos();
} //loop

void checkButtons()
{
  for (int i = 0; i < howManyButtons; i++)
  {
    buttonStates[i] = digitalRead(buttonPins[i]);
    // compare the buttonState to its previous state
    if (buttonStates[i] != lastButtonStates[i]) // means it changed... but which way?
    {
      if (buttonStates[i] == LOW)  // changed to pressed
      {
        //Serial.print(i);
        //Serial.println(" newly pressed");
        buttonIsNewlyPressed[i] = true;
      }
      // poor man's de-bounce
      delay(50);
    }
    // save the current state as the last state, for next time through the loop
    lastButtonStates[i] = buttonStates[i];
  }
} // checkButtons()

void manageServos()
{
  for (int i = 0; i < howManyButtons; i++)
  {
    if (buttonIsNewlyPressed[i])
    {
      Serial.print("Starting servo ");
      Serial.print(i);
      buttonIsNewlyPressed[i] = false;
      myServos[i].write(myServoSpeeds[i]);
      myServoStartedToMoveAt[i] = millis();
      myServoIsRunning[i] = true;
      Serial.print(" at ");
      Serial.print(myServoStartedToMoveAt[i]);
      Serial.print(" for ");
      Serial.print(myServoIntervals[i]);
      Serial.println("ms");
    }

    if (millis() - myServoStartedToMoveAt[i] >= myServoIntervals[i] && myServoIsRunning[i])
    {
      myServoIsRunning[i] = false;
      myServos[i].write(myServoStops[i]);
      Serial.print("  Stopping servo ");
      Serial.print(i);
      Serial.print(" at ");
      Serial.println(millis());
    }
  }//which button
}//manageServos

void pulse()
{
  if (millis() - previousMillisPulse >= pulseLedInterval)
  {
    previousMillisPulse = millis();
    pulseState = !pulseState;
    digitalWrite(LED_BUILTIN, pulseState);
  }
} //pulse

here's the serial log:

setup() ... run servos with buttons forum thread 638602 ....
C:\Users\ethan\AppData\Local\Temp\arduino_modified_sketch_104745\sketch_oct02a.ino
Compiler: 7.3.0, Arduino IDE: 10810
Created: 16:51:34, Oct  2 2019
Servo 0 is on pin 8
Servo 1 is on pin 9
Servo 2 is on pin 10
Servo 3 is on pin 11
setup() done
Press a button to start its servo....
 
Starting servo 1 at 404 for 3000ms
  Stopping servo 1 at 3404
Starting servo 1 at 3454 for 3000ms
  Stopping servo 1 at 6454
Starting servo 1 at 6504 for 3000ms
  Stopping servo 1 at 9504
Starting servo 1 at 9554 for 3000ms
  Stopping servo 1 at 12554
Starting servo 1 at 12604 for 3000ms

buttons on pins 0, 1, 2, 3

Pins 0 and 1 are for the serial interface, so don't use those either...

Issue is now resolved using above solutions.