Closed vaughanatworld closed 2 years ago
Interesting, thank you for the detailed report and the code samples. The library outputs the exact number of steps with move()
so there should be no drift in pulses.
I will try to replicate this. Until then, a possible explanation is the momentum of the motor pushes it one more step after the end, or the RPM is high enough that the motor misses steps at startup. Testing with a very low RPM and without load should show if this is the case. I see the test code uses a 400 step motor with 4 and 2ms steps, so it rotates at 37rpm and 75rpm, while the library is set at 100rpm.
A current setting that is lower than what the motor needs may also cause slippage, as it gives the motor less torque. I am not familiar with the TB6600 but it should have a way to set this.
Finally, the step impulse emitted by the library may be too short for the TB6600. The test code uses a 50% duty cycle so that's a very comfortable duration, but the BasicStepperDriver uses 1µs pulses. Will need to check the sheet for TB6600 to see what it needs. For example, DRV8834 needs 2µs and the library adjusted to that.
The stepper motors were unloaded and loaded. I was just looking at the flat of the D shaft to see the creep in both configurations. I noticed, on the first loop, the shaft rarely made all the way to 360 but usually made it back 360 on the second loop. This resulted in creep favoring the direction of the second loop. I had the same results on two separate motors (NEMA 23 sized, different manufacturers) and two separate controllers (TB6600 and an older design M5256 based on an STM32 and discrete mosfets). All 4 permutations had the same behavior.
The 400 step test was required on the M5256 controller because the minimum micro step was 2 on the configuration switches. I tried 200 and 400 on the TB6600.
Also I tried a variety of timer delays and speeds (not exhaustive) to see if things got better or worse. Engaged the enable pin or not. No change for any test.
I have a selection of stepper controllers for 3D printers that I can try. I believe I have some A4988s, DRV8834s, L297/L298 and at least one other type. If you have no success in duplicating the problem, let me know. I will try to duplicate your hardware setup at my end to run experiments.
I just realized the controllers I used have optical isolation (6N137, DP817C) where as the 3D printer controllers do not. Here is my TB6600 controller: https://www.amazon.com/gp/product/B07S64MBTR/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1 Is it possible the code has not been tested with optical isolators and associated timing requirements?
Optocouplers switch very fast, I do not think they would be a factor here with the relatively slow timings involved.
I found the datasheet for Toshiba TB6600 here: https://www.mouser.com/datasheet/2/408/TB6600HG_datasheet_en_20160610-771376.pdf
It shows a minimum clock pulse width of 2.2µs, so the 1µs pulse emitted by BasicStepperDriver is out of spec for this driver. You can try using the DRV8834 class without wiring the other pins, or modify these values in your copy of the library to see if it makes a difference.
I'm planning to use DRV8825 on STM32 with Arduino on a step critical application. Is this gonna be a problem for me? Do you have any other suggestions? (I didn't test mine to see if it drifts over time or not.)
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I have this same issue and have found that it has something to do with stepper.enable() and stepper.disable. If I put stepper.enable(); in setup, and comment out stepper.disable in the loop, the stepper doesn't drift. However, if the stepper is enabled and disabled in the loop, the stepper drifts several steps each rotation. Using the stepper without the library, it doesn't drift. Driver is DRV8825.
// This results in drift
`void loop() {
// energize coils - the motor will hold position
stepper.enable();
/*
* Moving motor one full revolution using the degree notation
*/
// 6400 = 1 rotation CW @ 32 microsteps
stepper.move(6400);
delay(1000);
/*
* Moving motor to original position using steps
*/
// -6400 = 1 rotation CCW @ 32 microsteps
stepper.move(-6400);
// pause and allow the motor to be moved by hand
stepper.disable();
delay(1000);
}
// This works without any drift
void loop () {
digitalWrite(DIR, HIGH);
digitalWrite(ENABLE, LOW);
for (long i = 0; i < 6400; i++) {
digitalWrite(STEP, HIGH);
delayMicroseconds(40);
digitalWrite(STEP, LOW);
delayMicroseconds(40);
}
digitalWrite(ENABLE, HIGH);
delay(1000);
digitalWrite(DIR, LOW);
digitalWrite(ENABLE, LOW);
for (long i = 0; i < 6400; i++) {
digitalWrite(STEP, HIGH);
delayMicroseconds(40);
digitalWrite(STEP, LOW);
delayMicroseconds(40);
}
digitalWrite(ENABLE, HIGH);
delay(1000);
}`
I suppose it has something to do with the stepper torque and the load on the stepper shaft. Usually, stepper motors have a lower torque on higher RPMs so when your stepper is loaded you should start rotation in lower RPM and then accelerate slowly to your desired speed or you may lose some steps along the way. It's the main reason for the "accelerate function" to be in this library in case you didn't aware of it. You may test with an unloaded stepper motor with a properly adjusted voltage and current for the stepper motor according to the datasheet of both motor and driver and then try to fix the motor on a chassis and then let it run back and forth for hours and then check for any step lose. Let us know if that works for you.
The issue for me is occurring while bench testing with nothing connected to the stepper.
@swappart Can you measure the error? like how many steps are getting lost during a rotation and is there any logical explanation or a relationship between steps taken lost steps and speed or code? or how frequent is the issue happening? a picture of the setup might help also. if there's an issue in the code, it should happen to all users, ain't it?
@sajjsamm thank you for helping out with this ticket. Unrealistic expectations of torque can indeed cause skipped steps, and may have for the other reports. For the last case reported by @swappart, I suspect signal timing, because of this comment which points to nENBL
signal as a possible cause:
If I put stepper.enable(); in setup, and comment out stepper.disable in the loop, the stepper doesn't drift. However, if the stepper is enabled and disabled in the loop, the stepper drifts several steps each rotation.
If the drift is small, it could could happen at the beginning of a loop where direction changes:
disable()
, DIR
is changed then STEP
is pulled up. This is reported to work fine.disable()
, nENBL
is pulled low, then DIR
is changed, then STEP
is pulled up. This loses (perhaps one?) step.DIR
-> nENBL
-> STEP
. This works despite being faster, and I don't have a good explanation why.The spec sheet requires only 0.65µs between nENBL/DIR and STEP.
Perhaps the problem is there isn't enough time between setting DIR and sampling it on rising STEP edge. I am thinking to ensure the timings are met even for the sub-microsecond intervals, because of faster cpus.
Actually, looking at the timings above, ensuring the enable()
/disable()
timings is needed when nSLEEP is used instead of nENBL with inverted logic, as it requires a lengthy 1.7ms delay to wake up and charge. It is not the case here, as the output is active LOW.
All of these timings are chip-dependent, and the very short ones may have parasitic capacitance to deal with as well, so it could help to be on the conservative side.
I'll get this project back out later and try to measure just how many steps it's missing. I'll also try to determine specifically when it misses steps. Is there any way I can test changing the delay time between nENBL and DIR, or alternatively, invert their order?
Adding a delayMicroseconds(1)
between these two lines should decalate STEP from DIR:
https://github.com/laurb9/StepperDriver/blob/master/src/BasicStepperDriver.cpp#L300-L301
The enable() already has a 2µs delay so it should be fine: https://github.com/laurb9/StepperDriver/blob/master/src/BasicStepperDriver.cpp#L349
What processor is this running on ?
@laurb9 I fixed it. Adding the delay between STEP and DIR didn't work, but adding it at the end of the disable function did. Processor is 328P BTW.
`void BasicStepperDriver::disable(void){
if IS_CONNECTED(enable_pin){
digitalWrite(enable_pin, (enable_active_state == HIGH) ? LOW : HIGH);
}
delayMicros(1); // Added this delay and solved the problem.
}`
@swappart This is interesting. disable()
is followed by a 1ms delay in your code, so I am at a loss to explain why adding an extra 0.001ms solves the problem...
@laurb9 I am confused by that as well. In any event, I appreciate the help. I wouldn't have figured it out without your suggestion.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Describe the bug Turn the stepper 200 steps clockwise, then 200 steps counterclockwise. Repeat. After a minute or so one can see the shaft home position creeping in one direction. Same behavior found in AccelStepper library. A simple nonlibrary implementation of the test shows no creep even after an hour.
To Reproduce Steps to reproduce the behavior: This creeps. Doesn't matter if one uses degrees or steps: /*
include
include "BasicStepperDriver.h"
// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
define MOTOR_STEPS 200
define RPM 100 //120
// Since microstepping is set externally, make sure this matches the selected mode // If it doesn't, the motor will move at a different RPM than chosen // 1=full step, 2=half step etc.
define MICROSTEPS 1
// All the wires needed for full functionality
define DIR 2
define STEP 3
//Uncomment line to use enable/disable functionality //#define SLEEP 13
// 2-wire basic config, microstepping is hardwired on the driver BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP);
//Uncomment line to use enable/disable functionality //BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP, SLEEP);
void setup() { stepper.begin(RPM, MICROSTEPS); // if using enable/disable on ENABLE pin (active LOW) instead of SLEEP uncomment next line // stepper.setEnableActiveState(LOW); }
void loop() {
}
Expected behavior This works:
include
/ Example sketch to control a stepper motor with TB6600 stepper motor driver and Arduino without a library: number of revolutions, speed and direction. More info: https://www.makerguides.com / // Define stepper motor connections and steps per revolution:
define dirPin 2
define stepPin 3
define stepsPerRevolution 400
void setup() { // Declare pins as output: pinMode(stepPin, OUTPUT); pinMode(dirPin, OUTPUT); }
void loop() { // Set the spinning direction clockwise: digitalWrite(dirPin, HIGH); delayMicroseconds(100); // Spin the stepper motor 1 revolution slowly: for (int i = 0; i < stepsPerRevolution; i++) { // These four lines result in 1 step: digitalWrite(stepPin, HIGH); delayMicroseconds(2000); digitalWrite(stepPin, LOW); delayMicroseconds(2000); } delay(1000); // Set the spinning direction counterclockwise: digitalWrite(dirPin, LOW); delayMicroseconds(100); // Spin the stepper motor 1 revolution quickly: for (int i = 0; i < stepsPerRevolution; i++) { // These four lines result in 1 step: digitalWrite(stepPin, HIGH); delayMicroseconds(1000); digitalWrite(stepPin, LOW); delayMicroseconds(1000); } delay(1000); }
Platform Setup (please complete the following information):
Additional context Add any other context about the problem here. If the library is supposed to only be used for speed control, this issue may not matter. If the library is supposed to support position control, then this is a problem.