Stepper motor questions and trying to runToPosition

Hey. I'm working on an x-y rotary table program and i'm stuck and need a little guidance. I'm making some progress, but i've reached a dead end, so i'd figure i'd finally ask for help after a week of no luck. Here's what i have going on. I'm making a gear cutter for wood gears. I have a rotary table similar to a record player that is connected to my mill/drill press. The first program will turn the gear to the correct angle, and my drill press drills the hole for the base of the tooth, and goes on to the next position. I have this part pretty much figured out.

The second program will be similar to the first program, but instead of drilling holes, a stepper motor will be connected to my milling table and the rest of the gear tooth will be cut out either using an end mill, or a scroll saw with a round blade. I haven't decided on which cutting method i'm going to use yet, but either way the program will be the same.

below is my code. it's just an experiment and i've been using different variations on code, so please don't criticize too much since i'm new and trying to figure it out. I've borrowed different parts of code, but i have it working for the most part.

Here's how it's supposed to work. When i turn it on. stepper1 rotates constantly until it, or I hit the home button, and then it stops, and this will be home.. I put this in the loop so i have the option of rehoming it anytime without hitting the reset button. And then it waits until a button is pressed to go forward or backward. I can make both steppers take the appropriate steps, which is basically my first program listed below. It spins, and then drills, and then repeats when i push the button. But i would like to modify this code so when i push the button, i get a blocking function where both steppers move together to cut the gear profile. And that's where i'm having problems. the MultiStepper functions are a recent addition trying to get both steppers working in unison, and i'm unsure if this is correct, or if i could do it strictly from accelstepper, and if so, how is this done?

any help would be appreciated. The question is in the loop below the function that has ????

Another issue i have is with the code. when i upload or start the program frest and i press the button at home the very first time it cycles through rest of the code, and then it stops like it's supposed too. And then i can restart the home and stop it on a dime. but i assume i'm missing a line of code at the end of the while loop that stops it from cycling rest of the code before stopping at home? I could work with this extra movement at the beginning, but it is something i'd like to fix eventually.

thanks for any input

#include <Stepper.h>
#include <AccelStepper.h>
#include <MultiStepper.h>

Stepper stepper1(6400, 4,3);
Stepper stepper2(3200, 11,12);

boolean MultiStepper::addStepper  ( AccelStepper &  stepper1 );
boolean MultiStepper::addStepper  ( AccelStepper &  stepper2 );

MultiStepper steppers;
 

        
const int dirPin  = 3;
const int stepPin = 4;
const int enPin   = 5;
     
       // Stepper 2
       
const int dirPin2 = 11;
const int stepPin2 = 12;
const int enPin2 = 13;

const int switchOne     = 8;           //forward switch
const int switchTwo     = 9;           //backward switch

int home_switch   = 10;                // Pin 10 connected to Home Switch (MicroSwitch)

int direction;                                // Variable to set Rotation (CW-CCW) of the motor
int steps;                                     // Used to set HOME position after Homing is completed

int p1buttonState = 0;                   // current state of the button
int lastp1buttonState = 0;             // previous state of the button

int p2buttonState = 0;                  // current state of the button
int lastp2buttonState = 0;             // previous state of the button

bool bPress = false;

bool isForward = false;
bool isBackward = false;



void setup() {

  
stepper1.setSpeed(100);
stepper2.setSpeed(100);

  
  pinMode( home_switch, INPUT_PULLUP);
  pinMode( switchOne, INPUT_PULLUP);
  pinMode( switchTwo, INPUT_PULLUP);

  pinMode(enPin,OUTPUT);
  pinMode(dirPin,OUTPUT);
  pinMode(stepPin,OUTPUT);


  pinMode(enPin2, OUTPUT);

  digitalWrite(enPin,HIGH);
  digitalWrite(enPin2,HIGH);



}
 

void loop() {

  
  while (digitalRead(home_switch)) {    // Do this until the switch is activated   
    digitalWrite(dirPin, LOW);                // (HIGH = anti-clockwise / LOW = clockwise)
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(100);                 // Delay to slow down speed of Stepper
    digitalWrite(stepPin, LOW);
    delayMicroseconds(100);                 //????  at startup, it continues and cycles the rest of the code 
                                                         //        before stopping.  Usually i just click the home button
                                                         //        once so it will cycle early, and then i let it hit the home 
                                                         //        switch, but this is wrong.
    
} 

   

   isForward = false;
   isBackward = false;

   p1buttonState = digitalRead(switchOne);
   p2buttonState = digitalRead(switchTwo);

  if (p1ButtonPress()) {

    
    delay(500);
  }

    if (p2ButtonPress()) {

     
      delay(500);
    }

  
  if( isForward ){

delay(100);

stepper1.step(6400);             //  ????  This is where i'd like it to runToPosition, or a similar blocking function.  
                                             //    Each stepper will need to make about 4-5 small movements, 
                                             //    and then returns to the waiting spot awaiting a button press
                                             //     before going to the next step.
stepper2.step(3200);
delay(2000);
        }
   
   if( isBackward ) {
       
delay(100);                           //  ???? This will be just like above code, but in reverse.
stepper1.step(-6400);
stepper2.step(-3200);

delay(100);
        
     }
           
    
}



bool p1ButtonPress()
{
   bool isPress = false;
                                                                // compare the p1buttonState to its previous state
  if (p1buttonState != lastp1buttonState) {
                                                                  // if the state has changed, increment the counter
    if (p1buttonState == LOW) {
                                                       // if the current state is HIGH then the button went from off to on:
      bPress = true;
      isPress = true;
    
    
    } else {
                                                       // if the current state is LOW then the button went from on to off:
 
      isForward = true;
    }
                                                        // Delay a little bit to avoid bouncing
    delay(50);
  }
                                                         // save the current state as the last state, for next time through the loop
  lastp1buttonState = p1buttonState;
  return isPress;
}

bool p2ButtonPress()
{
   bool isPress = false;
                                                           // compare the p1buttonState to its previous state
  if (p2buttonState != lastp2buttonState) {
                                                           // if the state has changed, increment the counter
    if (p2buttonState == LOW) {
                                                           // if the current state is HIGH then the button went from off to on:
      bPress = true;
      isPress = true;
     
    
    } else {
                                                            // if the current state is LOW then the button went from on to off:
     
      isBackward = true;
    }
                                                             // Delay a little bit to avoid bouncing
    delay(50);
  }
                                                             // save the current state as the last state, for next time through the loop
  lastp2buttonState = p2buttonState;
  return isPress;
}

If you want two stepper motors to do different numbers of steps in exactly the same time then you need the Multistepper library. However that library does not use acceleration.

If you need synchronized motion with acceleration then you will have to write your own code - it's actually not very difficult.

This code is wrong

Stepper stepper1(6400, 4,3);
Stepper stepper2(3200, 11,12);

It is using the Stepper library. You should not be using it at all - it is very primitive compared to AccelStepper and Multistepper.

You MUST NOT use delay() or delayMicroseconds() with the AccelStepper/Multi... libraries, Your code must ensure that loop() can repeat at a much faster rate than the step-rate.

I suggest you read all the buttons first thing in loop() and save their values. Create a function to read all the button pins.

Have a look at Planning and Implementing a Program

...R
Stepper Motor Basics
Simple Stepper Code
simple acceleration code.

I'll check out that planning and implementing a program page you recommended. I understand the stepper library is primitive compared to the others. but that's what i started on, and i'm trying to get the code right for the multistepper or accel to take its place. I have other variations of this code that has the Accel codes in place instead of the stepper which i'll start working on

The standard Stepper library is not intended for stepper drivers that take step and direction signals.

...R

Ok. so i've been working on this all day and am making progress, but i hit a wall and calling it a night. below is my updated code. i'm sure it makes a little more since than the first. right now i have it where it moves to a position when i press the switch one. but nothing happens on switch two. the code is similar, and i figure it should be working. but it's not. I've pretty much written all of this from my past experiments and examples, but i'm missing something.

#include <AccelStepper.h>
#include <MultiStepper.h>

                    
AccelStepper stepper1(AccelStepper::DRIVER, 4, 3);
AccelStepper stepper2(AccelStepper::DRIVER, 12, 11);

                  
MultiStepper steppers;
   
   const int dirPin  = 3;
   const int stepPin = 4;
const int enPin = 5;
const int enPin2 =13;
   const byte switchOne = 8;
   const byte switchTwo = 9;
   byte switchOneState;
   byte switchTwoState;
   int home_switch = 10; 

   

void setup() {
 

pinMode(enPin, OUTPUT);
pinMode(enPin2, OUTPUT);
  pinMode( home_switch, INPUT_PULLUP);
  pinMode( switchOne, INPUT_PULLUP);
  pinMode( switchTwo, INPUT_PULLUP);

digitalWrite(enPin, HIGH);
digitalWrite(enPin2, HIGH);
 
  stepper1.setMaxSpeed(6000);
  stepper2.setMaxSpeed(6000);

  steppers.addStepper(stepper1);
  steppers.addStepper(stepper2);


   while (digitalRead(home_switch)) {    // Do this until the switch is activated   
    digitalWrite(dirPin, LOW);        // (HIGH = anti-clockwise / LOW = clockwise)
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(100);            // Delay to slow down speed of Stepper
    digitalWrite(stepPin, LOW);
    delayMicroseconds(100); 
    
  }
  
  delay(2000);
   

  
}
  

void loop() {
  checkButtons();
  stepUp();
  stepDown();

  
}

void checkButtons() {
  
  switchOneState = digitalRead(switchOne);
  switchTwoState = digitalRead(switchTwo);
}

void stepUp() {
   if (switchOneState == LOW && switchTwoState == LOW)
  
  return;
   
   if (switchOneState == LOW){

  long positions[2]; // Array of desired stepper positions
  
  positions[0] = 4000;
  positions[1] = 1500;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  delay(1000);
  
  // Move to a different coordinate
  positions[0] = 100;
  positions[1] = 100;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  delay(1000);

  // Move to a different coordinate
  positions[0] = 500;
  positions[1] = 500;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  delay(1000);

   }
}

void stepDown(){

if (switchOneState == LOW && switchTwoState == LOW){
    return;

if (switchTwoState == LOW){

  long positions[2]; // Array of desired stepper positions
  
  positions[0] = 2000;
  positions[1] = 750;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  delay(1000);
  
  // Move to a different coordinate
  positions[0] = 100;
  positions[1] = 100;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  delay(1000);
  
}
}
}

I think you will find you have the } for this in the wrong place

if (switchOneState == LOW && switchTwoState == LOW){
    return;

If you use the AutoFormat tool to indent your code consistently it makes that sort of thing easier to see.

When I write a line with IF I always put the } on the next line before I fill in the rest of the code - so I don't forget it.

...R

Thanks for the help. this morning it jumped off the page and it was easy to fix. I had an extra set of {} where i shouldn't have had any. But i got that fixed. and i also cleaned up the code and added notes to make it easier to read, but i have one final question and am unsure how to do it. I've seen it done on other code, but not with regarding positions like this.

One of the stepper motors needs to save it's position at the end of each pushbutton loop. ie. the button is pressed. both steppers makes 6-8 movements. stepper1 stops and holds it's position until the next button press, but the stepper2 resets and goes back to zero and restarts running the same movements over and over each button press. But stepper1 is always going forward, so the next time i push the button, it resumes where it left off.

thanks for all your help.

#include <AccelStepper.h>
#include <MultiStepper.h>

                    
AccelStepper stepper1(AccelStepper::DRIVER, 4, 3);
AccelStepper stepper2(AccelStepper::DRIVER, 12, 11);

                  
MultiStepper steppers;
   
   const int dirPin  = 3;      // stepper1 direction pin for homing
   const int stepPin = 4;      // stepper1 step pin for homing
   const int enPin = 5;        // stepper1 enable
   const int enPin2 =13;       // stepper2 enable
   const byte switchOne = 8;   // stepUp switch
   const byte switchTwo = 9;   // stepDown switch
   byte switchOneState;        // stepUp switch state
   byte switchTwoState;        // stepDown switch state
   int home_switch = 10;       // homing switch

   

void setup() {
 

  pinMode(enPin, OUTPUT);                // stepper1 enable output
  pinMode(enPin2, OUTPUT);               // stepper2 enable output
  pinMode( home_switch, INPUT_PULLUP);   // home switch mode
  pinMode( switchOne, INPUT_PULLUP);     // stepUp switch mode
  pinMode( switchTwo, INPUT_PULLUP);     // stepDown switch mode

  digitalWrite(enPin, HIGH);             // stepper1 enable = high
  digitalWrite(enPin2, HIGH);            // stepper2 enable = high
 
  stepper1.setMaxSpeed(6000);            // stepper1 maxSpeed
  stepper2.setMaxSpeed(6000);            // stepper2 maxSpeed

  steppers.addStepper(stepper1);         // adding stepper1 to multiStepper
  steppers.addStepper(stepper2);         // adding stepper2 to multiStepper


   while (digitalRead(home_switch)) {     // makeshift homing code
    digitalWrite(dirPin, LOW);            
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(100);               // homing speed  
    digitalWrite(stepPin, LOW);
    delayMicroseconds(100); 
    
  }
  
  delay(2000);                            // delay after homing before able to push buttons stepUp or stepDown
   

  
}
  

void loop() {
  checkButtons();                       // read buttons status
  stepUp();                             // stepUp
  stepDown();                           // stepDown

  
}

void checkButtons() {
  
  switchOneState = digitalRead(switchOne);   // reading stepUp button
  switchTwoState = digitalRead(switchTwo);   // reading stepDown button
}

void stepUp() {
   
   if (switchOneState == LOW && switchTwoState == LOW)  
                                                           // nothing happens if both buttons are pushed
      
      return;                                           // return to loop and wait for button press
   
   if (switchOneState == LOW){                          // if stepUp button is activated

  long positions[2];                                   // Run these positions
  
  positions[0] = 0;
  positions[1] = 100;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); 
  delay(1000);
  
 
  positions[0] = 200;
  positions[1] = 200;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition();
  delay(1000);

  
  positions[0] = 400;
  positions[1] = 300;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition();         
  delay(1000);

  positions[0] = 200;
  positions[1] = 400;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition();
  delay(1000);

  positions[0] = 0;
  positions[1] = 500;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition();
  delay(1000);

   }
}

void stepDown(){

   if (switchOneState == LOW && switchTwoState == LOW)    
                                                            // nothing happens if both buttons are pushed
      
       return;                                            // return to loop and wait for button press

  if (switchTwoState == LOW){                             // stepDown button is activated

  long positions[2];                                      // Run these positions backwards.  NOT important yet
  
  positions[0] = 2000;
  positions[1] = 750;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); 
  delay(1000);
  
 
  positions[0] = 100;
  positions[1] = 100;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); 
  delay(1000);
  
}
}

wildcat99s:
ie. the button is pressed. both steppers makes 6-8 movements. stepper1 stops and holds it's position until the next button press, but the stepper2 resets and goes back to zero and restarts running the same movements over and over each button press. But stepper1 is always going forward, so the next time i push the button, it resumes where it left off.

I'm not sure I understand that.

Do you mean that stepper2 stays where it is but its position count is set to zero?
OR
Do you mean that stepper2 makes an extra movement that brings it back to the zero position?

...R

Robin2:
I'm not sure I understand that.

Do you mean that stepper2 stays where it is but its position count is set to zero?
OR
Do you mean that stepper2 makes an extra movement that brings it back to the zero position?

...R

Ok. I included a pic of what i'm trying to accomplish. I'm cutting the big sprocket. Firstly, i will cut the outside radius, and then i will drill out the inside radius of each tooth. And then come back and cut out rest of the meat between the gear teeth, and that's what this program is for.

My numbers will be different than these, but for an example. My stepper1 has 200 steps per rotation, which will be divided by 20 teeth. so stepper1 will move 10 steps per button press and these steps will be in sync with stepper2 as they cut; stepper2 moves 5 steps forward towards the inside radius, and then moves 5 steps backwards and then returns to zero at the top of the tooth.

At the end of this cycle. stepper1 should be sitting at 10 steps and stepper2 is at zero. When i press the button, the stepper1 goes from 10 to 20 while stepper2 cuts and returns to zero. when i press the button again. Stepper1 goes from 20 to 30... and so on.

Image from Reply #8 so we don't have to download it. See this Simple Image Upload Guide

...R

thanks. I was wondering how i could upload the pic directly to the forum without having to upload it online somewhere first.

wildcat99s:
My numbers will be different than these, but for an example. My stepper1 has 200 steps per rotation, which will be divided by 20 teeth. so stepper1 will move 10 steps per button press and these steps will be in sync with stepper2 as they cut; stepper2 moves 5 steps forward towards the inside radius, and then moves 5 steps backwards and then returns to zero at the top of the tooth.

Sorry I can't follow that. It sounds as if you want the motors to move to the following positions in sync - but I suspect I have it wrong

Stepper1     0 10 20 40 60 80 100 110 120 140 160 180   0
Stepper2     0  5  0  5  0  5   0   5   0   5   0   5   0

To be honest this seems like the sort of job that GCode is made for and the GRBL program

...R

yes, you are close on understanding.

1st button press;
Stepper1 moves from 0 to 5 as stepper2 moves from 0 to 10, and then stepper1 moves from 5 to 10 as stepper2 moves from 10 back to 0.

press button again;
stepper1 starts from 10 and moves to 15 as stepper2 moves from 0 to 10, and then stepper1 moves from 15 to 20 as stepper2 moves from 10 back to 0.

3rd button press,
stepper1 starts from 20 and moves to 25 as stepper2 moves from 0 to 10, and then stepper1 goes from 25 to 30 as stepper2 runs back to zero

I've thought about manually writing the code for the entire program run(30-80 teeth gear) but i really don't want it to run automatically because they're might be issues during the cutting process i need to address, so i would like it to cut one at a time while i monitor it.

I don't know much about GCode. I've played around a little with autocad back in high school and have had minimal CNC experience. But it's something i'll eventually learn.

I have a couple ideas i'm gonna try once i get done from lunch. i think i may be able to get it going. i'll post an update and hopefully a finished program

I was able to get the program working. it may not be pretty yet, but it gets the job done. I made switchOne cut the tooth profile only and both steppers returns to zero at the end. with the 2nd button, i planned on going in reverse if needed, but I changed that with a simple step counter instead. which moves the gear stock to the dead center of the next tooth, which resets the counter so both steppers are ready to cut the tooth, and then repeat. I'm sure i'm going to add another couple buttons for other functions as needed, but it's pretty cool.

thanks for your help. but i'm sure i'll have other questions down the line. I still have a lot of fabbing and math work before i can actually start cutting

#include <AccelStepper.h>
#include <MultiStepper.h>

                    
AccelStepper stepper1(AccelStepper::DRIVER, 4, 3);
AccelStepper stepper2(AccelStepper::DRIVER, 12, 11);

                  
MultiStepper steppers;
   
   const int dirPin  = 3;      // stepper1 direction pin for homing
   const int stepPin = 4;      // stepper1 step pin for homing
   const int enPin = 5;        // stepper1 enable
   const int enPin2 =13;       // stepper2 enable
   const byte switchOne = 8;   // stepUp switch
   const byte switchTwo = 9;   // stepDown switch
   byte switchOneState;        // stepUp switch state
   byte switchTwoState;        // stepDown switch state
   int home_switch = 10;       // homing switch
  
   

void setup() {
 

  pinMode(enPin, OUTPUT);                // stepper1 enable output
  pinMode(enPin2, OUTPUT);               // stepper2 enable output
  pinMode( home_switch, INPUT_PULLUP);   // home switch mode
  pinMode( switchOne, INPUT_PULLUP);     // stepUp switch mode
  pinMode( switchTwo, INPUT_PULLUP);     // stepDown switch mode

  digitalWrite(enPin, HIGH);             // stepper1 enable = high
  digitalWrite(enPin2, HIGH);            // stepper2 enable = high
 
  stepper1.setMaxSpeed(3000);            // stepper1 maxSpeed
  stepper2.setMaxSpeed(3000);            // stepper2 maxSpeed

  steppers.addStepper(stepper1);         // adding stepper1 to multiStepper
  steppers.addStepper(stepper2);         // adding stepper2 to multiStepper


   while (digitalRead(home_switch)) {     // makeshift homing code
    digitalWrite(dirPin, LOW);            
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(100);               // homing speed  
    digitalWrite(stepPin, LOW);
    delayMicroseconds(100); 
    
  }
  
  delay(2000);                            // delay after homing before able to push buttons stepUp or stepDown
   

  
}
  

void loop() {
  checkButtons();                       // read buttons status
  stepUp();                             // stepUp
  stepDown();                           // stepDown

  
}

void checkButtons() {
  
  switchOneState = digitalRead(switchOne);   // reading stepUp button
  switchTwoState = digitalRead(switchTwo);   // reading stepDown button
}

void stepUp() {
   
   if (switchOneState == LOW && switchTwoState == LOW)  // nothing happens if both buttons are pushed
      
      return;                                           // return to loop and wait for button press
   
   if (switchOneState == LOW){                          // if stepUp button activated

  long positions[2];                                   // Run these positions
  
  positions[0] = 0;
  positions[1] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); 
  delay(2000);
  
 
  positions[0] = -300;
  positions[1] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition();
  delay(2500);

  positions[0] = 0;
  positions[1] = 300;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition();         
  delay(2500);
  
  positions[0] = 300;
  positions[1] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition();         
  delay(2500);

  positions[0] = 0;
  positions[1] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition();         
  delay(2500);




   }

}

void stepDown(){

   if (switchOneState == LOW && switchTwoState == LOW)    // nothing happens if both buttons are pushed
      
       return;                                            // return to loop and wait for button press

  if (switchTwoState == LOW){                             // if stepDown button activated

      
       for(int x = 0; x < 640; x++) {            // change for tooth spacing
        digitalWrite(stepPin,HIGH);
        delayMicroseconds(500);
        digitalWrite(stepPin,LOW);
        delayMicroseconds(500);
      }
 

  
}
}

wildcat99s:
yes, you are close on understanding.

1st button press;
Stepper1 moves from 0 to 5 as stepper2 moves from 0 to 10, and then stepper1 moves from 5 to 10 as stepper2 moves from 10 back to 0.

Can you write it out in the style that I used - for me (at least) it is less confusing.

...R

PS ... I wrote the above before I saw you had a solution.

i'm not really familiar with your style. but yes, it looks to be correct. but of course. the number of steps i mentioned are just representative since stepper1 is geared down to have 102,400 steps per revelations, and stepper2 will be traveling about 50,000 steps back and forth from zero.

So for an 80 tooth gear for example, center to center of the tooth will be 1280 steps. and i may have 3 or 4 positions per cycle once i have everything in place and able to start cutting. but the cycle is still the same.

just an FYI. i was able to get the program finished where it would get the job done. so thanks for your help. but i still have a lot to learn. even tho i could stop where i'm at, i wanna take it farther and see what else it can do.

wildcat99s:
i'm not really familiar with your style.

I just meant in a two-line table like I included in Reply #11 - there is nothing to get familiar with.

...R