Function to drive a stepper motor by one single step

Hello,

I've built this little machine and I'm trying to code it to learn some skills and what not. I don't want to use GRBL so I'm trying to set up my own code to do this.

Ultimately my goal is to create a function I can draw a line directed at a given angle 0-359, and a given length.

Something like: drawline(angle, length)

At this point my goal along the way is to drive two stepper motors in a near simultaneous way instead of moving motor#1 by distance_a and motor#2 by distance_a. I assume the only way to do it is by moving each motor by 1 step followed by the next motor, back and forth.

Ive used this link:

Arduino Stepper Doc

But I can't figure out how to drive them simultaneously so thats why I'm going about it like this... I'm trying to make a function with these arguments: drive(motor, speed) such that drive will return one single step from the chosen motor. Using this single step function I will loop it as I did.

Please and thanks for anyone's help.

Here is my code at the moment.

#include <Stepper.h>

const int rev=1600;

Stepper x(rev,8,9);
Stepper y(rev,10,11);

void setup() {

  Serial.begin(9600);
}

void loop() {

  for(int n; n<rev; ++n){
    drive(x,60);
    drive(y,60);
  }
  end();
}

int drive(Stepper m,int s){

  m.setSpeed(s);
  m.step(1);

  return 0;
}

void end(){
  while(1){}
}

My motor is wired like this:

  • Simultaneously, :thinking: ?
    You will need to add some external hardware, possibly an OR gate with a bit of software changes.

  • Consider direct port manipulation.

  • Moving the motors one step at a time is so fast that it should give good results.

1 Like

you need to determine rates for movements, step along the longer dimension, x or y, which should require moving one stepper at each step and the 2nd motor periodically. keep track of steps infractions and move step a motor whenever the accumulated value increases about the previous integer value

1 Like

Remember that Einstein proved that nothing can happen simultaneously ('c' being a speed limit and all that), so you have to decide what your definition of "simultaneously" is.

The arduino can send the step command to both motors far faster than they can physically respond to it, so what is the problem that you're seeing?

Can you tell by my code why it's not working to move the motors one step at a time?

your diagram shows a stepper motor driven thru a controller board with 2 inputs: direction and presumably pulse. That board.

with that board, your code should simply toggle the pulse input once for each step, not use the stepper library

look this over

const byte PinDirX = 2;
const byte PinPulX = 3;

enum { For, Rev };

unsigned long MsecStep = 100;

// -----------------------------------------------------------------------------
void step (int pin) {
    Serial.println (__func__);

    digitalWrite (PinPulX, HIGH);
    delay (MsecStep/2);
    digitalWrite (PinPulX, LOW);
    delay (MsecStep/2);
}

// -------------------------------------
void run (int N, int dir)
{
    Serial.print   ("run: ");
    Serial.println (N);

    digitalWrite (PinDirX, dir);
    
    for (int n; n < N; ++n)  {
        step (PinPulX);
    }
}

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

    pinMode (PinDirX, OUTPUT);
    pinMode (PinPulX, OUTPUT);
    digitalWrite (PinPulX, LOW);

    run (100, Rev);
}

// -------------------------------------
void loop ()
{
}

For example, this following code where the motors moves 1600 steps for one revolution 1600 when called by drive(stepper m, s) function works fine; however, the code alternates back and fourth between the two steppers spinning one revolution for x then one revolution for y over and over.

#include <Stepper.h>

const int rev=1600;
int drivefunc;

Stepper x(rev,8,9);     //Defining Stepper Pins
Stepper y(rev,10,11);

void setup() {

  Serial.begin(9600);
}

void loop() {

  for(int n; n<rev; ++n){       //Loop to repeat drive()
    drivefunc=drive(x,60);
    drivefunc=drive(y,60);
  }
  end();
}

int drive(Stepper m,int s){     //Drive function moves motor in arg by speed in arg for steps in m.step()
  m.setSpeed(s);
  m.step(1600);    //changing this value to 1 produces no motor motion

  return 1;
}

void end(){  // This function uses a while loop to stop running the void loop
  while(1){}
}

I would like to drive() to drive the motor only 1 step so that alternating between motor x and motor y for one step each in a for loop determined length by Const Int Rev appears to draw a diagonal line. I don't know why the following code program outputs no motor movement when the former code program alternates the motor one rev by one rev.

#include <Stepper.h>

const int rev=1600;
int drivefunc;

Stepper x(rev,8,9);     //Defining Stepper Pins
Stepper y(rev,10,11);

void setup() {

  Serial.begin(9600);
}

void loop() {

  for(int n; n<rev; ++n){       //Loop to repeat drive()
    drivefunc=drive(x,60);
    drivefunc=drive(y,60);
  }
  end();
}

int drive(Stepper m,int s){     //Drive function moves motor in arg by speed in arg for steps in m.step()
  m.setSpeed(s);
  m.step(1);    //produces no output

  return 1;
}

void end(){  // This function uses a while loop to stop running the void loop
  while(1){}
}

I tried running youre code with changing the pins to 8 and 9 which is how its on my board but I didnt see any result.

should the ENA pins be connected to something?

The wiring diagram I have says just DIr and Pul need to be connected with 1 ground pin

is there any reason not to try connecting the ENA+ pin to a HIGH level signal and ENA- to Gnd?

The reason is because the diagram I have doesnt say to do that.

I put it together the way the diagram said to and it worked someways like I explained initially with m.step(1600) but not m.step(1) ...

Your problem is the stepper.h library. All stepper movements of this library are blocking. So you cannot move two steppers at the same time simultaneously.
Use another ( non blocking ) stepper library . Or create the steps without a library at all.

If you don't need acceleration, the multistepper part of the AccelStepper library may be a solution.

1 Like

Or learn to use direct port manipulation, that's how I would start.

At any angle other than 45°, you need to drive one motor more steps than the other, so they can't all be "simultaneous" or paired.

You don't need a function to drive a stepper moter by one step, you already have that in drive(). What you need is a function to decide whether or not the slower axis needs to take a step or not.

Take a look into the Bresenham Line Algorithm for scheduling whether the axis with slower stepping needs to do a step or not.

The trick is figuring out which axis needs more steps, and each time you to take a step, decide whether or not the other axis also needs a step. The Bresenham algorithm does the ratio math with repeated additions and subtractions so it is fast and precise.

CNCs and 3d printers use the algorithm to coordinate motion between axes.

For example:

1 Like

the Stepper library code you're using is designed to drive the individual coils of the motor. The TB6600 board has direction and pulse inputs.

it doesn't make sense that your code for 1600 steps did what you say given the diagram you posted and you're use of the Stepper library

the Stepper library will generate pulses so maybe that's why you saw some movement, but if there are 1600 steps/revolution, did the motor turn one complete revolution?

Stepper.h will drive a step/dir driver with the two-pin initialization setup, but it will be slow (1/4 speed) because it sends quadrature signals out on the two pins and needs to send a full 4-step cycle to toggle the PULSE line once.

what do you mean by 4-step cycle?

once the direction pin is set, it shouldn't change and the pulse pin should be pulsed the # of steps, on/off

I'm trying to do this instead:

int rev = 400;
int d=0;
void setup() {

  pinMode(8,OUTPUT);    //XPul
  pinMode(9,OUTPUT);    //XDir

}

void loop() {    //loop to call drive func in a loop for steps in one revolution

  while(d<rev){ 
    drive(8,9);
    ++d;
  }

while(1){}    //loop to "end" this void loop() program body function

}

int drive(int pul,int dir){   //function to drive motor one step

  digitalWrite(pul,HIGH);

  digitalWrite(dir,HIGH);
  delayMicroseconds(500);
  digitalWrite(dir,LOW);
  delayMicroseconds(500);

  digitalWrite(pul,LOW);
  return ;
}

can you fix this code so that it works so I can understand?

I feel like this should turn the X stepper one revolution which I set to have 400 steps on the driver dip switches. Unfortunately nothing happens.