How to run multiple for loop parallelly in arduino?

I want to run 2 for loop at the same time, it would be great to hear some solutions.

Look at the following link:

Here by using this logic we can surely execute if loop parallelly but if we try to use this in for loop then it will get stuck in one of the for loop and after executing whole function it will look for next one and here I am looking for solution to run 2 for loop parallelly.

I am not sure but there is concept of threads in C++, I don't know if we can use it in this or not and if we can then I don't know how.

What arduino do you have?
Most arduinos have only one core. So they will never do 2 things at the same time.
By switching between tasks it may seem that 2 tasks happen at the same time.
What is your actual problem? Why would you need 2 for loops in parallel? Are they connected so that the cannot be performed one after the other? On a multi core system, that would also put challenges because variables need to be protected from reading and writing at the same time by different cores/threads.

I have Arduino Uno and I want to control stepper and servo motor same time and both the motor are working in for loop step by step.

My real code is more complex so here is the example, hope it will be helpful.

for (i = 0;  i < x; i++ ){
ServoAngle(i);
}

for (y=5 ; y < z; y++){
StepperSteps(y);
}

for (i = 0; i < x; i++ ){
ServoAngle(i);
StepperSteps(i/x*5)
}

But the other answers are better.

You use void loop as the only loop.

You make a function that does what each for loop does inside of the for loop.
In each function you make static variables: "for-next" init, index, limit.
Each function starts with an index limit check and ends with index increment.

yess!

Hi,
the (UNO/Mega/mini) only has a processor, so
running multiple loops at the same time is impossible using these arduino.
Using a library that breaks the tasks into small time lapses, and it looks like the multiple loops are running at the same time.
The library I use when I need this kind of solution is the library: " GitHub - ivanseidel/ArduinoThread: ⏳ A simple way to run Threads on Arduino ".
It has several usage examples.

Oh dear. The main lesson taught here is cooperative multitasking on a single thread using the same means that EE's did in the late 70's and since.

If you want, we could compare with library vs technique to see which has less overhead.

Here's demo that I have to make easier for Beginners.

// NoBlockUndelayDemoV3 2022 by GoForSmoke @ Arduino.cc Forum
// Free for use, May 10, 2022 by GFS. Compiled on Arduino 2.1.0.5
// This sketch shows a general method to get rid of delays in code.
// You could upgrade code with delays to work with add-a-sketch.
// .. adding looped cases
// revisions with forum help:
// dlloyd --  added state enums May 11. <--- changed as needed.
// V3 gets new tasks added -- the non-blocking payoff!

////////////////////////////////////////////////////////////////////////////

// This example/demo takes 3 sketches that use delay() and COMBINE THEM
// by using simple techniques the sketch demonstrates.
// Plus there's a user stop/go that violates how the 3 together work.

// Code that does not sit or loop in one spot to wait, 
// does not block other code from executing during a wait.
// In 1 ms, code can use or lose 16000 cpu cycles. So don't block!

// The 3 delay-sketches void loop() code goes into 3 or more functions that run as tasks. 
// Arduino void loop() runs the same functions over and over, these functions don't wait
// but instead check time and if time's not up then run the next function.
// Every delay() has a built-in timer. I replace it with a timer that only runs when set.
// The timer is first so that the function can wait without blocking.
// It only runs when the time to wait set > 0. 
// Where a delay was removed, the time is set and function returns to run again.
// When the time is done, the time to wait set = 0. Finished wait, run the other code.

// This demo also addresses loops inside of void loop(), which can hog cycles terribly.
// It also contains a state machine, a code tool of value beyond what the demo does.


// task StopGo. --  Block - unBlock on a keystroke to stop serial monitor 

// task LoopCounter  --  lets you know how often void loop() ran last second.
// LoopCounter value
#define microsInOneSecond 1000000UL

// task PrintNumbers --  prints from printNum to setNum, pnWait ms apart
// PrintNumbers variables
unsigned long pnStart;
unsigned long pnWait = 1000UL; 
int setNum = 300;
int printNum = 0;

// task BlinkPattern --  blinks led13
// BlinkPattern variables
const byte ledPin = 13;
unsigned long blinkStart;
unsigned long blinkWait; 
byte indexMax = 12;
byte index;

enum blinkStates {BLINK_1_ON, BLINK_1_OFF, BLINK_2_ON, BLINK_2_OFF, BLINK_3_ON, BLINK_3_OFF};
blinkStates blinkStep; // state tracking for BlinkPattern() below


void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Un-Delay Example, free by GoForSmoke\n" ));
  Serial.println( F( "This sketch shows how to combine sketches." ));
  Serial.println( F( "Press Enter to toggle monitor scrolling." ));

  pinMode( ledPin, OUTPUT );

  blinkStep = BLINK_1_ON;  // actual value is 0
};


/* LoopCounter -- void loop() code to count loops per second
*
*  delay( 1000 );
*  Serial.println( "1" );
*/

void LoopCounter() // tells the average response speed of void loop()
{ // inside a function, static variables keep their value from run to run
  static unsigned long count, countStartMicros; // only this function sees these

  count++; // adds 1 to count after any use in an expression, here it just adds 1.
  if ( micros() - countStartMicros >= microsInOneSecond ) // 1 second
  {
    countStartMicros += microsInOneSecond; // for a regular second
    Serial.println( count ); // 32-bit binary into decimal text = many micros
    count = 0; // don't forget to reset the counter 
  }
}


/* PrintNumbers -- void loop() code to count from one value to another with wait between.
*
* for ( printNum = 0; printNum <= setNum; printNum++ )
* {
*   Serial.print( F( "Number " ));
*   Serial.print( printNum );
*   Serial.print( F( "   Time " ));
*   Serial.println( millis() );
*   delay( pnWait );
* }
*/

void PrintNumbers()
{
  if ( setNum < 1 )  return; // how to turn this task off, setNum = 0;
  
  // This repeat timer replaces delay()  
  // start of repeat timer
  if ( millis() - pnStart < pnWait )  // wait is not over
  {
    return; // instead of blocking, the undelayed function returns
  }

  Serial.print( F( "Number " ));
  Serial.print( printNum );
  Serial.print( F( "   Time " ));
  Serial.println( millis() );
  
  pnStart += pnWait; // starting 1 sec after last start, not the same as millis()

  if ( ++printNum >= setNum )  
  { 
    setNum = printNum = 0;
  }
}


/* BlinkPattern -- void loop() code to blink led13 using delay()
 * 
 * digitalWrite( ledPin, HIGH );   --  BLINK_1_ON
 * Serial.print( F( "BLINK_1_ON, time " ));
 * Serial.println( millis());
 * delay( 500 );
 * digitalWrite( ledPin, LOW );    --  BLINK_1_OFF
 * Serial.print( F( "BLINK_1_OFF, time " ));
 * Serial.println( millis());
 * delay( 500 );
 * for ( i = 0; i < 12; i++ )
 * (
 *   digitalWrite( ledPin, HIGH );   --  BLINK_2_ON
 *   Serial.print( F( "BLINK_2_ON, time " ));
 *   Serial.println( millis());
 *   delay( 250 );
 *   digitalWrite( ledPin, LOW );    --  BLINK_2_OFF
 *   Serial.print( F( "BLINK_2_OFF, time " ));
 *   Serial.println( millis());
 *   delay( 250 );
 * }
 * digitalWrite( ledPin, HIGH );   --  BLINK_3_ON
 * Serial.print( F( "BLINK_3_ON, time " ));
 * Serial.println( millis());
 * delay( 1000 );
 * digitalWrite( ledPin, LOW );    --  BLINK_3_OFF
 * Serial.print( F( "BLINK_3_ON, time " ));
 * Serial.println( millis());
 * delay( 1000 );
 */

void BlinkPattern()  // does the same as above without delay()
{
  // This one-shot timer replaces every delay() removed in one spot.  
  // start of one-shot timer
  if ( blinkWait > 0 ) // one-shot timer only runs when set
  {
    if ( millis() - blinkStart < blinkWait )
    {
      return; // instead of blocking, the undelayed function returns
    }
    else
    {
      blinkWait = 0; // time's up! turn off the timer and run the blinkStep case
    }
  }
  // end of one-shot timer

  // here each case has a timed wait but cases could change Step on pin or serial events.
  switch( blinkStep )  // runs the case numbered in blinkStep
  {
    case BLINK_1_ON :
    digitalWrite( ledPin, HIGH );
    Serial.print( F( "BLINK_1_ON, time " ));
    Serial.println( blinkStart = millis()); // able to set a var to a value I pass to function
    blinkWait = 500; // for the next half second, this function will return on entry.
    blinkStep = BLINK_1_OFF;   // when the switch-case runs again it will be case 1 that runs
    break; // exit switch-case

    case BLINK_1_OFF :
    digitalWrite( ledPin, LOW );
    Serial.print( F( "BLINK_1_OFF, time " ));
    Serial.println( blinkStart = millis());
    blinkWait = 500;
    blinkStep = BLINK_2_ON;
    break;

    case BLINK_2_ON :
    digitalWrite( ledPin, HIGH );
    Serial.print( F( "BLINK_2_ON, time " ));
    Serial.println( blinkStart = millis());
    blinkWait = 250;
    blinkStep = BLINK_2_OFF;
    break;

    case BLINK_2_OFF :
    digitalWrite( ledPin, LOW );
    Serial.print( F( "BLINK_2_OFF, time " ));
    Serial.println( blinkStart = millis());
    blinkWait = 250;
    // this replaces the for-loop in non-blocking code.
    if ( index++ < indexMax ) // index gets incremented after the compare
    {
      blinkStep = BLINK_2_ON;
    }
    else
    {
      index = 0;
      blinkStep = BLINK_3_ON;
    }  // how to for-loop in a state machine without blocking execution.
    break;

    case BLINK_3_ON :
    digitalWrite( ledPin, HIGH );
    Serial.print( F( "BLINK_3_ON, time " ));
    Serial.println( blinkStart = millis());
    blinkWait = 1000;
    blinkStep = BLINK_3_OFF;
    break;

    case BLINK_3_OFF :
    digitalWrite( ledPin, LOW );
    Serial.print( F( "BLINK_3_OFF, time " ));
    Serial.println( blinkStart = millis());
    blinkWait = 1000;
    blinkStep = BLINK_1_ON;
    break;
  }
}


void StopGo()  // user keyboard block / unblock 
{
  if ( Serial.available() )
  {
    while ( Serial.available() )  // clearing the buffer
    {
      Serial.read();
      delay(1); // don't care
    }
  }
  else
  {
    return;
  }
  
  while ( ! Serial.available() ); // waiting for Go, ! is logical NOT
  
  while ( Serial.available() )  // clearing the buffer
  {
    Serial.read();
    delay(1); // don't care
  }
}

void loop()  // runs over and over, see how often
{            
  LoopCounter(); // the function runs as a task, the optimizer will inline the code.
  PrintNumbers();
  BlinkPattern();
  StopGo();
}

And here's the demo that has the delay code unchanged.
Run both and watch Serial Monitor to see the difference.

// NoBlockUndelayDemoV3 2022 by GoForSmoke @ Arduino.cc Forum
// Free for use, May 10, 2022 by GFS. Compiled on Arduino 2.1.0.5
// This sketch shows a general method to get rid of delays in code.
// You could upgrade code with delays to work with add-a-sketch.
// .. adding looped cases
// revisions with forum help:
// dlloyd --  added state enums May 11. <--- changed as needed.

// V3 gets new tasks added -- the non-blocking payoff!

// StopGo. --  Block - unBlock on a keystroke to stop serial monitor 

// LoopCounter  --  lets you know how often void loop() ran last second.
// LoopCounter value
#define microsInOneSecond 1000000UL

// PrintNumbers --  prints from printNum to setNum, pnWait ms apart
// put delay in a loop code in comments here as below for BlinkPattern -- edit
// PrintNumbers variables
unsigned long pnStart;
unsigned long pnWait = 1000UL; 
int setNum = 300;
int printNum = 0;

// BlinkPattern is the original finction/task of the demo.
/* The section of the original sketch with delays to make BlinkPattern()
 * 
 * digitalWrite( ledPin, HIGH );   --  BLINK_1_ON
 * delay( 500 );
 * digitalWrite( ledPin, LOW );    --  BLINK_1_OFF
 * delay( 500 );
 * for ( i = 0; i < 12; i++ )
 * (
 *   digitalWrite( ledPin, HIGH );   --  BLINK_2_ON
 *   delay( 250 );
 *   digitalWrite( ledPin, LOW );    --  BLINK_2_OFF
 *   delay( 250 );
 * }
 * digitalWrite( ledPin, HIGH );   --  BLINK_3_ON
 * delay( 1000 );
 * digitalWrite( ledPin, LOW );    --  BLINK_3_OFF
 * delay( 1000 );
 */

// BlinkPattern variables
const byte ledPin = 13;
unsigned long blinkStart;
unsigned long blinkWait; 
byte indexMax = 12;
byte index;

enum blinkStates {BLINK_1_ON, BLINK_1_OFF, BLINK_2_ON, BLINK_2_OFF, BLINK_3_ON, BLINK_3_OFF};
blinkStates blinkStep; // state tracking for BlinkPattern() below


void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Un-Delay Example, free by GoForSmoke\n" ));
  Serial.println( F( "This sketch shows how to get rid of delays in code.\n" ));

  pinMode( ledPin, OUTPUT );

  blinkStep = BLINK_1_ON;  // actual value is 0
};


void BlinkPattern()
{
  // This one-shot timer replaces every delay() removed in one spot.  
  // start of one-shot timer
  if ( blinkWait > 0 ) // one-shot timer only runs when set
  {
    if ( millis() - blinkStart < blinkWait )
    {
      return; // instead of blocking, the undelayed function returns
    }
    else
    {
      blinkWait = 0; // time's up! turn off the timer and run the blinkStep case
    }
  }
  // end of one-shot timer

  // here each case has a timed wait but cases could change Step on pin or serial events.
  switch( blinkStep )  // runs the case numbered in blinkStep
  {
    case BLINK_1_ON :
    digitalWrite( ledPin, HIGH );
    Serial.print( F( "BLINK_1_ON, time " ));
    Serial.println( blinkStart = millis()); // able to set a var to a value I pass to function
    blinkWait = 500; // for the next half second, this function will return on entry.
    blinkStep = BLINK_1_OFF;   // when the switch-case runs again it will be case 1 that runs
    break; // exit switch-case

    case BLINK_1_OFF :
    digitalWrite( ledPin, LOW );
    Serial.print( F( "BLINK_1_OFF, time " ));
    Serial.println( blinkStart = millis());
    blinkWait = 500;
    blinkStep = BLINK_2_ON;
    break;

    case BLINK_2_ON :
    digitalWrite( ledPin, HIGH );
    Serial.print( F( "BLINK_2_ON, time " ));
    Serial.println( blinkStart = millis());
    blinkWait = 250;
    blinkStep = BLINK_2_OFF;
    break;

    case BLINK_2_OFF :
    digitalWrite( ledPin, LOW );
    Serial.print( F( "BLINK_2_OFF, time " ));
    Serial.println( blinkStart = millis());
    blinkWait = 250;
    // this replaces the for-loop in non-blocking code.
    if ( index++ < indexMax ) // index gets incremented after the compare
    {
      blinkStep = BLINK_2_ON;
    }
    else
    {
      index = 0;
      blinkStep = BLINK_3_ON;
    }  // how to for-loop in a state machine without blocking execution.
    break;

    case BLINK_3_ON :
    digitalWrite( ledPin, HIGH );
    Serial.print( F( "LED_ON_1000, time " ));
    Serial.println( blinkStart = millis());
    blinkWait = 1000;
    blinkStep = BLINK_3_OFF;
    break;

    case BLINK_3_OFF :
    digitalWrite( ledPin, LOW );
    Serial.print( F( "LED_OFF_1000, time " ));
    Serial.println( blinkStart = millis());
    blinkWait = 1000;
    blinkStep = BLINK_1_ON;
    break;
  }
}


void PrintNumbers()
{
  if ( setNum < 1 )  return; // how to turn this task off, setNum = 0;
  
  // This repeat timer replaces delay()  
  // start of repeat timer
  if ( millis() - pnStart < pnWait )  // wait is not over
  {
    return; // instead of blocking, the undelayed function returns
  }

  Serial.print( F( "Number " ));
  Serial.print( printNum );
  Serial.print( F( "   Time " ));
  Serial.println( millis() );
  
  pnStart += pnWait; // starting 1 sec after last start, not the same as millis()

  if ( ++printNum >= setNum )  
  { 
    setNum = printNum = 0;
  }
}


void LoopCounter() // tells the average response speed of void loop()
{ // inside a function, static variables keep their value from run to run
  static unsigned long count, countStartMicros; // only this function sees these

  count++; // adds 1 to count after any use in an expression, here it just adds 1.
  if ( micros() - countStartMicros >= microsInOneSecond ) // 1 second
  {
    countStartMicros += microsInOneSecond; // for a regular second
    Serial.println( count ); // 32-bit binary into decimal text = many micros
    count = 0; // don't forget to reset the counter 
  }
}


void StopGo()  // user keyboard block / unblock 
{
  if ( Serial.available() )
  {
    while ( Serial.available() )  // clearing the buffer
    {
      Serial.read();
      delay(1); // don't care
    }
  }
  else
  {
    return;
  }
  
  while ( ! Serial.available() ); // waiting for Go, ! is logical NOT
  
  while ( Serial.available() )  // clearing the buffer
  {
    Serial.read();
    delay(1); // don't care
  }
}

void loop()  // runs over and over, see how often
{            
  LoopCounter(); // the function runs as a task, the optimizer will inline the code.
  PrintNumbers();
  BlinkPattern();
  StopGo();
}

Untested. It should slow move so you can see the steps.
If you can watch for the motor to reach position instead of reach time it would go faster.

const byte L1min = 0;
const byte L1max = 20;
const byte L2min = 5;
const byte L2max = 20;

unsigned long servMoveStart, servMoveTime = 500;  // millis - slow to be seen
unsigned long stepMoveStart, stepMoveTime = 700;  // millis - slower

void setup()
{
  Serial.begin( 115200 );  // set Serial Monitor speed to that
}

void loop()
{
  static byte L1index = L1min;
  static byte L2index = L2min;

  if ( L1index <= L1max )
  {
    if ( millis() - servMoveStart >= servMoveTime )
    {
      ServoAngle( L1index++ );
      servMoveStart += servMoveTime;

      Serial.print( F( "time " ));
      Serial.print( millis() ));
      Serial.print( F( "  servo index " ));
      Serial.println( L1index ));
    }
  }

  if ( L2index <= L2max )
  {
    if ( millis() - stepMoveStart >= stepMoveTime )
    {
      StepperSteps( L1index++ );
      stepMoveStart += stepMoveTime;

      Serial.print( F( "time " ));
      Serial.print( millis() ));
      Serial.print( F( "  stepper index " ));
      Serial.println( L2index ));
    }
  }

  if ( Serial.available() )
  {
    while ( Serial.read() > 0 ); // empties the Serial Input Buffer
    1index = L1min;
    2index = L2min;
    stepMoveStart = servMoveStart = millis();
  }
}

Replace...

With...


int i = 0;
int y = 5;

void loop()
{
  ServoAngle(i++);

  if (i >= x)
    i = 0;
    
  StepperSteps(y++);

  if (y >= z)
    y = 5;
}

The loops now run concurrently.

a conventional approach for executing multiple loops simultaneously would be to have separate timer loops for each.

consider following which generically handles multiple sub-functions executing asynchronously from one another.

arguments to functions can elicit different behaviors or actions on different pins.

funcB demonstrates how loops can be handles using static/global variables.

function could be passed ptrs to structs describing parameters of job

there's no reason a function can't change the parameters (e.g. period) of it's execution

// demonstrate multiple jobs

// -------------------------------------
void
funcA (
    int arg)
{
    Serial.print   (__func__);
    Serial.print   (" ");
    Serial.println (arg);
}

// -------------------------------------
#define FuncBmax  5
void
funcB (
    int arg)
{
    static int n = 0;

    if (FuncBmax <= ++n)
        n = 0;

    Serial.print   (" ");
    Serial.print   (__func__);
    Serial.print   (" ");
    Serial.println (n);
}


// -------------------------------------
void
funcC (
    int arg)
{
    digitalWrite (arg, ! digitalRead (arg));
}

// -----------------------------------------------------------------------------
struct Job {
    void        (*func) (int arg);
    int           arg;
    unsigned long Period;
    unsigned long msecLst;
};

Job jobs [] = {
    { funcA,  2, 1000 },
    { funcB,  0,  800 },
    { funcA,  3, 1100 },
    { funcC, LED_BUILTIN , 500 },
};
#define Njob    (sizeof(jobs)/sizeof(Job))

// -----------------------------------------------------------------------------
void
loop (void)
{
    unsigned long msec = millis ();

    Job *j = jobs;
    for (unsigned n = 0; n < Njob; n++, j++)  {
        if (msec - j->msecLst > j->Period)  {
            j->msecLst = msec;
            j->func (j->arg);
        }
    }
}

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

    pinMode (LED_BUILTIN, OUTPUT);
}

What happens when you give about 1 second worth of motor movement instructions to a motor in a tiny fraction of a millisecond? Run that sketch and find out!

1 Like

You obviously missed the point of my post.... and of the OP's question... which was about running things in parallel.

Do you think the code in post #5 is any better ?

you're overlooking the OP's oversight

It was an EXAMPLE piece of code (NOT their actual code)... to highlight what they were trying to achieve... I think you are missing that.

I think that he added real world elements to what -was- a theoretic discussion.

It's like sure the pin is HIGH or LOW but buttons have to be debounced.

so you're trying to help the OP recognize his real problem?

Yes, and not really interested in having an argument about something irrelevant to the original post. I presume you're here for the same reason, although there are quite a few that would prefer to critique others answers rather than focus on the original question. Each to their own I guess.