DC motor positioning with external absolute encoder

Hi
I need your help on this project. I built an 12V DC motor with attached external absolute encoder. The motor a 12V 150W Bus Wiper which elevate lift than sink it down to a specific CEP position... I use BTS7960B 12V 43A driver board..

The motor shall rotate between 0...180degree which means 380 to 960 signal in the absolute encoder.
Now the problem is when I try to move the motor into a specific position it does not go smoothly. even if the code looks simple and easy.. What is happening: Motor start rotating from 960 back to the set CEP=870 Position but suddenly stops at 935 than restart rotating to 905 than stop around 865.. so every time at least 3 sub steps happening before it reach the desired value.. I do not understand why... The importance of this system to avoid over rotation of the set CEP value .... if it would stop 5 or 10 value earlier but as fast as possible would be great.... I tried with different PWM values but it did not help a lot...

So I want to move the DC motor from 960 back to 870 position smoothly and quickly in one step:
The entire code as it was asked :

int LPWMpin=5;
int RPWMpin=6;
int L_R_ENpin=7;
int actuatorpin=10;
int BKpin=12;

volatile int MPmax=960;
volatile int MPmin=380;
int a=1;
int CEP =0;
int CES = 0;
volatile int CMPactualext;
volatile int CMPactualint;
volatile int CEPext;
volatile int CMPactual =0;
volatile int MP = 0;
int BKsw;
int actuatorbuttonState;
boolean CMaktiv;

// the setup routine runs once when you press reset:
void setup() {

pinMode(actuatorpin,INPUT);
pinMode(BKpin,INPUT);
pinMode(LPWMpin,OUTPUT);
pinMode(RPWMpin,OUTPUT);
pinMode(L_R_ENpin,OUTPUT);
digitalWrite(LPWMpin,LOW);
digitalWrite(RPWMpin,LOW);
digitalWrite(L_R_ENpin,LOW);
delay(200);
}

// the loop routine runs over and over again forever:
void loop() {
// read the input pin:
CEP = analogRead(2);
CEP = map(CEP,0,1023,700,MPmax);
CMPactual = analogRead(5);
CMPactual = map(CMPactual,0, 1023, MPmin, MPmax);
CMPactualext=CMPactual-10;
CMPactualint=CMPactual-5;
CEPext=CEP+15;

actuatorbuttonState = digitalRead(actuatorpin);
BKsw = digitalRead(BKpin);
if (actuatorbuttonState==LOW||BKsw==HIGH){
MP = 1023 - analogRead(0);
if (MP<CMPactualext){
digitalWrite(L_R_ENpin, HIGH);
analogWrite(RPWMpin,255);
analogWrite(LPWMpin,0);
a=1;
while (a<2){
MP = 1023 - analogRead(0);
if (MP>CMPactualint){
digitalWrite(L_R_ENpin, LOW);
analogWrite(LPWMpin,0);
analogWrite(RPWMpin,0);
a=2;
}
}
}
}

actuatorbuttonState = digitalRead(actuatorpin);
BKsw = digitalRead(BKpin);
if ((actuatorbuttonState==HIGH)&&(BKsw==LOW)){
MP = 1023 - analogRead(0);
if (MP>CEPext){
digitalWrite(L_R_ENpin, HIGH);
analogWrite(RPWMpin,0);
analogWrite(LPWMpin,80);
CMaktiv = true;
while (CMaktiv != false){
MP = 1023 - analogRead(0);
if (MP<CEPext){
digitalWrite(L_R_ENpin, LOW);
analogWrite(LPWMpin,0);
analogWrite(RPWMpin,0);
CMaktiv = false;
}

}
}
}
}

The DC motor actually moves for a while than stop than start rotation again but with a shorter time.... The system shall be fast and accurate The major challenge is that the load during MP increment requires 255PWM while when it moves back an 40PWM more than enough however the DC motor getting noisy therefore I increased to 80PWM.

Unfortunately I am not familiar with the PID stuff and I am not sure how make it slow down the routine....

Circuit schematic attached below in the discussion

Please advice how I can improve the accuracy of the DC positioning.
Thanks in advance

               }
                }
                     }
                                            }

It's a bit raggedy, isn't it.

Please post your complete code and put it in code tags - the # button - so it looks like the above.

The Tools/Auto Format menu item in the Arduino IDE should tidy up the code so we (and you) can more easily see what belongs to what.

...R

Edit to change to code tags as pointed out by @JimboZA in Reply #3
(slap self on wrist for the second time today) ...R

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png or pdf?

Also what speed is your motor and does it have a gearbox?

Tom...... :slight_smile:

Robin2:

}
}
}
}

It's a bit raggedy, isn't it.

Please post your complete code and put it in code tags - the # button - so it looks like the above.

.... although Robin accidentally hit the quotes button not the hash for code. In his defence, they are neighbours....

               }
                }
                     }
                                            }

The whole approach is wrong. You are implementing a servo-loop.

This means you need a part of the code that drives the motor, and takes as
input a signed value where +ve represents turning one way, -ve the other and
zero no force.

Then you need to calculate the position error - the difference between desired position
and current (measured) position. This yields a signed error value.

Then you glue the two parts together with a PID controller. Or to start with
just a P-controller (in other words drive = Pcoeff * error).

In general you will need to add a D-term to prevent oscillation (your existing
code seems to be a P-only controller with huge gain, this can only oscillate)

There are lots of resources about tuning a PID controller loop, but the key insight
is that you setup this flow:

encoder ----> calculate error ----> PID controller ----> motor drive level ----> H-bridge

It can be a dozen lines of code, its not really that complicated if you start with
just the P-term.

JimboZA:
.... although Robin accidentally hit the quotes button not the hash for code. In his defence, they are neighbours....

Well spotted, thanks. I have corrected it with a note crediting you.

...R

The 12V 43A motor driver board what I use for the project:
http://www.rcmodelpart.com/double-bts7960b-43a-motor-driver-highpower-modulesmart-car-driver-arduino_p332.html

As per your request the circuit schematic attached

BKsw has no pull-down resistor, its pin will be floating/undefined.

Where is the encoder? Is it one of the potentiometers?