So I want to use two of these motors or something similar to control a 2 axis actuator:
I want to use an arduino to read the signals from the encoders and then work out the necessary PWM values to send to my DC motor controllers.
I have two questions, firstly has anyone know of a good example of this that has been done before, I have looked at the PID library, but can't seem to find a good working example.
Secondly will an arduino be able to handle the frequency of interrupts that these encoders will be sending?
The motors have an output RPM of 285, but also a gearing ratio of 14:1 so the actual motor shaft speed is 3990RPM. The encoders have a resolution of 1440 pulses per revolution (360 cycles). So each motor encoder could be throwing 5,745,600 interrupts per minute!
For both motors that would be 191,520 interrupts per second.
So I would need an arduino with at least 4 interrupt pins that could deal with 191,520 interrupts per second.
If you are only looking to measure the speed (not absolute position), then you can try route one of the encoder signals to T1 (digital
pin 5) and configure timer1 to count the pulses - then you merely need to read the TCNT1 register regularly to measure the speed.
If you want position control then yes its going to be tight for cpu cycles - if you wire one of the encoder pins to an interrupt pin and then
read the other in the interrupt routine you'll only get about 45,000 interrupts per second per motor. That still only leaves about 160
clock cycles per interrupt - you'll need to keep the instruction count in the routine to a minimum.
There are tricks for reducing the work in the interrupt routine (for instance using byte or int counters, but extending these to long
by regular inspection (perhaps in another timer interrupt routine). The 328 is an 8 bit processor so that using ints and longs takes
many more instructions than byte variables.
catanimal:
The motors have an output RPM of 285, but also a gearing ratio of 14:1 so the actual motor shaft speed is 3990RPM. The encoders have a resolution of 1440 pulses per revolution (360 cycles). So each motor encoder could be throwing 5,745,600 interrupts per minute!
Looking at the link you supplied, the encoder is 360 CPR as you state but is it on the motor shaft or the output shaft? If it's on the output shaft then that's only 102,600 or 205,200 interrupts.
You should only need 1 interrupt per motor. When a pin change interrupt occurs on a phase you need to read the other one at the same time.
catanimal:
The motors have an output RPM of 285, but also a gearing ratio of 14:1 so the actual motor shaft speed is 3990RPM. The encoders have a resolution of 1440 pulses per revolution (360 cycles). So each motor encoder could be throwing 5,745,600 interrupts per minute!
Looking at the link you supplied, the encoder is 360 CPR as you state but is it on the motor shaft or the output shaft? If it's on the output shaft then that's only 102,600 or 205,200 interrupts.
You should only need 1 interrupt per motor. When a pin change interrupt occurs on a phase you need to read the other one at the same time.
Pretty sure the encoder is mounted to the rear of the motor, so is reading the rotation and position of the motor shaft, not the gearbox output.
So I've done a little timing test on an Uno at 16MHz using two bare-bones encoder interrupt routines:
volatile long pin2_count = 0L ;
volatile long pin3_count = 0L ;
void pin2_handle ()
{
if (PIND & 0x40)
pin2_count ++ ;
else
pin2_count -- ;
}
void pin3_handle ()
{
PORTC = 0x01 ; // purely to show up on the scope!
if (PIND & 0x80)
pin3_count ++ ;
else
pin3_count -- ;
PORTC = 0x00 ; // purely to show up on the scope!
}
So we have interrupt handlers on pins 2 and 3, the one for pin 2 uses pin 6 to select whether to increment or
decrement its counter (a long), and ditto for pins 3 and 7.
I routed PWM from pins 9 (timer1) and 11 (timer2) and upped the timers to maximum clock rate, so they cycle at 16MHz / 510 = 31.4kHz,
which means with CHANGE interrupts 62.8kHz interrupt rate on each pin. The counts kept accurate.
Latency time from pin3 state changing to the "PORTC = 0x01" instruction was 3.5us (if pin2 disconnected) and 8.6us (pin2 clocked). The
output pin (PORTC 0x01 is analog pin 0 in fact) toggled high for 1.6us.
Thus latency for handling the interrupt is 3.5us, time to test one pin directly and increment or decrement a long is 1.6us. With both
interrupts running that meant 5.1us followed by 5.1us (pin 2 has higher priority than pin 3), or 10.2us - thus a max interrupt rate of about 90kHz is achievable and keep long counters in step. Direct port manipulation is needed to get this performance.
With digitalRead() the time for each interrupt routine to run increases from 1.6us to 5.8us
[edit: actually that logic isn't right for an interrupt that runs on pin CHANGE (as opposed to RISING), so I'm a little over-optimistic on the timings]
Thanks for the help, from reading what you said and a few other source I found online it did seem that I may be able to just about get two encoders working with the arduino, bit I have decided to go for an external counting IC to keep things simple.
Here is the board I am going to try out, anyone have any experience with it?