Multiple lines of code running simultaneously?

Hi, I’m doing a project with servos and I need each servo to run a certain code simultaneously with the others. However, when I put the three servos in the loop function, the movements are done in order instead of each servo looping a certain motion. I tried making multiple loops but this causes errors in the code. Here is my current code, which only loops one servo:

#include <Servo.h>
Servo Servo1;
Servo Servo2;
Servo Servo3;
void setup()
{
Servo1.attach(3);
Servo2.attach(4);
Servo3.attach(5);
}
void loop()
{
Servo3.write(70);
delay(250);
Servo3.write(120);
delay(250);
Servo3.write(70);
delay(1);
}

Basically, is there a way to have all three servos run separate lines of code? Is there a different function type than “loop” that can allow me to simply run a line of code? Also I have a continuous servo that spins randomly when I run this code, but that’s another issue. Thanks in advance.

You can't run separate lines of code simultaneously on a single processor, but you can make it look like they are

Robin2 even has a tutorial topic on how to do it.

Your use of delays might have some detrimental effect upon your simultaneity.

@AWOL

I checked it out, it looks a bit over my head but I'll try it out.

@boolrules

Should I be doing something differently with the delays, or not use them at all? I basically just did trial and error to get a back and forth movement and this worked, but the 1 especially seems like it could mess things up.

Edit: I actually removed the last delay in the loop and it worked just fine.

Have a look at how the code is organized in Several Things at a Time

Note how each function runs very briefly and returns to loop() so the next one can be called. None of the functions tries to complete a task in one call. And there may be dozens of calls to a function before it is actually time for it to do anything.

...R

To make 3 servos run at the same time you just write to them with no delays in between the writes. But I suspect that's not what you mean. Probably you want them to run with different timings. Some real detail of EXACTLY what you are trying to achieve would be useful.

Steve

@Robin2

Thank you for explaining that, it makes a bit more sense now. I might give it a try if it ends up being what I need.

@slipstick

Sure. My project is an animatronic in which I need three points of movement (mouth and two arms). I have a servo opening and closing the jaw and a servo moving each arm. The mouth servo will be programmed to open and close the jaw while a speech is running whilst the arm servos move the arms up and down to wave and make certain gestures.

So basically, I need the mouth servo to be able to operate while the arm servos move the arms (at the same time). Ideally what I want to do is have a line of code for the mouth and tack on a line of code for each arm and have each line of code run simultaneously and without interfering with one another. Now if only this could somehow be translated into coding language.

OP, try this as an example of something supposed to do multiple things at once. It compiles and blinks the LED on my Mega2560 but I don’t have servos to verify that part of the function. Hopefully it gives you an idea of the concepts used.

#include <Servo.h> 

//statemachine state names
#define ST_1    0
#define ST_2    1

//pin definitions
const byte pinServo1 = 3;
const byte pinServo2 = 4;
const byte pinServo3 = 5;
const byte pinLED = LED_BUILTIN;

Servo Servo1; 
Servo Servo2;
Servo Servo3;

void setup() 
{ 
    Servo1.attach( pinServo1 );
    Servo2.attach( pinServo2 );
    Servo3.attach( pinServo3 ); 

    //set LED pin mode and initial level
    pinMode( pinLED, OUTPUT );
    digitalWrite( pinLED, LOW );
        
}//setup

void loop()
{
    unsigned long
        currTime;

    //get the current time for all servos and LEDs to help them stay in sync
    currTime = millis();
    Servo1_SM( currTime );  //call each servo control
    Servo2_SM( currTime );
    Servo3_SM( currTime );
    BlinkLED( currTime );   //and blink the LED for good measure
    
}//loop 

void Servo1_SM( unsigned long timeNow )
{
    static unsigned long
        timeS1_Delay = 0,   //variable holds the current time delay (e.g. 250mS)
        timeS1 = 0;         //holds the millis() count at the beginning of the current delay
    static byte
        stateS1 = ST_1;     //the state we're in

    //if the delay time has passed...
    if( (timeNow - timeS1) < timeS1_Delay )
        return;
    //set timeSx to the current time
    timeS1 = timeNow;

    //and process the state machine
    switch( stateS1 )
    {
        case    ST_1:
            //in state 1, send 70 to the servo...
            Servo1.write( 70 );
            //...hold for 250mS
            timeS1_Delay = 250;
            //...and set up for state 2
            stateS1 = ST_2;
            
        break;

        case    ST_2:
            //in state 2, send 120...
            Servo1.write( 120 );
            //hold for 250mS
            timeS1_Delay = 250;
            //and prep for state 1
            stateS1 = ST_1;
        
        break;
        
    }//switch
    
}//Servo1_SM

//all servo state machine functions are basically the same with different timing and values for effect
void Servo2_SM( unsigned long timeNow )
{
    static unsigned long
        timeS2_Delay = 0,
        timeS2 = 0;
    static byte
        stateS2 = ST_1;
        
    if( (timeNow - timeS2) < timeS2_Delay )
        return;
    timeS2 = timeNow;
    
    switch( stateS2 )
    {
        case    ST_1:
            Servo2.write( 30 );
            timeS2_Delay = 500;
            stateS2 = ST_2;
            
        break;

        case    ST_2:
            Servo2.write( 150 );
            timeS2_Delay = 500;
            stateS2 = ST_1;
        
        break;
        
    }//switch
    
}//Servo2_SM

void Servo3_SM( unsigned long timeNow )
{
    static unsigned long
        timeS3_Delay = 0,
        timeS3 = 0;
    static byte
        stateS3 = ST_1;
        
    if( (timeNow - timeS3) < timeS3_Delay )
        return;
    timeS3 = timeNow;
    
    switch( stateS3 )
    {
        case    ST_1:
            Servo3.write( 120 );
            timeS3_Delay = 750;
            stateS3 = ST_2;
            
        break;

        case    ST_2:
            Servo3.write( 50 );
            timeS3_Delay = 250;
            stateS3 = ST_1;
        
        break;
        
    }//switch
    
}//Servo3_SM

//to drive home doing multiple things, blink the LED too
void BlinkLED( unsigned long timeNow )
{
    static bool
        stateLED = false;
    static unsigned long
        timeLED = 0;

    //LED changes state every 300mS
    if( (timeNow - timeLED) < 300 )
        return;
    timeLED = timeNow;

    //toggle the state of stateLED by using the exclusive-OR
    //a 0 XORd with 1 is 1
    //a 1 XORd with 1 is 0; in this way, the value of stateLED toggles every 300mS
    stateLED ^= true;
    
    //use the value of stateLED to know what to write to the pin for the LED
    digitalWrite( pinLED, (stateLED)?HIGH:LOW );
    
}//BlinkLED

Blackfin:
OP, try this as an example of something supposed to do multiple things at once. It compiles and blinks the LED on my Mega2560 but I don’t have servos to verify that part of the function. Hopefully it gives you an idea of the concepts used.

#include <Servo.h> 

//statemachine state names
#define ST_1    0
#define ST_2    1

//pin definitions
const byte pinServo1 = 3;
const byte pinServo2 = 4;
const byte pinServo3 = 5;
const byte pinLED = LED_BUILTIN;

Servo Servo1;
Servo Servo2;
Servo Servo3;

void setup()
{
    Servo1.attach( pinServo1 );
    Servo2.attach( pinServo2 );
    Servo3.attach( pinServo3 );

//set LED pin mode and initial level
    pinMode( pinLED, OUTPUT );
    digitalWrite( pinLED, LOW );
       
}//setup

void loop()
{
    unsigned long
        currTime;

//get the current time for all servos and LEDs to help them stay in sync
    currTime = millis();
    Servo1_SM( currTime );  //call each servo control
    Servo2_SM( currTime );
    Servo3_SM( currTime );
    BlinkLED( currTime );  //and blink the LED for good measure
   
}//loop

void Servo1_SM( unsigned long timeNow )
{
    static unsigned long
        timeS1_Delay = 0,  //variable holds the current time delay (e.g. 250mS)
        timeS1 = 0;        //holds the millis() count at the beginning of the current delay
    static byte
        stateS1 = ST_1;    //the state we’re in

//if the delay time has passed…
    if( (timeNow - timeS1) < timeS1_Delay )
        return;
    //set timeSx to the current time
    timeS1 = timeNow;

//and process the state machine
    switch( stateS1 )
    {
        case    ST_1:
            //in state 1, send 70 to the servo…
            Servo1.write( 70 );
            //…hold for 250mS
            timeS1_Delay = 250;
            //…and set up for state 2
            stateS1 = ST_2;
           
        break;

case    ST_2:
            //in state 2, send 120…
            Servo1.write( 120 );
            //hold for 250mS
            timeS1_Delay = 250;
            //and prep for state 1
            stateS1 = ST_1;
       
        break;
       
    }//switch
   
}//Servo1_SM

//all servo state machine functions are basically the same with different timing and values for effect
void Servo2_SM( unsigned long timeNow )
{
    static unsigned long
        timeS2_Delay = 0,
        timeS2 = 0;
    static byte
        stateS2 = ST_1;
       
    if( (timeNow - timeS2) < timeS2_Delay )
        return;
    timeS2 = timeNow;
   
    switch( stateS2 )
    {
        case    ST_1:
            Servo2.write( 30 );
            timeS2_Delay = 500;
            stateS2 = ST_2;
           
        break;

case    ST_2:
            Servo2.write( 150 );
            timeS2_Delay = 500;
            stateS2 = ST_1;
       
        break;
       
    }//switch
   
}//Servo2_SM

void Servo3_SM( unsigned long timeNow )
{
    static unsigned long
        timeS3_Delay = 0,
        timeS3 = 0;
    static byte
        stateS3 = ST_1;
       
    if( (timeNow - timeS3) < timeS3_Delay )
        return;
    timeS3 = timeNow;
   
    switch( stateS3 )
    {
        case    ST_1:
            Servo3.write( 120 );
            timeS3_Delay = 750;
            stateS3 = ST_2;
           
        break;

case    ST_2:
            Servo3.write( 50 );
            timeS3_Delay = 250;
            stateS3 = ST_1;
       
        break;
       
    }//switch
   
}//Servo3_SM

//to drive home doing multiple things, blink the LED too
void BlinkLED( unsigned long timeNow )
{
    static bool
        stateLED = false;
    static unsigned long
        timeLED = 0;

//LED changes state every 300mS
    if( (timeNow - timeLED) < 300 )
        return;
    timeLED = timeNow;

//toggle the state of stateLED by using the exclusive-OR
    //a 0 XORd with 1 is 1
    //a 1 XORd with 1 is 0; in this way, the value of stateLED toggles every 300mS
    stateLED ^= true;
   
    //use the value of stateLED to know what to write to the pin for the LED
    digitalWrite( pinLED, (stateLED)?HIGH:LOW );
   
}//BlinkLED

Good example Blackfin.

I would make currTime global and use BlinkLED( ); instead of BlinkLED( currTime ); but no big deal leaving it as is.

eguirguis2005:
I might give it a try if it ends up being what I need.

[....]

I need the mouth servo to be able to operate while the arm servos move the arms (at the same time). I

Seems to me it is exactly what you need.

...R

Alright, thanks folks, I will give this complex code a try. Wish me luck

eguirguis2005:
Alright, thanks folks, I will give this complex code a try. Wish me luck

If you are basing your program on my code then just make a copy of the servo function for each of your servos and give the relevant variables different names. Then it should "just work"

...R

Wish me luck

I've got a clue for you. Writing good code does NOT involve luck.

@Robin2

I attempted to use the code, but since I don’t have/need LEDs, I removed the parts involving LEDs. I don’t know if this changed anything important, but I’m trying to make the code work to make three servos move at the same time. However it is not working and I have no idea what I am looking at. Help would be appreciated. Here is my code:

#include <Servo.h>

// ----CONSTANTS (won’t change)

const int servoPin3 = 3; // the pin number for the servo signal
const int servoPin4 = 4;
const int servoPin5 = 5;
const int servoMinDegrees = 20; // the limits to servo movement
const int servoMaxDegrees = 150;

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

int servoPosition = 90; // the current angle of the servo - starting at 90.
int servoSlowInterval = 80; // millisecs between servo moves
int servoFastInterval = 10;
int servoInterval = servoSlowInterval; // initial millisecs between servo moves
int servoDegrees = 2; // amount servo moves at each step
// will be changed to negative value for movement in the other direction

unsigned long currentMillis = 0; // stores the value of millis() in each iteration of loop()
unsigned long previousOnBoardLedMillis = 0; // will store last time the LED was updated
unsigned long previousLed_A_Millis = 0;
unsigned long previousLed_B_Millis = 0;

unsigned long previousButtonMillis = 0; // time when button press last checked

unsigned long previousServoMillis = 0; // the time when the servo was last moved

//========

void setup() {

Serial.begin(9600);
Serial.println(“Starting SeveralThingsAtTheSameTimeRev1.ino”); // so we know what sketch is running

// set the Led pins as output:

myservo.write(servoPosition); // sets the initial position
myservo.attach(servoPin3);
myservo.attach(servoPin4);
myservo.attach(servoPin5);

}

//=======

void loop() {

// Notice that none of the action happens in loop() apart from reading millis()
// it just calls the functions that have the action code

currentMillis = millis(); // capture the latest value of millis()
// this is equivalent to noting the time from a clock
// use the same time for all LED flashes to keep them synchronized

}

//========

void servoSweep() {

// this is similar to the servo sweep example except that it uses millis() rather than delay()

// nothing happens unless the interval has expired
// the value of currentMillis was set in loop()

if (currentMillis - previousServoMillis >= servoInterval) {
// its time for another move
previousServoMillis += servoInterval;

servoPosition = servoPosition + servoDegrees; // servoDegrees might be negative

if (servoPosition <= servoMinDegrees) {
// when the servo gets to its minimum position change the interval to change the speed
if (servoInterval == servoSlowInterval) {
servoInterval = servoFastInterval;
}
else {
servoInterval = servoSlowInterval;
}
}
if ((servoPosition >= servoMaxDegrees) || (servoPosition <= servoMinDegrees)) {
// if the servo is at either extreme change the sign of the degrees to make it move the other way
servoDegrees = - servoDegrees; // reverse direction
// and update the position to ensure it is within range
servoPosition = servoPosition + servoDegrees;
}
// make the servo move to the next position
myservo.write(servoPosition);
// and record the time when the move happened
}
}

//=====END

@larryd

I tried your code and it seems to be working well, however I am still trying to work out the delay times so I can get the movements to be correct. I have two questions though. First, how do I dictate a start position The reason I ask is that the servos need to start from a certain position since they are controlling body parts (i.e. arms start down, mouth starts closed). Secondly, how do I make it so I don’t need to loop the code? I need separate lines of code that need to progress (such as the mouth opening and closing, but with different timings to match a speech, rather than simply opening and closing and doing the same thing in a loop). If there is a way to run the three lines of code independently of one another, and possibly even loop the unique code rather than looping two movements, this would be perfect.

eguirguis2005:
I attempted to use the code, but since I don’t have/need LEDs, I removed the parts involving LEDs. I don’t know if this changed anything important, but I’m trying to make the code work to make three servos move at the same time. However it is not working and I have no idea what I am looking at. Help would be appreciated. Here is my code:

It is much easier to help if you use the code button </> when posting code so it looks like this

#include <Servo.h>

// ----CONSTANTS (won't change)

const int servoPin3 = 3; // the pin number for the servo signal
const int servoPin4 = 4;
const int servoPin5 = 5;  
const int servoMinDegrees = 20; // the limits to servo movement
const int servoMaxDegrees = 150;

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

int servoPosition = 90;     // the current angle of the servo - starting at 90.
int servoSlowInterval = 80; // millisecs between servo moves
int servoFastInterval = 10;
int servoInterval = servoSlowInterval; // initial millisecs between servo moves
int servoDegrees = 2;       // amount servo moves at each step 
                           //    will be changed to negative value for movement in the other direction

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
unsigned long previousOnBoardLedMillis = 0;   // will store last time the LED was updated
unsigned long previousLed_A_Millis = 0;
unsigned long previousLed_B_Millis = 0;

unsigned long previousButtonMillis = 0; // time when button press last checked

unsigned long previousServoMillis = 0; // the time when the servo was last moved

//========

void setup() {

 Serial.begin(9600);
 Serial.println("Starting SeveralThingsAtTheSameTimeRev1.ino");  // so we know what sketch is running
 
     // set the Led pins as output:
     
 myservo.write(servoPosition); // sets the initial position
 myservo.attach(servoPin3);
 myservo.attach(servoPin4);
 myservo.attach(servoPin5);

}

//=======

void loop() {

     // Notice that none of the action happens in loop() apart from reading millis()
     //   it just calls the functions that have the action code

 currentMillis = millis();   // capture the latest value of millis()
                             //   this is equivalent to noting the time from a clock
                             //   use the same time for all LED flashes to keep them synchronized

}

//========

void servoSweep() {

     // this is similar to the servo sweep example except that it uses millis() rather than delay()

     // nothing happens unless the interval has expired
     // the value of currentMillis was set in loop()
 
 if (currentMillis - previousServoMillis >= servoInterval) {
       // its time for another move
   previousServoMillis += servoInterval;
   
   servoPosition = servoPosition + servoDegrees; // servoDegrees might be negative

   if (servoPosition <= servoMinDegrees) {
         // when the servo gets to its minimum position change the interval to change the speed
      if (servoInterval == servoSlowInterval) {
        servoInterval = servoFastInterval;
      }
      else {
       servoInterval = servoSlowInterval;
      }
   }
   if ((servoPosition >= servoMaxDegrees) || (servoPosition <= servoMinDegrees))  {
         // if the servo is at either extreme change the sign of the degrees to make it move the other way
     servoDegrees = - servoDegrees; // reverse direction
         // and update the position to ensure it is within range
     servoPosition = servoPosition + servoDegrees; 
   }
       // make the servo move to the next position
   myservo.write(servoPosition);
       // and record the time when the move happened
 }
}

You say the program is not working but you have not said what it actually does. The more detail the better.

In this part of your program

 myservo.attach(servoPin3);
 myservo.attach(servoPin4);
 myservo.attach(servoPin5);

you change the pin the servo is attached to from 3 to 4 to 5.

I suspect you should have had 3 different instances of the Servo - for example

Servo myservoA;
Servo myservoB;
Servo myservoC;

and then you should have a separate copy of the function servoSweep() (each with a different name) for each servo.

And I think I see why your program is not working - you have no call to servoSweep() in loop() - it should be like this

void loop() {

     // Notice that none of the action happens in loop() apart from reading millis()
     //   it just calls the functions that have the action code

 currentMillis = millis();   // capture the latest value of millis()
                             //   this is equivalent to noting the time from a clock
                             //   use the same time for all LED flashes to keep them synchronized
 servoSweep();
}

And if you have two more functions for the other 2 servos then they will also need to be called from loop()

…R

Robin2:
And if you have two more functions for the other 2 servos then they will also need to be called from loop()

Better still, a single ServoSweep function, that takes arguments, so it can handle all 3 servos, based on those arguments, rather than having three almost identical functions to maintain.
Regards,
Ray L.

RayLivingston:
Better still, a single ServoSweep function, that takes arguments, so it can handle all 3 servos, based on those arguments, rather than having three almost identical functions to maintain.

I agree completely. However I suspect making copies would be easier for a beginner.

...R

…Go on, even beginners will eventually have to learn about functions and arrays…

lastchancename:
...Go on, even beginners will eventually have to learn about functions and arrays...

For me that word "eventually" is key. In my mind it means tomorrow or next week, but not "now".

My philosophy is that if a beginner gets something working today they may be sufficiently interested to continue learning into next week. But if it seems too complicated today they will find some other hobby, YMMV

...R