Motion Decoder Timestamp Switching to Microseconds
I want to decode motion reported by the rotation quadrature encoder inside a Canon Pixma MX340 multi-function inkjet. My first attempt comparing encoder count differences proved to be a failure, so I will have to incorporate those lessons before trying again.
The first lesson is that making decisions on changes between two iterations of a loop makes the code dependent on microcontroller execution speed. This is an unreliable metric because behavior would change if I compile it to run on different hardware. And even if the hardware is unchanged, doing different things within an iteration (like printing data out to serial port) would consume more or less time than than a different iteration. For some projects, such variability doesn't matter much, but it has proven to matter greatly here.
To solve the loop iteration-to-iteration variability problem, I need to switch to a system where calculations are based on a measure of time. Arduino uses millis()
for time stamps in many examples, so I'll start with milliseconds as my time stamp against encoder readings. And for reference, I'll also count how many loop iterations were spent at each encoder position. My earlier failure told me this number is occasionally greater than one even when the system is moving, I wanted to know more.
Here's the output for machine startup:
timestamp,position,count
0,0,878490
10604,2,95584
11758,4,1871
11782,6,341550
15905,7,1
15906,8,1
15906,10,1
15907,13,1
15907,15,1
15908,19,1
15908,23,1
[...]
As expected, a lot of time was spent near position zero as the machine powered up. But as soon as the paper feed motor started turning in earnest, encoder position count started changing more dramatically changing once per encoder poll iteration. Critically, both were changing faster than the millisecond time stamp counter. Position 8 and 10 were both stamped with 15906. Position changed from 13 to 15 within the same millisecond, etc.
Now I know the Arduino sketch is running fast enough to keep up at some speed faster than 1 kHz, which I wasn't sure about before. This is actually excellent news. The timestamp issue is thankfully easy to resolve, because Arduino framework also provides micros()
so it was easy to switch to microseconds for my time stamps.
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
[...]
That looks much better. It's not literally 1000 times better because, as Arduino documentation stated, micros()
doesn't always deliver microsecond resolution. For ATmega328-based Arduino boards like the Nano I'm using, the resolution is limited to four microseconds when running at 16MHz. And looking at my output, the timestamps are indeed all multiples of 4. Still a huge improvement but it made me wonder: can I do even better?
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.