Arduino - Interrupt pin is picking up noise

Hi everyone,

I'm using Arduino Mega.
Problem - Arduino is placed on a golf cart with an encoder attached to the arduino. When I press the accelerator on the cart, the interrupt pin is picking that noise and calling the Interrupt routine again and again.

Setup - Encoder is attached to the steering wheel to keep track of the angle. The encoder wires run below the cart along with the accelerator wires. Encoder has 5 wires, I'm using 4 of them (VCC, GND, Channel A and Channel B). When the steering rotates, the encoder gives proper interrupts on Channel A and B, allowing me to track the angle it rotated. When I press the accelerator, it takes random interrupts, leading to a wrong angle.

Encoder specification -

MH38-10-128-5-26F-1MTR
METRONIX MAKE HOLLOW SHAFT ENCODER

RESOLUTION:100 PPR
O/P: LINE-DRIVER
MOUNTING:SERVO
OUTER DIA:38MM
BORE DIA: 10MM
SUPPLY VOLT:5-26VDC
CHANNEL:A,B,Z,
CONNECTION:RADIAL CABLE 1 MTR LONG

Circuit -


I'm using single core wires connected to the encoder's multicore wires at one-end and to the breadboard at another end. I'm using 1k ohm Pull down resistor as shown in the image, but it isn't helping.

How can remove the noise completely? (because even a small wrong angle can break the whole code, it needs to be perfect)
Do I need to change the wires? I've tried connecting the wires from above (not under the cart) and it still picks noise.

Full Code -

// Zen Cruise Steering module v1.0
// @author - Himanshu Pahadia (52954)
// Contact - h.pahadia@zensar.com

#define encoderPinA 2
#define encoderPinB 3
#define ppr 100
#define pi_val 3.14159265359
#define THRESHOLD 0.5

// 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 = 52;
int clockwiseRelay = 50;
int anticlockwiseRelay = 48;

// 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;

//int buffer_angle = 0.5;

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);
   
  }
    if(dir == 1){
      // Clockwise
      if(current_steering_value >= steering_value){
        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(9600);

  // Initialize to the neutral position of the steering
  current_steering_value = 0.0;
  steering_value = 0.0;
  counter = 0;
  
  pinMode(encoderPinA, INPUT);
  pinMode(encoderPinB, INPUT);
  // Orginal
   attachInterrupt(digitalPinToInterrupt(encoderPinA), pulseAtPinA, RISING);

  pinMode(motorRelay, OUTPUT);
  pinMode(clockwiseRelay, OUTPUT);
  pinMode(anticlockwiseRelay, OUTPUT);

  digitalWrite(motorRelay, LOW);

  // NO direction 
  digitalWrite(clockwiseRelay, LOW);
  digitalWrite(anticlockwiseRelay, LOW);

}

void loop() {
//  Serial.println(counter);
  if (Serial.read() == 'b') {
    Serial.readBytes(msg, LEN);
    delay(10);
    if (Serial.read() == 'e') {
//      if (msg[6] == 'e') {
      steering_value = atof(msg);
      
      // Check direction of rotation
      // Clock wise
      if((steering_value - current_steering_value) > 0){
        
        dir = 1;
        if(steering_value > 2.2* pi_val){
          steering_value = 2.2*pi_val;
        }
      }
      else{
        
        dir = 0;
        if(steering_value < -2.2* pi_val){
          steering_value = -2.2*pi_val;
        }
      }

      if(abs(steering_value - current_steering_value) > THRESHOLD){
        if(dir == 1){
          turnAntiClockwise();
        }
        else if(dir == 0){
          turnClockwise();
        }
      }
    }
  }

}

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);
}

Interrupt routine -

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);
   
  }
    if(dir == 1){
      // Clockwise
      if(current_steering_value >= steering_value){
        stopMotor();
      }
    }
    else if(dir == 0){
      // Anti Clockwise
      if(current_steering_value <= steering_value){
        stopMotor();
      }
    }

}

Thank you. :slight_smile:

Set your two input pins to 'input pullup".

Paul

Paul_KD7HB:
Set your two input pins to 'input pullup".

Hi Paul,
Just to clarify, should I change pin mode of pins 2 and 3 to INPUT_PULLUP while the 1k Ohm pull down resistor is connected?
Thanks.

What is it You have placed on that breadboard? Having experience from both golf cars and forklift trucks I know they are shaking more or less. Laboratory cables and breadboard has no future in a moving vehicle.
Think about shielding the A- and B- channels signals so they don't suffer from any electrical noice from the drive- or steering- motor.

Railroader:
What is it You have placed on that breadboard? Having experience from both golf cars and forklift trucks I know they are shaking more or less. Laboratory cables and breadboard has no future in a moving vehicle.

Breadboard also has the cables for steering motor which is being controlled by 3 relays, but they are not creating problem anymore as I've placed them away from the encoder wiring and powering those relays using another Arduino.
Actually, I'll design a PCB for the Arduino completely removing the breadboard from the picture. Right now, the car is elevated, so, it's not moving when I press the accelerator.

Railroader:
Think about shielding the A- and B- channels signals so they don't suffer from any electrical noice from the drive- or steering- motor.

Yes, how do I shield the channel wires? I'm a newbie to this. Some video/link will be appreciated.

First, I'd get rid of the breadboard as they're notorious for bad connections.

Make sure the ground connection for your Arduino board is solid and that it has clean power.

Make sure you route the encoder wiring as far away as possible from the drive motor control and power leads (or any sources of electrical noise.) If the wiring for the motor and controller runs on one side of the cart, run the encoder wiring on the other.

Consider the use of shielded cable. Even something like a USB cable might work (4-wire, shielded etc). You might have to try different shield termination techniques but generally a termination to chassis ground at one end is best.

Also, if I interpret "single core" correctly, don't use solid core wire for mobile equipment. It will fatigue and break over time. Use stranded wiring.

In a shielded cable the signal carrying cables are surrounded by a conducting shield looking like a fine fishingnet. That is preferably connected to ground near the controller. Several different shielded cables exist containg 1, 2, 3 or more signal wires. As told by other members, keep the signal wires away from the powering system. Also keep them away from the steering.
1K Ohm to ground is safe. No need for INPUT_PULLUP.
Ok, vehicle is lifted. Check the contact of the A and B anyway. Try a temporary soldering in some way.