I'm using a shaft encoder attached to a DC motor to measure RPM, a L293D IC to drive the motor and a Arduino board. My objective is to control the DC motor speed to roughly 200 RPM, and I'm trying to use the PID library of the arduino to achieve this. My problem, right now, is with the tuning. The system oscillates a lot, and I've tried several methods, but nothing seems to work. I've tried setting Kd and Ki to zero and adjusting Kp until I get a steady oscillation, without success. Also, adjusting Kd isn't doing damping. I've tried using a simple Python program to plot the RPM in function of time and this is what I'm getting:
Below is the Arduino code I'm using:
#include <PID_v1.h>
#define SpeedSetPoint 200
double Input, Output, Setpoint; //PID Variables
int potKp = 2;
int potKd = 3;
int potKi = 4;
float Kp = 0, Kd = 0, Ki =0;
PID myPid(&Input, &Output, &Setpoint, 0, 0, 0, DIRECT);
//RPM Counter
unsigned long start;
const byte encoderPinA = 2;//A pin -> interrupt pin 0
const byte encoderPinB = 4;//B pin -> digital pin 4
volatile long pulse;
volatile bool pinB, pinA, dir;
const byte ppr = 25, upDatesPerSec = 2;
const int fin = 1000 / upDatesPerSec;
const float konstant = 60.0 * upDatesPerSec / (ppr * 2);
int rpm=0;
int outputValue=0;
//DC Motor Pins
int pwm = 5;
int motorA1 = 10;
int motorA2 = 9;
void setup(){
Serial.begin(19200);
Input = 25;
Setpoint = SpeedSetPoint;
myPid.SetMode(AUTOMATIC);
attachInterrupt(0, readEncoder, CHANGE);
pinMode(encoderPinA,INPUT_PULLUP);
pinMode(encoderPinB,INPUT_PULLUP);
pinMode(pwm, OUTPUT);
pinMode(motorA1, OUTPUT);
pinMode(motorA2, OUTPUT);
//Start DC Motor
digitalWrite(pwm, HIGH);
digitalWrite(motorA1, HIGH);
digitalWrite(motorA2, LOW);
}
void loop() {
Kp = analogRead(potKp)/100.0;
Ki = analogRead(potKi)/1000.0;
Kd = analogRead(potKd)/1000.0;
myPid.SetTunings(Kp, Ki, Kd);
if(millis() - start > fin)
{
start = millis();
rpm = pulse * konstant;
rpm = abs(rpm);
Serial.println(rpm);
pulse = 0;
}//End RPM reading
Input = rpm;
myPid.Compute();
outputValue = Output;
//outputValue = map(outputValue, 0, 400, 180, 255);
analogWrite(pwm, outputValue);
Serial.print("RPM = ");
Serial.print(rpm);
Serial.print("\t");
Serial.print("Kp = ");
Serial.print(Kp);
Serial.print("\t");
Serial.print("Ki = ");
Serial.print(Ki);
Serial.print("\t");
Serial.print("Kd = ");
Serial.println(Kd);
}
void readEncoder()
{
pinA = bitRead(PIND,encoderPinA);
pinB = bitRead(PIND,encoderPinB);
dir = pinA ^ pinB; // if pinA & pinB are the same
dir ? --pulse : ++pulse; // dir is CW, else CCW
}
Any tips?