Arduino Stack Exchange is a question and answer site for developers of open-source hardware and software that is compatible with Arduino. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am new to Arduino and I am learning how to avoid using delay.

I have written some code to move my servo by 20° using delays, but can only move the servo once with my current code. In setup(), I assign the servo 150. The next value the servo receives is 15, which it performs. It does not iterate through the following values though. I have been using this guide, BlinkWithoutDelay, with no luck.

Here is my code:

#include <Servo.h>
Servo myservo;
unsigned long previousMillis = 0; 
const long interval = 1000; 

    void setup() { 
       myservo.attach(9);
       myservo.write(150); 
    }

   void loop() {
       unsigned long currentMillis = millis();

       if (currentMillis - previousMillis >= interval) {
            previousMillis = currentMillis;
            myservo.write(15);
       }
       if (currentMillis - previousMillis >= interval) {
            previousMillis = currentMillis;
            myservo.write(35);
       }
       if (currentMillis - previousMillis >= interval) {
            previousMillis = currentMillis;
            myservo.write(65);
   }
share|improve this question

You are resetting the timer on the first phase [write(15)] instead of after the last phase [after write(65)]! The previousMillis = currentMillis should be only after the last phase, before the loop repeats. Not only that, but the time at which each phase executes needs to be different. Currently every if() statement is set to run after interval has elapsed. If, for example, you wanted interval to be the delay between each phase, you could use interval*1 on the first phase, interval*2 on the second, and interval*3 on the third. For example:

   if (currentMillis - previousMillis <= interval * 1) {
        // Runs from interval*0 to interval*1;
        myservo.write(15);
   }
   else if (currentMillis - previousMillis <= interval * 2) {
        // Runs from interval*1 to interval*2;
        myservo.write(35);
   }
   else if (currentMillis - previousMillis <= interval * 3) {
        // Runs from interval*2 to interval*3;
        myservo.write(65);
   }
   else {
        // Runs once after interval*3;
        // *or* runs on first iteration when previousMillis is zero;
        previousMillis = currentMillis;// Reset the loop;
   }

To put the above logic in English:

  1. write(15) while time is between 0 and 1 intervals;
  2. write(35) while time is between 1 and 2 intervals;
  3. write(65) while time is between 2 and 3 intervals;
  4. reset the loop once time reaches 3+ intervals.

Note the use of else if instead of simply if on consecutive statements. This prevents more than one code block from running on the same iteration of the loop().

Edit: I highly recommend having a small delay (like 1ms) somewhere in the loop(), such as at the end. It would be a bad idea to constantly run the write() function when the value is the same as on the last call.

On the other hand, if your starting value is indeed 150 and the loop should start only after interval*1, you may want to iterate from interval*2 through interval*4:

   if (currentMillis - previousMillis <= interval * 1) {
        // Runs from interval*0 to interval*1;
        // Do nothing; servo is set to either 150 or 65 during this time;
   }
   else if (currentMillis - previousMillis <= interval * 2) {
        // Runs from interval*1 to interval*2;
        myservo.write(15);
   }
   else if (currentMillis - previousMillis <= interval * 3) {
        // Runs from interval*2 to interval*3;
        myservo.write(35);
   }
   else if (currentMillis - previousMillis <= interval * 4) {
        // Runs from interval*3 to interval*4;
        myservo.write(65);
   }
   else {
        // Runs once after interval*4;
        // *or* runs on first iteration when previousMillis is zero;
        previousMillis = currentMillis;// Reset the loop;
   }
share|improve this answer

If you want to change the servo every second, try to use a conditional expression in the timing structure. If you want to use more parallel structure with multiple intervals use different counters (example see: here).

Here is an example of the every second version:

#include <Servo.h>
Servo myservo;
unsigned long previousMillis = 0; 
const long interval = 1000; 
int angle = 150; 

void setup() { 
   myservo.attach(9);
   myservo.write(angle); 
}

void loop() {
    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;

        switch (angle) {
            case 150:
            case 65:
              angle = 15;
              myservo.write(angle);
              break;
            case 15:
              angle = 35;   
              myservo.write(angle);
              break;
            case 35: 
              angle = 65;     
              myservo.write(angle);
              break;
        }
    }
}

EDIT: Add variable assignment angle in conditional expression.

share|improve this answer
    
You should probably also set the angle to the one you have just written in each switch case. – ratchet freak Jan 6 at 11:51
    
If instead of "previousMillis = currentMillis;" you do a "previousMillis -= interval'; then your intevals will absorb the other processing times and won't drift. – Dave X Jan 10 at 6:08

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.