Power feed with stepper motor

Hello guys! I’m trying to achieve power feed onto my lathe that I’m currently building.. but I’m to much of a newbie in programming to be able to achieve my goals..

I’ve already got a ELS (Electric leadscrew) controller that is responsible for most of the work the lathe will do,

And it also have a separate MPG (Encoder) circuit for manual machining up and working, thanks to nice people who helped me here on this forum,

The current arduino was only intended for one axis.
My plan was to use a 4pole relay to switch between which stepper driver I want to control, but I think that’s a bad idea,

The problem I have now is that I want to add functions to the existing code to run parallel with the other functions

The existing code is responsible for jogging with precision and speed on one axis, works very good,

Would love if the code could be 2 axis compatible, dual Enable, Step, Direction, 5V outputs to 2 drivers.

And then the extra stuff I want to add is:

Power feed with a joystick (switch) and a potentiometer to run parallel with the existing code and convert the code to 2 axis with 2 MPGs to control each axis,

4 position “joystick” acts like buttons in every state, (4 separate buttons)

The idea is to use the joystick to choose axis and direction, Y+ Y- Z+ Z- to engage power feed when triggered,

So when the joystick is engaged to the left the carriage will start to move left when standing in front of the lathe, and adjust the speed with the pot,

The Arduino due in this case will have to have output for 2 different stepper drivers

And maintain the function of the MPG code while feeding to move another axis if needed (done by 2 MPGs)

don’t know if it’s possible to use 2 separate arduinos wired to the stepper drivers at the same time

Sorry for my bad programming skills

This is the code I use for 1 axis control at the moment,

Planned to use this with a switching relay for choosing axis to control,

And a relay to switch between the arduino and the ELS 4 Controller

#include <AccelStepper.h>
 
#define encoder_pin_A 2
#define encoder_pin_B 3
int encoder_pin_A_last = LOW;
float encoder_pos = 0;
int n = LOW;
/////////////////////////////////////////////////////////////////////
const int buttonPin = 4;     // the number of the pushbutton pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers
/////////////////////////////////////////////////////////////////////
#define stepper_pin_step 8
#define stepper_pin_dir  9
 
// Enc have 100 steps per revolution
// The motor have 400 steps per revolution
// Want: 1 encoder rev = 1 stepper rev
// 400 / 100 = 4...
float steps_per_pulse = 4;
 
AccelStepper stepper(AccelStepper::DRIVER, stepper_pin_step, stepper_pin_dir);
 
void setup() {
  stepper.setMaxSpeed(3000.0);
  stepper.setAcceleration(4000.0);
   
  pinMode(encoder_pin_A, INPUT_PULLUP);
  pinMode(encoder_pin_B, INPUT_PULLUP);
  pinMode(buttonPin, INPUT);

}
 
void loop() {
  // read encoder
  n = digitalRead(encoder_pin_A);
   
  if ((encoder_pin_A_last == LOW) && (n == HIGH)) {
    if (digitalRead(encoder_pin_B) == LOW) {
      encoder_pos -= steps_per_pulse ;
    } else {
      encoder_pos += steps_per_pulse ;
    }
 
    // set stepper to the new calculated position
    stepper.moveTo((long) round(encoder_pos));
  }
   
  encoder_pin_A_last = n;
 
  stepper.run();
////////////////////////////////////////////////////////////////////////
// read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        steps_per_pulse = 8;
      
      } else { 

        steps_per_pulse = 4;        
      }
    }
  }

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}

Why not use the driver enable signal to decide which stepper will run? Running 2 steppers at the same time looks like quite pointless, useless, to me.

There’s 2 different stepper drivers one for the Y-axis and one for the Z-Axis

I was planning to use a relay to select which axis to control with the arduino, sometimes it’s nessesarry to use both at the same time with two different MPGs “handwheel encoders”

At the picture you can se the mpg hand wheel and the joystick I’ll add another mpg hand wheel, one for each axis,

The goal is to be able to feed with MPGs on both axis but also be able to engage auto power feed with the joystick and adjust the speed with a potentiometer, when needed,

And if possible only use one arduino due,

So the workflow will look something like this:

You put your workpiece in the chuck and start to machine it by rotating the MPGs, position accuracy and such will be shown by the soon mounted DRO on both axises, but sometimes you want to feed for a longer time in a steady phase to achieve nice surface finish that’s when I need the power feed “flip the joystick to the desired direction and trim the speed with the potentiometer, just like power feed on a normal mechanical lathe, but still be able to move it by the MPGs the second after power feed is “in neutral position”

How will You run both steppers at the same time then?
Why use a relay when the controller can use the driver enable signal to do the selecting?

My plan from the beginning was to use 2 Arduinos one for each axis with the MPG code, and isolate them with a relay when the ELS is working,
And a third Arduino with the power feed function,

The problem is that the 2 Arduinos responsible for the MPGs function will also be isolated when the Feed Arduino is in action, unless I’m able to isolate the signals from each other so all controllers can be connected to the driver at all times,

Which I’m not sure about,

I don’t know it’s possible to use a diode on the step and direction signal, probably not, another option is opto isolated outputs from all controllers,

Controllers

ELS Basic 4 (Rocketronics) have 2 axis support
Arduino MPG Only one axis code at the moment
Arduino MPG Only one axis code at the moment
Arduino Power Feed no code at the moment

Unless there’s a solution to seamlessly put all controllers signals to the motor drivers without extra steps and PWM signals overlapping that’s a pretty good solution, probably never gonna use any function at the same time, but as soon as feed mode is disabled by letting the feed joystick go to neutral position the MPGs needs to be enabled and usable

But would be fantastic if only one Arduino was responsible for all functions with 2 axis output

But that challenge is to great for me

It's time You post a drawing showing things. Your words make no sense.

Yes it is - the Due has plenty of pins and is fast too. Just don't try to add all the other new features at once.

So it’s possible to run 2-3 arduinos to the same stepper driver or you mean it’s possible to run all functions on 1 arduino?

I don’t have the knowledge to re write the code for 2 axis and also add feed rate function into the same code

I mean that you should be able to run all of it using one Arduino. You'll want two stepper drivers I think though.

There’s already 2 stepper drivers, one for each axis

I’ll try to make a wiring diagram of some sort to make it more clear to what components is involved and what I’m trying to achieve,

Potentiometer and joystick controls power feed,

Button and MPGs control jogging

Something like that is what I’m gonna do the arduino is only programmed to function on one axis at the moment,

And then I want to add power feed output also, maybe if easier add a secondary arduino that’s responsible for the power feed part but would be better if only one arduino was used

Have absolutely no clue how to even begin,

What makes you think there would be an advantage in using more than one Arduino?

Clearly a single Arduino is capable of all the necessary operations, using more than one means you have to invent a communications protocol to synchronise them and that complexity may even impair reliability.

1 Like

The 3 different arduinos would never communicate with each other in that setup,

The idea behind 3 Arduinos is to use relays to choose which axis to control when function is needed,

the feed function would be chosen by a switch,
Let’s say that there is a 3 position switch and each position is to select which arduino is hardwired to the stepper driver,

Much like a railway rail switch, which function (arduino) will end up controlling the stepper driver

Easier in some aspects, especially when I’m not sure about the code controlling it all.

But it’s much cheaper and better to use only one arduino.. 3 arduino due’s plus the relays and stuff needed to make it work isn’t cheap, and in the end it isn’t as solid as I want,

#include <AccelStepper.h>

#define encoder_pin_Ay 2
#define encoder_pin_By 3
#define encoder_pin_Az 4   //added
#define encoder_pin_Bz 5   //added
int encoder_pin_Ay_last = LOW;
int encoder_pin_Az_last = LOW;  //added
float encoder_pos_y = 0;
float encoder_pos_z = 0;        //added
int ny = LOW;
int nz = LOW;            //added
/////////////////////////////////////////////////////////////////////
const int buttonPin = 4;     // the number of the pushbutton pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers
/////////////////////////////////////////////////////////////////////
#define stepper_pin_step_y 8
#define stepper_pin_dir_y  9
#define step_pin_step_z 10  //added
#define step_pin_dir_z  11  //added

 
// Enc have 100 steps per revolution
// The motor have 400 steps per revolution
// Want: 1 encoder rev = 1 stepper rev
// 400 / 100 = 4...
float steps_per_pulse = 1;
 
AccelStepper stepper(AccelStepper::DRIVER, stepper_pin_step_y, stepper_pin_dir_y, step_pin_step_z, step_pin_dir_z); 
 
void setup() {
  stepper.setMaxSpeed(3000.0);
  stepper.setAcceleration(4000.0);
   
  pinMode(encoder_pin_Ay, INPUT_PULLUP);
  pinMode(encoder_pin_By, INPUT_PULLUP);
  pinMode(encoder_pin_Az, INPUT_PULLUP);
  pinMode(encoder_pin_Bz, INPUT_PULLUP);
  pinMode(buttonPin, INPUT);

}
 
void loop() {
  // read encoder
  ny = digitalRead(encoder_pin_Ay);
   
  if ((encoder_pin_Ay_last == LOW) && (ny == HIGH)) {
    if (digitalRead(encoder_pin_By) == LOW) {
      encoder_pos_y -= steps_per_pulse ;
    } else {
      encoder_pos_y += steps_per_pulse ;
    }
 
    // set stepper to the new calculated position
    stepper.moveTo((long) round(encoder_pos_y));
  }
   
  encoder_pin_Ay_last = ny;
 
  stepper.run();
  
////////////////////added///////////////////
    nz = digitalRead(encoder_pin_Az);
   
  if ((encoder_pin_Az_last == LOW) && (nz == HIGH)) {
    if (digitalRead(encoder_pin_Bz) == LOW) {
      encoder_pos_z -= steps_per_pulse ;
    } else {
      encoder_pos_z += steps_per_pulse ;
    }
 
    // set stepper to the new calculated position
    stepper.moveTo((long) round(encoder_pos_z));
  }
   
  encoder_pin_Az_last = nz;
 
  stepper.run();
////////////////////////////////////////////////////////////////////////
// read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        steps_per_pulse = 4;
      
      } else { 

        steps_per_pulse = 2;        
      }
    }
  }

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}

There are a few errors that stop it from compiling and at least one that will stop it from working.

You can get the compiler to help you out here. You need to be sure that the copy pasted code has been altered everywhere to use a Z-axis constant or variable.

Change all the definitions that refer to the Y axis items to have a Y in them, in the same way that you did for Z. Then, if you forgot to change a name anywhere for the Z code, the compiler will catch it. Stepper is an example of this :wink:

I edited the code from a phone app and the compiling feature didn’t work, switched to the pc now and fixed the code.

It compiles but this code works in a odd way,

#define encoder_pin_Ay 2
#define encoder_pin_By 3
#define encoder_pin_Az 4   //added
#define encoder_pin_Bz 5   //added

2-3/4-5 only sends stepper step/dir out to 8-9 and not 10-11

They should be linked:
In 2-3 > out 8-9
In 4-5 > out 10-11

Now it is:

In 2-3, 4-5 > out 8-9 and nothing on out 10-11

Post the new version.

#include <AccelStepper.h>

#define encoder_pin_Ay 2
#define encoder_pin_By 3
#define encoder_pin_Az 4  
#define encoder_pin_Bz 5  
int encoder_pin_Ay_last = LOW;
int encoder_pin_Az_last = LOW; 
float encoder_pos_y = 0;
float encoder_pos_z = 0;      
int ny = LOW;
int nz = LOW; 
/////////////////////////////////////////////////////////////////////
const int buttonPin = 4;     // the number of the pushbutton pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers
/////////////////////////////////////////////////////////////////////
#define stepper_pin_step_y 8
#define stepper_pin_dir_y  9
#define step_pin_step_z 10
#define step_pin_dir_z  11

 
// Enc have 100 steps per revolution
// The motor have 400 steps per revolution
// Want: 1 encoder rev = 1 stepper rev
// 400 / 100 = 4...
float steps_per_pulse = 1;
 
AccelStepper stepper(AccelStepper::DRIVER, stepper_pin_step_y, stepper_pin_dir_y, step_pin_step_z, step_pin_dir_z); 
 
void setup() {
  stepper.setMaxSpeed(3000.0);
  stepper.setAcceleration(4000.0);
   
  pinMode(encoder_pin_Ay, INPUT_PULLUP);
  pinMode(encoder_pin_By, INPUT_PULLUP);
  pinMode(encoder_pin_Az, INPUT_PULLUP);
  pinMode(encoder_pin_Bz, INPUT_PULLUP);
  pinMode(buttonPin, INPUT);

}
 
void loop() {
  // read encoder
  ny = digitalRead(encoder_pin_Ay);
   
  if ((encoder_pin_Ay_last == LOW) && (ny == HIGH)) {
    if (digitalRead(encoder_pin_By) == LOW) {
      encoder_pos_y -= steps_per_pulse ;
    } else {
      encoder_pos_y += steps_per_pulse ;
    }
 
    // set stepper to the new calculated position
    stepper.moveTo((long) round(encoder_pos_y));
  }
   
  encoder_pin_Ay_last = ny;
 
  stepper.run();
  
////////////////////added///////////////////
    nz = digitalRead(encoder_pin_Az);
   
  if ((encoder_pin_Az_last == LOW) && (nz == HIGH)) {
    if (digitalRead(encoder_pin_Bz) == LOW) {
      encoder_pos_z -= steps_per_pulse ;
    } else {
      encoder_pos_z += steps_per_pulse ;
    }
 
    // set stepper to the new calculated position
    stepper.moveTo((long) round(encoder_pos_z));
  }
   
  encoder_pin_Az_last = nz;
 
  stepper.run();
////////////////////////////////////////////////////////////////////////
// read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        steps_per_pulse = 4;
      
      } else { 

        steps_per_pulse = 2;        
      }
    }
  }

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}