I have a prety simple loop, at least I thought it would be, but I can't get it to work as I planned it.
When I pust a button, a value goes from 0 to 1 in void loop();
If the value is 1, it calls stepperHold();
void stepperHold() {
//stepper1.runSpeedToPosition();
int HoldWaarde = double(setting1 * 60) / (setting7 + 3); //Not used in debugging at the moment
double steppersnelheidHOLD = double(setting3 * 10) / double(HoldWaarde * 3) * steps; //Not used in debugging at the moment
// stepper1.setMaxSpeed(steppersnelheidHOLD); //Not used in debugging at the moment
// stepper1.setSpeed(steppersnelheidHOLD);//Not used in debugging at the moment
// stepper1.moveTo((setting7 * 3));//Not used in debugging at the moment
stepper1.setMaxSpeed(1000);
stepper1.moveTo(2000);
stepper1.setSpeed(1000);
stepper1.runSpeedToPosition();
stepper1.setMaxSpeed(0);
stepper1.setSpeed(0);
// unsigned long currentMillisHold = millis();
// if (currentMillisHold - previousMillisHold >= 1000) { // 20 seconden hold -> holdTime
// previousMillisHold = currentMillisHold;
// steppersnelheidHOLD = 0;
// Serial.print("-DELAY: "); Serial.println("1000"); //debugging
// } // millis
}
What I want it to do it move the stepper 2000 steps at a speed of 1000.
After 2000 steps I turn off the speed so the motor is not humming but keeps it's torque, also works.
After that I want so serial print something, just to see that it executes AFTER it has run 2000 steps and block everything for 1 second and do it all again.
I cannot get that to work (using millis(), non blocking) or delay() (blocking).
What happens is that every time stepperHold() cycles, it will only move 1 step, wait 1 sec and move another step.
I've tried putting the delay in the void loop() but that does not work either. in millis() it will just serial print every time the cycle hits the serial print code, as expected.
Can someone please help me or point me in the right direction to get 2000 steps, serial print a message, hold for 1 second and run do it all over again?
Hard to tell without seeing the entire program but I am thinking you need to add a couning variable that goes up one everytime the motor takes a step like this instead of a delay each time loop runs
It is perfectly possible to program a period of apparent inactivity using millis(). Just have a variable to record the fact that the inactive period has started and use millis() to change it when the time is up.
if (inactivePeriod == true) {
if (millis() - startOfInactivePeriod >= durationOfInactivePeriod) {
inactivePeriod = false;
}
}
How your other code responds when it finds inactivePeriod == true is entirely up to you
In an ideal setup you would get feedback from the stepper indicating its current position or that it had reached a particular position but either of these requires extra hardware to do it. Could you possible incorporate such hardware into your system, either a rotary encoder for absolute position feedback or limit switches for particular position feedback.
Robin2:
I suspect you meant to say feedback from the stepper library indicating
...R
Actually, no, I meant what I said but I could perhaps have explained it better. The program has no idea where the stepper actually is only where it should be or is on its way to. A rotary encoder driven by the stepper would allow the absolute position to be known assuming, of course, that the start position is known and no encoder "ticks" are missed.
Limit switches provide an easy way to determine that the stepper, or more likely the mechanical components driven by it, are in a particular position.
UKHeliBob:
Actually, no, I meant what I said but I could perhaps have explained it better. The program has no idea where the stepper actually is only where it should be or is on its way to. A rotary encoder driven by the stepper would allow the absolute position to be known assuming, of course, that the start position is known and no encoder "ticks" are missed.
Thanks - now I see what was in your mind.
For myself I would prefer to select a motor that would not miss steps and thus would not require any external position verification.
For myself I would prefer to select a motor that would not miss steps and thus would not require any external position verification
A laudable ambition, but I suspect that is no motor exists that would not miss a step under some conditions such as when highly loaded or even prevented from moving entirely.
Either way the motor will take time to reach its target position and if non blocking code is used then the program will have moved on before the target is reached.
Try the following.
I havn't debugged it but it does give you some ideas.
I'm assuming that you're using accelstepper.
/**********************
All your globals, defines includes etc here
**********************/
bool stepperHold_finished = true; /* When false will force stepperHold to run until set true again */
void setup() {
/*****
All your setup stuff here
*****/
stepper1.setMaxSpeed(1000);
stepper1.setSpeed(1000);
stepper.setAcceleration(1000);
}
void loop() {
stepper.run(); /* This line will actually move the stepper one step. */
/* It will only move the stepper if it is time to do so. */
/* If the stepper does not need to move, it will do nothing */
/* It should stay in loop() */
/******************************************************************************/
/* */
/* The rest of your loop code goes here */
/* */
/******************************************************************************/
/****
the call to stepperHold get called when the button gets pressed.
but it will also get called every loop until it finishes. once it does, press the button again to run it again
****/
if (button_pressed || !stepperHold_finished)
stepperHold()
}
void stepperHold() {
/********
will start the stepper moving if it is not already moving
otherwise will do nothing while the stepper is moving
when the stepper stops, it will print a message and delay stepper movement for +- 1 sec
but will not block anything else. all other code in loop will continue
************/
static bool steppermoved = false;
static bool stepper_stop_logged = false;
static unsigned long stopped_time;
static unsigned long destination = 2000l;
char bufr[80];
bool
if (!steppermoved) { /* Have we moved the stepper yet? */
stepper1.moveTo(destination); /* No. Tell stepper driver to move the stepper to destination */
steppermoved = true; /* remember that we have told the stepper to move */
stepperHold_finished = false; /* set flag to ensure stepperHold get called until we're finished
return; /* We have started the stepper moving. Nothing else to do until the stepper arrives at destination */
}
/***
Check to see if the stepper has stopped.
****/
if (!stepper1.isRunning()) {
/* The stepper has stopped. */
if (!stepper_stop_logged) { /* Have we noticed that it is stopped before now? */
stopped_time = millis(); /* No. Take note of the time, and print out a message */
sprintf(bufr, "Stepper stopped at position: %li", stepper1.currentPosition());
Serial.println(bufr);
stepper_stop_logged = true;
}
else { /* Yes, we have noted that we stopped before now */
if ((unsigned long)(millis() - stopped_time) >= 1000) { /* Have we delayed for at least one second */
destination += 2000;
steppermoved = false;
stepper_stop_logged = false;
stepperHold_finished = true;
}
}
}
}
UKHeliBob:
A laudable ambition, but I suspect that is no motor exists that would not miss a step under some conditions such as when highly loaded or even prevented from moving entirely.
I suspect that is a case of the best being the enemy of the good.
I wasn't aware I got so many help while I was trying to get it running, thanks!
The millis() solution I tried before even posting here but failed to get it to work with the stepper, it just slowed down the stepper with delays between each step. Just like my original problem.
I forgot to mention I use accellstepper, mailnly because I want it the sketch to have a mode where the stepper bounced with acceleration.
I did get it to work by counting the number of steps and resetting after every cycle.
The only thing that triggers this is a button so there's not a whole lot going on there.
void stepperHold() {
int HoldWaarde = double(setting1 * 60) / (setting7 + 2); //totale tijd interval INCLUSIEF runtime (3 is 3 seconden...
double steppersnelheidHOLD = double(setting3 * 10) / double(HoldWaarde * 2) * steps; // holdspeed snelheid stepper, exclusief de holdtime.
int MoveAfstand = steppersnelheidHOLD * 2;
stepper1.setMaxSpeed(MoveAfstand);
stepper1.moveTo(MoveAfstand);
stepper1.setSpeed(MoveAfstand);
stepper1.runSpeedToPosition();
stepper1.setMaxSpeed(0);
stepper1.setSpeed(0);
if (stepper1.currentPosition() == MoveAfstand) {
delay(1000); // halve seconde wachten om motor tot rust te brengen
Serial.println("- SHOOT -");
delay(holdTime); // shutter open
stepper1.setCurrentPosition(0);
}
}
I know delay() is a big no-no so I will change that to millis(). With 'HoldWaarde' I figure out how many times it will need to loop, with 'steppersnelheidHOLD' the stepper speed per second is calculated (it calculates it over a period of 2 seconds) and with 'MoveAfstand' the stepper converts the distance in just 1 second. After that, it pauses for 1 second before it 'shoots' and hold for another daly(holdTime).
And then do it again until an endswitch is hit.
snewpers:
The millis() solution I tried before even posting here but failed to get it to work with the stepper, it just slowed down the stepper with delays between each step.
You need to post the complete program so we can see exactly what you did.
snewpers:
I have included the sketch as I have it working now, without the millis for holding the steppers.
Before I start looking at the code (which is long) can you please give us an update about what this version actually does and what you want it to do that is different.
An indication of what parts you have changed would also help.
The part that I had problems with and what this thread is about is:
// ########
// VOID STEPPERSTUFF WITH HOLD
What I wanted it to do is run the stepper for x steps in x amount of time, do nothing at all for 20 seconds and do it all again.
I am not sure this is the best solution possible, but it is what I got working. All other things that I tried without using the stepper1.currentposition() line failed because if I just add a delay of 20 seconds at end of the stepper movement, it will put that delay in between steps, instead of running x amount of steps and then stopping. In the complete sketch there is still the (commented out) part using millis().
void stepperHold() {
int HoldWaarde = double(setting1 * 60) / (setting7 + 2); // Total hold time INCLUDING 2 seconds for running to steppers
double steppersnelheidHOLD = double(setting3 * 10) / double(HoldWaarde * 2) * steps; // The stepperspeed to travel distance in 2 seconds
int MoveAfstand = steppersnelheidHOLD * 2; // Run that distance in just 1 seconds -leaves a spare second.
// The spare second is used to stabilize the camera/gantry before releasing the shutter.
stepper1.setMaxSpeed(MoveAfstand); // Stepper speed is same as distance to move
stepper1.moveTo(MoveAfstand); // Stepper moves specified distance in 1 second
stepper1.setSpeed(MoveAfstand); // Stepper speed is set
stepper1.runSpeedToPosition(); // Stepper moves to specified distance
stepper1.setMaxSpeed(0); // Stepper is there, set speed to 0 to prevent humming
stepper1.setSpeed(0); // Stop stepper and prevent humming without losing torque
if (stepper1.currentPosition() == MoveAfstand) { // The stepper has finished it's run and has stopped
Serial.print("-holdtime: "); Serial.println(holdTime - 500); // debugging
Serial.print("aantal steps; "); Serial.println(steppersnelheidHOLD * 2); // debugging
Serial.print("aantal steps; "); Serial.println(MoveAfstand); // debugging
Serial.print("snelheid p sec; "); Serial.println(steppersnelheidHOLD); // debugging
delay(1000); // Use spare second to hold everything
Serial.println("- SHOOT -"); // Release shutter, optocoupler code not inserted yet
delay(holdTime); // shutter open // This is the actual delay time as set by user setting7
stepper1.setCurrentPosition(0); // Reset the steppers position
}
}
Oh no sorry - I needed the steppers to stop for some time. I couldn't get that done using delay() or Millis() because every cycle would do: step - delay - step - etc, so if the stepper needed to go 10 steps it would also delay as many times in between.