I know the paper feed motor in a Canon Pixma MX340 multi-function inkjet does more than just feed paper, and I want to see how much I can understand. One small step at a time. Right now I have an Arduino Nano watching its rotation quadrature encoder. I want some level of precision, but I don't want to spend time learning an entirely new field.

So I'll stay with Arduino's micros() API to give me a timestamp a few hundred microseconds after the most recent encoder position update. The variability will add error to my calculations, but I'm hopeful the errors will average out across multiple data points. If not, I'll have to revisit the topic of timestamp precision.

timestamp,position,count
16,0,448737
6489548,1,1
6490076,2,1
6490688,5,1
6491300,8,1
6491912,12,1
6492540,17,1
6493220,21,1
6493876,25,1

[...]

The next most obvious step is to calculate velocity between each of these data points. For the final two line in the excerpt above, the distance is 25-21=4 encoder counts. That took place within 6493876-6493220 = 656 microseconds. 4/656 = 0.006 encoder counts per microsecond. Easy enough on paper, but a big problem in practice. The ATmega328P chip at the heart of this Arduino Nano has no floating point math hardware, so such a calculation would have to run through a math library that will add a lot of computation time to this very time-constrained project.

My first thought was maybe I can aggregate calculation across multiple data points, but that means tracking multiple data points. So far I've been trying to limit it to just two: the "now" data point and the "previous" data point. It makes for simple code with few things to go wrong, so I'm trying to avoid multiple data points for as long as I can get away with it.

Since I'm reluctant to pull in floating math or multiple data points, I thought I would try a different approach. If my problem is that "encoder counts per microsecond" is a small floating point number, perhaps its reciprocal "microseconds per encoder count" could help me? It would be a much easier calculation: Instead of 4/656 = 0.006 encoder counts per microsecond, I can look at it as 656/4 = 164 microseconds per encoder count. Staying in integer math should keep the code fast, and staying with two data points ('now' and a single history point) make the code simple. I ran the simple code and plotted its output... it looks promising, but there's definitely still work to do.


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.