Running Two Motors In A Loop

Hello,

I am trying to run a DC motor for two iterations, then run a different DC motor for two iterations, and run this code indefiitely. In my void loop code, you can see I am running the DC motor for 1/2 a second then turning it off for two seconds. After that, I'd like to run another motor for two iterations. Then, I'd like to return to the first motor. Currently, my motor runs for two iterations and stops.


//declare pins
int motor1pin1 = 2;
int motor1pin2 = 3;

int motor2pin1 = 4;
int motor2pin2 = 5;

void setup() {
  Serial.begin(115200);
  // put your setup code here, to run once:
  pinMode(motor1pin1, OUTPUT);
  pinMode(motor1pin2, OUTPUT);
  pinMode(motor2pin1, OUTPUT);
  pinMode(motor2pin2, OUTPUT);

  pinMode(9, OUTPUT); 
  pinMode(10, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:   

 for (i = 0; i < 2; i++);
  {
  //Controlling speed (0 = off and 255 = max speed):
  analogWrite(9, 100); //ENA pin
  analogWrite(10, 140); //ENB pin
  
  digitalWrite(motor1pin1, HIGH);
  digitalWrite(motor1pin2, LOW);

  delay(500);

  digitalWrite(motor1pin1, LOW);
  digitalWrite(motor1pin2, LOW);

  delay (2000);
  }
 return (0);
}

Have you posted the right code?

Your topic was MOVED to its current forum category as it is more suitable than the original

return is unnecessary. Returning a value is even more unnecessary since loop() returns nothing.

It wasn't in the code originally posted - the poster keeps editing the original post.

Better get a coffee - this is going to be a long one.

coffee empty and demo-code ready to post

here is a demo-code that does

This is a somehow advanced functionality that requires a somehow advanced programming-technique. It can be done with while-loops and delay() but using while-loops and delay is blocking.

using a state-machine enables this functionality in a non-blocking manner.
The non-blocking is shown through the constant blinking of the on-board-LED (IO-pin 13)

It does this based on non-blocking timing and a state-machine.
State-Machines have the advantage to reduce the number of if-conditions and flag-variables
because in a state-machine the code of each state is executed mutually exclusive.

The mutually exclusive code-execution reduces the if-conditions and flag-variables that - without a state-machine -
would be nescessary to get the same functionality.
The command "break;" creates the mutually exclusiveness.

The variable- and function names are self-explaining which means there is not much additionally comments nescessary.

Well if you are completely new to switch-case and non-blocking timing it is pretty sure that you have quetions about this code.
So just ask these questions

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);



void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}



boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - expireTime >= TimePeriod ) {
    expireTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}

const byte OnBoard_LED = 13;

void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


//declare pins
const byte motor1pin1 = 2;
const byte motor1pin2 = 3;

const byte motor2pin1 = 4;
const byte motor2pin2 = 5;

const byte motor1EnablePin =  9;
const byte motor2EnablePin = 10;

// define constants for state-machine
const byte motor1Start   = 0;
const byte motor1Run     = 1;
const byte motor1Stop    = 2;
const byte motor1WaitOff = 3;

const byte motor2Start   = 4;
const byte motor2Run     = 5;
const byte motor2Stop    = 6;
const byte motor2WaitOff = 7;

byte MyStateNr = motor1Start;

// define contants for non-blocking timing
const unsigned long motor1OnPeriod  =  500;
const unsigned long motor1OFFPeriod = 2000;

const unsigned long motor2OnPeriod  =  500;
const unsigned long motor2OFFPeriod = 2000;

unsigned long MyMotorTimer = 0;                   // Timer-variables MUST be of type unsigned long

byte interationCounter = 1;

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();

  pinMode(motor1pin1, OUTPUT);
  pinMode(motor1pin2, OUTPUT);
  pinMode(motor2pin1, OUTPUT);
  pinMode(motor2pin2, OUTPUT);

  pinMode(motor1EnablePin, OUTPUT);
  pinMode(motor2EnablePin, OUTPUT);

  //Controlling speed (0 = off and 255 = max speed):
  analogWrite(motor1EnablePin, 100); //ENA pin
  analogWrite(motor2EnablePin, 140); //ENB pin
}


void loop() {
  // blink onboard-LED to show loop is looping
  BlinkHeartBeatLED(OnBoard_LED, 100);

  MotorSequenceStateMachine();
}

// define functions for motors on / OFF
void Motor1ON() {
  digitalWrite(motor1pin1, HIGH);
  digitalWrite(motor1pin2, LOW);
}

void Motor1OFF() {
  digitalWrite(motor1pin1, LOW);
  digitalWrite(motor1pin2, LOW);
}

void Motor2ON() {
  digitalWrite(motor2pin1, HIGH);
  digitalWrite(motor2pin2, LOW);
}

void Motor2OFF() {
  digitalWrite(motor2pin1, LOW);
  digitalWrite(motor2pin2, LOW);
}



void MotorSequenceStateMachine() {

  switch (MyStateNr) {

    // Motor 1
    case motor1Start:
      MyMotorTimer = millis(); // store time-stamp when motor is switched on
      Motor1ON();
      MyStateNr = motor1Run;
      dbg("motor1Start", MyMotorTimer);
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor1Run:
      if ( TimePeriodIsOver(MyMotorTimer, motor1OnPeriod) ) {
        MyStateNr = motor1Stop;
      }
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor1Stop:
      MyMotorTimer = millis(); // store time-stamp when motor is switched OFF
      Motor1OFF();
      MyStateNr = motor1WaitOff;
      dbg("motor1Stop", MyMotorTimer);
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor1WaitOff:
      if ( TimePeriodIsOver(MyMotorTimer, motor1OFFPeriod) ) {
        if (interationCounter <= 1) {
          interationCounter++;
          MyStateNr = motor1Start;
        }
        else {
          interationCounter = 1;
          MyStateNr = motor2Start;          
        }
      }
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    // 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    // Motor 2
    case motor2Start:
      MyMotorTimer = millis(); // store time-stamp when motor is switched on
      Motor2ON();
      MyStateNr = motor2Run;
      dbg("motor2Start", MyMotorTimer);
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor2Run:
      if ( TimePeriodIsOver(MyMotorTimer, motor2OnPeriod) ) {
        MyStateNr = motor2Stop;
      }
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor2Stop:
      MyMotorTimer = millis(); // store time-stamp when motor is switched OFF
      Motor2OFF();
      MyStateNr = motor2WaitOff;
      dbg("motor2Stop", MyMotorTimer);
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor2WaitOff:
      if ( TimePeriodIsOver(MyMotorTimer, motor2OFFPeriod) ) {
        if (interationCounter <= 1) {
          interationCounter++;
          MyStateNr = motor2Start;
        }
        else {
          interationCounter = 1;
          MyStateNr = motor1Start;          
        }
      }
      break; // jump immidiately to the code marked with "xx-EXIT-xx"
  } // xx-EXIT-xx
}

best regards Stefan

consider

//declare pins
const byte motor1pin1 = 2;
const byte motor1pin2 = 3;
const byte motor1en   = 9;

const byte motor2pin1 = 4;
const byte motor2pin2 = 5;
const byte motor2en   = 10;

unsigned long msecLst;
unsigned long period;

enum { St0, St1, St2, St3, StLast };
int state = St0;

#define PeriodOn    500
#define PeriodOff   2000

// -----------------------------------------------------------------------------
void
swState (void)
{
    Serial.println (state);

    switch (state)  {
    case St0:
        analogWrite (motor1en, 100);
        period = PeriodOn;
        break;

    case St1:
        analogWrite (motor1en, 0);
        period = PeriodOff;
        break;

    case St2:
        analogWrite (motor2en, 100);
        period = PeriodOn;
        break;

    case St3:
        analogWrite (motor2en, 0);
        period = PeriodOff;
        break;
    }

    state = StLast <= ++state ? St0 : state;
}

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

    if ( (msec - msecLst) > period)  {
        msecLst = msec;
        swState ();
    }
}

// -----------------------------------------------------------------------------
void setup () {
    Serial.begin (115200);
    // put your setup code here, to run once:
    pinMode (motor1pin1, OUTPUT);
    pinMode (motor1pin2, OUTPUT);
    pinMode (motor2pin1, OUTPUT);
    pinMode (motor2pin2, OUTPUT);

    // set motor speed off
    analogWrite (motor1en, 0);
    analogWrite (motor2en, 0);

    // enable motor
    digitalWrite (motor1pin1, HIGH);
    digitalWrite (motor1pin2, LOW);
        
    digitalWrite (motor1pin1, LOW);
    digitalWrite (motor1pin2, LOW);
}

hi Stefan,

Thank you for your help. I will try and understand it more as I use it. Is there a way to turn on motor 2 while motor 1 is running, and vice versa?

For example, while running motor 1 for 1/2 second (counterclockwise), I would like motor 2 to also be running for 1/2 a second concurrently (counterclockwise). Then, turning both motors off for two second. Then doing this for a second iteration. Then, running motor 2 for 1/2 a second (clockwise) and run motor 1 for 1/2 a second (clockwise), and stopping them both for two seconds, and then repeating it for another iteration.

Yes this is possible

The names for the constants

const byte motor1Start   = 0;
const byte motor1Run     = 1;
const byte motor1Stop    = 2;
const byte motor1WaitOff = 3;

const byte motor2Start   = 4;
const byte motor2Run     = 5;
const byte motor2Stop    = 6;
const byte motor2WaitOff = 7;

are free choosable
for something like motor1 running ccw and motor 2 cw a self-explaining name would be
something like

const byte m1CCW_m2CW = 99;

but you could it name even something like
const byte blablah = 139;

but the name should be self-explaining
and then add the code that does

I gave you a start. Best way to understand the given code is playing with the code through modifying it.

You really should make an own attempt and - even if the code does not run or compile coming back with a specific question about the code.

the repeating is done by loop() itself

iterations can be controlled by a variable that is counting up or down

best regards Stefan

thanks, i'll take a crack at it as it'll help me learn as well

Hi Stefan, this was my first attempt at trying to solve the puzzle of running two motors at once. I tried adding code to the functions to allow both motors to move at once, rather than just one. Unfortunately, I was unable to cause motor 1 and motor 2 to move at the same time. Instead, motor 2 would move counterclockwise for a duration and then clockwise for a duration, and motor 1 did not move.

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);



void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}



boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - expireTime >= TimePeriod ) {
    expireTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}

const byte OnBoard_LED = 13;

void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


//declare pins
const byte motor1pin1 = 2;
const byte motor1pin2 = 3;

const byte motor2pin1 = 4;
const byte motor2pin2 = 5;

const byte motor1EnablePin =  9;
const byte motor2EnablePin = 10;

// define constants for state-machine
const byte motor1Start   = 0;
const byte motor1Run     = 1;
const byte motor1Stop    = 2;
const byte motor1WaitOff = 3;

const byte motor2Start   = 4;
const byte motor2Run     = 5;
const byte motor2Stop    = 6;
const byte motor2WaitOff = 7;

byte MyStateNr = motor1Start;

// define contants for non-blocking timing
const unsigned long motor1OnPeriod  =  500;
const unsigned long motor1OFFPeriod = 2000;

const unsigned long motor2OnPeriod  =  500;
const unsigned long motor2OFFPeriod = 2000;

unsigned long MyMotorTimer = 0;                   // Timer-variables MUST be of type unsigned long

byte interationCounter = 1;

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();

  pinMode(motor1pin1, OUTPUT);
  pinMode(motor1pin2, OUTPUT);
  pinMode(motor2pin1, OUTPUT);
  pinMode(motor2pin2, OUTPUT);

  pinMode(motor1EnablePin, OUTPUT);
  pinMode(motor2EnablePin, OUTPUT);

  //Controlling speed (0 = off and 255 = max speed):
  analogWrite(motor1EnablePin, 140); //ENA pin
  analogWrite(motor2EnablePin, 140); //ENB pin
}


void loop() {
  // blink onboard-LED to show loop is looping
  BlinkHeartBeatLED(OnBoard_LED, 100);

  MotorSequenceStateMachine();
}

// define functions for motors on / OFF
void Motor1ON() {
  digitalWrite(motor1pin1, HIGH);
  digitalWrite(motor1pin2, LOW);
  digitalWrite(motor2pin1, LOW);
  digitalWrite(motor2pin2, HIGH);
}

void Motor1OFF() {
  digitalWrite(motor1pin1, LOW);
  digitalWrite(motor1pin2, LOW);
  digitalWrite(motor2pin1, LOW);
  digitalWrite(motor2pin2, LOW);
}

void Motor2ON() {
  digitalWrite(motor2pin1, HIGH);
  digitalWrite(motor2pin2, LOW);
  digitalWrite(motor1pin1, LOW);
  digitalWrite(motor1pin2, HIGH);
}

void Motor2OFF() {
  digitalWrite(motor2pin1, LOW);
  digitalWrite(motor2pin2, LOW);
  digitalWrite(motor1pin1, LOW);
  digitalWrite(motor1pin2, LOW);
}



void MotorSequenceStateMachine() {

  switch (MyStateNr) {

    // Motor 1
    case motor1Start:
      MyMotorTimer = millis(); // store time-stamp when motor is switched on
      Motor1ON();
      MyStateNr = motor1Run;
      dbg("motor1Start", MyMotorTimer);
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor1Run:
      if ( TimePeriodIsOver(MyMotorTimer, motor1OnPeriod) ) {
        MyStateNr = motor1Stop;
      }
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor1Stop:
      MyMotorTimer = millis(); // store time-stamp when motor is switched OFF
      Motor1OFF();
      MyStateNr = motor1WaitOff;
      dbg("motor1Stop", MyMotorTimer);
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor1WaitOff:
      if ( TimePeriodIsOver(MyMotorTimer, motor1OFFPeriod) ) {
        if (interationCounter <= 1) {
          interationCounter++;
          MyStateNr = motor1Start;
        }
        else {
          interationCounter = 1;
          MyStateNr = motor2Start;          
        }
      }
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    // 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    // Motor 2
    case motor2Start:
      MyMotorTimer = millis(); // store time-stamp when motor is switched on
      Motor2ON();
      MyStateNr = motor2Run;
      dbg("motor2Start", MyMotorTimer);
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor2Run:
      if ( TimePeriodIsOver(MyMotorTimer, motor2OnPeriod) ) {
        MyStateNr = motor2Stop;
      }
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor2Stop:
      MyMotorTimer = millis(); // store time-stamp when motor is switched OFF
      Motor2OFF();
      MyStateNr = motor2WaitOff;
      dbg("motor2Stop", MyMotorTimer);
      break; // jump immidiately to the code marked with "xx-EXIT-xx"

    case motor2WaitOff:
      if ( TimePeriodIsOver(MyMotorTimer, motor2OFFPeriod) ) {
        if (interationCounter <= 1) {
          interationCounter++;
          MyStateNr = motor2Start;
        }
        else {
          interationCounter = 1;
          MyStateNr = motor1Start;          
        }
      }
      break; // jump immidiately to the code marked with "xx-EXIT-xx"
  } // xx-EXIT-xx
}

Your code-modification did change from motor1ON to

motor1 and motor2 on
the functions name

void Motor**1**ON() {

does no longer explain what is really happening inside this function
the name says "motor1ON"
what is really happening is
motor1ON clockwise and motor2 on counterclockwise

The sense of a function is to do one singular thing. Not multiple things.

And as a new thing you want the motors to rotate clockwise and counterclockwise.
This means write one function for each thing which now are 6 things.

  1. Motor1OnClockwise

  2. Motor1OnCounterClockwise

  3. Motor1Off

  4. Motor2OnClockwise

  5. Motor2OnCounterClockwise

  6. Motor2Off

So as a next step write these six functions

You can invest time into programming in two ways
The have-NO-fun-way:

modify an existing code quick & dirty how it may works. Needs only a few minutes to modify and needs 5 hours to analyse why it is not yet working. Still not knowing how to make it work.

The "need some patience and have fun later on" way:
taking 0,5 hours time to write multiple functions where each functions does one singular thing

Adding one function and RE-test
Adding one function and RE-test
Adding one function and RE-test
...
takes two hours time code is working and your knowledge about coding has grown.

So my recommendation is write the six functions where each function does one singular thing

then your code explains itself by just reading the function-calls.

Motor1_onCW()
Motor2_onCCW()

Motor1_off();
Motor2_off();

best regards Stefan

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.