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);
}
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
}
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.
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.
Motor1OnClockwise
Motor1OnCounterClockwise
Motor1Off
Motor2OnClockwise
Motor2OnCounterClockwise
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.