Needs to speed-up arduino

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

https://tr.aliexpress.com/item/Lpd3806-600bm-g5-24c-AB-Iki-Fazl-5-24-V-600-Bakliyat-Art-msal-Optik-Enkoder/32857035640.html

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...

With 600 pulses per revolution and 3000RPM, you're generating 50rev/s x 600 p/r = 30,000 ticks per second per phase; phase A interrupts at 30kHz and phase B interrupts at the same rate, 90-degrees out of phase.

30kHz is 33.3uS. It is unlikely the processor will keep up with that, let alone two of them... And being completely swamped as it is, there are precious few cycles left over to do other things, like compute PIDs or send serial messages.

Do You really need such a high resolution as 600 cycles per revolution? At least, for faultfinding, could You try using a significantly lower numer of cycles per rev.?

Actually, I just noticed you're interrupting on change so rising & falling edges of both phases are occurring.

Can you not interrupt on one phase's falling edge (e.g.) and derive direction information from the level of the other phase?

For example:

#define A 2
#define B 3

.
.
.

void setup() 
{
    pinMode(A, INPUT_PULLUP);
    pinMode(B, INPUT_PULLUP);

    .
    .
    .
    
    attachInterrupt(digitalPinToInterrupt(A), encodA, FALLING );

}//setup

.
.
.

//
//DIRECTION 'CCW'
//       ___     ___     ___     ___     ___
//PHA___|   |___|   |___|   |___|   |___|   
//         ___     ___     ___     ___     ___
//PHB  ___|   |___|   |___|   |___|   |___|   
//
//DIRECTION 'CW'
//          ___     ___     ___     ___     ___
//PHA   ___|   |___|   |___|   |___|   |___|   
//        ___     ___     ___     ___     ___
//PHB ___|   |___|   |___|   |___|   |___|   
//
// At each falling edge of PHA, PHB will be high (CCW) or low (CW)
// no need to look at each edge of both phases, no?

void encodA( void ) 
{
    encoderPos += (digitalRead(B) == HIGH) ? +1:-1;
}

If all you want to do is control the speed of the motor then one pulse per revolution should be sufficient. It works for me with a motor that runs at speeds from about 1,500 to 15,000 RPM.

...R

https://www.microcenter.com/product/437846/robogaia-industries-3-axis-encoder-counter-arduino-shield

Hi,
Why did you connect all your mechanism to the motor when you have not got motor control?
Can I suggest you just run the motor with out the mechanism connected, until you have control of the motor.


You need an EMERGENCY STOP connected to remove power from the motor when something like this occurs.
It looks like a very dangerous machine with a screw thread drive, have you calculated the amount of force it can apply?

  • What motor controller are you using?
  • What speed do you want to run the motor at?
  • Have you set it up to limit the motor current?
  • Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Have you got some code that JUST controls the motor, no PID, no encoder, just controls the motor?
You need limit switches at the ends of the mechanism.

When you get the motor control working, then put an oscilloscope on the encoder and investigate the frequency of the pulses.

Then think about PID.
Stages, work your project in stages and get each stage working before combining them.

But first put an easy to reach EMERGENCY STOP on your project.

Have you tried using just one controller?

Tom... :slight_smile: