Thursday, March 17, 2011

Naive Acceleration

Last post I wrote about how the motor action was not smooth. I made a number of guesses about what was wrong. I looked into resonance and was pretty sure that was it since my motors are just sitting on the bench and have no load on them. I also suspected my acceleration algorithm. Back in January I wrote about how I would handle acceleration in the host software. A graph of speed against time is a straight line. This is known as "constant acceleration". I figured I'd start with a certain large time value between steps and knock it down by a constant amount for each step taken until I got to the minimum time between steps. That constant amount is the "constant" in "constant acceleration", right? Not quite.

The RepRap project has several lineages of firmware doing GCode interpreting / stepper motor control. Most use a constant acceleration method. This page here describes approaches to acceleration:
The official FiveD firmware changes speed by a fixed amount each step, however this also alters the step time. Acceleration = dv/dt, so with a fixed dv but a changing dt, acceleration changes during a move. This makes high speeds quite unattainable as the acceleration quickly outstrips the motor's ability to keep up.
I'm pretty sure that's the problem I have going on. If the slowest speed has, say, 20,000 microseconds between steps and each step we knock off 1,000, eventually we'll work our way down to 2,000 microseconds between steps. Then we knock off 1,000 and *poof* we've just asked the stepper to double its speed in one step. I think that's a pretty easy way to see the problem. We know that an object in a vacuum falls at 9 something meters per second per second. A graph of time vs distance would be a logarithmic or exponential curve. We want a straight line. I kinda feel like an idiot now.


Here's the portion of the code which changes the speed:

// perform constant acceleration
if (period < targetPeriod) {
period += PER_STEP_PERIOD_CHANGE;
if (period > targetPeriod) period = targetPeriod;
if (period > MAX_PERIOD) period = MAX_PERIOD;
} else if (period > targetPeriod) {
period -= PER_STEP_PERIOD_CHANGE;
if (period < targetPeriod) period = targetPeriod;
if (period < MIN_PERIOD) period = MIN_PERIOD;
}
Timer1.setPeriod(period);

I wrote a Java/Processing app to graph the period. The above code looks like this:


You can see the sharp upward curve. Near top speed I'm asking the stepper to to make advances in speed that are very large compared to the current speed. (I'm really doing "speed" in the reverse, faster speeds are generated by shorter pauses between steps.)

The RepRap link above references another article here which seems to be what a lot of microcontrollers base linear acceleration on. There's a lot of fancy math symbols and stuff there. I made it through calculus in college but it wasn't easy. I'm not really motivated to work through it. I figured the RepRap firmware already has an implementation of this so I'd just rip it off. But it's not all that easy to wade through someone else's code. But then I got this idea. Rather than reduce the current period by a fixed amount per step, I'll reduce the period by a value that's proportional to the current period.




// perform constant acceleration
long change;
if (period > UPPER_PERIOD_SPLIT) change = map(period, MAX_PERIOD, UPPER_PERIOD_SPLIT, 500, 50);
else change = map(period, UPPER_PERIOD_SPLIT, MIN_PERIOD, 50, 1);
if (period < targetPeriod) {
period += change; //PER_STEP_PERIOD_CHANGE;
if (period > targetPeriod) period = targetPeriod;
if (period > MAX_PERIOD) period = MAX_PERIOD;
} else if (period > targetPeriod) {
period -= change; //PER_STEP_PERIOD_CHANGE;
if (period < targetPeriod) period = targetPeriod;
if (period < MIN_PERIOD) period = MIN_PERIOD;
}
Timer1.setPeriod(period);





This produces a graph like so:


That's a pretty straight line! You might notice the split thing. The straight map still produced a slight lift at the top end. I split the range to compress the values at the top and straighten it out. I tested it out this evening driving the real motors and it's quite nice. I have the 3 steppers on 3 different microstepping settings and all 3 run smoothly from stop to max. I could add a couple more split points and that would be enough to really tune it. Now I feel like a genius. The computational power required for this is very minimal. It seems to be working very well so maybe I'm being fooled by something.

No comments:

Post a Comment