Hi Everyone,
I'm using Arduino Mega.
Use case - A high torque dc motor is rotating an external shaft (using 3:1 ratio gears) to which a 3-channel rotary encoder is attached that keeps track of the angle of that shaft. Now, when the motor is rotating and the rotary encoder is not rotating, the arduino is still seeing an interrupt with RISING edge and incrementing the counter in the ISR.
Specification -
Motor is 12 V, 8 Amps, 60 RPM
Encoder is 3-channel optical incremental encoder (using 4 pins - VCC (red), GND (black), A (green), B (white))
Diagram of connections -
Snippets of Code (Complete code) -
#define encoderPinA 2
#define encoderPinB 3
#define ppr 100
#define pi_val 3.14159265359
#define THRESHOLD 0.1
// length of the actual message
#define LEN 6
// Motor relay - To break the circuit
// NO - Connected to positive of battery, NC - NILL, COM - NO of other two relays
// Clockwise relays - Change polarity of the current going to motor
// NO - COM of motor relay, NC - negative of battery
// COM1 of clockwise - +ve of motor
// COM2 of anticlockwise - -ve of motor
// messages expected
// Stop - b000000e
// Rotate clockwsie - b000001e
// Clockwise - b-00001e
int motorRelay = 8;
int clockwiseRelay = 9;
int anticlockwiseRelay = 10;
// Input from vision system
// Message from serial communication
// Position message
char msg[LEN];
char pos_msg[LEN];
// Current steering position
float current_steering_value = 0.0;
// Steering value
float steering_value;
// Steering direction
volatile boolean dir;
volatile int counter = 0;
//volatile int count = 0;
volatile boolean flag;
volatile int var_degrees = 0;
void pulseAtPinA(){
flag = true;
if(digitalRead(encoderPinA) == HIGH){
if(digitalRead(encoderPinB) == LOW){
counter = counter -1; //Counter-clockwise
}
else{
counter = counter +1; //Clockwise
}
}
else{
if(digitalRead(encoderPinB) == LOW){
counter = counter + 1; //CW
}
else{
counter = counter - 1 ; //CCW
}
}
if(flag == true){
var_degrees = ((360/100.0)*counter);
var_degrees = var_degrees/3.0;
current_steering_value = getRadianFromDegree(var_degrees);
Serial.print("Current steering value is ");
Serial.print(current_steering_value);
Serial.print(" Radian and ");
Serial.print(var_degrees);
Serial.print(" Degrees");
Serial.print(" and reaching");
Serial.println(steering_value);
}
// Stop the rotation when the steering angle is achieved
if(dir == 1){
// Clockwise
if(current_steering_value >= steering_value){
Serial.print("Stopping clockwise rotation");
stopMotor();
}
}
else if(dir == 0){
// Anti Clockwise
if(current_steering_value <= steering_value){
stopMotor();
}
}
}
float getRadian(int c){
return (float)(c*2.0*pi_val) / 100.0;
}
float getRadianFromDegree(int degree){
return (float)degree*(pi_val/180.0);
}
void setup() {
Serial.begin(115200);
// Initialize to the neutral position of the steering
current_steering_value = 0.0;
steering_value = 0.0;
counter = 0;
Serial.print("STARTING");
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
// Orginal
attachInterrupt(digitalPinToInterrupt(encoderPinA), pulseAtPinA, RISING);
// flag = true;
pinMode(motorRelay, OUTPUT);
pinMode(clockwiseRelay, OUTPUT);
pinMode(anticlockwiseRelay, OUTPUT);
digitalWrite(motorRelay, LOW);
// NO direction
digitalWrite(clockwiseRelay, LOW);
digitalWrite(anticlockwiseRelay, LOW);
}
void loop() {
// Serial message from computer
if (Serial.read() == 'b') {
Serial.println("Begin");
Serial.readBytes(msg, LEN);
Serial.println(msg);
if (Serial.read() == 'e') {
Serial.println("End");
// Angle to which the steering has to rotate
steering_value = atof(msg);
Serial.print("Steering Value: ");
Serial.println(steering_value);
Serial.print("Current Steering Value: ");
Serial.println(current_steering_value);
// Check direction of rotation
// Clock wise
if((steering_value - current_steering_value) > 0){
dir = 1;
// Serial.print("CLOCKWISE with dir = ");
// Serial.println(dir);
// Limit the rotation of steering
if(steering_value > 2.4* pi_val){
steering_value = 2.4*pi_val;
}
}
else{
dir = 0;
// Serial.print("ANTI-CLOCKWISE with dir = ");
// Serial.println(dir);
// Limit the rotation of steering
if(steering_value < -2.4* pi_val){
steering_value = -2.4*pi_val;
}
}
// Start rotation of the steering wheel
// It will stop inside the ISR when the angle is achieved
if(abs(steering_value - current_steering_value) > THRESHOLD){
if(dir == 1){
turnClockwise();
}
else if(dir == 0){
turnAntiClockwise();
}
}
}
}
}
void turnClockwise(){
// NO direction
digitalWrite(clockwiseRelay, LOW);
digitalWrite(anticlockwiseRelay, HIGH);
// Start motor
digitalWrite(motorRelay, HIGH);
}
void turnAntiClockwise(){
// NO direction
digitalWrite(clockwiseRelay, HIGH);
digitalWrite(anticlockwiseRelay, LOW);
// Start motor
digitalWrite(motorRelay, HIGH);
}
void stopMotor(){
// Turn the motor off
digitalWrite(motorRelay, LOW);
// Clockwise direction
digitalWrite(clockwiseRelay, LOW);
digitalWrite(anticlockwiseRelay, LOW);
}
Switching of Relays run the motor.
Strange behaviour - When the motor is not connected to the circuit, and the relays are still switching off and on, the encoder works fine (there is no anomaly interrupt). But once, the motor is running, interrupt is there, no matter what the state of encoder is. It gives wrong angle.
Please help me solve this. Let me know the possible reasons of why the interrupt is going HIGH when the motor is running.
Updates -
I've updated the post with complete code. Attached the schematic picture in the post.

