I am working on a school project which we need to drive a motor by encoder data
At this moment, we are just trying to reach a pre-determinet value in code, defined in "ref" variable below.
We use Arduino Mega for motor control and another Arduino Uno which is parallel grounded together connected parallel to the encoder so I may follow the data without Mega using serial communication, saving from time.
Motor:HXKJ-GS52-400W
Encoder:lpd3806 600 pulse
To match the speed of encoder to that of motor, we used 1:2 pulley mechanism.
Our power supply is rated as 24V-15A and gives 27.5V when we measured it. So our roughly maximum RPM is 6000 and 3000 on the encoder.
We tried to implement a PID loop with some adjustments and that's our code
#define A 2
#define B 3
#define PI 3.1415926535897932384626433832795
boolean A_set = false;
boolean B_set = false;
long encoderPos = 0;
const int in1 = 4;
const int in2 = 5;
const int enA = 6;
long ref=600;
void setup() {
Serial.begin(9600);
pinMode(A, INPUT_PULLUP);
pinMode(B, INPUT_PULLUP);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(enA, OUTPUT);
attachInterrupt(digitalPinToInterrupt(A),encodA,CHANGE);
attachInterrupt(digitalPinToInterrupt(B),encodB,CHANGE);
}
long K=0;
long AV;
long BV;
double W;
int sayac;
double Kp=0.80;
double Kd=-15; //225
double Ki=0.00002637;
long lastpos=0;
long err=0;
long sumerr=0;
long derr=0;
long lasterr=0;
long I=0;
int theta_ref=0;
void loop() {
//ref=analogRead(A8)*3.2258;
ref=-5400; //Bir tur 300
if (millis()>(K+3))
{err=(ref-encoderPos);
derr=(encoderPos-lastpos)/(3.3);
if (abs(err)<300)
{
sumerr+=err*(millis()-K);
}
lastpos=encoderPos;
K=millis();
}
if ((Kp*err+Ki*sumerr+Kd*derr)<0){
analogWrite(in1, min(255,(abs((Kp*err+Ki*sumerr+Kd*derr))+10)*(1-(abs(err)<50))*(1+0.4*(derr==0))));
analogWrite(in2, 0);
}
else
{
analogWrite(in1, 0);
analogWrite(in2, min(255,(abs((Kp*err+Ki*sumerr+Kd*derr))+10)*(1-(abs(err)<50))*(1+0.4*(derr==0))));
}
void encodA() {
// Test transition
A_set = digitalRead(A) == HIGH;
// and adjust counter + if A leads B
encoderPos += (A_set != B_set) ? +1 : -1;
}
// Interrupt on B changing state
void encodB() {
// Test transition
B_set = digitalRead(B) == HIGH;
// and adjust counter + if B follows A
encoderPos += (A_set == B_set) ? +1 : -1;
}
And this is the code on Arduino Uno
#define A 2
#define B 3
#define PI 3.1415926535897932384626433832795
boolean A_set = false;
boolean B_set = false;
long encoderPos = 0;
//unsigned int lastReportedPos = 1;
const int in1 = 4;
const int in2 = 5;
const int enA = 6;
long ref=30000;
void setup() {
Serial.begin(9600);
pinMode(A,INPUT_PULLUP);
pinMode(B,INPUT_PULLUP);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(enA, OUTPUT);
pinMode(8, OUTPUT);
digitalWrite(8, HIGH);
attachInterrupt(digitalPinToInterrupt(A),encodA,CHANGE);
attachInterrupt(digitalPinToInterrupt(B),encodB,CHANGE);
//digitalWrite(in1, ((ref)>0));
//digitalWrite(in2, 1-((ref)>0));
//analogWrite(enA, 120);
}
long K=0;
long AV;
long BV;
double W;
int sayac;
double Kp=0.50;
double z1=0.000128;
double z2=2.1;
double Kd=20*(-z1-z2)*Kp; //225
double Ki=z1*z2*Kp*0.013;
long lastpos=0;
long err=0;
long sumerr=0;
long derr=0;
long lasterr=0;
//long K=0;
void loop() {
//ref=analogRead(A3)*3.2258064516;
Serial.println(encoderPos);
}
void encodA() {
// Test transition
A_set = digitalRead(A) == HIGH;
// and adjust counter + if A leads B
encoderPos += (A_set != B_set) ? +1 : -1;
}
// Interrupt on B changing state
void encodB() {
// Test transition
B_set = digitalRead(B) == HIGH;
// and adjust counter + if B follows A
encoderPos += (A_set == B_set) ? +1 : -1;
}
We made some tests initially and at one point, motor suddenly started to turn in one direction continuously and damaged our mechanism.
Yes, I was the one managing the experiment, unfortunately...
I investigated the problem after this incident and my investigation revealed that
1.This problem starts to happen at PWM values higher than 160, when the mechanism reachs a speed. It just turns on the same direction continuously.
2. When I try to read data from other COM port by Uno, when PWM value is 255, hoping that It may be encoder error of some sort, It does not write anything to the Serial Port at all.
At values like 185, It sure fails but Arduino Uno keeps writing values to Serial Port continuously, although laggy.
3. When I cut the power from motor, Arduino Uno suddenly writes so many number to the Serial Port, but not before.
4. Using values near to 160 as PWM maximum value, It sometimes fail but when It does not, the value I get from Uno is very different from ref value. For example, in 150 pwm, when ref value is 16000, It stops at 23000. It is like Mega misses some data.
So, I suppose our encoder chokes Arduinos by supplynig so much data that It just locks both Arduinos so Arduino just keeps supplying last ArduinoRead data to the port and this makes him turn continuously.
If that is the problem, can I get Arduino faster so it will not choke under data?
I read some suggestions about faster digitalread, analogwrite and all that but I have no idea where to start. Removing some safety measurements are suggested but I am not sure that's a good idea.
Any suggestion helps.
Regards...