Good day All,
I am having a huge amount of issues with the readings from my rotary optical encoder. The problem seems to be with the interrupt in my program (which is quite large). The encoder reads the revolution speed of a hydraulic motor and uses this for further speed calculations. The encoder I am using is a 1000PPR optical encoder with the hydraulic motor running at the maximum of approx. 500 rpm which means an interrupt occurs every 0.12ms.
If I run a small sketch with only the speed calculations and the interrupt, it works fine. However in the larger program the "diff" variable which is the difference between current encoder count and previous encoder count is CHAOTIC.
In the same sketch I have a while loop running (See funtion "Calibrate" near the bottom of the sketch) and all works fine. The problem just occurs inside my loop. (See from Sketch Section "Determine encoder Speed").
How can I possibly solve this problem?
Thanks for all the advice in advance!!
//Define Encoder wires
#define ENCA 2 //Green
#define ENCB 3 //White
#define WINDOW_SIZE 5
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Include Libraries
#include <SimpleKalmanFilter.h>
#include <PID_v1.h>
#include <SoftwareSerial.h>
#include <TinyGPS++.h>
#include <EasyNextionLibrary.h>
#include <trigger.h>
#include <EEPROM.h>
#include <ezButton.h>
#include <Encoder.h>
//Kalman Library
SimpleKalmanFilter Filter(2, 2, 0.01);
SimpleKalmanFilter Filterdiff(2, 2, 0.01);
//Define Encoder
int INDEX=0;
int SUM=0;
int READINGS[WINDOW_SIZE];
int AVERAGE=0;
//Define GPS Port
TinyGPSPlus gps;
SoftwareSerial mySerial(10, 11);
//Define Nextion Serial Port
EasyNex myNex(Serial);
//Define time variables
unsigned long prevT = 0;
float deltaT = 0.0;
unsigned long currT = 0;
unsigned long previousMillis = 0;
unsigned long advcurT;
unsigned long advprevT = 0;
unsigned long RPM_T;
unsigned long RPM_Ti = 0;
int RPM_deltaT;
//Define Encoder variables
int a;
float PPRev = 1000.0;
unsigned long diff = 0;
int diff_Filt;
float velocity2;
float v2;
float vFilt = 0.0;
float vFilt_i = 0.0;
float vPrev = 0;
unsigned long pos_i = 0;
unsigned long pos = 0;
unsigned long count_i = 0;
unsigned long count = 0;
//Define other variables
float GSpeed_current_old = 0.0;
float GSpeed_current_new = 0.0;
int GSpeed_display;
float GSpeed_set;
float GSpeed_save_cal = 0.0;
int Rate;
float Rate_display;
float Rate_save_cal = 0.0;
int Rate_set;
int MSpeed_set;
float MSpeed_conv;
float MSpeed_save_conv;
float MSpeed_current;
float MSpeed_percentage;
float MSpeed_cal;
int Satellites;
float Grad;
int fan_col = 0;
int i = 0;
bool run0 = 0;
bool run1 = 0;
bool run2 = 0;
bool fan = 0;
int LS = 1;
int Motor = 3;
int Diff_save;
int RPM_max;
int RPM_set;
int Diff_set;
float aggKp_set;
float Kp_set;
float aggKi_set;
float Ki_set;
float aggKd_set;
float Kd_set;
float Input_i = 0.0;
long prevT_i;
long currT_i;
float velocity_i = 0.0;
static boolean rotate= false;
//Define EEPROM variables
float Rate_save;
float MSpeed_save;
float GSpeed_save;
float Rpmmax_save;
float Diffpid_save;
float aggKp_save;
float aggKi_save;
float aggKd_save;
float Kp_save;
float Ki_save;
float Kd_save;
//PID variables
double Kp, Ki, Kd, aggKp, aggKi, aggKd;
double Input, Output, Setpoint;
PID encoder(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
void setup() {
//Start communication & Define pins
Serial.begin(9600);
mySerial.begin(9600);
// pinMode (7, OUTPUT);
// digitalWrite(7, LOW);
pinMode(ENCA, INPUT_PULLUP);
pinMode(Motor, OUTPUT);
encoder.SetMode(AUTOMATIC);
encoder.SetSampleTime(300);
attachInterrupt(digitalPinToInterrupt(ENCA), readEncoderA, RISING);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Retrieve EEPROM values
GSpeed_save = EEPROM.read(0);
GSpeed_save_cal = GSpeed_save / 10.0;
Serial.println("GSpeed_save_cal");
Serial.println(GSpeed_save_cal);
Rate_save = EEPROM.read(10);
Rate_save_cal = Rate_save * 1.0;
Serial.println("Rate_save_cal");
Serial.println(Rate_save_cal);
MSpeed_save = EEPROM.read(15);
Serial.println("Mspeed_save_cal");
Serial.println(MSpeed_save);
MSpeed_save_conv = MSpeed_save / 100.0;
Serial.println("MSpeed_save_conv");
Serial.println(MSpeed_save_conv);
Rpmmax_save = EEPROM.read(20);
RPM_max = Rpmmax_save;
aggKp_save = EEPROM.get(25, aggKp_set);
aggKp = aggKp_save / 100.0;
aggKi_save = EEPROM.get(30, aggKi_set);
aggKi = aggKi_save / 1000.0;
aggKd_save = EEPROM.read(40);
aggKd = aggKd_save / 100.0;
Kp_save = EEPROM.get(50, Kp_set);
Kp = Kp_save / 100.0;
Ki_save = EEPROM.get(60, Ki_set);
Ki = Ki_save / 1000.0;
Kd_save = EEPROM.read(70);
Kd = Kd_save / 100.0;
Diffpid_save = EEPROM.read(80);
Diff_save = Diffpid_save;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//MotorSpeed conversion
MSpeed_conv = MSpeed_save_conv * 255.0;
//Serial.println(MSpeed_conv);
Grad = MSpeed_conv / 800.0;
Serial.println(Rate_save);
Serial.println(MSpeed_save);
Serial.println(Rpmmax_save);
Serial.println(aggKp);
Serial.println(aggKi, 3);
Serial.println(aggKd);
Serial.println(Kp);
Serial.println(Ki, 3);
Serial.println(Kd);
Serial.println(Diff_save);
}
void loop() {
//Listen for HMI commands
myNex.NextionListen();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Determine GPS Values
// while (mySerial.available()) {
// gps.encode(mySerial.read());
//
// }
//
// myNex.NextionListen();
//
//
//
// if (gps.location.isUpdated())
// {
// // Serial.println("Satelite Count:");
// Satellites = gps.satellites.value();
// Serial.println(Satellites);
// Serial.println();
//
// myNex.NextionListen();
//
// // // Serial.println("GSpeed km/h");
// // GSpeed_current_old = gps.speed.kmph();
// // GSpeed_current_old *= 1;
// // Serial.println("GPS SPEED:");
// // Serial.println(GSpeed_display);
//
// // Serial.println("GSpeed km/h");
// GSpeed_current_old = gps.speed.kmph();
// GSpeed_current_old *= 1;
// GSpeed_display = GSpeed_current_old * 10;
// // Serial.println(GSpeed_display);
// }
myNex.NextionListen();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Determine Encoder Speed
currT = millis();
deltaT = currT - prevT;
myNex.NextionListen();
if (deltaT >= 10) {
diff=0;
deltaT /= 1.0e03 ;
SUM=SUM-READINGS[INDEX];
int diff=count-count_i;
diff*=5;
READINGS[INDEX]=diff;
SUM+=diff;
INDEX=(INDEX+1)%WINDOW_SIZE;
AVERAGE=SUM/WINDOW_SIZE;
diff_Filt=Filterdiff.updateEstimate(AVERAGE);
diff_Filt=Filterdiff.updateEstimate(diff_Filt);
velocity2 = ((float)count - count_i) / deltaT;
count_i = count;
v2 = (velocity2 / PPRev) * 60.0;
vFilt = Filter.updateEstimate(v2);
myNex.NextionListen();
// Serial.println();
// Serial.print("Count");
// Serial.print(" ");
// Serial.print("Count_i");
// Serial.print(" ");
// Serial.println("diff");
// Serial.print(count);
// Serial.print(" ");
// Serial.print(count_i);
// Serial.print(" ");
Serial.println(diff);
Input = (vFilt / RPM_max) * 255;
prevT = currT;
//pos_i = pos;
}
//
// if (vFilt < RPM_max && vFilt > 0) {
// vFilt_i = vFilt;
// }
//
// if (vFilt > RPM_max || vFilt < 0) {
// vFilt = vFilt_i;
// }
// Serial.println();
// Serial.println("deltaT");
// Serial.println(pos);
myNex.NextionListen();
Input = (vFilt / RPM_max) * 255;
// Serial.println(v2);
//
// if (Input < 255 && Input > 0) {
// Input_i = Input;
// }
//
// if (Input > 255 || Input < 0) {
// Input = Input_i;
// }
mySerial.begin(9600);
myNex.NextionListen();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Start Run loop
if ( run0 == 1 && LS == 1 ) {
GSpeed_current_new = GSpeed_current_old;
myNex.NextionListen();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Set Motor Speed
MSpeed_current = (GSpeed_current_new / GSpeed_save_cal) * MSpeed_conv;
// Serial.println(GSpeed_current_new);
// Serial.println(MSpeed_current);
MSpeed_percentage = (MSpeed_current / 255.0) * 100.0;
myNex.NextionListen();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Determine PID Parameters
Setpoint = MSpeed_current;
int gap = abs(Setpoint - Input);
myNex.NextionListen();
if (gap < Diffpid_save) {
encoder.SetTunings(Kp, Ki, Kd);
} else
{
encoder.SetTunings(aggKp, aggKi, aggKd);
}
myNex.NextionListen();
//Write PWM to motor
encoder.Compute();
analogWrite(Motor, Output);
myNex.NextionListen();
//Determine GPS Display Speed
GSpeed_display = GSpeed_current_old * 10;
//Determine Rate
Rate_display = (Input / MSpeed_current) * Rate_save_cal;
myNex.NextionListen();
// Serial.print("Setpoint");
// Serial.print(" ");
// Serial.print("Input");
// Serial.print(" ");
// Serial.println("Output");
// Serial.print(Setpoint);
// Serial.print(" ");
// Serial.print(Input);
// Serial.print(" ");
// Serial.println(Output);
} else {
analogWrite(Motor, 0);
myNex.NextionListen();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Delay 500ms >> Write to HMI
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > 500) {
previousMillis = currentMillis;
myNex.NextionListen();
// if (MSpeed_percentage < 100)
// {
// myNex.writeNum("Speed.val", MSpeed_percentage);
// } else {
// myNex.writeNum("Speed.val", 100);
// }
myNex.NextionListen();
//Write to HMI
myNex.writeNum("Sats.val", Satellites);
myNex.writeNum("RGSpeed.val", GSpeed_display);
myNex.writeNum("RRate.val", Rate_display);
myNex.writeNum("Speed.val", MSpeed_percentage);
myNex.writeNum("VSrpm.val", Setpoint);
myNex.writeNum("VArpm.val", Input);
}
//delay(1);
myNex.NextionListen();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Read Encoder interrupt
void readEncoderA() {
count++;
long currT_i = micros();
deltaT = ((float)(currT_i - prevT_i)) / 1.0e06;
float velocity_i = (count-count_i) / deltaT;
prevT_i = currT_i;
//pos_i = pos;
count_i=count;
Serial.println(velocity_i);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Enable Stop Funtion
void trigger1() {
run0 = 0;
MSpeed_current = 0;
analogWrite(Motor, MSpeed_current);
myNex.writeNum("Speed.val", 0);
myNex.writeNum("Speed.bco", 65535);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Enable Start Function
void trigger2() {
i = 0;
run0 = 1;
myNex.writeNum("Speed.bco", 1024);
unsigned long startMillis = millis();
unsigned long stopMillis = millis();
myNex.writeNum("Speed.val", MSpeed_save);
// while (stopMillis - startMillis < 5000 && MSpeed_current <= MSpeed_save && run0 == 1) {
//
// myNex.NextionListen();
//
//
// stopMillis = millis();
// i++;
// MSpeed_current = Grad * i;
// analogWrite(Motor, MSpeed_current);
//
// MSpeed_percentage = (MSpeed_current / MSpeed_conv) * 100.0;
// myNex.writeNum("Speed.val", MSpeed_percentage);
// }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Save Button
void trigger3() {
//Read & Save new values
Rate_set = myNex.readNumber("Rate.val");
MSpeed_set = myNex.readNumber("MSpeed.val");
// GSpeed_set = myNex.readNumber("SGSpeed.val");
if (Rate_save != Rate_set) {
EEPROM.write(10, Rate_set);
}
if (MSpeed_save != MSpeed_set) {
EEPROM.write(15, MSpeed_set);
}
if (EEPROM.read(10) == Rate_set) {
myNex.writeStr("b0.txt", "SAVED");
}
delay(1000);
myNex.writeStr("b0.txt", "SAVE");
setup();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Cailbrate Confirm
void trigger11() {
GSpeed_set = myNex.readNumber("CGSpeed.val");
GSpeed_set = myNex.readNumber("CGSpeed.val");
Rate_set = myNex.readNumber("CRate.val");
MSpeed_set = myNex.readNumber("CMSpeed.val");
if (GSpeed_save != GSpeed_set) {
EEPROM.write(0, GSpeed_set);
}
if (Rate_save != Rate_set) {
EEPROM.write(10, Rate_set);
}
if (MSpeed_save != MSpeed_set) {
EEPROM.write(15, MSpeed_set);
}
Serial.println("GSpeed_set");
Serial.println(GSpeed_set);
Serial.println("Rate_set");
Serial.println(Rate_set);
Serial.println("MSpeed_set");
Serial.println(MSpeed_set);
delay(500);
setup();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Calibrate GO
void trigger6() {
run1 = 1;
MSpeed_cal = myNex.readNumber("SMS.val");
MSpeed_cal = myNex.readNumber("SMS.val");
Calibrate();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Calibrate Stop
void trigger7() {
run1 = 0;
Calibrate();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Blower Fan
void trigger8() {
if (fan == 0) {
fan = 1;
myNex.writeNum("t7.bco", 1024);
myNex.writeNum("t7.bco", 1024);
myNex.writeNum("t8.bco", 50674);
} else if (fan == 1) {
fan = 0;
myNex.writeNum("t7.bco", 50674);
myNex.writeNum("t7.bco", 50674);
myNex.writeNum("t8.bco", 63488);
}
if (fan == 1) {
digitalWrite(7, HIGH);
// Serial.println("FAN ON");
}
else {
digitalWrite(7, LOW);
// Serial.println("FAN OFF");
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Adv Cal Stop
void trigger10() {
run2 = 0;
analogWrite(Motor, 0);
analogWrite(Motor, 0);
AdvCalibrate();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Adv Cal Run
void trigger9() {
run2 = 1;
MSpeed_cal = 255.0;
AdvCalibrate();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Adv Cal Save
void trigger4() {
//Read Maximum RPM
RPM_set = myNex.readNumber("rpmlock.val");
RPM_set = myNex.readNumber("rpmlock.val");
run2 = 0;
analogWrite(Motor, 0);
if (RPM_set != RPM_max) {
EEPROM.write(20, RPM_set);
}
if (EEPROM.read(20) == RPM_set) {
myNex.writeStr("rpmsave.txt", "SAVED");
delay(1000);
}
myNex.writeStr("rpmsave.txt", "SAVE");
setup();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Adv Cal1 Save
void trigger5() {
Diff_set = myNex.readNumber("diff.val");
aggKp_set = myNex.readNumber("aggKp.val");
Kp_set = myNex.readNumber("Kp.val");
aggKi_set = myNex.readNumber("aggKi.val");
Ki_set = myNex.readNumber("Ki.val");
aggKd_set = myNex.readNumber("aggKd.val");
Kd_set = myNex.readNumber("Kd.val");
// aggKi_set /= 1000;
Serial.println();
Serial.println(aggKp_set);
Serial.println(Kp_set);
if (Diff_set != Diff_save) {
EEPROM.write(80, Diff_set);
}
if (aggKp_set != aggKp_save) {
EEPROM.put(25, aggKp_set);
}
if (Kp_set != Kp_save) {
EEPROM.put(50, Kp_set);
}
if (aggKi_set != aggKi_save) {
EEPROM.put(30, aggKi_set);
}
if (Ki_set != Ki_save) {
EEPROM.put(60, Ki_set);
}
if (aggKd_set != aggKd_save) {
EEPROM.write(40, aggKd_set);
}
if (Kd_set != Kd_save) {
EEPROM.write(70, Kd_set);
}
if (EEPROM.get(80, Diff_set) == Diff_set) {
myNex.writeStr("pidsave.txt", "SAVED");
delay(1000);
}
myNex.writeStr("pidsave.txt", "SAVE");
setup();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Run Calibration Function
void Calibrate() {
MSpeed_cal = (MSpeed_cal / 100.0) * 255.0;
while (run1 == 1) {
mySerial.end();
myNex.NextionListen();
currT = millis();
deltaT = currT - prevT;
myNex.NextionListen();
if (deltaT >= 10) {
deltaT /= 1.0e03 ;
diff = pos - pos_i;
velocity2 = diff / deltaT;
v2 = (velocity2 / PPRev) * 60.0;
vFilt = Filter.updateEstimate(v2);
myNex.NextionListen();
Serial.println(vFilt);
Input = (vFilt / RPM_max) * 255;
prevT = currT;
pos_i = pos;
}
myNex.NextionListen();
Setpoint = MSpeed_cal;
int gap = abs(Setpoint - Input);
myNex.NextionListen();
if (gap < Diffpid_save) {
encoder.SetTunings(Kp, Ki, Kd);
} else
{
encoder.SetTunings(aggKp, aggKi, aggKd);
}
myNex.NextionListen();
encoder.Compute();
analogWrite(Motor, Output);
myNex.NextionListen();
//
// Serial.print("Setpoint");
// Serial.print(" ");
// Serial.print("Input");
// Serial.print(" ");
// Serial.println("Output");
// Serial.print(Setpoint);
// Serial.print(" ");
// Serial.print(Input);
// Serial.print(" ");
// Serial.println(Output);
// myNex.writeNum("VSrpm.val", Setpoint);
// myNex.writeNum("VArpm.val", Input);
if (run1 == 0) {
analogWrite(Motor, 0);
mySerial.begin(9600);
break;
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Run Advanced Calibration Function
void AdvCalibrate() {
while (run2 == 1) {
mySerial.end();
myNex.NextionListen();
currT = millis();
deltaT = currT - prevT;
myNex.NextionListen();
if (deltaT >= 200) {
deltaT /= 1.0e03 ;
diff = pos - pos_i;
velocity2 = diff / deltaT;
v2 = (velocity2 / PPRev) * 60.0;
vFilt = Filter.updateEstimate(v2);
myNex.NextionListen();
Input = (vFilt / RPM_max) * 255;
prevT = currT;
pos_i = pos;
// Serial.print("v2");
// Serial.print(" ");
// Serial.println("V Filt");
// Serial.print(v2);
// Serial.print(" ");
// Serial.println(vFilt);
}
//myNex.writeNum("rpmtest.val", vFilt);
myNex.NextionListen();
analogWrite(Motor, 255);
myNex.NextionListen();
advcurT = millis();
if (advcurT - advprevT >= 500) {
myNex.writeNum("rpmtest.val", vFilt);
advprevT = advcurT;
}
myNex.NextionListen();
if (run2 == 0) {
analogWrite(Motor, 0);
mySerial.begin(9600);
break;
}
}
}