Hello Everyone. I am stuck in a rut because I am not understanding the logic needed to get my project to work. Basically, I am trying to make two steppers run at the same time but at different speeds (using two A4988 drivers), then I reverse one of the motors but still run at different speeds. I have everything working except I can't change the speed on one motor without it changing the speed on the other motor?? Can someone shine the light on this for me? What am I doing wrong? My code is below:
#include <Stepper.h>
const int stepPin = 5;
const int dirPin = 3;
const int stepPin1 = 8;
const int dirPin1 = 9;
const int stepsPerRevolution = 5390;
const int buttonPin = 4;
const int limitPin = 6;
int buttonState = 0;
int button1State = 0;
int Distance = 0;
void setup()
{
// Declare pins as Outputs
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(stepPin1, OUTPUT);
pinMode(dirPin1, OUTPUT);
pinMode(buttonPin, INPUT);
pinMode(limitPin, INPUT);
}
void loop()
{
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
// Set motor direction clockwise
digitalWrite(dirPin, LOW);
digitalWrite(dirPin1, LOW);
// Spin motor slowly
for (int x = 0; x < stepsPerRevolution; x++)
{
digitalWrite(stepPin, HIGH);
delayMicroseconds(400);
digitalWrite(stepPin, LOW);
delayMicroseconds(400);
digitalWrite(stepPin1, HIGH);
delayMicroseconds(400);
digitalWrite(stepPin1, LOW);
delayMicroseconds(400);
Distance = Distance + 1;
}
} else {
// turn motor off:
digitalWrite(stepPin, LOW);
digitalWrite(stepPin1, LOW);
delay (1000);
if ( Distance == 5390) {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
// Set motor direction countrerclockwise
digitalWrite(dirPin, HIGH);
digitalWrite(dirPin1, HIGH);
const int stepsPerRevolution = 5390;
// Spin motor slowly
for (int x = 0; x < stepsPerRevolution; x++)
{
digitalWrite(stepPin, HIGH);
delayMicroseconds(400);
digitalWrite(stepPin, LOW);
delayMicroseconds(400);
digitalWrite(stepPin1, HIGH);
delayMicroseconds(400);
digitalWrite(stepPin1, LOW);
delayMicroseconds(400);
Distance = 0;
}
} else {
// turn motor off:
digitalWrite(stepPin, LOW);
digitalWrite(stepPin1, LOW);
}
}
}
}
That's because you do the steps for both motors in one for loop. So you step them both with every loop pass. The steps are only offset, but equally frequent
It would make things much more easy to use a suitable library for the steppers.
You could take a look at my MobaTools library. The MoToStepper class allows up to 6 steppers running all with individual speeds as you need.
PS: If you run the steppers with different speeds, they will not do one turn at the same time ( as it is now ). What do you want to achive? And which Arduino are you using?
I am using an Uno, I am using one stepper to rotate a plate that the other stepper is connected two. The second stepper is then cutting in a circle.
I tried to put the steppers in different loops but I could not ever get it to compile. How do you get the sketch to start at the top and run through both loops?
800µs per step is 2500 steps per second, with a 200 step per rev motor, that's 750 RPM, it's impossible to jump from standstill to 750 RPM instantly without acceleration. try a sane speed like 1500µs.
What motors are you using and what power supply?
Actually there are 4x400µs delay in one loop, what means 625 steps / sec.
You cannot simply use 2 loops with delays. You must get rid of your delays. The most easy way is to use a library to drive the steppers.
This is an approch with my MobaTools library ( untested ). I didn't really understand the logic of your button, but i tried to be as close as possible to your sketch:
#include <MobaTools.h>
const int stepPin = 5;
const int dirPin = 3;
const int stepPin1 = 8;
const int dirPin1 = 9;
const int stepsPerRevolution = 5390;
const int buttonPin = 4;
const int limitPin = 6;
int buttonState = 0;
int button1State = 0;
int Distance = 0;
MoToStepper plateStepper( stepsPerRevolution, STEPDIR );
MoToStepper cutterStepper( 200, STEPDIR ); // Don't know steps/rev for this stepper
void setup()
{
// Declare pins as Outputs
plateStepper.attach( stepPin, dirPin );
cutterStepper.attach( stepPin1, dirPin1 );
plateStepper.setSpeedSteps( 12500 ); // = 12500 steps/sec
plateStepper.setRampLen( 200 ); // acceleration: steps until full speed is reached
cutterStepper.setSpeedSteps( 12500 ); // adjust for your needs
cutterStepper.setRampLen( 200 ); // acceleration: steps until full speed is reached
pinMode(buttonPin, INPUT);
pinMode(limitPin, INPUT);
}
void loop()
{
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
// Spin motor clockwise
plateStepper.writeSteps( stepsPerRevolution ); // Do one turn
cutterStepper.rotate(1); // rotate until stopped
while ( plateStepper.moving() ); // wait until one turn is done
cutterStepper.rotate(0); // stop cutterStepper
} else {
delay (1000);
if ( plateStepper.readSteps() == stepsPerRevolution) {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
// Spin motor counterclockwise
plateStepper.writeSteps( 0 ); // Back one turn to starting position
cutterStepper.rotate(1); // rotate until stopped
while ( plateStepper.moving() ); // wait until one turn is done
cutterStepper.rotate(0); // stop cutterStepper
}
}
}
}
Maybe you simply meant : one press go forward one turn, next press: go backward ?
I believe a step occurs on the rising edge of the pulse, so 400 high then 400 low would be 1 pulse, I agree 4 X 400 per loop, but that would be 1250 SPS or 350 RPM, still too fast without acceleration or microstepping (at least 8X).
Hello Again, I just wanted to let you know that I tried your code and it works perfectly! I was able to change the speeds independently. Thank you very much!! I will study the code more so I understand what is going on. Also, it sounds cool when it is accelerating and de-accelerating
That could be done more easily: When you press the button, check where your stepper is positioned and turn to the oppsite position:
#include <MobaTools.h>
const int stepPin = 5;
const int dirPin = 3;
const int stepPin1 = 8;
const int dirPin1 = 9;
const int stepsPerRevolution = 5390;
const int buttonPin = 4;
const int limitPin = 6;
int buttonState = 0;
int button1State = 0;
int Distance = 0;
MoToStepper plateStepper( stepsPerRevolution, STEPDIR );
MoToStepper cutterStepper( 200, STEPDIR ); // Don't know steps/rev for this stepper
void setup()
{
// Declare pins as Outputs
plateStepper.attach( stepPin, dirPin );
cutterStepper.attach( stepPin1, dirPin1 );
plateStepper.setSpeedSteps( 12500 ); // = 1250 steps/sec ( 12500 steps/10sec )
plateStepper.setRampLen( 200 ); // acceleration: steps until full speed is reached
cutterStepper.setSpeedSteps( 12500 ); // adjust for your needs
cutterStepper.setRampLen( 200 ); // acceleration: steps until full speed is reached
pinMode(buttonPin, INPUT);
pinMode(limitPin, INPUT);
}
void loop()
{
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
// Spin motor to opposite position ( 0 or stepsPerRevolution )
// first check the actual position, and set the target position accordingly
long targetPos = 0;
if ( plateStepper.readSteps() == 0 ) targetPos =stepsPerRevolution;
plateStepper.writeSteps( targetPos ); // Do one turn ( CW or CCW )
cutterStepper.rotate(1); // rotate until stopped
while ( plateStepper.moving() ); // wait until one turn is done
cutterStepper.rotate(0); // stop cutterStepper
}
}
Hello again. I have had to change gears on my project and now I need to figure out a different sketch. I have tried but so far I am missing the target. Maybe you can help again? I am still controlling the same motor with the same driver but now the conditions of the invention have changed. I need 3 different scenarios using either one push button or 3 pushbuttons. I need to turn CW 1/2 rev and then back for push button one. Then, I need to turn 1/2 rev CCW then back for push button 2, then for push button 3 it needs to turn CCW 1/2 rev, short delay then CW one full rev. It sounds complicated to me and I keep getting stuck in the if statements. Thanks again for your help and when this is working I will be glad to share it with you.
Hi, this is a first attempt with blocking code. Just to see if this is what you want. It should be improved to a nonblocking design with a FSM (finite state machine).
I'm not shure about rev and 1/2rev. Is it always relative, or is it absolute?
The code uses absolute positions - that may not be what you want, I'm not shure about it. But because button 3 turns the stepper asymmetrically ( 1/2 CCW, full CW ), you could turn it over and over in one direction with a relative step design.
#include <MobaTools.h>
const int stepPin = 5;
const int dirPin = 3;
const int stepPin1 = 8;
const int dirPin1 = 9;
const int stepsPerRevolution = 5390;
const byte buttonPins[] = {A0,A1,A2}; // you may adjust the pins. The buttons must be connected to Gnd
const byte buttonCnt = sizeof(buttonPins); // buttonPins must be of type byte
enum buttonNames : byte { btnCW, btnCCW, btnCCW_CW };
MoToButtons myButton( buttonPins, buttonCnt, 20, 500 ); // debounce 20ms, longpress: >500ms
//const int limitPin = 6;
//int buttonState = 0;
//int button1State = 0;
//int Distance = 0;
MoToStepper plateStepper( stepsPerRevolution, STEPDIR );
MoToStepper cutterStepper( 200, STEPDIR ); // Don't know steps/rev for this stepper
void setup()
{
// Declare pins as Outputs
plateStepper.attach( stepPin, dirPin );
cutterStepper.attach( stepPin1, dirPin1 );
plateStepper.setSpeedSteps( 12500 ); // = 1250 steps/sec ( 12500 steps/10sec )
plateStepper.setRampLen( 200 ); // acceleration: steps until full speed is reached
cutterStepper.setSpeedSteps( 12500 ); // adjust for your needs
cutterStepper.setRampLen( 200 ); // acceleration: steps until full speed is reached
//pinMode(buttonPin, INPUT);
//pinMode(limitPin, INPUT);
}
void loop()
{
// read and process the button pins:
myButton.processButtons();
if ( myButton.pressed(btnCW) ) {
plateStepper.write(+180); // turn to 180 deg.
while( plateStepper.moving() ); // this is blocking! Should be inproved
plateStepper.write(0); // Turn back to starting point ( -180 deg )
}
if ( myButton.pressed(btnCCW) ) {
plateStepper.write(-180); // turn to -180 deg.
while( plateStepper.moving() ); // this is blocking! Should be inproved
plateStepper.write(0); // Turn back to starting point ( moves +180 deg )
}
if ( myButton.pressed(btnCCW_CW ) ) {
plateStepper.write(-180); // turn to -180 deg.
while( plateStepper.moving() ); // this is blocking! Should be inproved
delay(200);
plateStepper.write(+180); // Turn to +180 deg ( moves +360 deg, from -180 to +180 )
}
}
Thank you again very much. I failed in my description, I had to loose the cutter motor, it was just not the right way to go. I am using just the plate (Blade) stepper once again. It is actually working but now I need to get the timing correct in order for this to be efficient. That is why the new code is needed. Sorry for the confusion. Maybe this code will work, I can try it tonight and see.
Thanks for all of your help.
This is the code I am trying to modify, I think it will do the trick I just need to figure out how to make it switch dir and only use three buttons. Any ideas?
#include <MobaTools.h>
const int stepRev = 3200; // steps per revolution ( 1/16 microsteps )
// adjust stepper pins to your needs
const byte dirPin = 5;
const byte stepPin = 6;
const byte enablePin = 7;
// create stepper object
MoToStepper myStepper( stepRev, STEPDIR );
// create button objects
const byte buttonPins[] = { A0,A1,A2,A3,A4 }; // adjust pins to your needs
const long stepperPositions[] = { 0, 90, 180, 270, 360 }; // in degrees, must be same number of elements as buttonPins
const byte buttonCnt = sizeof(buttonPins); // number of buttons/positions
MoToButtons myButtons( buttonPins, buttonCnt, 20, 500 );
void setup() {
myStepper.attach(stepPin, dirPin);
myStepper.setSpeed( 600 ); // = 60 rpm
myStepper.setRampLen( 100 ); // 100 steps to achive set speed
myStepper.attachEnable( enablePin, 100, LOW ); // if you want to switch off power when stepper reached position
// a homing procedure may be needed here
}
void loop() {
myButtons.processButtons(); // Check buttonstates
for( byte pos= 0; pos<buttonCnt; pos ++ ) {
if ( myButtons.pressed(pos) ) {
// Button was pressed, move stepper to the according position
myStepper.write( stepperPositions[pos] );
}
}
}
I think this sketch works fairly different from what you explained in #12. It moves the motor to fixed positions assigned to each button.
But may be I didn't understand your explanation correctly.
I will try and be more specific. using one stepper and 3 buttons. 1 button turns CW 180 (delay .5 second) then CCW 180 Stop. 2 button turns CCW 180 (delay .5 second) then CW180 Stop. 3 button turns CW180 (delay .5 second) then CCW 180, (delay .5 second) then CCW 180 (delay .5 second) then CW 180 Stop.
I hope this is a better explanation.