A button push that starts a series of servo momements using no delay

Hi. I am very new to arduino and I’m trying to make the SERVO head swivel on my (alien pilot halloween costume) which will start a series of movements from one button push. At the moment I have this working effectively using regular delay function. However, I wish to multi task other things at the sametime (such as fade in/out) LEDS and also use DFmini mp3 player all working from my arduino nano at the same time.

I got the LED working effectively using millis() function for delay. I was wondering if it were possible to do something similar with my servo (which will swivel the alien head into various positions).
I have searched long and hard before posting here. I came across some good stuff which uses a knob and millis() function for delay. Controlling a servo without the delay function

Also adafruit website has great example A clean sweep | Multi-tasking the Arduino - Part 1 | Adafruit Learning System

but I would like to use vary my positions not just sweeping movement and do all this from just one button push.

I will attach the basic code of what I would like to achieve but with delay function
Thank you for reading this. Will appreciate any help :slight_smile:

#include <Servo.h>

Servo servo1;


#define button 3 //attaches button to pin 3
int buttonState = 0; //buttonState stores state of input

//Initial Servo Position
int servo1_Pos = 90;

int timer = 500;
int greenLED = 7;

void setup() {
  pinMode (greenLED, OUTPUT);
  pinMode(button, INPUT_PULLUP); //sets button as input

}

void loop() {
  digitalWrite (greenLED, HIGH);
  delay (100);
  digitalWrite (greenLED, LOW);
  delay (100);
  servo1.attach(9);
  buttonState = digitalRead(button); //reads state of button

  if (buttonState == LOW) { //and button is pressed
    servo1.write(160); 
    delay(timer);

    servo1.write(80);
    delay(timer);

    servo1.write(40);
    delay(timer);

    servo1.write(180);
    delay(timer);

    servo1.write(120);
    delay(timer);

    servo1.write(90);
    delay(timer);

    servo1.write(160);
    delay(timer);

    servo1.write(80);
    delay(timer);

    servo1.write(40);
    delay(timer);

    servo1.write(180);
    delay(timer);

    servo1.write(120);
    delay(timer);

    servo1.write(90);
    delay(timer);

  }
  if (buttonState == HIGH) { //button is not pressed
    servo1.write(90); //run this servo sequence
    servo1.detach();


  }
}

Your current code moves the servo to predetermined positions at regular intervals. To use millis() for timing you could put the positions into an array then, as each time period elapses read the next position from the array using an index variable, write it to the servo, increment the index ready for next time and begin millis() timing. You could use different intervals for each movement if required by putting them in a second array or a struct.

Some ideas to get you started

const byte positions[] = {120, 80, 180, 0, 20};
const byte numberOfPositions = sizeof(positions);
byte currentPosition = 0;
unsigned long period = 1000;
unsigned long startTime;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  unsigned long currentTime = millis();
  if (currentTime - startTime >= period)
  {
    Serial.println(positions[currentPosition % numberOfPositions]);
    currentPosition++;
    startTime = currentTime;
  }
  //any other non blocking code that you want to include in loop() goes here
}

The demo Several Things at a Time illustrates the use of millis() to manage timing. It may help with understanding the technique.

…R

UKHeliBob:
Your current code moves the servo to predetermined positions at regular intervals. To use millis() for timing you could put the positions into an array then, as each time period elapses read the next position from the array using an index variable, write it to the servo, increment the index ready for next time and begin millis() timing. You could use different intervals for each movement if required by putting them in a second array or a struct.

Some ideas to get you started

const byte positions[] = {120, 80, 180, 0, 20};

const byte numberOfPositions = sizeof(positions);
byte currentPosition = 0;
unsigned long period = 1000;
unsigned long startTime;

void setup()
{
 Serial.begin(115200);
}

void loop()
{
 unsigned long currentTime = millis();
 if (currentTime - startTime >= period)
 {
   Serial.println(positions[currentPosition % numberOfPositions]);
   currentPosition++;
   startTime = currentTime;
 }
 //any other non blocking code that you want to include in loop() goes here
}

Thank you for that. I thought that an array would be the best solution too but wasn’t sure how to implement that.

Right now I’m trying to implement your code into mine but not having much success. I have to keep pushing the button in order for the servo to move.

#include <Servo.h>

Servo servo1;
#define button 7 //attaches button to pin 7
int buttonState = 0; //buttonState stores state of input


const byte positions[] = {120, 80, 180, 0, 20};
const byte numberOfPositions = sizeof(positions);
byte currentPosition = 0;
unsigned long period = 1000;
unsigned long startTime = 0;
int greenLED = 11;

void setup()
{
  Serial.begin(9600);
  pinMode (greenLED, OUTPUT);
  pinMode(button, INPUT_PULLUP); //sets button as input
}

void loop()
{
  digitalWrite (greenLED, HIGH);
  delay (100);
  digitalWrite (greenLED, LOW);
  delay (100);
  servo1.attach(5);
  buttonState = digitalRead(button); //reads state of buttonunsigned long currentTime = millis();
  unsigned long currentTime = millis();
  if ((currentTime - startTime >= period) && (buttonState == LOW))
  {
    servo1.write(positions);
    Serial.println(positions[currentPosition % numberOfPositions]);
    currentPosition++;
    startTime = currentTime;
  }
  if (buttonState == HIGH) { //button is not pressed
    servo1.write(90); //run this servo sequence
    //any other non blocking code that you want to include in loop() goes here
  }
}

Robin2 Thanks for that example! I like how you have commented on each line of code and the functions are easy to use in other sketches. Thanks!
I've printed it out and going to look over it at my own pace.

I have to keep pushing the button in order for the servo to move.

Should the sevo complete the set of movements for each button press then stop ?

If so, then test the button and when it becomes pressed set a boolean variable to true to indicate that the sequence is running. Also, set the current position to zero and write the first position to the servo.

Then only test whether it is time to move the servo when the variable is true. Test the current position variable after you increment it and set the boolean to false when all steps have been executed.