MX340 Paper Feed Motor Acceleration/Deceleration
I'm working to interpret quadrature decoder positions reported for the paper feed motor of a Canon Pixma MX340 multi-function inkjet. I was happy a relatively simple debounce filter cleaned up a lot of the noise introduced by small encoder movements, but I was still having a hard time interpreting the results. I knew this would be a problem when I chose to log "microseconds per encoder count". It was the reciprocal of the more obvious "encoder count per microsecond" velocity. I chose it to keep computation in the integer realm, avoiding floating point math. It should help keep the ATmega328 microcontroller in my Arduino Nano fast and responsive, with the tradeoff of causing me headaches now in analysis.

After squinting at this for a while, I realized I was being silly. I'm looking at the data after the fact, I no longer have to concern myself with keeping code fast and responsive. Furthermore, I'm now on a desktop computer whose CPU had floating point capabilities the ATmega328 lacked. I added a new column in Excel, with the simple formula of 1 divided by us/enc, and graphed resulting enc/us as my orange line.

Beautiful! Now the graph is a lot easier for me to grasp at an intuitive level. It's easy to see motions for this startup sequence occur at several different peak velocities, and it even showed an artifact I wanted to investigate further: little velocity spikes book-ended some of these movements. (Might not be visible at blog resolution here. There's a zoomed-in version below.)
When skimming through the raw us/enc data, I noticed the change in velocity was not uniform.
[...]
2963072,4484,1,992
2964064,4485,1,980
2965044,4486,28,1448
2966492,4487,27,1428
2967920,4488,1,1052
2968972,4489,1,1076
2970048,4490,1,1024
2971072,4491,1,1024
2972096,4492,14,1248
2973344,4493,130,3148
2976492,4494,324,6376
2982868,4495,88,2564
2985432,4496,18,1408
2986840,4497,5,1132
2987972,4498,3,1108
2989080,4499,1,1016
2990096,4500,952,[...]
This excerpt was from second movement decelerating towards its final position of 4500. From a peak speed where only about 65 microseconds were spent at each encoder position, this excerpt started when we're slowed enough to spend almost 1000 microseconds (1 millisecond) at each position. Position 4486-4487 each got around 1400us, then the system sped up. Then it slowed down towards position 4494. Over 6 milliseconds were spent there, then we see a final kick to bring it to position 4500.

Zooming in to the velocity plot of first three movements, I can see this "not quite there... little more power... not quite there... more power" as a bit of saw tooth shape at the end of each deceleration curve. This graph also showed me something I hadn't noticed earlier: a similar saw tooth at the beginning of the second and third movements. They started moving with a sharp acceleration that was then dialed back before reaching their target velocity.
What might this mean? I speculate movements started with extra power in order to overcome static friction in the system. Once things started turning, the closed-loop motor control algorithm reevaluated power levels to maintain target acceleration on its way to target velocity. Then for deceleration, the control algorithm might deliberately aim for a slight undershoot, adding little bursts of power towards the end to reach target position. Aiming for a slight undershoot makes sense to me. If it had overshot, correction would have had to deal with gear backlash and reversing the inertia of the entire system, a much bigger can of worms.
Whatever the reason, the fact is acceleration/deceleration rates varied within a single movement, something easily visible once I actually plotted velocity vs. position. It's a pretty cool discovery even though it invalidated a plan I had.
This teardown ran far longer than I originally thought it would. Click here to rewind back to where this adventure started.
Captured CSV and Excel worksheets are included in the companion GitHub repository.