Driving Stepper Motor with Variable Frequency PWM

I found a major contributor to the 715 microsecond delay. It's the stepper driver hardware! When I disconnect power to it, the delay is diminished! Tonight I'll put in an optoisolator! I've should have done this from the beginning. This is the driver I'm using:

http://www.amazon.com/SainSmart-Router-Single-Stepper-Stepping/dp/B008BGLOTQ/ref=pd_sim_indust_8?ie=UTF8&refRID=159TQHW5XHHKTVHN44NX

Overall, I like the DDS approach. I'm now able to change out the waveform in the lookup table so I can use it for other purposes. And I've learned about bitwise manipulation and binary math. I'm glad it was suggested by @MarkT.

The AccelStepper library is good, but not in a fixed time-step loop environment. This whole thread is for a robot project involving stepper motors to compensate an unstable condition. The feedback control system requires a fixed time step, so I'm very emphatic about this. I've been using regular motors, but they have very little torque at low RPM. The steppers have their highest torque at low RPM, so they are ideal for my situation. And because the steppers don't need gearboxes, they're actually a cheaper solution.

So I really need to make this work. Hopefully the optoisolator will solve the problem. If not, I have no problem dedicating a second CPU for this. Not sure what the fastest communication will be between the CPUs. Maybe I'll use the DAC on the main CPU, and the ADC on the DDS CPU. ADCs only requre 42 microseconds.

Those stepper drivers have slow opto-isolators,* they are designed for heavy-duty low rate CNC type setups. I can't see why that would cause a 715 us delay in the code though.

I am familiar with fixed time control loops, I work on motor control software. Our turbo pumps run around 100,000 RPM with 20 kHz PWM. I've also written control software for 3D printers, so I am familiar with driving stepper motors.

Obviously, a variable step algorithm can be converted to a fixed step, it is just a matter of maths, but it doesn't change the principle. Velocity is just an integral of acceleration.

  • This version claims to have high speed optos, so you should be good. Worth checking they have 6N137 fitted though.

bobcousins: I can't see why that would cause a 715 us delay in the code though.

The DDS function speed should be totally independent on whether or not the driver is powered. The function call rate is 16,384 Hz. Once it computes an amplitude (0 or 1 in my case) at the desired frequency, it calls the "digitalWrite" function and sets pin 22 at the proper state. This directly feeds the "step" port in the stepper driver.

Is a pull-up or pull-down resistor needed on m pin 22? Maybe pin 22 is a poor choice?

I'm very suspicious of the stepper driver. Not sure the driver inputs are truly isolated.

I found the source of my delay problem. The delay is not completely gone, but at least it's constant and that's important for my fixed time step project. The problem is the encoder. I put in the "Encoder.h" library to track the stepper position. When the stepper spins fast, the delay increase. When the stepper spins very slowly, the delay variability diminishes.

Adding optoisolators to the driver did not help. So then I looked at the encoder. What's happening here is that at higher RPMs, encoder ISR interrupts occur more frequently and therefore increases the delay. When the stepper is stopped, there are no interrupts, so no time delay. This is what I saw when I powered down the stepper driver.

Wow, not sure what to do next. Maybe I'll add another DueTimer object for the whole control system and have it sample at 200hz. Hopefully that won't interfere with my DDS function operating at 16,384 Hz. Anyone have other suggestions? Thanks.

Okay, I finally have a working control system with a clean fixed time step irregardless of the Encoder and Direct Digital Synthesizer. The key is to add another DueTimer object to serve as the control system clock for the main program loop. This object calls a very simple ISR function that sets a "beacon" flag at the desired rate (200hz in my case).

Originally I wrapped the main loop in "micros()" function calls at the start and end of the main loop to calculate how long the control system loop took. Then I used "delayMicroseconds" to add a small delay to force the control loop timing equal to the desired time step (0.005 sec). However, interrupts incurred by the Encoder disrupted this whole scheme. Using the "beacon" approach with the DueTimer eliminates that issue.

Of course, whatever "beacon" scheme is used, the duration of each control system loop must be less than fixed time step. Otherwise, the whole loop seizes.