Maker Pro
Maker Pro

quadrature encoder rotation rate averaging

J

Jamie Morken

Jan 1, 1970
0
Hi,

I am using this quadrature encoder:
"http://www.usdigital.com/products/e4p/"

with 300 cycles per revolution / 1200 pulses per revolution.
I have it hooked up to an AVR microcontroller (atmega168) using two
external interrupt pins for the A and B channel (there is no
index channel). This is working and I have a variable that
keeps track of the encoder pulses and uses a 4state machine
to check the rotation direction, so the variable goes + for
forward rotation and - for reverse rotation.

I am now trying to get an averaged rotation rate for the last 1ms, 10ms,
100ms, 1s and 10s. I have an interrupt that runs every 1ms for this
but the code only updates the rotation rate variables once per period,
ie. once per second for the 1s variable, instead of giving a
continuously updated value from the last second.

Any ideas on how to fix this? I was thinking about using a digital
lowpass filter:
(http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html)
for each rotation rate variable but am not sure if that is the best way
to do it.

cheers,
Jamie
 
T

Tim Wescott

Jan 1, 1970
0
Jamie said:
Hi,

I am using this quadrature encoder:
"http://www.usdigital.com/products/e4p/"

with 300 cycles per revolution / 1200 pulses per revolution.
I have it hooked up to an AVR microcontroller (atmega168) using two
external interrupt pins for the A and B channel (there is no
index channel). This is working and I have a variable that
keeps track of the encoder pulses and uses a 4state machine
to check the rotation direction, so the variable goes + for
forward rotation and - for reverse rotation.

I am now trying to get an averaged rotation rate for the last 1ms, 10ms,
100ms, 1s and 10s. I have an interrupt that runs every 1ms for this
but the code only updates the rotation rate variables once per period,
ie. once per second for the 1s variable, instead of giving a
continuously updated value from the last second.

Any ideas on how to fix this? I was thinking about using a digital
lowpass filter:
(http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html)
for each rotation rate variable but am not sure if that is the best way
to do it.

cheers,
Jamie

What is best depends entirely on just what you want to do with the
information, and what your memory resources are. The IIR filters that
you'll get from that page will certainly give you effective averaging at
low phase delay and low memory requirements, but they won't give exact
moving averages, if that's what you really need.

--

Tim Wescott
Wescott Design Services
http://www.wescottdesign.com

Posting from Google? See http://cfaj.freeshell.org/google/

"Applied Control Theory for Embedded Systems" came out in April.
See details at http://www.wescottdesign.com/actfes/actfes.html
 
A

ADM

Jan 1, 1970
0
If save in a variable each 1ms the you need an accumulator for
each 10ms, 1s , 10s , this will be difficult if the integers are below 16
bit.



webmaster
www.hostpupil.com
Database of Web Hosting Plans, Featuring Cheap Web Hosting Plans, Ecommerce
Hosting, Dedicated Hosting
 
V

vic

Jan 1, 1970
0
Any ideas on how to fix this? I was thinking about using a digital
lowpass filter:


You need to store the values for each interrupt period in a circular
array and do the sum on the entire array. If you have 1ms interrupts you
will need to store 1000 values in the array. This is a lot of memory so
you'll probably want to store values only every 10 or 100ms.

Strictly speaking it is a digital filter, only much simpler than
Chebychev & al.

vic
 
L

Luhan

Jan 1, 1970
0
Jamie said:
Hi,

I am using this quadrature encoder:
"http://www.usdigital.com/products/e4p/"

with 300 cycles per revolution / 1200 pulses per revolution.
I have it hooked up to an AVR microcontroller (atmega168) using two
external interrupt pins for the A and B channel (there is no
index channel). This is working and I have a variable that
keeps track of the encoder pulses and uses a 4state machine
to check the rotation direction, so the variable goes + for
forward rotation and - for reverse rotation.

I am now trying to get an averaged rotation rate for the last 1ms, 10ms,
100ms, 1s and 10s. I have an interrupt that runs every 1ms for this
but the code only updates the rotation rate variables once per period,
ie. once per second for the 1s variable, instead of giving a
continuously updated value from the last second.

Any ideas on how to fix this? I was thinking about using a digital
lowpass filter:
(http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html)
for each rotation rate variable but am not sure if that is the best way
to do it.

This does not look doable, especially the longer times. So the
question becomes why do you need these values and what are you doing
with them? And, is there another way of accomplishing that?

Luhan
 
B

Ben Bradley

Jan 1, 1970
0
You need to store the values for each interrupt period in a circular
array and do the sum on the entire array. If you have 1ms interrupts you
will need to store 1000 values in the array. This is a lot of memory so
you'll probably want to store values only every 10 or 100ms.

I can see how to do this in four circular buffers of 10 values
each, and an accumulator (or two) for each circular buffer.

Requoting more of the OP:
I am using this quadrature encoder:
"http://www.usdigital.com/products/e4p/"

with 300 cycles per revolution / 1200 pulses per revolution.

What will be the maximum RPM of this thing? This will tell you the
number of bytes to allocate for each value at each stage.
I am now trying to get an averaged rotation rate for the last 1ms, 10ms,
100ms, 1s and 10s. I have an interrupt that runs every 1ms for this
but the code only updates the rotation rate variables once per period,
ie. once per second for the 1s variable, instead of giving a
continuously updated value from the last second.

Any ideas on how to fix this?

Presuming fix means rewrite:

Use a circular buffer of the last 10 1ms values. You could
brute-force sum all ten values every 1ms, which may be feasible and is
simpler programming, but you can find the sum much faster (presuming
they start out zero when the code starts, which they really should) by
using an accumulator. Subtract the 10th value from the accumulator,
put the new value into the circular buffer (erasing the old 10th value
you just subtracted), and add this value to the accumulator. Thus the
accumulator will always have the sum of the most recent 10 values in
the circular buffer. The usual caveats apply, be sure everything has
enough bits for the maximum value it can hold. If you need an actual
average, divide the accumulator value by 10 (and store in yet another
varuable, and use THAT as the input to the next, uh, paragraph), but
if you have enough bits to hold all the sums or need higher resolution
on the longer averages, just continue using sums, and only use
division to get the actual average values to send off somewhere.
Use a circular array of the last 10 10ms values you got from the
previous paragraph, and do likewise with it to get a 100ms sum or
average. Continue for 100ms and 1s, giving 1s and 10s averages/sums
respectively.
Total operations each 1mS (not counting division to get actual
averages and whatever code to send these values somewhere) is four
subtracts, four adds, and eight buffer operations. The brute-force
option changes that to 40 adds and and eight buffer operations. To get
actual averages instead of sums, you also need to do four divides each
1mS, each by a fixed power of 10.

Strictly speaking it is a digital filter, only much simpler than
Chebychev & al.

This is a FIR filter with 10 coeficients of value 1 each (or 0.1 if
you want the output automatically divided by 10). But you don't need
to know that. ;-)
 
J

John B

Jan 1, 1970
0
Ben Bradley scrobe on the papyrus:
I can see how to do this in four circular buffers of 10 values
each, and an accumulator (or two) for each circular buffer.

Requoting more of the OP:


What will be the maximum RPM of this thing? This will tell you the
number of bytes to allocate for each value at each stage.


Presuming fix means rewrite:

Use a circular buffer of the last 10 1ms values. You could
brute-force sum all ten values every 1ms, which may be feasible and is
simpler programming, but you can find the sum much faster (presuming
they start out zero when the code starts, which they really should) by
using an accumulator. Subtract the 10th value from the accumulator,
put the new value into the circular buffer (erasing the old 10th value
you just subtracted), and add this value to the accumulator. Thus the
accumulator will always have the sum of the most recent 10 values in
the circular buffer. The usual caveats apply, be sure everything has
enough bits for the maximum value it can hold. If you need an actual
average, divide the accumulator value by 10 (and store in yet another
varuable, and use THAT as the input to the next, uh, paragraph), but
if you have enough bits to hold all the sums or need higher resolution
on the longer averages, just continue using sums, and only use
division to get the actual average values to send off somewhere.
Use a circular array of the last 10 10ms values you got from the
previous paragraph, and do likewise with it to get a 100ms sum or
average. Continue for 100ms and 1s, giving 1s and 10s averages/sums
respectively.
Total operations each 1mS (not counting division to get actual
averages and whatever code to send these values somewhere) is four
subtracts, four adds, and eight buffer operations. The brute-force
option changes that to 40 adds and and eight buffer operations. To get
actual averages instead of sums, you also need to do four divides each
1mS, each by a fixed power of 10.



This is a FIR filter with 10 coeficients of value 1 each (or 0.1 if
you want the output automatically divided by 10). But you don't need
to know that. ;-)

All of the software is much simpler if you use an average buffer of 8
or 16 samples. Dividing by 10 is a PITA.
 
Top