Well just a few thoughts on your project. First without knowing the RPM and steps per revolution of that your encoders will be turning it's hard to determine the timing requirements that the Arduino will have to handle.
I played with two optical encoders wired to my Arduino and was able to have both operating using interrupts. I used interrupt pin 2 for channel A of encoder #1 and the other interrupt pin 3 for channel A of encoder #2, channel B of #1 wired to digital pin 4 and B of #2 wired to digital pin 5.
Things I learned about my encoder(s):
While my manufacture rated my encoder as 128 steps per revolution, one can get either 128, 256 or 512 steps per revolution on it depending on if you use both interrupt pins for one encoder and utilize either FALLING or CHANGE interrupt mode. If you are using two encoders then I couldn't have the highest step rate, 512, as each encoder requires at least one interrupt pin. Read the comments on my posted sketch to see if you can see how the different configurations can effect the resulting step rate. Also I'm posting the version using the Arduino digitalRead(pin) functions, but if one uses direct port reads instead there can be quite a faster response (faster interrupt routine time) to steps and therefore able to handle a faster RPM.
Keep the Interrupt functions as short and simple as possible if you want maximum speed capacity and remember that you can't use any functions that utilize interrupts while you are inside a interrupt routine.
// Proof of concept- handling two optical rotory encoders using Arduino interrupts 0 & 1
// Also added a digital output pin for both direction and step pulses for each encoder
#define encoderPinA 2 // Encoder #1, A channel, Arduino pin2, Interrupt0
#define encoderPinB 4 // Encoder #1, B channel, Arduino pin3
#define encoderdir 6 // Encoder #1, direction output, Arduino pin6
#define encoderstep 7 // Encoder #1, step output, Arduino pin7
#define encoder2PinA 3 // Encoder #2, A channel, Arduino pin2, Interrupt1
#define encoder2PinB 5 // Encoder #2, B channel, Arduino pin5
#define encoder2dir 8 // Encoder #2, direction output, Arduino pin8
#define encoder2step 9 // Encoder #2, step output, Arduino pin9
volatile unsigned int encoderPos = 0; // Variables for encoder #1
unsigned int encoderLast = 0;
int position = 0;
int positionB = 0;
volatile unsigned int encoder2Pos = 0; // Variables for encoder #2
unsigned int encoder2Last = 0;
int position2 = 0;
int position2B = 0;
void setup() {
// Setup Encoder #1 pins
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
digitalWrite(encoderPinA, HIGH); // activate soft pull-ups
digitalWrite(encoderPinB, HIGH);
pinMode(encoderdir, OUTPUT); //Encoder #1, output direction pin
digitalWrite(encoderdir, LOW);
pinMode(encoderstep, OUTPUT); //Encoder #1, step output pin
digitalWrite(encoderstep, LOW);
// Setup Encoder #2 pins
pinMode(encoder2PinA, INPUT);
pinMode(encoder2PinB, INPUT);
digitalWrite(encoder2PinA, HIGH); // activate soft pull-ups
digitalWrite(encoder2PinB, HIGH);
pinMode(encoder2dir, OUTPUT); //Encoder #2, output direction pin
digitalWrite(encoderdir, LOW);
pinMode(encoder2step, OUTPUT); //Encoder #2, step output pin
digitalWrite(encoder2step, LOW);
// Enable Interrupts
attachInterrupt( 0, doEncoder1, FALLING ); // Encoder #1, FALLING=128 steps/rev CHANGE=256 steps/rev
attachInterrupt( 1, doEncoder2, FALLING ); // Encoder #2, FALLING=128 steps/rev CHANGE=256 steps/rev
// Note that if one uses just one encoder wired to both interrupt pins using CHANGE on can increase to 512 steps/rev
Serial.begin(57600);
Serial.println ("Encoder ready"); // End of setup
}
void loop() {
// Start of Rotary Encoder #1 Code
if ( encoderPos != encoderLast ) {
if ( encoderPos > encoderLast )
position = ++position;
else position = --position;
encoderLast = encoderPos;
Serial.print ("Encoder #1 = "); // use serial output for demonstration showing encoder movement
Serial.print (position, DEC);
Serial.print (" Encoder #2 = ");
Serial.println (position2, DEC);
// digitalWrite(encoderstep, HIGH); // generate step pulse 1 millsec
// delay(1); // or use other methods to set pulse width
// digitalWrite(encoderstep, LOW);
}
// End of Rotary #1 Encoder Code
// Start of Rotary Encoder #2 Code
if ( encoder2Pos != encoder2Last ) {
if ( encoder2Pos > encoder2Last )
position2 = ++position2;
else position2 = --position2;
encoder2Last = encoder2Pos;
Serial.print ("Encoder #1 = "); // use serial output for demostration showing encoder movement
Serial.print (position, DEC);
Serial.print (" Encoder #2 = ");
Serial.println (position2, DEC);
digitalWrite(encoder2step, HIGH); // generate step pulse 1 millsec
delay(1);
digitalWrite(encoder2step, LOW);
}
// End of Rotary Encoder #2 Code
//
// Any additonal application code goes here
//
}
// Start of Interrupt routine for encoder #1
void doEncoder1() {
if (digitalRead(encoderPinA) == HIGH) { // test for a low-to-high on channel A
// reserve for direct port I/O
if ( digitalRead(encoderPinB) == LOW ) { // check channel B to see which way encoder is turning
// reserve for direct port I/O
encoderPos = ++encoderPos; // CW rotation
digitalWrite(encoderdir, HIGH); // Set direction output pin to 1 = forward
// reserve for direct port I/O
}
else {
encoderPos = --encoderPos; // CCW rotation
digitalWrite(encoderdir, LOW); // Set direction output pin to 0 = reverse
// reserve for direct port I/O
}
}
else { // it was a high-to-low on channel A
if ( digitalRead(encoderPinB) == HIGH ) { // check channel B to see which way encoder is turning
// reserve for direct port I/O
encoderPos = ++encoderPos; // CW rotation
digitalWrite(encoderdir, HIGH); // Set direction output pin to 1 = forward
// reserve for direct port I/O
}
else {
encoderPos = --encoderPos; // CCW rotation
digitalWrite(encoderdir, LOW); // Set direction output pin to 0 = reverse
// reserve for direct port I/O
}
}
digitalWrite(encoderstep, HIGH); // generate step pulse 1 millsec
// reserve for direct port I/O
digitalWrite(encoderstep, LOW);
// reserve for direct port I/O
} // End of interrupt code for encoder #1
// Start of Interrupt routine for encoder #2
void doEncoder2(){
if (digitalRead(encoder2PinA) == HIGH) { // test for a low-to-high interrupt on channel A
if ( digitalRead(encoder2PinB) == LOW ) { // check channel B to see which way encoder is turning
encoder2Pos = ++encoder2Pos; // CW rotation
digitalWrite(encoder2dir, HIGH); // Set direction output pin to 1 = forward
}
else {
encoder2Pos = --encoder2Pos; // CCW rotation
digitalWrite(encoder2dir, LOW); // Set direction output pin to 0 = reverse
}
}
else { // it was a high-to-low interrupt on channel A
if ( digitalRead(encoder2PinB) == HIGH ) { // check channel B to see which way encoder is turning
encoder2Pos = ++encoder2Pos; // CW rotation
digitalWrite(encoder2dir, HIGH); // Set direction output pin to 1 = forward
}
else {
encoder2Pos = --encoder2Pos; // CCW rotation
digitalWrite(encoder2dir, LOW); // Set direction output pin to 0 = reverse
}
}
digitalWrite(encoder2step, HIGH); // generate step pulse 1 millsec
digitalWrite(encoder2step, LOW);
} // End of interrupt code for encoder #2
On your main motor control, you can't control speed of most AC motors using PWM, only DC motors. Controlling the speed of a AC motor is not an easy task as most are controlled by the AC power frequency of the AC voltage applied to the motor, so would require a invertor driver that can change frequency of the AC power, not cheap or simple, so utilize a DC motor using PWM control or a DC stepper motor using digital outputs.
Good luck and work with little sections at a time rather then try and write/build the whole project at once.
Lefty