Go Down

Topic: Making a Machine - Cannot program two steppers to stop at the same time (Read 1 time) previous topic - next topic

Yinno

Hello All -

This is my first sketch, so any feedback is welcome.

I'm making a machine that bonds two plastic discs together. The discs are cicular and are joined with solvent.

I have one stepper that spins the discs and one stepper that applies the solvent. The stepper that applies the solvent is a linear stepper (lead screw) that pushes on the plunger of a syringe.

The discs only need to spin one revolution to apply one bead of solvent.

I want to be able to vary:
(1) The rotational speed of the discs
(2) The amount of sovent dispensed

I want to be able to keep constant:
(1) Discs must only rotate one revolution in order to apply one bead of solvent all the way around.
(2) Both motors must start and stop at the same time.

The issue I am having is that I cannot get the two steppers to stop at the same time. In my application, if the motors don't stop at the same time, there will either be lack of solvent (the solvent stopped dispensing before the disc could rotate a full turn) or there will be too much solvent (the solvent continues to dispense into a puddle after the disc stops rotating).

I am using:
Two Big Easy Drivers
Arduino UNO R3
AccelStepper library

I chose the AccelStepper library because it allows the independent and simultaneous control of two steppers. However, I don't think I need the ability to accelerate the two steppers. For my application, I think it would be fine to start/stop as instantaneous as possible. I'm wondering if this time to accelerate is where my problem is (the motors not stopping at the same time) coming from. In an attempt to mitigate this error, I set the acceleration to max "999999999" to get the motors up to speed quickly. Is is possible to remove acceleration all together?

Please take a look at my code. Since time is the same for both motors, my attempt is to calculate the "linear_travel" (steps) based on the rotational speed, rotational travel and dispensing speed.

When this code is run, the rotary stepper runs for a longer period of time than the linear stepper. I don't understand why.

I'm fine with scrapping this code if there is a better option for getting motors to start/stop at the same time.

Thanks.
Code: [Select]

#include <AccelStepper.h> // This section introduces the "AccelStepper" library (a pre-written set of instructions) to this program
// This sketch controls two stepper motors. The motors run at the same time, but at different speeds, distances and accelerations.
// There is one steppper called "rotator" that turns the filter and there is one linear stepper called "dispenser" that applies the solvent.
// The program only runs once (application of solvent to one part) and stops.
// The steppers are each controlled by their own Big Easy Driver connected to an Arduino UNO R3.

// Rotator stepper wiring:
// Connect the "Direction" pin of the Big Easy Driver (BED) to pin "8" of the Arduino UNO
// Connect the "Step" pin of the BED to pin "9" of the Arduino UNO
AccelStepper rotator(1, 9, 8); // This instruction declares the physical Direction & Step connections noted above

// Dispenser stepper wiring:
// Connect the "Direction" pin of the Big Easy Driver (BED) to pin "6" of the Arduino UNO
// Connect the "Step" pin of the BED to pin "7" of the Arduino UNO
AccelStepper dispsenser(1, 7, 6); // This instruction declares the physical Direction & Step connections noted above
int rotational_speed = 300;   // This is where the spinning speed of the filer is set (steps per second).
int rotational_travel = 3200; // This is where the amount of steps is defined for the rotary stepper.
                             // This stepper motor has 200 steps per one full rotation (1.8 degrees).
                             // Per default, the BED provides 16 microsteps per motor step, so 200 x 16 = 3200 steps per one full rotation.
                             // To dispense the solvent on the filter, we only want the filter to rotate around once.
                             // So, this "rotational_travel" will stay around 3200 (more if we want some overlap of solvent application)
                             
int dispenser_speed = 15000;  // This is where the amount of solvent dispensed can be adjusted;
// the higher the number, the more solvent is dispensed.                            
int linear_travel = ( rotational_travel / rotational_speed ) * dispenser_speed;
// This calculation defines the linear travel (amount of microsteps) of the dispenser.
                                                                               // This value is calculated in order to stop the two stepper motors at the same time.
                                                                               // Since distance = (time * speed) for each motor
                                                                               // and since the time for each motor is required to be equal for this application
                                                                               // then, distance divided by speed for each motor are equal.

void setup()
{  
 rotator.setMaxSpeed(rotational_speed); // This is the fastest speed that the rotator will achieve (steps per second)
 rotator.setAcceleration(999999999); // This is the acceleration of the rotator as it ramps up to max speed
 
 dispsenser.setMaxSpeed(dispenser_speed); // This is the fastest speed that the dispenser will achieve (steps per second)
 dispsenser.setAcceleration(999999999); // This is the acceleration of the dispenser as it ramps up to max speed
 
}
void loop()
{
   rotator.moveTo(rotational_travel);
   dispsenser.moveTo(linear_travel);
   
 rotator.run();
 dispsenser.run();
 

}


Moderator edit: Code tags added


UKHeliBob

Is this line right ?
Code: [Select]
AccelStepper rotator(1, 9, ; // This instruction declares the physical Direction & Step connections noted above
No third parameter and no right bracket ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

AWOL

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

PaulS

You need to adjust the speed of the two steppers so that they complete in the same period of time.

Yinno

Quote
Moderator edit: Code tags added


Thank you. I've now know that this is the correct way to post code.


You didn't read the new notice, did you?  :~


modeller, thank you for the link. I have now read it and won't make the same mistakes again. Thanks for keeping things tidy on this forum.

Is this line right?


That was a consequence of not using the "insert code" option. Copy/paste actually made that part a smiley, I think. Thanks for error checking my code, UKHeliBob; I appreciate it.


Duplicate post deleted. Do not cross-post, IT WASTES TIME.


AWOL, this is another misstep I won't repeat. This machine is for a fast-moving project at work and I'm nervous about the timeline since I'm not confident with programming. It's definitely a challenge for me and I guess I was grasping for answers.


You need to adjust the speed of the two steppers so that they complete in the same period of time.


PaulS, thanks for the advice. That is what I'm trying to get my code to do for me. If I change the "dispenser_speed" (to adjust the amount of solvent pushed out the syringe and onto the plastic discs), I want the program to calculate the total amount of steps required to dispense a continuous bead of solvent around the edge of the disc. Specifically, this was my attempt. Does this calculation work?

Code: [Select]
int linear_travel = ( rotational_travel / rotational_speed ) * dispenser_speed;

Three additional questions:

(1) I've been running the two steppers each with their own power supplies. One stepper/Big-Easy-Driver is fed 12V and the other stepper/Big-Easy-Driver is fed 24V. Is this where my speeds vary? Voltage/current factors into the torque of the motor. Maybe if the motor has less voltage, it might have less "oomph" to get rotating and will lag behind. I do not have a single power supply with enough amperage to hook both steppers up to a single power source in order to test this. I'll keep looking, though.
(2) Can I somehow remove acceleration from this sketch or is that not possible with AccelStepper?
(3) I've read a little about "interleaving", which I believe is when alternating step instructions are sent to the motors. Would this be a solution to my timing problem and still give the ability to run the motors at different amount of steps and speeds?

Thanks, again, for the feedback; both concerning my issue and posting on the forum, in general.




PaulS

Quote
Is this where my speeds vary? Voltage/current factors into the torque of the motor. Maybe if the motor has less voltage, it might have less "oomph" to get rotating and will lag behind. I do not have a single power supply with enough amperage to hook both steppers up to a single power source in order to test this. I'll keep looking, though.

It could have an influence. The biggest issue, though, is that there is no direct correlation between disc travel distance and dispenser travel distance. Both must be measured independently and then the best that you can hope for is getting the independent actions to complete it approximately the same time.

Quote
(2) Can I somehow remove acceleration from this sketch or is that not possible with AccelStepper?

Set the value to 1.0.

Quote
(3) I've read a little about "interleaving", which I believe is when alternating step instructions are sent to the motors. Would this be a solution to my timing problem and still give the ability to run the motors at different amount of steps and speeds?

If there is an exact ratio between the number of steps needed to rotate the disc the correct amount and the number of steps needed to move the actuator the correct amount, yes, you could use the regular Stepper library, and simply alternate which stepper moves each time, stepping each one the correct (one at 1.0, the other more or less than 1.0) number of steps.

Yinno

PaulS, thanks, again, for the quick reply.

I was able to find a single power supply that runs both steppers. Unfortunately, this did not solve the timing issue.

I tried your suggestion of setting "...setAcceleration(1.0)". I thought this would definitely work, but what I find is the motors will still slowly decelerate until they stop. I can hear/see them running slower and slower until they have completed their steps. I'm pretty confused about this.

Another option I'm trying to test is to use the AccelStepper "constant speed" example with "runSpeedToPosition()". I'm having trouble figuring out how to write code for two steppers.

PeterH

Can you afford to step each motor synchronously? This does not sound like the sort of system that needs especially high speed, and if you can afford to control the stepping directly within your sketch then it would be much simpler to synchronise them. The sort of approach I mean is to decide which motor needs to take the most steps, and step that one at a constant speed. At each step, calculate the position that the second stepper should be at (a simple linear scaling, or a call to map()) and if that has changed then step the second stepper.
I only provide help via the forum - please do not contact me for private consultancy.

Yinno

Okay, I have some code that works, but I am still having trouble with this portion:

Code: [Select]
int dispense_speed = dispense_steps * (spin_speed / spin_steps);

Am I calculating the dispense_speed incorrectly? Am I using the wrong variable type? I tried float and double, but I couldn't get that to work either.

When I run the sketch, the "dispensing" stepper doesn't move at all.

Help would be much appreciated. Thanks!

Code: [Select]
#include <AccelStepper.h>

AccelStepper spinning(1, 9, 8);
AccelStepper dispensing(1, 7, 6);

int spin_steps = 3200; // This sets the amount of disc rotation. 3200 is one full rotation (200 steps x 16 microsteps per step = 3200).
int spin_speed = 1000; // This sets how fast the discs spin.

int dispense_steps = 6400; // This sets the amount of solvent dispensed.
// int dispense_speed = 2000; // I've commented this out, but the program runs as intended if I don't calculate "dispense_speed" as shown directly below
int dispense_speed = dispense_steps * (spin_speed / spin_steps); // If I run the sketch with "dispense_speed" being calculated, the motor doesn't move at all

void setup()
{   
spinning.setMaxSpeed(10000);  // Sets the maximum spinning speed. This value is far above any speed that the fixture will achieve, but is required to be defined by the program.
spinning.moveTo(spin_steps);  // Defines a step target for spinning.
spinning.setSpeed(spin_speed);  // Sets the speed (previously defined above).
dispensing.setMaxSpeed(10000);  // Sets the maximum dispensing speed. This value is far above any speed that the fixture will achieve, but is required to be defined by the program.
dispensing.moveTo(dispense_steps); // Defines a step target for dispensing.
dispensing.setSpeed(dispense_speed); // Sets the speed (previously defined above).
}

void loop()
{   
spinning.runSpeedToPosition(); // Instructs to spin at the "spinning_speed" (without acceleration or deceleration) to the "spinning_steps" target.
dispensing.runSpeedToPosition(); // Instructs to dispense at the "dispensing_speed" (without acceleration or deceleration) to the "dispensing_steps" target.
}

UKHeliBob

Code: [Select]
int spin_steps = 3200; // This sets the amount of disc rotation. 3200 is one full rotation (200 steps x 16 microsteps per step = 3200).
int spin_speed = 1000; // This sets how fast the discs spin.

So, what will
Code: [Select]
spin_speed / spin_steps
expressed as an int as in
Code: [Select]
int dispense_speed = dispense_steps * (spin_speed / spin_steps);
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Yinno


So, what will
Code: [Select]
spin_speed / spin_steps
expressed as an int...


UKHeliBob, thanks for making me take a good look at what I was actually calculating. I now see that this "int" will return a value of zero. I've also verified this with the "serial.print()" of the calculated variable.

I've changed the variables to doubles and now the sketch executes as intended.

The only thing that has me scratching my head is that I am 99% sure that I changed these to doubles (and I also tried float) before and it didn't work.....now it's working. As long as it works from here on out, I'm happy. I must have done something wrong before.

Thanks, again, UKHeliBob.

For reference, here is the sketch (two steppers, no acceleration/deceleration and both stepper start/stop at the same time with different speeds/steps):

Code: [Select]
#include <AccelStepper.h>

AccelStepper spinning(1, 9, 8);
AccelStepper dispensing(1, 7, 6);

double spin_steps = 3200; // This sets the amount of disc rotation. 3200 is one full rotation (200 steps x 16 microsteps per step = 3200).
double spin_speed = 500; // This sets how fast the discs spin.

double dispense_steps = 5000; // This sets the amount of solvent dispensed.
double dispense_speed = dispense_steps * (spin_speed / spin_steps); // "dispense_speed" is calculated based on the three other parameters

void setup()
{    
spinning.setMaxSpeed(10000);  // Sets the maximum spinning speed. This value is far above any speed that the fixture will achieve, but is required to be defined by the program.
spinning.moveTo(spin_steps);  // Defines a step target for spinning.
spinning.setSpeed(spin_speed);  // Sets the speed (previously defined above).
dispensing.setMaxSpeed(10000);  // Sets the maximum dispensing speed. This value is far above any speed that the fixture will achieve, but is required to be defined by the program.
dispensing.moveTo(dispense_steps); // Defines a step target for dispensing.
dispensing.setSpeed(dispense_speed); // Sets the speed (previously defined above).
}

void loop()
{    
spinning.runSpeedToPosition(); // Instructs to spin at the "spinning_speed" (without acceleration or deceleration) to the "spinning_steps" target.
dispensing.runSpeedToPosition(); // Instructs to dispense at the "dispensing_speed" (without acceleration or deceleration) to the "dispensing_steps" target.
}




Go Up