Differential drive not driving straight

Hi,
I have a three wheel differential drive that I am trying to drive straight using only encoders(no other sensor). I am using a teensy 3.2 microcontroller, a sabertooth 2x12 motor driver, HC-05 Bluetooth module, two dc motors, and two external rotary/incremental encoders having 360ppr. I am new to Arduino and learning slowly.

The problem is that I am unable to get a stable RPM value for my motors. I have tried adjusting the gains but the result is always varying in a range of 140-160 RPM. I started with P first then D and then I, but got no success. After changing the gains again and again the best I got was a constant oscillation of RPM from 133 to 166 and some 150 values in between. Increasing D does not damp the oscillation. I am getting the same result with both motors but bigger amplitude in motor 2.

As a result of there is a difference in the speed of wheels every time and the bot deviates from a straight path. I am stuck here so please help. Here is my code and sorry for any mistakes. Do correct me.

#include <SoftwareSerial.h>
#include <SabertoothSimplified.h>

SoftwareSerial SWSerial1(4, 2); //Software Serial to communicate with the motor controller
SoftwareSerial SWSerial2(0,1); //communicating with HC-05
SabertoothSimplified ST1(SWSerial1);

int pinA1 = 11; 
int pinB1 = 12;
int pinA2 = 7;
int pinB2 = 8;
int count1 = 0, count2 = 0; 
int prevCount1=0, prevCount2 = 0;

unsigned long prevTime1=0,prevTime2=0,prevTime3=0,prevTime4=0,prevTime5=0;

float reqRPM1 = 0,reqRPM2 = 0,reqTheta = 0 ;
float actRPM1 =0,actRPM2= 0;
float baseSpeed = 0,I1=0,II1=0,II2 = 0,I2 = 0,I3=0,II3=0,motorInput1 = 0,motorInput2=0,correction = 0;
float kp1 = 0.25,ki1 = 0.015,ki2 = 0.008,kp3 = 1.2,ki3=0.01;
float error1=0,error2 = 0, errorRPM = 0,errorTheta = 0,lr = 0;
float Theta =0, DTheta = 0,lTheta = 0;

String t;
char driveBot;

#define TWOPI    6.2831853072

void Check2() // interrupt to count encoder2 ticks
{
    if(digitalRead(pinB2) == digitalRead(pinA2))
     count2--; 
     else
     count2++; 

}
void Check1() // interrupt to count encoder1 ticks
{
    if(digitalRead(pinB1) == digitalRead(pinA1))
     count1++; 
     else
     count1--;

}

void setup() 
{
   Serial.begin(115200);
   SWSerial1.begin(9600);
   SWSerial2.begin(115200);
  
   ST1.motor(2,0);  
   delay(1000);
 
   pinMode(pinA1,INPUT);
   pinMode(pinB1,INPUT);
   pinMode(pinA2,INPUT);
   pinMode(pinB2,INPUT);
  
   attachInterrupt(digitalPinToInterrupt(pinA1),Check1,RISING);
   attachInterrupt(digitalPinToInterrupt(pinA2),Check2,RISING);


   baseSpeed = reqRPM1*kp1;  // providing a minimum speed at startup
   ST1.motor(2,baseSpeed);   
   ST1.motor(1,baseSpeed);
   
   prevTime1 = micros(); 
   prevTime2 = micros();
   prevTime3 = micros();
   prevTime4 = micros();
   prevTime5 = micros();

}

void loop() {

  if(SWSerial2.available())
{
  t = SWSerial2.readStringUntil('\n');
  driveBot = t.charAt(0);
  SWSerial2.print(" driveBot = ");
  SWSerial2.print(driveBot);
  kp3 = (t.substring(2,6).toFloat());
  SWSerial2.print(" kp3 = ");
  SWSerial2.println(kp3);
  ki3 = (t.substring(8).toFloat());
  SWSerial2.print(" ki3 = ");
  SWSerial2.println(ki3);
  
//resetting values each time I start driving
  ST1.motor(1,0);
  ST1.motor(2,0);
  error1=0,error2=0,errorRPM=0;
  I1=0,II1=0,II2 = 0,I2 = 0,I3=0,II3=0,motorInput1 = 0,motorInput2=0;
  }
  
 if(driveBot == 'f')  reqRPM1 = -150,reqRPM2 = -150;
 if(driveBot == 'b') reqRPM1 = 150,reqRPM2 = 150;
 if(driveBot == 's') 
 {
  reqRPM1 = 0,reqRPM2 = 0,Theta=0;
  ST1.motor(1,0);
  ST1.motor(2,0);  
 }

 delay(100);

 Drive();

}

void Drive()
{
  if((micros()-prevTime1)>1000)
  {
   actRPM1 = getRPM1();
   Pid1();
   actRPM2 = getRPM2();
   Pid2();
   Pid3();

   ST1.motor(1,motorInput1);
   ST1.motor(2,motorInput2);
   
   prevTime1 = micros();
  }
}

int getRPM1()
{
    long pps1 = long(count1 - prevCount1);
    float ppr1 = 360;
    prevTime2 = micros() - prevTime3;
    double tt =  prevTime2 / 6000.0 ;
    double actRPM1 = ((pps1*10000.0)/(tt*ppr1));
    prevTime3 = micros();
    SWSerial2.print("   rpm1= " );
    SWSerial2.print(count1);
    prevCount1 = count1;
    return actRPM1;
}

int getRPM2()
{
    long pps2 = long(count2 - prevCount2);
    float ppr2 = 360;
    prevTime4 = micros() - prevTime5;
    double tt =  prevTime4 / 6000.0 ;
    double actRPM2 = ((pps2*10000.0)/(tt*ppr2));
    prevTime5 = micros();
    SWSerial2.print("   rpm2= " );
    SWSerial2.print(count2);
    prevCount2 = count2;
    return actRPM2;
}

void Pid1()
{
  error1 = reqRPM1 - actRPM1;
  I1 = error1 * ki1;
  II1 = II1 + I1;
  if(II1 > 127)II1 = 127;
  if(II1 < -127) II1 = -127;
  motorInput1 = baseSpeed + II1;
  if(motorInput1 > 127) motorInput1 = 127;
}

void Pid2()
{
  error2 = reqRPM2 - actRPM2;
  I2 = error2 * ki2;
  II2 = II2 + I2;
  if(II2 > 127)II2 = 127;
  if(II2 < -127) II2 = -127;
  motorInput2 = baseSpeed + II2;
  if(motorInput2 > 127) motorInput2 = 127;
}

void Pid3()
{
  errorRPM = actRPM1-actRPM2;
  DTheta=((100*3.14159265359*errorRPM)/348);
  Theta = Theta + atan(DTheta);
  errorTheta = reqTheta - Theta;
  I3 = errorTheta * ki3;
  II3 = II3 + I3;
  correction = kp3*errorTheta+II3;

  if(t != 's')   lTheta = Theta;  

  SWSerial2.print(" LastTheta = ");
  SWSerial2.print(lTheta);
  SWSerial2.print(" Theta = ");
  SWSerial2.println(Theta);
  
  motorInput1 = motorInput1 + correction;
}

The Pid3 function keeps the bot straight in the beginning but after a while the difference in speed causes much deviation and it starts to deviate.

SoftwareSerial SWSerial2(0,1); //communicating with HC-05

Why are you doing software serial on the hardware serial pins?

   Serial.begin(115200);

You can't possibly do hardware AND software serial on the same set of pins at the same time.

delay(100);

You are waiting a tenth of a second between each check for relative speed of the wheels. I suspect that this is enough time for error to grow.

vinceherman:

delay(100);

You are waiting a tenth of a second between each check for relative speed of the wheels. I suspect that this is enough time for error to grow.

I was using micros everywhere so I thought that delay would also be in the same unit. I have used it with 10ms interval but it still didn't give me the same speed nor straight motion

PaulS:

SoftwareSerial SWSerial2(0,1); //communicating with HC-05

Why are you doing software serial on the hardware serial pins?

   Serial.begin(115200);

You can't possibly do hardware AND software serial on the same set of pins at the same time.

I was using it on 6 and 7 but there was some error, so a senior told me to use 0 and 1. I think I just changed it to 0 and 1 without realizing this. Also, earlier I was using the serial on 0,1 for getting readings but after bluetooth I am not so I thought there would be no issue as I received info without any error.

Hi, since I was not getting any success above so I turned to tune my motors once again. I am using the Zeigler Nichols approach for which I am increasing my P gain untill I get constant oscillations in my system, while keeping I and D gains zero. Here is my code:

#include <SoftwareSerial.h>
#include <SabertoothSimplified.h>

SoftwareSerial SWSerial1(4, 2);
SabertoothSimplified ST1(SWSerial1);

int pinA1 = 11; 
int pinB1 = 12;

long count1 = 0;
long prevCount1=0;

unsigned long prevTime1=0,prevTime2=0,prevTime3=0;

float reqRPM1 = 150,actRPM1 =0,motorInput1 = 0;
float kp1 = 0.2,ki1 = 0,kd1 = 0;
float error1=0,lerror1=0;
float P1 = 0,I1=0,II1=0,D1 = 0;


void Check1()
{
    if(digitalRead(pinB1) == digitalRead(pinA1))
     count1++; 
     else
     count1--;

}

void setup() {
   Serial.begin(115200);
   SWSerial1.begin(38400);

   pinMode(pinA1,INPUT);
   pinMode(pinB1,INPUT);
   attachInterrupt(digitalPinToInterrupt(pinA1),Check1,RISING);

   prevTime1 = micros(); 
   prevTime2 = micros();
   prevTime3 = micros();
}

void loop() {
  Drive();
  
}
void Drive()
{
  if((micros()-prevTime1)>10000)
  {
   actRPM1 = getRPM1();
   Pid1();
   ST1.motor(1,motorInput1);
   ST1.motor(2,0);
   prevTime1 = micros();
  }
}
int getRPM1()
{
    long pps1 = long(count1 - prevCount1);
    float ppr1 = 360;

    prevTime2 = micros() - prevTime3;
    double tt =  prevTime2 / 6000.0 ;
    double actRPM1 = (((pps1*10000.0)/(tt*ppr1))*0.5);
    prevTime3 = micros();

    Serial.print("   rpm1= " );
    Serial.println(actRPM1);
    prevCount1 = count1;
    return actRPM1;  
}
void Pid1()
{
  error1 = reqRPM1 - actRPM1;
  P1 = error1*kp1;
  I1 = error1 * ki1;
  II1 = II1 + I1;
  D1 = kd1*(error1 - lerror1);

  if(II1 > 127)II1 = 127;
  if(II1 < -127) II1 = -127;

  motorInput1 = P1 + II1 + D1;
  lerror1 = error1;

  if(motorInput1 > 127) motorInput1 = 127;
}

Now, my PID takes current RPM as input and feeds the output to motor to reach setpoint of 150RPM. But, the thing is that when I start increasing my P, I don't get a stable RPM infact the value oscillates on every kp at a different value. The video links below will help you to understand this better. Sorry I was unable to explain it but please go through them and help me to determine whether I can use these as my constant oscillations to calculate my gains.

Kp = 0.1

kp=0.2

kp=0.3

After kp=0.3, a small jittery sound starts to come from my motor and is very low at this point. It gets louder as I increase my P.
kp=0.4

kp=0.5

Beyond 0.5, It gets louder and louder. It is doing so at all these rapid ups and downs that you can see.
kp=0.6

kp=0.8

Please help me.

Perhaps a mechanical solution may work. I did a search, using my favorite search engine, on the words "rc car differential gears' and found, what I believe, a few solutions.

There are at least two potential problems with your interrupt code that should be fixed, and I'm surprised that it works at all.

  1. It is usually required to declare variables shared with interrupt routines as "volatile", e.g.
volatile long count1 = 0;
  1. You need to protect accesses to those variables, otherwise they can become corrupted. Make a copy of "count1" before using it in the main program.
             noInterrupts();
             long count1Copy = count1;
             interrupts();
             long pps1 = count1Copy - prevCount1;
             ...
             prevCount1 = count1Copy;

Finally, you can't accurately measure RPM using a very short interval. The result will be noisy and you may need to smooth it by averaging some measurements. Otherwise the PID will overreact to noise.

jremington:

  1. It is usually required to declare variables shared with interrupt routines as "volatile", e.g.
volatile long count1 = 0;

I understood this part.

jremington:
2. You need to protect accesses to those variables, otherwise they can become corrupted. Make a copy of "count1" before using it in the main program.

But for now the call to interrupt is in my setup func., shall I call it from the loop.

jremington:
Finally, you can't accurately measure RPM using a very short interval. The result will be noisy and you may need to smooth it by averaging some measurements. Otherwise, the PID will overreact to noise.

So, should I opt for another approach or continue with averaging. Also, how to do so, cause if I'll do it directly within the loop, I'll get the same value of count multiple times and it will give me zero pps thus hindering my calculation

the call to interrupt is in my setup func.

Interrupts happen automatically. In the setup() function, you are defining which interrupt processing routine to use, as appropriate.

Two options: (1) break this loop apart, and get several values of RPM and average, before calling Pid1() or (2) use longer sampling periods than 10 ms.

  if((micros()-prevTime1)>10000)
  {
   actRPM1 = getRPM1();
   Pid1();
   ST1.motor(1,motorInput1);
   ST1.motor(2,0);
   prevTime1 = micros();
  }

jremington:
Two options: (1) break this loop apart, and get several values of RPM and average, before calling Pid1()

Thanks for the suggestion jremington, I used the moving average method to remove the noise and made a reset after every 100th value.

This helped me give stable RPM readings but when I used it as an input for my PID1, I was getting an oscillating value probably because the average was taking longer to reach the setpoint whenever it crossed it, and within that period the I term would increase so much that the wheel would reach the max speed and min speed again and again and oscillate back and forth.

So, I looked up for it and tried out the Kalman Filter to remove the input noise with a little bit of lag. This is the library I used SimpleKalmanFilter .

This is the code:

#include <SimpleKalmanFilter.h>
#include <SoftwareSerial.h>
#include <SabertoothSimplified.h>

SoftwareSerial SWSerial1(4, 2);
SabertoothSimplified ST1(SWSerial1);
SimpleKalmanFilter rpmKalmanFilter(1,1,0.01);

int pinA1 = 11; 
int pinB1 = 12;
long count1 = 0,i=1;
long prevCount1=0;
unsigned long prevTime1=0,prevTime2=0,prevTime3=0;
double reqRPM1 = 150,actRPM1 =0,motorInput1 = 0;
double total=0,avgRPM=0,est_avgRPM=0;
float Kp1 =  0.17232,Ki1 = 0.10114,Kd1 =0.07340;
float error1=0,lerror1=0;
float I1,P,I,D,lastInput1;

void Check1()
{
    if(digitalRead(pinB1) == digitalRead(pinA1))
     count1++; 
     else
     count1--;
}

void setup() {
   Serial.begin(115200);
   SWSerial1.begin(38400);

   pinMode(pinA1,INPUT);
   pinMode(pinB1,INPUT);
   attachInterrupt(digitalPinToInterrupt(pinA1),Check1,RISING);
 
   prevTime1 = micros(); 
   prevTime2 = micros();
   prevTime3 = micros();
}

void loop() {
 while(!Serial.available()) ;
 
 Drive();
  
}

void Drive()
{
  if((micros()-prevTime1)>10000)
  { 
    actRPM1 = getRPM1();  

//    if(actRPM1!=0){
//      if(i>100){
//      i=2;
//      total = avgRPM   ;            // resetting total to last average and starting again for next 100
//    }
//    total = total+actRPM1;
//    avgRPM = total/i;              // averaging last 100 values
//    i++;

    est_avgRPM = rpmKalmanFilter.updateEstimate(actRPM1);
    Serial.print(actRPM1);
//    Serial.print("  ");
//    Serial.print(avgRPM);
    Serial.print("  ");
    Serial.println(est_avgRPM);
    
      Pid1();
//      Serial.print(" ku= ");
//      Serial.print(Ku,5);
//      Serial.print(" Pu= ");
//      Serial.print(Pu,5);
//      Serial.print(" Kp= ");
//      Serial.print(Kp1,5);
//      Serial.print(" Ki= ");
//      Serial.print(Ki1,5);
//      Serial.print(" kd= ");
//      Serial.println(Kd1,5);
   
   ST1.motor(1,motorInput1);
   ST1.motor(2,0);
   prevTime1 = micros();}
   
  }

void Pid1()
{
  error1 = reqRPM1 - est_avgRPM;
  P = error1 * Kp1;
  I1 = error1 * Ki1;
  I = I + I1;
  D = (est_avgRPM - lastInput1)*Kd1;
  lastInput1 = est_avgRPM;
  
  if(I > 127)I = 127;
  if(I < -127) I = -127;
  motorInput1 = P + I + D;
  if(motorInput1 > 127) motorInput1 = 127;
}
int getRPM1()
{
    long pps1 = long(count1 - prevCount1);
    prevCount1 = count1;
    float ppr1 = 360;
    prevTime2 = micros() - prevTime3;
    double tt =  prevTime2 / 6000.0 ;
    double RPM = (((pps1*10000.0)/(tt*ppr1))*0.5);
    prevTime3 = micros();
    return RPM;  
}

The result was way better and responsive and worked well with my PID, no more oscillations. However, I think I have to tune my system again to adapt to the new input. Image attached below.

Also, if there are any suggestions/ references to learn more about kalman filter, I would love it, because I think I will have to tune my kalman parameters too, right now I am using the default values.

Thanks again :slight_smile:

If the PID output is oscillating, then the PID algorithm is not tuned properly.

This does not sound like a good idea, as it involves an arbitrary parameter and a physically unrealistic discontinuity:

made a reset after every 100th value

In one dimension, a Kalman filter is equivalent to an exponential filter, and really does not add anything useful except another parameter to be tuned.

jremington:
If the PID output is oscillating, then the PID algorithm is not tuned properly.

It wasn't I guess for the average method but the same parameters worked well when I used the output of the Kalman filter as input for my PID.

jremington:
This does not sound like a good idea, as it involves an arbitrary parameter and a physically unrealistic discontinuity:

You are right, it wasn't. :smiley:

jremington:
In one dimension, a Kalman filter is equivalent to an exponential filter, and really does not add anything useful except another parameter to be tuned.

But, it did help my result to stabilize. I'll keep looking though, to improve it further.

Hi again, been a while but I got another problem with my differential :sweat_smile:

After I used the Kalman filtered RPM value as my PID input, the motors are now giving an oscillating output that somewhat looks sinusoidal. I am using the SimpleKalmanFilter arduino library with the measurement error value set to 10, rest is the default. The code is below:

#include <SimpleKalmanFilter.h>
#include <SoftwareSerial.h>
#include <SabertoothSimplified.h>

SoftwareSerial SWSerial1(4, 2);   
SoftwareSerial bt(21,19);

SabertoothSimplified ST1(SWSerial1);

SimpleKalmanFilter rpmKalmanFilter1(1,1,0.01);
SimpleKalmanFilter rpmKalmanFilter2(1,1,0.01);

int pinA1 = 12; 
int pinB1 = 11;
int pinA2 = 7; 
int pinB2 = 8;

long count1 = 0,count2 = 0;
long prevCount1=0,prevCount2=0;

unsigned long prevTime1=0,prevTime2=0,prevTime3=0,prevTime4=0,prevTime5=0;

double reqRPM1 = 30,actRPM1 =0,motorInput1 = 0;
double reqRPM2 = 30,actRPM2 =0,motorInput2 = 0;
double est_avgRPM1=0,est_avgRPM2=0;

float Kp2= 0.36965, Ki2= 0.068877, Kd2= 0.04960;
float Kp1= 0.32740, Ki1= 0.072460, Kd1= 0.03698; 
float error1=0,lerror1=0;
float error2=0,lerror2=0;
float i1,P1,I1,D1,lastInput1;
float i2,P2,I2,D2,lastInput2;

void Check1()
{
    if(digitalRead(pinB1) == digitalRead(pinA1))
     count1++; 
     else
     count1--;
}
void Check2()
{
    if(digitalRead(pinB2) == digitalRead(pinA2))
     count2++; 
     else
     count2--;
}


void setup() {
   Serial.begin(115200);
   SWSerial1.begin(38400);
   bt.begin(9600);
   
   pinMode(pinA1,INPUT);
   pinMode(pinB1,INPUT);
   pinMode(pinA2,INPUT);
   pinMode(pinB2,INPUT);
   
   attachInterrupt(digitalPinToInterrupt(pinA1),Check1,RISING);
   attachInterrupt(digitalPinToInterrupt(pinA2),Check2,RISING);
   
   prevTime1 = micros(); 
   prevTime2 = micros();
   prevTime3 = micros();
   prevTime4 = micros();
   prevTime5 = micros();
}

void loop() {
//   while(!Serial.available()) ;
 
   Drive(); 
}


void Drive()
{
  if((micros()-prevTime1)>10000)
  { 
    prevTime1 = micros();
    actRPM1 = getRPM1(); 
    actRPM2 = getRPM2(); 
    est_avgRPM1 = rpmKalmanFilter1.updateEstimate(actRPM1);
    est_avgRPM2 = rpmKalmanFilter2.updateEstimate(actRPM2);
    Pid1();
    Pid2();
    ST1.motor(1,motorInput1);
    ST1.motor(2,motorInput2);
    Serial.print("  ");
    Serial.print(est_avgRPM1 - est_avgRPM2);
// Serial.print("  ");
// Serial.print(actRPM1);
    Serial.print("  ");
    Serial.print(est_avgRPM1);
// Serial.print("  ");
// Serial.print(actRPM2);
    Serial.print("  ");
    Serial.println(est_avgRPM2);

   }

}


void Pid1()
{
  error1 = reqRPM1 - est_avgRPM1;
  P1 = error1 * Kp1;
  i1 = error1 * Ki1;
  I1 = i1 + I1;
  D1 = (est_avgRPM1 - lastInput1)*Kd1;
  lastInput1 = est_avgRPM1;
  
  if(I1 > 127)I1 = 127;
  if(I1 < -127) I1 = -127;
  motorInput1 = P1 + I1 + D1;
  if(motorInput1 > 127) motorInput1 = 127;
}
void Pid2()
{
  error2 = reqRPM2 - est_avgRPM2;
  P2 = error2 * Kp2;
  i2 = error2 * Ki2;
  I2 = i2 + I2;
  D2 = (est_avgRPM2 - lastInput2)*Kd2;
  lastInput2 = est_avgRPM2;
  
  if(I2 > 127)I2 = 127;
  if(I2 < -127) I2 = -127;
  motorInput2 = P2 + I2 + D2;
  if(motorInput2 > 127) motorInput2 = 127;
}


int getRPM1()
{
    long pps1 = long(count1 - prevCount1);
    prevCount1 = count1;
    float ppr1 = 360;
    prevTime2 = micros() - prevTime3;
    double tt1 =  prevTime2 / 6000.0 ;
    double RPM1 = (((pps1*10000.0)/(tt1*ppr1)));
    prevTime3 = micros();
    return RPM1;  
}
int getRPM2()
{
    long pps2 = long(count2 - prevCount2);
    prevCount2 = count2;
    float ppr2 = 360;
    prevTime4 = micros() - prevTime5;
    double tt2 =  prevTime4 / 6000.0 ;
    double RPM2 = (((pps2*10000.0)/(tt2*ppr2)));
    prevTime5 = micros();
    return RPM2;  
}

When I Keep the bot on ground, the bot drives and slows and drives and slows and so on. Here is the link to result. OnGround

Now, when I hold it in air, the result is exactly what I need and as soon as I Place it again on ground the result changes to sinusoidal(if it is one). Here is link InAir. For first 10 sec its in air then I place it on ground.

I tried lowering the gains(speically I) but it just changed the amplitude of oscillation.What to do? :frowning:

Perhaps the current issue is about the physical load on the motors? Wheels turn good with not load, wheels turn bad with load. More power, lighter load, bigger motors.

Idahowalker:
Perhaps the current issue is about the physical load on the motors? Wheels turn good with not load, wheels turn bad with load. More power, lighter load, bigger motors.

Yeah, forgot to add one thing, when I remove kalman filter from the equation, i.e. give the noisy input to PID it works fine even in load condition. I mean drives without stopping, although it causes an error in straight motion and bot deviates. Also, Is adding a Kalman Filter the right option, I mean is its application needed for my system.

LuciferMrningStr:
Also, Is adding a Kalman Filter the right option, I mean is its application needed for my system.

Have you used the plotter ( Tools | Serial Plotter ) to compare the raw data to the filtered data to see if the filtered data is what you want?

I like using PLX-DAQ (PLX-DAQ version 2 - now with 64 bit support! (and further new features) - Interfacing w/ Software on the Computer - Arduino Forum) to send data to an Excel spreadsheet for analysis.

Idahowalker:
Have you used the plotter ( Tools | Serial Plotter ) to compare the raw data to the filtered data to see if the filtered data is what you want?

I like using PLX-DAQ (PLX-DAQ version 2 - now with 64 bit support! (and further new features) - Interfacing w/ Software on the Computer - Arduino Forum) to send data to an Excel spreadsheet for analysis.

Yes, I am using it from the start and the raw data is definitely not what I want I think. The raw data as you can see in previous posts varies too much from the set point.eg. if I set my setpoint to 50RPM then my values go from 66-50-33 something like this. and the wheel RPM, when measured via tachometer, changes noticeably as 47.5,49.2,52.3,54.9,46.1 etc. Now, after I used the filter the value is somewhat like 49.5,50.5,49.1 etc. close to 50 I mean.

So, filtered one is I think the right one for me. Otherwise, I'm open to suggestions:).

Are those number with load or without load?

without load but I have tried the pid with load too and it works fine as long as I dont use Kalman filter. Also, I have monitored the data on my laptop via bluetooth communication while the bot was on ground when I didn't use Kalman filter and it drove without stopping.