Remove delay for pausing Stepper

Hi,
I have read quite a few posts about millis() and pausing led's but am still not sure how to manipulate that into controlling my stepper motor. I'm using the Accelstepper library for moving multiple steppers at the same time at different speeds and hope I can get someone to point me in the proper direction.

At the bottom of my code I'm trying to move stepper2 50 steps and then delay for some period of time and then step 50 again and so on.

Thanks for the help.

#include <AccelStepper.h>

AccelStepper stapler(AccelStepper::DRIVER, 5, 6);
AccelStepper stepper2(AccelStepper::DRIVER, 3, 4 );

//VALUES FOR BUTTON
const int button = 2;            // pin button is on
int val = LOW;                     // current button state
int old_val = LOW;
int buttonstate = LOW;
unsigned long previousMillis = LOW;


//VALUES FOR TURNING STAPLER 4 TURNS(using stapler hall Sensor)
int staplercounter = 0;
int staplercurrentState = 0;
int staplerpreviousState = 0;
int staplerSensor = A0;

//VALUE FOR PAUSING ROSETTE TURN
unsigned long previousMillis2 = 0;
const long interval = 1000;


void setup() {

  pinMode(button, INPUT_PULLUP);
  pinMode(staplerSensor, INPUT_PULLUP);
  Serial.begin(9600);

}

void loop() {

  readButton();
  staplefour();
  rosette();
}

void readButton() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= 100) {
    val = digitalRead(button);
    if ((val == LOW) && (old_val == HIGH)) {
      buttonstate = HIGH;
    }
    previousMillis = currentMillis;
    old_val = val;
  }
}

void staplefour() {

  stapler.setMaxSpeed(1000.0);
  stapler.setAcceleration(6000.0);


  staplercurrentState = digitalRead(staplerSensor);   //set state for movement
  if (buttonstate == 1 ) {
    stapler.move(-50);
    if (staplercounter >= 4); {                  //keep checking till it hits 4
      stapler.stop();
    }
  }
  if (staplercurrentState != staplerpreviousState) {
    if (staplercurrentState == 1) {
      staplercounter = staplercounter + 1;
      Serial.println(staplercounter);
    }
  }
  staplerpreviousState = staplercurrentState;
  if (staplercounter >= 4) {
    buttonstate = LOW;                   //reset button
    staplercounter = 0;                    //reset counter for next button push
    staplercurrentState = 0;               //reset state for next button push
  }
  stapler.run();
}

void rosette() {

  stepper2.setMaxSpeed(100.0);
  stepper2.setAcceleration(800.0);

  unsigned long currentMillis2 = millis();
  if (buttonstate == 1) {
    if (currentMillis2 - previousMillis2 >= interval) {
      previousMillis2 = currentMillis2;
      stepper2.move(50);
    }
  }
  stepper2.run();
}

If it was my program I would move the calls to stepper.run() into loop(). However because you call your functions repeatedly it probably won't make any difference. But having the calls in loop() makes it very clear that they are separate from the business of telling the library what to do.

In any case, you need to check using stepper.distanceToGo() to determine when the motor has completed its steps. Then save the value of millis() and regularly compare the saved value to the latest value. When enough time has passed issue the next stepper.move() instruction.

Have a look at how millis() is used to manage timing in Several things at a time.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

...R
Stepper Motor Basics
Simple Stepper Code

At the bottom of my code I'm trying to move stepper2 50 steps and then delay for some period of time and then step 50 again and so on.

After initiating the 50 step move save the current value of millis().

Each time through loop() check whether the required period has elapsed by subtracting the start value from the current value of millis() When the period has elapsed move 50 steps and save the current value of millis() as the new start time.

Note that there must be no code in loop() to block the free running of the loop() function.

Robin2:
If it was my program I would move the calls to stepper.run() into loop(). However because you call your functions repeatedly it probably won't make any difference. But having the calls in loop() makes it very clear that they are separate from the business of telling the library what to do.

In any case, you need to check using stepper.distanceToGo() to determine when the motor has completed its steps. Then save the value of millis() and regularly compare the saved value to the latest value. When enough time has passed issue the next stepper.move() instruction.

Have a look at how millis() is used to manage timing in Several things at a time.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

...R
Stepper Motor Basics
Simple Stepper Code

Hi Robin2,
Several things at once was the first thing I read and just wasn't able to make the jump from servos to steppers with a pause, great example by the way and very helpful with learning how to make multiple steppers work. I found it more understandable than the Accelstepper site.
I will try to figure out how to use distanceToGo() and see if I can get it to work.

UKHeliBob:
After initiating the 50 step move save the current value of millis().

Each time through loop() check whether the required period has elapsed by subtracting the start value from the current value of millis() When the period has elapsed move 50 steps and save the current value of millis() as the new start time.

Note that there must be no code in loop() to block the free running of the loop() function.

Hey Bob,
I'm working to not have any blocking commands in the loop so That it won't block the multiple steppers I will be running hence the need for millis() on pausing 1 of the steppers.

I tried this but the motor runs continuously, not just 50 steps and then check, not sure what to fix. I want the motor to start on the 2nd count of the staplercounter, which it does, and then run 50 and pause. Not sure what I need to add.

  unsigned long currentMillis2 = millis();

  if (buttonstate == 1 && staplercounter >= 2 ) {
    stepper2.move(50);
    if (currentMillis2 - previousMillis2 >= interval) {
      stepper2.move(50);
    }
    previousMillis2 = currentMillis2;
  }
  stepper2.run();
}

  previousMillis2 = currentMillis2;You are doing this each time through loop() but you should only be doing it at the start of a new period.

UKHeliBob:
  previousMillis2 = currentMillis2;You are doing this each time through loop() but you should only be doing it at the start of a new period.

You lost me, anywhere I put it will continually run through the loop, if I move it into the IF statement it will still run through the loop each time will it not?

Here is what I think you want in pseudo code

boolean waiting = false
save the current millis() value as the start time

start of loop()
//other non blocking code goes here

if the button is pressed, the counter is greater than 1, the period has ended and waiting is false
  move the stepper 50 steps
  save the current millis() value as the start time
  set waiting to true
end if

if the period has ended and waiting is true
  set waiting to false
end if
end of loop()

Also, there's no delay. You're testing (currentMillis2 - previousMillis2) against interval and then just moving on to the next statement. If you want a delay there, change to while((currentMillis2 - previousMillis2) <= interval);
or pull the next statements into the if{} so they won't be executed every pass through.

DKWatson:
If you want a delay there, change to while((currentMillis2 - previousMillis2) <= interval);

I think the OP is trying to avoid a delay - hence WHILE is not appropriate.

@ribbonman, I think @UKHeliBob has described the situation nicely except that I have a suspicion that you also want to move the stepper 50 steps in the second IF, regardless of the other conditions. But I may well be wrong.

...R

Robin2:
I think the OP is trying to avoid a delay - hence WHILE is not appropriate.

@ribbonman, I think @UKHeliBob has described the situation nicely except that I have a suspicion that you also want to move the stepper 50 steps in the second IF, regardless of the other conditions. But I may well be wrong.

...R

@Robin2 I do want it to move in the second IF, the first if is to start it after the first stepper has made 1 rev. and then pause every 50 steps after that. That is the way my thought process went about it but if I could just run the millis delay for all of it I could remove the first IF statement. I haven't figured out how to do so yet. I took another stab at the code but the stepper2 doesn't run 50 steps for any of it, it just runs continually until the stapler stepper runs it's 4 turns and then everything turns off to wait for the next button press.

I tried this code

  stepper2.setMaxSpeed(100.0);
  stepper2.setAcceleration(800.0);

  if (buttonstate == 1 && staplercounter >= 2 ) {
    stepper2.move(50);
    if (stepper2.distanceToGo() == 0 && timerstarted == false) {
      currentMillis2 = millis();
      timerstarted = true;
    }
    if (timerstarted && millis() - currentMillis2 >= interval) {
      stepper2.move(50);
      timerstarted = false;
    }
  }
  stepper2.run();
}

ribbonman:
I tried this code

Rather than write code you should write down (in English) the detailed actions that you want to happen with each action on a separate line - maybe something like this

  • press button
  • stepper A rotate N steps
  • stepper A stops after N steps
  • XX
  • stepper B moves K steps
  • stepper B stops after K steps
  • wait N millisecs
  • repeat indefinitely from XX

When you describe a problem like that is s usually straightforward to write code to give effect to that.

...R

Robin2:
Rather than write code you should write down (in English) the detailed actions that you want to happen with each action on a separate line - maybe something like this

  • press button
  • stepper A rotate N steps
  • stepper A stops after N steps
  • XX
  • stepper B moves K steps
  • stepper B stops after K steps
  • wait N millisecs
  • repeat indefinitely from XX

When you describe a problem like that is s usually straightforward to write code to give effect to that.

...R

@Robin2 I do that before any code writing to help me with my thought process, the problem is translating it into code syntax that I have no knowledge in. LOL

I went back to basics last night with the blink without delay sketch and just moving 1 stepper to minimize the clutter of the other code and found my problem to have a working code.
I post the problem here so I can get well pointed question's to get me thinking in the correct manner and appreciate the help all you folks give.

I will post the finished code in my original post if anyone has the need for this in the future.

I will post the finished code in my original post if anyone has the need for this in the future.

Post it in a new reply so as not to cause confusion to anyone reading it

ribbonman:
@Robin2 I do that before any code writing to help me with my thought process,

Then post your list of actions so we can see your thought process.

And, as @UKHeliBob says, please don't make changes to older posts other than to correct typos.

...R

Final working code.

#include <AccelStepper.h>

AccelStepper stapler(AccelStepper::DRIVER, 5, 6);
AccelStepper stepper2(AccelStepper::DRIVER, 3, 4 );

//VALUES FOR BUTTON
const int button = 2;            // pin button is on
int val = LOW;                     // current button state
int old_val = LOW;
int buttonstate = LOW;
unsigned long previousMillis = LOW;


//VALUES FOR TURNING STAPLER 4 TURNS(using stapler hall Sensor)
int staplercounter = 0;
int staplercurrentState = 0;
int staplerpreviousState = 0;
int staplerSensor = A0;

//VALUE FOR PAUSING ROSETTE TURN
unsigned long previousMillis2 = 0;
const long interval = 1000;


void setup() {

  pinMode(button, INPUT_PULLUP);
  pinMode(staplerSensor, INPUT_PULLUP);
  Serial.begin(9600);

}

void loop() {

  readButton();
  staplefour();
  rosette();
}

void readButton() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= 100) {
    val = digitalRead(button);
    if ((val == LOW) && (old_val == HIGH)) {
      buttonstate = HIGH;
    }
    previousMillis = currentMillis;
    old_val = val;
  }
}

void staplefour() {

  stapler.setMaxSpeed(1000.0);
  stapler.setAcceleration(6000.0);


  staplercurrentState = digitalRead(staplerSensor);   //set state for movement
  if (buttonstate == 1 ) {
    stapler.move(-50);
    if (staplercounter >= 4); {                  //keep checking till it hits 4
      stapler.stop();
    }
  }
  if (staplercurrentState != staplerpreviousState) {
    if (staplercurrentState == 1) {
      staplercounter = staplercounter + 1;
      Serial.println(staplercounter);
    }
  }
  staplerpreviousState = staplercurrentState;
  if (staplercounter >= 4) {
    buttonstate = LOW;                   //reset button
    staplercounter = 0;                    //reset counter for next button push
    staplercurrentState = 0;               //reset state for next button push
  }
  stapler.run();
}

void rosette() {

  stepper2.setMaxSpeed(100.0);
  stepper2.setAcceleration(800.0);

  unsigned long currentMillis2 = millis();
  if (buttonstate == 1) {
    if (currentMillis2 - previousMillis2 >= interval) {
      previousMillis2 = currentMillis2;
      stepper2.move(50);
    }
  }
  stepper2.run();
}

Robin2:
Then post your list of actions so we can see your thought process.

And, as @UKHeliBob says, please don't make changes to older posts other than to correct typos.

...R

List of actions,

  1. Check for button press to start movement
  2. stapler stepper starts rotating
  3. need to count rotations for how many staples to shoot, stapler stepper is key for everything
    so make sure to reset counter and button things will start over at button press
  4. while stapler is moving start rosette rotation after first stapler stepper rotation
  5. rosette rotation needs to move and stop for short periods for the stapler stepper to staple
  6. don't forget to call run commands often

ribbonman:
List of actions,

I am confused now. Does your Reply #15 mean that all your problems are now solved?

In any case, this is not at all my idea of a single action

  1. need to count rotations for how many staples to shoot, stapler stepper is key for everything
    so make sure to reset counter and button things will start over at button press

That description can be (and should be) broken out into 20 or 30 separate actions.

I think the same is true of your other lines also.

When you have the actions indentified at their finest level of detail it will become obvious how to write code.

You must always keep in mind that computers are monumentally stupid and things that seem like common sense to a human are meaningless for a computer.

Another thing to keep in mind is that time and effort spent in specifying in great detail what needs to be done greatly reduces the time needed to write and debug the code.

...R

This code worked perfectly with an Arduino Mega but on an Arduino Due the first motor doesn't continue to turn until it hits 4 on the counter, it moves maybe 50 steps before it stops and waits for a button press to move again.

If I unplug the staplercounter(hall sensor) the motor will turn at the set speed continuously, so why when the staplercounter is plugged in does the motor not turn until it hits 4?

Can anyone explain the difference between the 2 controllers for why it wouldn't work the same?

ribbonman:
This code worked perfectly ...

Nearly a month has elapsed since your previous Reply. What code are you referring to?

And you have not responded at all to my previous Reply.

I have no experience with a Due.

...R