Encoder Control/ Reading errors

Good day,

I am using an encoder to control the PWM speed of a motor. The encoder I am using is an industrial grade, optical encoder with 1000 pulses per rev. Together with the encoder, I am implementing the use of the PID library for smooth operation of the motor. The problem I am having is that I am getting random spikes in my encoder reading which directly influences the output PWM signal. I would appreciate if someone could assist me in this matter. Below is the code as well as an image from the serial plotter. The blue line represent the setpoint, The red the encoder reading (from which these spikes can be seen) and the read is the PWM output. The help is much appreciated!!

#include <PID_v1.h>


#define ENCA 2 //Green
#define ENCB 3 //White


float eintegral=0;

float PWRPrev;
float RPMset;
float vFilt = 0;
float vPrev = 0;
int pos = 0;
int Motor = 9;
long prevT = 0;
int posPrev = 0;
float deltaT = 0;
volatile int pos_i = 0;
volatile float velocity_i = 0;
volatile long prevT_i = 0;
int t = 0;
int rev = 0;
float RPM = 0.0;

double Kp = 5, Ki =2 , Kd = 0;
double Input,Output,Setpoint;
PID encoder(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(ENCA, INPUT_PULLUP);
  pinMode (ENCB, INPUT_PULLUP);
  pinMode(Motor, OUTPUT);
  encoder.SetMode(AUTOMATIC);
  attachInterrupt(digitalPinToInterrupt(ENCA), readEncoderA, RISING);
//  attachInterrupt(digitalPinToInterrupt(ENCB), readEncoderB, RISING);

    Serial.print("Setpoint");
  Serial.print("  ");
  Serial.print("Input");
  Serial.print("  ");
  Serial.print("Output");
  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:
  float velocity2;

 
  velocity2 = velocity_i;


  float v2 = velocity2 / 1000.0 * 60.0;
  int Res = analogRead(A0);
  int PWM = map(Res, 0, 1014, 255, 0);
  
  
  //int b=digitalRead(ENCB);
  vFilt = 0.969 * vFilt + 0.0155 * v2 + 0.0155 * vPrev;
  vPrev = v2;
  Input=(vFilt/125)*255;
  
  
//  float kp=5;
//  float ki=7;
//  float e=PWM-Input;
//  eintegral=eintegral+e*deltaT;
//
//  float u=kp*e+ki*eintegral;
//
//  int PWR=(int)fabs(u);
//  if(PWR>255){
//    PWR=255;
//  }
  
Setpoint=PWM;

 encoder.Compute();

  analogWrite(Motor, Output);

  Serial.print(Setpoint);
  Serial.print("  ");
  Serial.print(Input);
  Serial.print("  ");
  Serial.print(Output);
  Serial.println();
  delay(1);
}

void readEncoderA() {
  int a = digitalRead(ENCA);
  deltaT = 0;

  if (a > 0) {
    pos++;
  }
  else {
    pos--;
  }

  long currT = micros();
  deltaT = ((float)(currT - prevT_i)) / 1.0e06;
  velocity_i = (pos - pos_i) / deltaT;
  prevT_i = currT;
  pos_i = pos;

}

unwanted spikes when you have a motor involved could indicate an issue with galvanic isolation / EMF

Possible solution?

details about your circuit and how things are wired / powered would be a good starting point

Have you tested the encoder alone ? do you see spikes when no motor is involved?

Currently I do not have the means to constantly power the encoder by means other than an electric motor.

I have a 12V motor connected to a motor driver which is also connected to a 12V battery. The motor driver is grounded on an arduino Uno and receives the PWM signal from pin 9.
The encoder is soldered is soldered to a prototyping board where it receives 5V and GND together with a variable resistor(to vary set point) from the board there is a jumper wire to digital pin 2 for the ENCA input (the pin which gives the signal spikes)

Something to watch out for is when you use for volatile variables in your main loop. You need to disable interrupts, copy them and then re-enable interrupts.

  noInterrupts();
  velocity2 = velocity_i;
  interrupts();

Also, micros() returns unsigned long so your time variables should be the same type.

Changed the interrupts but the problem remains

Another thing to consider...

You are computing your velocity with every interrupt and you said your encoder is 1000 tics/rev. If you are using an UNO or Mega, micros() has a resolution of 4usec which means you could simply be getting some sort of rounding error. I don't know how fast your motor is travelling, so can't do the math - but you can.

An alternative approach would be to simply inc/dec your position counter in the ISR and then every 100 or 200 or xxx useconds, compute your velocity and adjust your PID all within your main loop().

It might provide some insight if you displayed the RAW velocity information rather than only showing it after it has been filtered. It could be that there is an obvious flaw in the raw data that isn't clearly visible after the data has been filtered.