Notifications
Clear all

Stepper acceleration

28 Posts
4 Users
2 Likes
2,748 Views
 GAM
(@gam)
Member
Joined: 3 years ago
Posts: 58
Topic starter  

Basic question on stepper acceleration. I posted my code below and it works as designed. However it has only been tested with a simple pointer.  The stepper that is installed on the actual project has trouble overcoming the inertia require to spin a disk. I tried to use the accelstepper library and can't get it to work at all (motor not attached to anything).  So I tried to just change the delay's that controls the speed and I'm able to get some movement out of it while attached to project. Using degrees the longest movement would be 180* (half a revolution).

So am I thinking right that increasing the delay time would give more torque since speed is not really an issue?  

Using stepperonline 23HS41-1804S,  Bipolar,  1.8amps/phase,  rotor inertia(g-cm/squared) 680.00

driver DRV8825  adj to 1.2ref/v,   p/s 20volts 2.25A

Code below and I know I write a little cryptic. I high lighted the area that pertain to speed.  If interested in the project I had a post earlier about using arrays,  I describe the project in more detail.

Thanks for any input

 

[code]

/*Auto Blast gate project: for dust collection in wood shop.
Arduino Nano
ACS712 current sensor
DRV8825 stepper driver with expansion card
Nema 17 stepper/Nema 23
Halls effect sensor
Homing routine is run at startup or reset to establish stepper position
Each tool will be monitor by a current sensor and when that analog port exceeds a given threshold
1. Rotate the stepper to a predetermined position to align ports for that tool.
2. After the gate is align a digital pin will drive relay to turn on Vacuum system.
Vacuum will stay on as long as sensor exceed the threshold while tool is running.
When tool stops vacuum will continue for 4 seconds to clear remaining dust.
3. If the same tool is used next, the Stepper will remain in it's current position.
But the vacuum system should still operate the same.
4. currently using buttons to simulate tools and also one ACS712 for testing */

#include <MobaTools.h>

// defines pins numbers
const int stepPin = 3;
const int dirPin = 2;
const int enPin = 8;
const int vacPin = 4;
const int halPin = 6;
MoToTimer vacTimer; // for delayed switch off
const long runOnTime = 3000; //time for vac delay adjustable

int ca = 0; //currentAngle
int na = 0; //angle
int stepPerAngle = 5 / 9; // full step = 1.8 or could have used "*1.8"
int numstep;
int analogValue = 0;

void homefunction() {

// Set motor speed pulse duration
int pd = 2000;
int numstep;
// Move motor until home position reached
while (digitalRead(halPin) == 1) {
//digitalWrite(EN, LOW);
digitalWrite(dirPin, LOW);
digitalWrite(stepPin, HIGH);
delayMicroseconds(pd);
digitalWrite(stepPin, LOW);
delayMicroseconds(pd);

}
for (int i=0; i<7; i++){
digitalWrite(dirPin, LOW);
digitalWrite(stepPin, HIGH);
delayMicroseconds(pd);
digitalWrite(stepPin, LOW);
delayMicroseconds(pd);
}
//(digitalRead(halPin)!=1) {
//(numstep=25);
}

 

void setup() {
Serial.begin(9600);

// Sets the 3 pins as Outputs
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enPin, OUTPUT);
pinMode(vacPin, OUTPUT);
pinMode(halPin, INPUT);

//set values for 3 outputs
digitalWrite(enPin, LOW);
digitalWrite(dirPin, HIGH);
digitalWrite(vacPin, LOW);

//home the motor
homefunction();

}

void loop() {
int n;
analogValue = 0;

// Assign button degrees section
if ( analogRead(A0) > 600) {
analogValue = (analogRead(A0));
Serial.print("AO = ");
Serial.println(analogValue);
na = 0;
}

else if ( analogRead(A1) > 600) {
analogValue = (analogRead(A1));
Serial.print("A1 = ");
Serial.println(analogValue);
na = 45;
}

else if ( analogRead(A2) > 600) {
analogValue = (analogRead(A2));
Serial.print("A2 = ");
Serial.println(analogValue);
na = 225;
}

else if ( analogRead(A3) > 600) {
analogValue = (analogRead(A3));
Serial.print("A3 = ");
Serial.println(analogValue);
na = 270;
}

// vacuum control section

if(analogValue > 600 && ca==na) {
digitalWrite(vacPin, HIGH);
}

if ( vacTimer.expired() ) {
// switch off vac if timer expires
Serial.println( "Vac = off");
digitalWrite(vacPin, LOW);
}

if (analogValue < 600 && digitalRead( vacPin ) && !vacTimer.running()) {
// start timer to switch off vac after time
Serial.println( " start vac run-on-time" );
vacTimer.setTime( runOnTime );
}

// this section just determines stepper direction (CW/CCW) and steps
if ( ca != na ) {

//1st SCENARIO
if (na - ca > 0 && na - ca <= 180)
{ digitalWrite(dirPin, HIGH);
n = ((na - ca) * 5 / 9);
numstep = n;
ca = na;
}

//2nd SCENARIO
else if (ca - na > 0 && ca - na > 180)
{ digitalWrite(dirPin, HIGH);
n = ((na + 360 - ca) * 5 / 9);
numstep = n;
ca = na;
}

// 3rd SCENARIO
else if (na - ca < 0 && na - ca <= 180)
{ digitalWrite(dirPin, LOW);
n = ((ca - na) * 5 / 9);
numstep = n;
ca = na;
}

//4th SCENARIO
else if (na - ca > 0 && na - ca > 180)
{ digitalWrite(dirPin, LOW);
n = ((ca + 360 - na) * 5 / 9);
numstep = n;
ca = na;
}

//stepper control and speed

for (int x = 0; x < numstep; x++) {

digitalWrite(stepPin, HIGH);
delayMicroseconds(1000);
digitalWrite(stepPin, LOW);
delayMicroseconds(1000);
}

// do I need this??
delay(200);
}

}

[/code]


   
Quote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2504
 

Changing delay will change speed, but probably won't affect torque. You can try increasing the voltage to the steppers, that should increase torque.

Anything seems possible when you don't know what you're talking about.


   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2504
 

A sure way to increase torque (especially if changing position isn't a major problem) would be to add a gear or GT2 pulley to the disk's axle and use another gear or GT2 pulley to drive it.

 

The increase in torque (assuming no loss from the gear) would be the ratio of gear teeth For instance with a 60 tooth GT2 pulley on the disk and a 20 tooth pulley on the stepper motor, the motor would effectively provide (60/20 =) 3 times the torque; albeit at 1/3 of the speed.

Anything seems possible when you don't know what you're talking about.


   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2037
 

   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1608
 

Hi @gam,

I don't know much about stepper motors, but a couple of unrelated thoughts/points.

..........

I am not a mechanical engineer, just someone trying to remember some basics, so I am hoping an expert can improve on my vague thoughts...

Have you thought about measuring/estimating the actual torque required for your application?

In the absence of any 'specialised' tools, I was thinking of temporarly attaching a short lever to the spindle of the object you want to rotate, and measuring the force at the free end of the lever required to cause the rotation .. possibly by using some sort of spring balance or even the weight of an object. Then, by knowing the length of the lever, and the force applied to cause it to rotate, you can calculate the applied torque.

Compare this value, with the expected motor torque, allowing a generous 'experimental error' if your measurement is on the crude side.

If the torque needed to rotate is either much more, or much less, than you should expect from the motor, then you will have some guidance as to whether you may need to change your design, or if the motor is underperforming for some reason.

Of course, if the required torque and expected torque are about the same, then the position is less clear, but maybe you should consider whether the torque requiremnt is likely to increase when dust, etc. have accumulated with usage.

If you think the motor is underperforming, maybe consider estimating the torque that the motor is producing, possibly by seeing if it is able to lift a known weight on the end of a string. Again a level attached to the motor spindle may be appropriate.

......

And a line of code, which you are probably not using yet, but concerned me for the future was:

int stepPerAngle = 5 / 9; // full step = 1.8 or could have used "*1.8"

Obviously this might just be be a one-off typo, but just in case, "int" can only take an integer number. So stepPerAngle cannot become equal to 1.8

In this case, the danger is fairly obvious, but sometimes similar 'unexpected' results in the middle of a mathematical expression can appear. Often the C compiler will 'upgrade' integers to floats automatically but occasionally it all goes wrong and it can be very difficult to spot.

..........

Best wishes.


   
ReplyQuote
 GAM
(@gam)
Member
Joined: 3 years ago
Posts: 58
Topic starter  
Posted by: @davee

And a line of code, which you are probably not using yet, but concerned me for the future was:

int stepPerAngle = 5 / 9; // full step = 1.8 or could have used "*1.8"

Obviously this might just be be a one-off typo, but just in case, "int" can only take an integer number. So stepPerAngle cannot become equal to 1.8

@davee

Thanks for your reply,  I have thought about measuring the the torque required and that may need to be done. I have been using the system manually and haven't seen any significant amount of dust build up.

As for your concern about the above quote, That is only used to convert the steps needed to degrees.  I have been using this on my test jig and works OK.      


   
ReplyQuote
 GAM
(@gam)
Member
Joined: 3 years ago
Posts: 58
Topic starter  

@will

I have up the voltage to 40 and didn't see a big change.  My thinking was in the accelstepper library document I thought I understood that by starting slow and building up speed would reduce skipping steps. The same with deceleration so you don't overshoot the stopping point. 

I may have that wrong,  it may be taking smaller steps and increasing step size as it accelerates.


   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2504
 

@gam

I think that's right, trying to start off with a high speed overwhelms the stepper motor. But using acceleration allows it to start at a lower speed and then speed it up gradually as the disk starts spinning.

The disk will need to use the torque to overcome the static friction when it first tries to turn the disk as well as overcoming the inertia of the disk. Can you feel how much extra force it takes to start the disk moving when you use your hand to spin it ?

How are the disk and the stepper connected ? Is the disk clamped directly onto the stepper's shaft ? If so, you may need to get a more powerful stepper motor.

I've used the accelstepper library a lot in the past and it does work. I made a drum plotter and used a NEMA17 to turn the drum (13" of 100mm ABS drainpipe plus 3D printed end caps plus fibreglass axle rod) and that was a little slow spinning the disk, had some tuning to do.

Anything seems possible when you don't know what you're talking about.


   
ReplyQuote
 GAM
(@gam)
Member
Joined: 3 years ago
Posts: 58
Topic starter  

@will

It is connected straight to the shaft.  If I let it try to home (with the sensor disconnected)  it will turn and build up speed.  I also have the disk spring loaded to keep pressure on it.  Been playing with reducing the pressure.

Not sure why I can't get the accelstepper to work.  I tried it with the driver and stepper only.  It loads with no errors but just sit there.  I may need to check on the enable pin setup.

Thanks


   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2504
 

@gam

Why do you need to spring load the disk ?

If you try accelstepper again and it still doesn't work, please post the code so I can take a look at it. Maybe I can help you get it working.

One other quick thing to try is to increase the delay time from 1000 micros to about 10 mills and see if that makes any difference.

Anything seems possible when you don't know what you're talking about.


   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2504
 
Posted by: @gam

@will

Not sure why I can't get the accelstepper to work.  I tried it with the driver and stepper only.  It loads with no errors but just sit there.  I may need to check on the enable pin setup.

This code is for a NEMA17 with an A4988 motor control. I believe that the DRV8825 has an identical pin layout, but haven't used one so I'm not sure.

Here's what I use ...

//
//    Define pins for stepper motors and step multipliers
//
#define LDIR 4
#define LSTEP 5
#define LENA 6
#define LMULTISTEP 1

//
// Stepper motors objects
//
AccelStepper stepperX(1,LSTEP,LDIR); // Left stepper motor

//
// Utility to set up stepper motors consistently
//
void setupStepper( AccelStepper &motor, int enablePin )
{
motor.setSpeed(100); // Initialize
motor.setMaxSpeed(500); // Set speed
motor.setAcceleration(30); // Set acceleration
motor.setEnablePin(enablePin); // Set it
}

In setup ...

pinMode(LENA,OUTPUT); // Declare enable pins
 
//
// Set up stepper motors
//
setupStepper(stepperX,LENA); // Setup stepper motors
 
Invert to correct direction (easier than shifting wires) and enable pin operation
 
stepperX.setPinsInverted(false,true,true);

 

Enable and disable stepper

stepperX.enableOutputs();
stepperX.disableOutputs();

Motion

stepperX.moveTo(newX);
... in loop() ...
if (stepperX.distanceToGo()==0 && stepperY.distanceToGo()==0 ) {
... steppers have finished moving, interpret next command ...

 

Hope this helps.

Anything seems possible when you don't know what you're talking about.


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1608
 

   
ReplyQuote
 GAM
(@gam)
Member
Joined: 3 years ago
Posts: 58
Topic starter  

@davee

Never occur to me to try a torque wrench.  That's a good thought.

Thanks for the programming info.  If I follow what your telling me, my program will work but might be slower the way I wrote it?

The rest was way over my head.  I did enjoy the history lesson on why C got to where it is. 

Thanks


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1608
 

Hi @gam,

  Good luck if you try to use the torque wrench .. please be careful not to injure yourself.

----------------------------------------------------------

Unfortunately, this software problem is very dull and geeky, but also important, so I recommend you try to figure it out, otherwise it will continually bite you in the future. Sorry, this will need a good deal of your patience.

----------------------------------

  As for the code line of yours that I looked at  

int stepPerAngle = 5 / 9; // full step = 1.8 or could have used "*1.8"

... I didn't spot a place in your program code actually that used the variable stepPerAngle, so presently it may not matter what value is in it.

----------------------------------------------

What I did was to transplant your line into a very simple sketch that printed out its value to demonstrate you would have a problem if your program used it.

The printed output showed that the value was zero. I guess you thought it would be 5/9 as a fraction roughly 0.5555

13:43:28.589 -> stepPerAngle = 0 

---------------------------------------------

So I then explored why it was zero. It turns out there are two different errors, both of which cause the same problem!

--------------------------------------------

The first error related to "int" at the beginning of the line.

int stepPerAngle says to the compiler, create a 'box' called stepPerAngle, that hold a single integer. Integers are sometimes called 'whole numbers' and examples include -35, -2, -1, 0, 1 and 2, 45, 2004.

Thus this 'box' can remember a number like 0 or 2, but not 0.5 or 1.5. If you tried to put 0.55 into the 'box' you will either get an error, or the value will be 'rounded down' to the nearest integer value, which happens to be zero.

The fix is to specify a different type of 'box' ... in C a common choice is "float". A"float" type of 'box' is capable of holding a floating point number, like -45.7, -0.567, 0.0, 0.55,  or 1,987.54

So the fix is to start the line

float stepPerAngle

-----------------------------------------

Now we have the right type of 'box' to hold a number like 0.5555, but unfortunately the "5/9" also has a problem -- to humans it looks like it is approximately 0.5555, but to a C compiler it is zero!!

To demonstrate this, I added a slightly modified version of your line, which used "float". I also made a new variable name or 'box' stepPerAngle_mixed, so that it didn't get muddled with the first 'box'. Hence my line and the resulting print were:

 float stepPerAngle_mixed = 5 / 9; // full step = 1.8 or could have used "*1.8"

13:43:28.589 -> stepPerAngle_mixed = 0.000000

 

So what is wrong with "5/9". Well it is the compiler doing what you asked ... not what you wanted!

The compiler has a choice of at least two software routines to select from when asked to divide one number by another.

  1. Integer divide ... which produces an integer number result
  2. float divide ... which produces a float result

Let's consider each routine in turn

Look at some integer divide calculations and their results :
1/4         will produce 0
3/4         will produce 0
4/4         will produce 1
6/4         will produce 1
8/4         will produce 2

So if it divides exactly, such as 8 divided by 4 gives 2, then it behaves as you might expect, but if it divides with a remainder, such as 6/4 is 1 remainder 2, then the remainder is forgotten, just leaving the 1.

By comparison the float divide works more like the way you might expect
1/4         will produce 0.25
3/4         will produce 0.75
4/4         will produce 1.0
6/4         will produce 1.5
8/4         will produce 2.0

------------------

So hopefully you can now appreciate there are two possible choices for the compiler, the next question is which one does it pick.

Well it looks to see what it is 'told'. So far as it is concerned "5" and "5.0" are not the same! "5" is an integer of value 5, and "5.0" is float of value "5.0"

And if the compiler thinks if:

  • it is dividing an integer by an integer, then it will use the integer division routine
  • it is dividing a float by a float, then it will use the float routine

----------------------------------------------------------------------------------------

In my example above, it was 5 divided by 9, which is integer divided by integer, and integer division of 5 divided by 9 is zero.

The fix is to make sure the numbers are both floats. This was the third version of your program line:

float stepPerAngle_float = 5.0 / 9.0; // full step = 1.8 or could have used "*1.8"

which results in the expected print out:

13:43:28.589 -> stepPerAngle_float = 0.555556 

------------------------------------

I am sorry that is very long and frankly, quite difficult to understand. However, I hope you will persevere to make sense of it. Please feel free to ask about any bit that is still confusing.

The other bit of my code example attempted to demonstrate what would happen if you tried to use the stepPerAngle, and my variations in a subsequent bit of program. Hopefully you will now be able to follow it.

Thanks for your patience. Good luck.


   
ReplyQuote
 GAM
(@gam)
Member
Joined: 3 years ago
Posts: 58
Topic starter  

@davee

Thanks for the info.  I agree that I need to understand this better. I appreciate the time you spent explaining this.  I sort of understand the floating part.  In my case, since the program appears to work correctly (other than the power issue related to load).  

I have no doubt that you understand coding far better than me. I think I may need to explain what my code does. The below piece of code just reads a current sensor connected to A3 (analog pin A3) if the statement is true it assigns (in this case) na (new angle) the setting of 270 degrees.

There will be 8 positions in all each with its own degree setting.

 

else if ( analogRead(A3) > 600) {
analogValue = (analogRead(A3));
Serial.print("A3 = ");
Serial.println(analogValue);
na = 270;
}

 

With na now determined the next section on code below compares na to ca (current angle).  It uses that info to decide the shortest route (CW or CCW). Then it does the math in question, (new angle - current angle) this result is in degrees so we need to calculate how many steps that is.  So if the current angle (ca) is 45 degrees and the new angle (na) is 270 in this case.  270-45= 225 degrees.  I need to convert that in steps.  The stepper is 1.8 degrees per step so 225 X 5/9=125 steps.   Or 225 / 1.8 = 125.  After that new angle is changed to current angle for a new position if needed.

 

//1st SCENARIO
if (na - ca > 0 && na - ca <= 180){
digitalWrite(dirPin, HIGH);
n = ((na - ca) * 5 / 9);
numstep = n;
ca = na;
}

//2nd SCENARIO
else if (ca - na > 0 && ca - na > 180)
{ digitalWrite(dirPin, HIGH);
n = ((na + 360 - ca) * 5 / 9);
numstep = n;
ca = na;
}

Hope that make sense and I not sure if it changes what your explaining to me?

Thanks


   
ReplyQuote
Page 1 / 2