Trying to replace DC-motors with stepper motors in existing code

Hi.
This might seem like a weird thing to do, but I'm trying to use an existing code written for DC-motors, and replace them with steppers. The reason is that I want to control some precise peristaltic pumps. These pumps come with both DC and tepper motors, and I have the stepper version. They are quite expensive, so I'd like to be able to use the ones I have.

For now, all the steppers do is buzz a little every second within the timeframe they are suppose to be running, and getting very hot.

I have tested my circuits with a simpler code to verify that everything works.

I'm using a Arduino Mega 2560 R3 board, and two A4988 stepper drivers. The motors are these:https://mm.digikey.com/Volume0/opasdata/d220001/medias/docus/571/PG20L-D20-HHC0.pdf

I have adjusted the current limiter on the A4988 boards to match the 350mA of the motors.

The code also controls some solenoid valves, but they are not connected for now.

I'm in way over my head, so any help is appreciated.

The code I'm trying to modify is this:


```cpp
//Code for Arduino Mega1
//This code 
//1. Take commands from PC and execute (liquid transfer pumps). 
//2. Send voltage to gas sparger. 
//3. Send voltage to pumps for liquid transfer.
//The following time stamps are all in seconds
//Start is earlier for inlet than outlet to compensate for evaporation
//For this, we just need food to colon and colon to waste
//Feed every 4 hours. Transfers for all reactors will happen at exact same time
//Inputting ~4.5ml of content and outputing ~4ml of content
//This ensures an overall ~30 hours retention time
#define TimeStamp1 14000//Food to start inputting liquid into reactors
#define TimeStamp2 14040 //Food to start removing liquid from reactors
#define TimeStamp3 14280 //Time to stop both transfers
#define TimeStamp4 14400 //Time to reset the system



// Define pin connections & motor's steps per revolution
const int dirPin = 2;
const int stepPin = 3;
const int stepsPerRevolution =3636;


char instring[4]; //This stores the input from the Serial port
int instring_int[4]; //This stores the input from the Serial port converted to integer  
int i; 
int k;
int j;//Placeholder counter

int inputpin = 3; //pin for multichannel pump of adding liquid into reactors
int outputpin = 2;//pin for multichannel pump of removing liquid from reactors
//only 1 pin used because of using 6-channel pump
int spargerpin = 10;



int timer = 0;//Timer for liquid transfer
int tspa = 0; // Timer for sparging gas


void setup() {
    Serial.begin(9600);
    pinMode (inputpin,OUTPUT);
    pinMode (outputpin,OUTPUT);
    pinMode (spargerpin,OUTPUT); 
  //Serial.setTimeout(50);
}

void loop() {
  
//Now, check if we need liquid transfer
  if ((timer > TimeStamp1) && (timer < TimeStamp3)){
    digitalWrite(inputpin,HIGH);
    Serial.println("Pumping1");
  }
  else {
    digitalWrite(inputpin,LOW);
  }
  
  if ((timer > TimeStamp2) && (timer < TimeStamp3)){
    digitalWrite(outputpin,HIGH);
  }
  else {
    digitalWrite(outputpin,LOW);
  }
  
  if (timer > TimeStamp4){
    timer = 0;
  }
  timer += 1;

//Now, handles the gas sparging
  if (tspa > 5){//reset timer if it exceeds 5 secs
    tspa = 0;
  }
  tspa += 1;
  if (tspa > 3 && tspa < 5){//At the fifth second, sparge
    digitalWrite(spargerpin,HIGH);
  }
  else {
    digitalWrite(spargerpin,LOW);
  }

 //After everything, wait for 1 sec
  delay(1000); 
  Serial.println(timer);

}


My attempt at incorporating steppers looks like this:

//Code for Arduino Mega1
//This code
//1. Take commands from PC and execute (liquid transfer pumps).
//2. Send voltage to gas sparger.
//3. Send voltage to pumps for liquid transfer.
//The following time stamps are all in seconds
//Start is earlier for inlet than outlet to compensate for evaporation
//For this, we just need food to colon and colon to waste
//Feed every 4 hours. Transfers for all reactors will happen at exact same time
//Inputting ~4.5ml of content and outputing ~4ml of content
//This ensures an overall ~30 hours retention time
#define TimeStamp1 5    //Food to start inputting liquid into reactors
#define TimeStamp2 70   //Food to start removing liquid from reactors
#define TimeStamp3 120  //Time to stop both transfers
#define TimeStamp4 240  //Time to reset the system





char instring[4];     //This stores the input from the Serial port
int instring_int[4];  //This stores the input from the Serial port converted to integer
int i;
int k;
int j;  //Placeholder counter


//only 1 pin used because of using 6-channel pump
int spargerpin = 10;
//Pin1 is input and Pin2 output
const int dirPin1 = 2;   //direction of input pump
const int dirPin2 = 4;   //direction of output pump
const int stepPin1 = 3;  //Pump for adding liquid to reactors
const int stepPin2 = 5;  //Pump for removing liquid from reactors.
const int stepsPerRevolution = 3636;



int timer = 0;       //Timer for liquid transfer
int tspa = 0;        // Timer for sparging gas


void setup() {
  Serial.begin(9600);
  // Declare pins as Outputs
  pinMode(stepPin1, OUTPUT);
  pinMode(dirPin1, OUTPUT);
  pinMode(stepPin2, OUTPUT);
  pinMode(dirPin2, OUTPUT);
  //Serial.setTimeout(50);
}

void loop() {
 
    //Now, check if we need liquid transfer
    if ((timer > TimeStamp1) && (timer < TimeStamp3)) {
      // Set motor direction clockwise
      // Spin motor
        digitalWrite(dirPin1, HIGH);

      for (int x = 0; x < stepsPerRevolution; x++)
    
      digitalWrite(stepPin1, HIGH);
      delayMicroseconds(1000);
      digitalWrite(stepPin1, LOW);
      delayMicroseconds(1000);
      Serial.println("Pumping1");
    } else {
      //digitalWrite(dirPin1, HIGH);
      digitalWrite(stepPin1, LOW);
    }

    if ((timer > TimeStamp2) && (timer < TimeStamp3)) {
      // Spin motor
digitalWrite(dirPin2, HIGH);

      for (int x = 0; x < stepsPerRevolution; x++)
        digitalWrite(dirPin2, HIGH);
      digitalWrite(stepPin2, HIGH);
      delayMicroseconds(1000);
      digitalWrite(stepPin2, LOW);
      delayMicroseconds(1000);
      Serial.println("Pumping2");
    } else {

      digitalWrite(stepPin2, LOW);
    }

    if (timer > TimeStamp4) {
      timer = 0;
    }
    timer += 1;

    //Now, handles the gas sparging
    if (tspa > 5) {  //reset timer if it exceeds 5 secs
      tspa = 0;
    }
    tspa += 1;
    if (tspa > 3 && tspa < 5) {  //At the fifth second, sparge
      digitalWrite(spargerpin, HIGH);
      Serial.println("Sparging");
    } else {
      digitalWrite(spargerpin, LOW);
    }

    //After everything, wait for 1 sec
    delay(1000);
    Serial.println(timer);
  }




![image|281x500](upload://qPO7HtQIVtz3jxtmfoDyjPndRuW.jpeg)

Did you already try a stepper library like AccelStepper?

You're probably sending the step pulses too quickly for the motor to respond when it's stopped. Try increasing the delays by 10X and see if they then move. If they do, then you need to add code to do an acceleration ramp, rather than simply starting them at "full speed" with no acceleration.

I didn't try a library yet, as I wanted to keep it simple.
I did get the motors to run now. It was a case of misplaced brackets.
I stil have a timing issue though. For now, the motors are running several times in a row, and it seems that they are somehow holding up the timer as they do.

The code looks like this at the moment:


```cpp
//Code for Arduino Mega1
//This code
//1. Take commands from PC and execute (liquid transfer pumps).
//2. Send voltage to gas sparger.
//3. Send voltage to pumps for liquid transfer.
//The following time stamps are all in seconds
//Start is earlier for inlet than outlet to compensate for evaporation
//For this, we just need food to colon and colon to waste
//Feed every 4 hours. Transfers for all reactors will happen at exact same time
//Inputting ~4.5ml of content and outputing ~4ml of content
//This ensures an overall ~30 hours retention time
#define TimeStamp1 5    //Food to start inputting liquid into reactors
#define TimeStamp2 70   //Food to start removing liquid from reactors
#define TimeStamp3 120  //Time to stop both transfers
#define TimeStamp4 240  //Time to reset the system





char instring[4];     //This stores the input from the Serial port
int instring_int[4];  //This stores the input from the Serial port converted to integer
int i;
int k;
int j;  //Placeholder counter


//only 1 pin used because of using 6-channel pump
int spargerpin = 10;
//Pin1 is input and Pin2 output
const int dirPin1 = 2;   //direction of input pump
const int dirPin2 = 4;   //direction of output pump
const int stepPin1 = 3;  //Pump for adding liquid to reactors
const int stepPin2 = 5;  //Pump for removing liquid from reactors.
const int stepsPerRevolution = 3636;



int timer = 0;       //Timer for liquid transfer
int tspa = 0;        // Timer for sparging gas


void setup() {
  Serial.begin(9600);
  // Declare pins as Outputs
  pinMode(stepPin1, OUTPUT);
  pinMode(dirPin1, OUTPUT);
  pinMode(stepPin2, OUTPUT);
  pinMode(dirPin2, OUTPUT);
  //Serial.setTimeout(50);
}

void loop() {
 
    //Now, check if we need liquid transfer
    //if ((timer > TimeStamp1) && (timer < TimeStamp3)) {
      if (timer =  TimeStamp1) {
      // Set motor direction clockwise
      // Spin motor
     digitalWrite(dirPin1, HIGH);
  digitalWrite(dirPin2, HIGH);

	// Spin motor
	for(int x = 0; x < stepsPerRevolution; x++)
	{
		digitalWrite(stepPin1, HIGH);
    digitalWrite(stepPin2, HIGH);
		delayMicroseconds(1000);
		digitalWrite(stepPin1, LOW);
    digitalWrite(stepPin2, LOW);
		delayMicroseconds(1000);
    
    }} else {
digitalWrite(stepPin1, LOW);
      digitalWrite(stepPin2, LOW);
    }

    if (timer > TimeStamp4) {
      timer = 0;
    }
    timer += 1;

    //Now, handles the gas sparging
    if (tspa > 5) {  //reset timer if it exceeds 5 secs
      tspa = 0;
    }
    tspa += 1;
    if (tspa > 3 && tspa < 5) {  //At the fifth second, sparge
      digitalWrite(spargerpin, HIGH);
      Serial.println("Sparging");
    } else {
      digitalWrite(spargerpin, LOW);
    }

    //After everything, wait for 1 sec
    delay(1000);
    Serial.println(timer);
  }


do you mean "=="?

looks like the code uses time values, but i don't see where millis() is being called

Using a library definitely makes it more simple.
You could try my MobaTools library. Making a stepper run is very simple, as the minimumStepper example shows.
The library can be installed via the library manager. ( There's also a class to create timing functions :wink: )

1 Like

Thanks. I´ll try this.

If you create the step-pulses with elementary function-calls like you do

The microcontroller is 100% busy with creating the step-pulses.
= no time for other things execept you put these other things in each and every for-loop

but then all other things have to be finished before the next step-pulse must be created.
all in all: complicated to write the code this way

really much easier if you use the MobaTools because the MobaTools create the step-pulses in the background.
This enables to do different things at the same time and these other things can take time minutes or hour long. The step-pulses are created and served very constant because the step-pulse-creation is based on a timer-interrupt.

best regards Stefan

With the MobaTools-library start / stopping a stepper-motor to rotate continiuosly is a single line of code
You simply replace

    //digitalWrite(inputpin,HIGH);
    stepperInputPump.rotate(1); // 1 = rotate clockwise  -1 = rotate counterclockwise

and you are done.

Here is your code modified for stepper-motors with using the MobaTools-Library

//Code for Arduino Mega1
//This code
//1. Take commands from PC and execute (liquid transfer pumps).
//2. Send voltage to gas sparger.
//3. Send voltage to pumps for liquid transfer.
//The following time stamps are all in seconds
//Start is earlier for inlet than outlet to compensate for evaporation
//For this, we just need food to colon and colon to waste
//Feed every 4 hours. Transfers for all reactors will happen at exact same time
//Inputting ~4.5ml of content and outputing ~4ml of content
//This ensures an overall ~30 hours retention time
#define TimeStamp1 5    //Food to start inputting liquid into reactors
#define TimeStamp2 70   //Food to start removing liquid from reactors
#define TimeStamp3 120  //Time to stop both transfers
#define TimeStamp4 240  //Time to reset the system

#include <MobaTools.h>

char instring[4];     //This stores the input from the Serial port
int instring_int[4];  //This stores the input from the Serial port converted to integer
int i;
int k;
int j;  //Placeholder counter


//only 1 pin used because of using 6-channel pump
int spargerpin = 10;
//Pin1 is input and Pin2 output
const int dirPinInputPump  = 2;   //direction of input pump
const int stepPinInputPump = 3;  //Pump for adding liquid to reactors

const int dirPinOutputPump  = 4;   //direction of output pump
const int stepPinOutputPump = 5;  //Pump for removing liquid from reactors.
const int stepsPerRevolution = 3636;

MoToStepper stepperInputPump( stepsPerRevolution, STEPDIR );  // create a stepper instance
MoToStepper stepperOutputPump( stepsPerRevolution, STEPDIR );  // create a stepper instance

int timer = 0;       //Timer for liquid transfer
int tspa = 0;        // Timer for sparging gas


void setup() {
  //               stepPin, DirPin
  stepperInputPump.attach( stepPinInputPump, dirPinInputPump );
  stepperInputPump.setSpeed( 300 ); //value 300 = 30 rev/min (if stepsPerRev is set correctly)
  stepperInputPump.setZero(); // set actual position as position zero

  stepperOutputPump.attach( stepPinOutputPump, dirPinOutputPump );
  stepperOutputPump.setSpeed( 300 ); //value 300 = 30 rev/min (if stepsPerRev is set correctly)
  stepperOutputPump.setZero(); // set actual position as position zero
  
  Serial.begin(9600);
  //Serial.setTimeout(50);
}


void loop() {
  
//Now, check if we need liquid transfer
  if ((timer > TimeStamp1) && (timer < TimeStamp3)){
    //digitalWrite(inputpin,HIGH);
    stepperInputPump.rotate(1); // 1 = rotate clockwise  -1 = rotate counterclockwise
    Serial.println("Pumping1");
  }
  else {
    //digitalWrite(inputpin,LOW);
    stepperInputPump.stop();
  }
  
  if ((timer > TimeStamp2) && (timer < TimeStamp3)){
    //digitalWrite(outputpin,HIGH);
    stepperOutputPump.rotate(1); // 1 = rotate clockwise  -1 = rotate counterclockwise
  }
  else {
    //digitalWrite(outputpin,LOW);
    stepperOutputPump.stop();
  }
  
  if (timer > TimeStamp4){
    timer = 0;
  }
  timer += 1;

//Now, handles the gas sparging
  if (tspa > 5){//reset timer if it exceeds 5 secs
    tspa = 0;
  }
  tspa += 1;
  if (tspa > 3 && tspa < 5){//At the fifth second, sparge
    digitalWrite(spargerpin,HIGH);
  }
  else {
    digitalWrite(spargerpin,LOW);
  }

 //After everything, wait for 1 sec
  delay(1000); 
  Serial.println(timer);
}

I have changed the names stepper1 / stepper2 with more self-explanatary names
Maybe you have to swap the IO-pins between inputPump and outputPump.

Maybe you have to change rotate(1) with rotate(-1) for inverted rotation-direction

best regards Stefan

the above suggests that the "Spin Motor" for loop should occur at the 5 second mark (i.e. if (timer == TimeStamp1) {).

since each iteration of the spin motor loop requires 2 msec, 3636 iterations will take 7.3 sec during which the timer won't be incremented (i.e. timer += 1;) which means the timer wont't be reset at the TimeStamp4 mark of 240 sec, but at 247+ sec.

it's unclear why a 2nd timer, tspa is needed.

look this over
(uncomment test values)

#define TimeStamp4 10           // test value 240  //Time to reset the system

const byte spargerpin = 10;

const byte dirPin1  = 2;   //direction of input pump
const byte dirPin2  = 4;   //direction of output pump
const byte stepPin1 = 3;  //Pump for adding liquid to reactors
const byte stepPin2 = 5;  //Pump for removing liquid from reactors.

const int StepsPerRevolution = 20;          // test value 3636;
int       nStep;


const unsigned long  MsecSpinMotor = 2;
      unsigned long  msecLast;
      unsigned long  msecTimer;
      int            timer;

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

    pinMode (dirPin1,  OUTPUT);
    pinMode (dirPin2,  OUTPUT);
    pinMode (stepPin1, OUTPUT);
    pinMode (stepPin2, OUTPUT);

    digitalWrite (dirPin1, HIGH);
    digitalWrite (dirPin2, HIGH);
}

// -----------------------------------------------------------------------------
void
stepMotor (
    byte stepPin )
{
    Serial.print   ("  stepMotor: ");
    Serial.println (stepPin);

    digitalWrite (stepPin, HIGH);
    delayMicroseconds (10);
    digitalWrite (stepPin, LOW);
    delayMicroseconds (10);
}

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

    if (msec - msecTimer >= 1000)  {
        msecTimer = msec;
        timer++;
        Serial.println (timer);
    }

    if (TimeStamp4 <= timer)  {
        timer = 0;
    }

    else if (3 == timer)  {
        digitalWrite (spargerpin, HIGH);
        Serial.println ("Sparging");
    }

    else if (5 == timer)  {
        digitalWrite (spargerpin, LOW);
        Serial.println (" Sparging end");

        // initialize for spin motor
        nStep    = 0;
        msecLast = msec;
    }

    else if (5 <= timer)  {
        if (StepsPerRevolution > nStep && msec - msecLast >= MsecSpinMotor)  {
            msecLast = msec;
            nStep++;

            stepMotor (stepPin1);
            stepMotor (stepPin2);
        }
    }
}

the big challenge with your (gcjr's)code is:

to analyse where has the logic for these steps

#define TimeStamp1 14000//Food to start inputting liquid into reactors
#define TimeStamp2 14040 //Food to start removing liquid from reactors
#define TimeStamp3 14280 //Time to stop both transfers
#define TimeStamp4 14400 //Time to reset the system

been gone to?
where does this logic hide?
does your code even have this logic?

What is "simple" about posting totally different code that deviates to the max from the thread-openers original code?

You over-simplified the code by making both stepper-motors run at the same time where this should be like specified here

huh? his code does toggle the step pins of both motors at the same time

If you look at the original code that uses DC-motors
you see

  if ((timer > TimeStamp1) && (timer < TimeStamp3)){
    digitalWrite(inputpin,HIGH);
    Serial.println("Pumping1");
  }
  else {
    digitalWrite(inputpin,LOW);
  }
  
  if ((timer > TimeStamp2) && (timer < TimeStamp3)){
    digitalWrite(outputpin,HIGH);
  }
  else {
    digitalWrite(outputpin,LOW);
  }

quoting the threadopener

combined with the modified code

where there are two different if-conditions

that use different timer-variables

from where do you conclude that both have to run at the same time?

And if you look into the latest code-version

You can conclude user @asche is a real beginner
remember

in the code i quoted from your post and in post #4

instead of providing these long winded criticisms why don't you provide the type of comments or code example that you think are helpful to the "beginner"?

I have provided this code.
The code that shows a complete solution - at least ready to test - is post # 9) .

Thank you both for your time, and sorry for the confusion caused by my coding attempt.
The code provided by StefanL38 is exactly what I was aiming for.

My thought when I started both steppers at the same time was that I would adjust number of rotations instead of time.

I learned a lot from this, so thanks again everyone.

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