I have a PID controller code that controls position. I have two motors to use that code. To use them at the same time, I wrote another code that does the same thing as Left Motor and Right Motor (L and R). However, in the second code(that is made for two motors) motors starts to stutter. Everything was fine in the first code and they were nailing the target position with the same PID constants. I don't know what is wrong. Everything should work. I am in hurry, I appreciate faster answers. Thank you...
Note: I used the word stuttering to mean "keeps changing directions very fast", CW,CCW,CW,CCW in miliseconds.
Code 1:
// This alternate version of the code does not require
// atomic.h. Instead, interrupts() and noInterrupts()
// are used. Please use this code if your
// platform does not support ATOMIC_BLOCK.
#define ENCA 2 // YELLOW
#define ENCB 4 // WHITE
#define PWM 10
#define IN2 8
#define IN1 9
volatile int posi = 0; // specify posi as volatile: https://www.arduino.cc/reference/en/language/variables/variable-scope-qualifiers/volatile/
long prevT = 0;
float eprev = 0;
float eintegral = 0;
void setup() {
Serial.begin(9600);
pinMode(ENCA,INPUT);
pinMode(ENCB,INPUT);
attachInterrupt(digitalPinToInterrupt(ENCA),readEncoder,RISING);
pinMode(PWM,OUTPUT);
pinMode(IN1,OUTPUT);
pinMode(IN2,OUTPUT);
Serial.println("target pos");
}
void loop() {
// set target position
//int target = 1200;
int target = 5000;
// PID constants
float kp = 30;
float kd = 0.48;
float ki = 0.05;
// time difference
long currT = micros();
float deltaT = ((float) (currT - prevT))/( 1.0e6 );
prevT = currT;
// Read the position
int pos = 0;
noInterrupts(); // disable interrupts temporarily while reading
pos = posi;
interrupts(); // turn interrupts back on
// error
int e = pos - target;
// derivative
float dedt = (e-eprev)/(deltaT);
// integral
eintegral = eintegral + e*deltaT;
// control signal
float u = kp*e + kd*dedt + ki*eintegral;
// motor power
float pwr = fabs(u);
if( pwr > 255 ){
pwr = 255;
}
// motor direction
int dir = 1;
if(u<0){
dir = -1;
}
// signal the motor
setMotor(dir,pwr,PWM,IN1,IN2);
// store previous error
eprev = e;
Serial.print(target);
Serial.print(" ");
Serial.print(pos);
Serial.println();
}
void setMotor(int dir, int pwmVal, int pwm, int in1, int in2){
analogWrite(pwm,pwmVal);
if(dir == 1){
digitalWrite(in1,HIGH);
digitalWrite(in2,LOW);
}
else if(dir == -1){
digitalWrite(in1,LOW);
digitalWrite(in2,HIGH);
}
else{
digitalWrite(in1,LOW);
digitalWrite(in2,LOW);
}
}
void readEncoder(){
int b = digitalRead(ENCB);
if(b > 0){
posi++;
}
else{
posi--;
}
}
Code 2:
#include <SoftwareSerial.h>
#define L_ENCA 2 // YELLOW
#define L_ENCB 4// GREEN
#define L_PWM 10
#define L_IN2 8
#define L_IN1 9
#define R_ENCA 3 // YELLOW
#define R_ENCB 5// GREEN
#define R_PWM 13
#define R_IN2 11
#define R_IN1 12
#define Enable_Wifi 6
#define Transmit_On_Off 7
const int pinRX = 0;
const int pinTX = 1;
volatile int posiL = 0; // specify posi as volatile: https://www.arduino.cc/reference/en/language/variables/variable-scope-qualifiers/volatile/
volatile int posiR = 0;
long prevT = 0;
float eprevL = 0;
float eprevR = 0;
float eintegralL = 0;
float eintegralR = 0;
char state;
char idle = '0';
char left = '1';
char right = '2';
char forward = '3';
char backward = '4';
SoftwareSerial apc220(pinRX, pinTX); // Crt softserial port and bind tx / rx to appropriate PINS
void setup() {
Serial.begin(9600);
pinMode(L_ENCA,INPUT);
pinMode(L_ENCB,INPUT);
attachInterrupt(digitalPinToInterrupt(L_ENCA),readEncoderL,RISING);
pinMode(L_PWM,OUTPUT);
pinMode(L_IN1,OUTPUT);
pinMode(L_IN2,OUTPUT);
Serial.println("targetL targetR posL posR");
pinMode(R_ENCA,INPUT);
pinMode(R_ENCB,INPUT);
attachInterrupt(digitalPinToInterrupt(R_ENCA),readEncoderR,RISING);
pinMode(R_PWM,OUTPUT);
pinMode(R_IN1,OUTPUT);
pinMode(R_IN2,OUTPUT);
pinMode (Enable_Wifi, OUTPUT);
digitalWrite (Enable_Wifi,HIGH);
pinMode (Transmit_On_Off, OUTPUT);
digitalWrite (Transmit_On_Off,LOW);
apc220.begin(9600);
}
void loop() {
if (apc220.available())
{
state = char(apc220.read());
}
long int target_L = -5000; //Target_L needs to be negative for to be forward
long int target_R = 1000; //
if(state == idle){ //0
long int target_L = 0;
long int target_R = 0;
Serial.println("default");
}
else if(state == forward){ //3
long int target_L = -5000;
long int target_R = 5000;
Serial.println("forward");
}
else if(state == backward){ //4
long int target_L = 5000;
long int target_R = -5000;
Serial.println("backward");
}
else if(state == left){ //1
long int target_L = -1000;
long int target_R = 5000;
Serial.println("left");
}
else if(state == right){ //2
long int target_L = -5000;
long int target_R = 1000;
Serial.println("right");
}
// PID constants
float kp_R = 30;
float kd_R = 0.48;
float ki_R = 0.05;
float kp_L = 30;
float kd_L = 0.48;
float ki_L = 0.05;
// time difference
long currT = micros();
float deltaT = ((float) (currT - prevT))/( 1.0e6 );
prevT = currT;
// Read the position
int posL = 0;
int posR = 0;
noInterrupts(); // disable interrupts temporarily while reading
posL = posiL;
interrupts(); // turn interrupts back on
noInterrupts(); // disable interrupts temporarily while reading
posR = posiR;
interrupts(); // turn interrupts back on
// error
int eL = posL - target_L;
int eR = posR - target_R;
// derivative
float dedtL = (eL-eprevL)/(deltaT);
float dedtR = (eR-eprevR)/(deltaT);
// integral
eintegralL = eintegralL + eL*deltaT;
eintegralR = eintegralR + eR*deltaT;
// control signal
float uL = kp_L*eL + kd_L*dedtL + ki_L*eintegralL;
float uR = kp_R*eR + kd_R*dedtR + ki_R*eintegralR;
// motor power
float pwrL = fabs(uL);
if( pwrL > 255 ){
pwrL = 255;
}
float pwrR = fabs(uR);
if( pwrR > 255 ){
pwrR = 255;
}
// motor direction
int dirL = 1;
if(uL<0){
dirL = -1;
}
int dirR = 1;
if(uR<0){
dirR = -1;
}
// signal the motor
setMotor(dirL,pwrL,L_PWM,L_IN1,L_IN2);
setMotor(dirR,pwrR,R_PWM,R_IN1,R_IN2);
// store previous error
eprevL = eL;
eprevR = eR;
Serial.print(target_L);
Serial.print(" ");
Serial.print(target_R);
Serial.print(" ");
Serial.print(posL);
Serial.print(" ");
Serial.print(posR);
Serial.println();
}
void setMotor(int dir, int pwmVal, int pwm, int in1, int in2){
analogWrite(pwm,pwmVal);
if(dir == 1){
digitalWrite(in1,HIGH);
digitalWrite(in2,LOW);
}
else if(dir == -1){
digitalWrite(in1,LOW);
digitalWrite(in2,HIGH);
}
else{
digitalWrite(in1,LOW);
digitalWrite(in2,LOW);
}
}
void readEncoderL(){
int bL = digitalRead(L_ENCB);
if(bL > 0){
posiL++;
}
else{
posiL--;
}
}
void readEncoderR(){
int bR = digitalRead(R_ENCB);
if(bR > 0){
posiR++;
}
else{
posiR--;
}
}
Image 1:(First Code)
Image 2:(Second Code, Check especially TargetL and posL)