Stepper motor missing steps on change of direction using AccelStepper library

Some back ground before I get into the details of the specific problem

Our model railway club has been working on building an HO scale turntable for a roundhouse and we are using a stepper motor to control the movement of the bridge of the turntable. We are using a Uno with a key pad to select the track that turntable bridge is rotate to. The stepper motor is a Longruner 17HS4401 controlled by a Stepperonline Driver, a DM542T and we are using a regulated power supply for the driver. There is no gear box attached to the motor shaft. There is a sensor attached to the turntable to provide a means to calibrate the stepper motor system to one of the tracks and to home it every time we start up the system.

In general I have been able to perform calibration, home and execute index movements of the stepper motor for the turntable movements successfully and accurately with one exception. We have set the dip switches on the driver to specify that the motor will have 6400 steps. We require this fine resolution so that we can calibrate the home track precisely to the bridge track. After that it is simple math to calculate the location of a track. We have 40 tracks around the turntable pit and we have decided to lay the track so that they are all an equal distance/angle to each other. So to move the bridge one track over we only need to move 160 micro steps ( 6400 / 40 = 160 ) to the next track.

Here's the problem.

After we have calibrated the system to find the home track, we are able to consistently and precisely move the bridge to the home track on start up of the system and always be able to index the turntable to the next track and further one or more tracks in the "clockwise" direction. However when the direction is changed and we go counter clockwise any multiple of 160 steps we are always short on the first CCW movement and it is always short by the same amount as long as we keeping going counterclockwise, no matter how many tracks we move. If we change direction again to clockwise we are short even more for the track we are moving to, but again we are consistently short the same amount if we keep going clockwise.

To compensate I added an adjustment to the movement and added 5 steps to the multiple of 160 step ( 5 + ( #tracks to move x 160 ) movement on a change of direction for the first movement in that direction. After that if a movement is made in the same direction I only calculate multiples of 160. It seemed to work, however when I tested some more on a change of direction where the movement is large.. say 3040 steps, or close to 180 degrees it appears my compensation does not work.

I have used the serial monitor to check how many steps I am telling the stepper motor to move before I added the 5 step adjustment. In the serial monitor I see correct multiples of 160 being used in the stepper.move() operations and when a change of direction occurs multiples of 160 are used but the actual motor move is short about 5 steps. So my 5 step adjustment is compensating for the stepper motor, program, system... missing 5 steps on change of direction.

So what is causing the consistent 5 step error? Why on larger moves 5 step compensation does not work. Is it code? Is it hardware?....I hope its code.

Here are the bits of code, I think are relevant. I've attached the full code below

I will provide schematic circuit diagram later, if required to diagnose the problem.

#include <AccelStepper.h> // I'm using version 1.57
AccelStepper stepper( AccelStepper::DRIVER, 4, 5 );

#define STEPSPERREV 6400 // matches the driver dip swithces used in a number of calculations
#define FULLSPEED 45.0

stepper.setAcceleration( 30.0 );

void loop()
....

stepper.move( StepsToMove ); // Calculated multiples of 160 ... if change of direction I add or subtract 5 steps to compensate for missed steps

.....
if ( isRunning
&& stepper.distanceToGo() != 0
&& stepper.speed() != 0 )
{ counter = 0;
stepper.setMaxSpeed( FULLSPEED );
while ( stepper.distanceToGo() != 0
&& stepper.speed() != 0 )
{ stepper.run();
++counter;
remainder = counter % 8; // Read the key for a stop command every 8th step. Reads are expensive and we don't want to do it too often
if ( remainder == 0 )
{ key = lcd.read(); // Read a key every 8th iteration to see if we want to force a stop
if ( key == '#' )
{ ForcedStop();
break;
}
}
}
....

YRM_Turntable_G2_V0.52.ino (27.4 KB)

It would be a big help if you could write a short program that illustrates the problem - there is a lot of stuff in your 27K program that is probably irrelevant.

I notice that you are stopping the motor simply by stopping the calls to stepper.run(). That is not the correct way. You should call stepper.stop() which calculates a new end point to allow the motor to decelerate without missing steps and then continue calling stepper.run() until the motor actually stops - indicated by stepper.distanceToGo() = 0

On the other hand if the motor is moving so slowly that acceleration is not needed then I would use stepper.runSpeed() which does not use acceleration.

Another thought is that the problem is due to backlash in your system. If that is the case then your program needs to add an appropriate number of extra steps to the move whenever the direction changes. I've done this with a small CNC lathe conversion and with an allowance for backlash I can get accuracy in both directions of about 0.02mm

I presume you have correctly set the current limit on your driver so it matches you motor.

...R
Stepper Motor Basics
Simple Stepper Code

The obvious potential issues are acceleration, micro stepping and backlash.

I've had trouble with micro steps impacting accuracy even always going CW, especially when using the largest number of steps the driver can give you. You're comfortably in the low end, but it may still be impacting your holding torque.

The fact that long moves defeat your 5 step adjustment again suggest that you're dropping steps - micro stepping again is the culprit perhaps. This also implies that acceleration issues aren't the cause, though it's worth give the motor more time stopping as an experiment and implementing Robin2's suggestion.

I suggest though that you go back to basics on the code and write the simplest test code you can manage. I spent a lot of time debugging a stepper driven system where we were certain that the issue was in the code somewhere, but it eventually transpired that we could not reliably drive the stepper.

Since long distance moves are problematic, how about 6400 steps CW and then come back the same CCW. I expect it will be off, but how much and does the error accumulate?

Robin2:
I notice that you are stopping the motor simply by stopping the calls to stepper.run(). That is not the correct way. You should call stepper.stop() which calculates a new end point to allow the motor to decelerate without missing steps and then continue calling stepper.run() until the motor actually stops - indicated by stepper.distanceToGo() = 0

Yes I do allow the operator to arbitrarily stop the motor while it is moving. I tested this and I ask where the new location is using currentPosition(), and when I start up again and calculate steps to move it seems to index correctly, but I will add the stop command as you suggested and see what happens.

Also are you also saying that I should execute the stop() operation after exiting the while loop even though distanceToGo() is already equal to zero and excute run() a few more times?

Robin2:
On the other hand if the motor is moving so slowly that acceleration is not needed then I would use stepper.runSpeed() which does not use acceleration.

I didn't want to use run speed since as I understand it you can't interrupt the movement. If the operator realizes that he made a mistake, he can't stop and try again until the full movement is completed.

Robin2:
I presume you have correctly set the current limit on your driver so it matches you motor.

Hmmm. I'll have to verify this.
And thanks for reading and giving me some ideas. I'll let you know what happens.

wildbill:
Since long distance moves are problematic, how about 6400 steps CW and then come back the same CCW. I expect it will be off, but how much and does the error accumulate?

I'll try and see if I can do a full rotation. But it would require changes to the code. Right now the program figures out which way is the shortest move to a track. There is no track indexing command that will allow a full 360 turn. At the moment the program only allows you to do a index move of up to 180 degrees. I'll do some 180s and see what happens.

acuksts:
I'll try and see if I can do a full rotation. But it would require changes to the code. Right now the program figures out which way is the shortest move to a track. There is no track indexing command that will allow a full 360 turn. At the moment the program only allows you to do a index move of up to 180 degrees. I'll do some 180s and see what happens.

I'm suggesting that you write a new program that just does the 360s to help figure out where the problem lies. Obviously you can use definitions from your main code, but you should end up with something short that will be easier to debug.

acuksts:
I didn't want to use run speed since as I understand it you can't interrupt the movement. If the operator realizes that he made a mistake, he can't stop and try again until the full movement is completed.

runSpeed() is equivalent to run() except that it does not use acceleration. It is runSpeedToPosition() and runToPosition() that can't be interrupted.

...R

wildbill:
I'm suggesting that you write a new program that just does the 360s to help figure out where the problem lies. Obviously you can use definitions from your main code, but you should end up with something short that will be easier to debug.

I strongly support this suggestion. When you run into a problem the first step should be to simplify.

...R

I changed the driver amps to match the motor's current spec. Motor spec says rated current is 1.7A. I set the driver dip switches to 2.37A Peak / 1.69 RMS.

No change in results. Same number of steps missed on change of direction... more...or... .less! when going longer distances.

I can try configuring the driver current up one more notch. The next notch up is 2.84 Peak / 2.03 RMS.

I tried runSpeed() instead of run(). Had to change the speed parameter to - or + depending on the direction .

No change in results.

I added a bit of code to execute the run() command 5 more times in a for loop after the while loop. Even though I execute run() operations in the while loop when distanceToGo() != 0 && speed() != 0 )

No change in results.

I changed the pulse width and made it longer. The driver specs says 2.5 uS minimum. I set it to 3 ...setMinPulseWidth( 3 ),

No change in results.

Perhaps I can increase it and see if that makes a difference.

If the bridge was off by 5 steps every time on change of direction we could live with it, and compensate but its not consistent on longer moves. I tried 180 and back again leaving the 5 steps adjustment in and it over shot the track coming back to the original position which means less steps were missed.

Could it be that the motor we are using just can't be be pushed to 6400 micro steps? We need 6400 since that gives us at the edge of the bridge about a .0075 inches of movement per step which will be good enough to calibrate the home track. 3200 will give us .015 inches per step. This is not good enough unless we are lucky. The driver spec says it can do 25600 for a 1.8degree step motor. So I don't think there is an issue with driver since we are not pushing it to the limit.

I'll try some 360 tests. And see what happens.

It may simply be that the motor can't reliably turn the table in that micro stepping mode. Lack of torque or perhaps there are spots on the rotation where there is more resistance. If so though, you probably have more than one problem given the 5 step issue on reversing. 360 tests should help figure it out.

Well I tried some 360 degree tests starteing a the home track as suggested. It appears that it is overshooting by 10 to 15 steps! Tried it a number of times clockwise. Same result. I have yet to try it counterclockwise. I did verify that I was setting the moveTo operation to 6400 before I started the run while loop. using the output from the serial monitor as evidence.

So is it possible that extra steps can be added through some sort of interference due to wiring, voltage or current issues or just a poor quality motor.?

Maybe we just need to spend more money on a higher quality motor.

If you're doing too many steps, I would suspect that the momentum of the table is causing it. Maybe your acceleration settings need tweaking. I would write something that steps slowly without the library and see how the accuracy is. Not that there should be any issue with the library.

acuksts:
Well I tried some 360 degree tests starteing a the home track as suggested. It appears that it is overshooting by 10 to 15 steps! Tried it a number of times clockwise. Same result. I have yet to try it counterclockwise. I did verify that I was setting the moveTo operation to 6400 before I started the run while loop. using the output from the serial monitor as evidence.

So is it possible that extra steps can be added through some sort of interference due to wiring, voltage or current issues or just a poor quality motor.?

Maybe we just need to spend more money on a higher quality motor.

Starting at the bottom ...

I would not waste money looking for a better motor. Stepper motors are fairly simple and I doubt very much that the fault is with your motor.

Extra steps are very unlikely to be generated by interference - I would ignore that line of enquiry for now.

Try moving the motor slowly with single stepping where you can physically count the steps. Single stepping is unlikely to be accurate enough for aligning with your other tracks, but it should bring you very precisely back to the original track And trry it with direction changes. (By the way if it was my project I would align the other tracks with full-step positions because, even with microstepping for smoothness the full-step positions will be more accurate)

If the single stepping works then try it with higher levels of microstepping. Debugging must be a systematic process moving gradually from a working situation into exploratory territory.

Also keep in mind that if the system is repeatable with reliability it does not matter whether it needs 6400 steps or 6388 steps.

...R

In my testing there is conflict in errors.
Short moves, no errors,
Change of direction, error of 5 steps short, fixed by adding steps to compensate
Long moves no change of direction, over shoot.

I’ve been reading specs for drivers, and they all talk about the concern of signal interference. They all say the signal wires should be shielded. Attached is a photo of where our Arduino board is situated that controls the turn table. Those other wires you see around the board have a DCC (Digital command control) current running through them. DCC is a model railway system to control engines an other devices. It’s a low voltage way to delver power and instructions through a low frequency AC square wave to decoders running the engines.

We are going to make the effort to move the arduino board and driver away from all this electrical clutter and wire them using shielded cable, and see if it helps improve some consistency of results that I can adjust for. Once done I’ll do the long rotation tests in both directions and see what happens.

Thanks for the input and I’ll let you know what the results are.

acuksts:
I’ve been reading specs for drivers, and they all talk about the concern of signal interference.

It would certainly be a good idea to isolate the wires and perhaps use twisted pairs (each pair carries signal and GND).

However the fact that your errors seem to be systematic rather than random suggests to me that interference is not the problem. And you could easily do some tests with the DCC system turned off.

I presume your comments in Reply #14 are based on a simple test program. Please post the program and provide details of each of your tests.

...R

Well it looks like we figured what was causing our problems. Here is the rest of the story

We spent a lot of time cleaning up the wiring, separating the DCC power bus from the stepper motor wiring and installed shielded wire that is grounded for all the stepper motor wiring. This actually improved the reliability and precision a bit with less steps missed but still not good enough. Still no consistency of results.

We replaced the motor with another that was the exact same model and manufacture. It performed worse!

Finally we replaced the Longruner 17HS4401 200 step motor with a A Wantai model 42BYGHM809 400 step motor and changed the program to remove all compensation code for missed steps..

Problem solved!

Short moves, long moves, 360 moves, clockwise, counterclockwise... indexing is consistent and precise.

So the 200 step motor we choose could not be pushed to 6400 micro steps. Perhaps there are 200 step motors that can do 6400 micro steps but the one we choose couldn't do it.

In this case spending just a few bucks more on a better motor solved the problem.

acuksts:
Finally we replaced the Longruner 17HS4401 200 step motor with a A Wantai model 42BYGHM809 400 step motor

That suggests to me that the original motor did not have sufficient torque for the job or the system was configured in such a way that it could not produce its design torque.

...R

Robin2:
That suggests to me that the original motor did not have sufficient torque for the job or the system was configured in such a way that it could not produce its design torque.

...R

I checked the specs on both motors the detent and holding torques are close, the current is exactly the same 1.7A and the phase resistance is close too, 1.5 vs 1.8. The voltage to the driver was not changed. The current setting configured in the driver for the motor was not changed either.
I'm not an engineer or know much about stepper motors, but my naive observation is the difference is the quality of the motor.

acuksts:
I'm not an engineer or know much about stepper motors, but my naive observation is the difference is the quality of the motor.

I don't have access to your motors so I can't comment on their quality.

However a stepper motor is a very simple thing and it is hard to see how it would not work reliably unless it has a specific fault.

...R