1

I want to control the accuracy of the motor using a rotary encoder.

For example, I want to move the motor to any side, for example, 70 degrees, and return to its original place using a rotary encoder. I wrote a code, but this code the motor does not move unless the rotary encode is moved.

Used parts

  • motor dc with gearbox
  • arduino mega
  • bts 7960
  • encoder rotary

Code:

// Rotary Encoder Inputs
#define inputCLK 3
#define inputDT 2
int LPWM = 6; //   
int LEN = 9; // 
int RPWM =5; // 
int REN = 8; // 
int counter = 0; 
int currentStateCLK;
int previousStateCLK; 

String encdir ="";
 void setup() { 
  
  // Set encoder pins as inputs  
 pinMode (inputCLK,INPUT);
 pinMode (inputDT,INPUT);
 pinMode(LPWM, OUTPUT); 
 pinMode(RPWM, OUTPUT); 
 pinMode(LEN, OUTPUT);
 pinMode(REN, OUTPUT);

 digitalWrite(LEN, HIGH);
 digitalWrite(REN, HIGH);
    // Setup Serial Monitor
  Serial.begin (9600);
  
  // Read the initial state of inputCLK
  // Assign to previousStateCLK variable
  previousStateCLK = digitalRead(inputCLK);

} 

void loop() 
{ 
 
 // Read the current state of inputCLK
  currentStateCLK = digitalRead(inputCLK);
   
  // If the previous and the current state of the inputCLK are different then a pulse has occured
  if (currentStateCLK != previousStateCLK){ 
      
    // If the inputDT state is different than the inputCLK state then 
    // the encoder is rotating counterclockwise
    if (digitalRead(inputDT) != currentStateCLK) { 
      counter --;
      encdir ="CCW";
        digitalWrite(RPWM,HIGH);   //move forward and backward
        digitalWrite(LPWM, LOW);
    
    } else {
      // Encoder is rotating clockwise
      counter ++;
      encdir ="CW";
        digitalWrite(RPWM,LOW);
        digitalWrite(LPWM, HIGH);
            
    }
    Serial.print("Direction: ");
    Serial.print(encdir);
    Serial.print(" -- Value: ");
    Serial.println(counter);
  } 
  // Update previousStateCLK with the current state
  previousStateCLK = currentStateCLK; 




} 
halfer
  • 19,824
  • 17
  • 99
  • 186
chosen one
  • 11
  • 1

1 Answers1

0
  1. You need to drive the H bridge PWM pins with PWM signal, pulling the PWM pins HIGH will cause motor to rotate at full speed, which is not suitable for position control.
  2. You need to connect the encoder pins to hardware timers (in counter mode) to improve the control performance, otherwise you may not get encoder values at the high motor speeds. Of course encoder signals are specially encoded, so you may need to decode them first before counting them. Please google it for more info.
  3. You need to utilize a P, or PI, or PID controller (in software) to effectively control the motor position. I will give an example of P control, you may check for more advanced one (PI or PID) once you get it work.
  4. Avoid calling Serial.print stuff inside a high speed loop, it will degrade the performance.

You can find the following code as a starting point (it is not tested though).

// Rotary Encoder Inputs
#define inputCLK 3
#define inputDT 2
int LPWM = 6; //   
int LEN = 9; // 
int RPWM =5; // 
int REN = 8; // 
int currentStateCLK;
int previousStateCLK; 

int counter = 0; // the actual place where the motor stand
int setPoint = 500; // The encoder counter value where you want the motor to go
float kp = 0.5; // proportional control gain

void doPControl(int set, int current) {
    int error = set - current;
    int level = (int)(kp * error);
    
    if (level < 0) {
        analogWrite(RPWM, 0); // need to use PWM signal instead of digital HIGH/LOW
        analogWrite(LPWM, -level);
    } else {
        analogWrite(LPWM, 0);
        analogWrite(RPWM, level);
    }
}

void setup() { 
    // Set encoder pins as inputs
    pinMode (inputCLK,INPUT);
    pinMode (inputDT,INPUT);
    pinMode(LPWM, OUTPUT); 
    pinMode(RPWM, OUTPUT); 
    pinMode(LEN, OUTPUT);
    pinMode(REN, OUTPUT);

    analogWrite(LPWM, 0);
    analogWrite(RPWM, 0);
    digitalWrite(LEN, HIGH);
    digitalWrite(REN, HIGH);
  
    // Read the initial state of inputCLK
    // Assign to previousStateCLK variable
    previousStateCLK = digitalRead(inputCLK);
} 

void loop() 
{ 
    // Read the current state of inputCLK
    currentStateCLK = digitalRead(inputCLK);

    // If the previous and the current state of the inputCLK are different then a pulse has occured
    if (currentStateCLK != previousStateCLK && currentStateCLK == 1){ // this block is a task updating the encoder counter
        // If the inputDT state is different than the inputCLK state then 
        // the encoder is rotating counterclockwise
        if (digitalRead(inputDT) != currentStateCLK) { 
            counter --;
        } else {
            // Encoder is rotating clockwise
            counter ++;
        }
    }

    doPControl(setPoint, counter); // this line needs to get executed regardless of the encoder reading task
    
    // Update previousStateCLK with the current state
    previousStateCLK = currentStateCLK; 
}
msuzer
  • 51
  • 1
  • 8
  • I did not understand if you explain a little because I am a beginner I tried the code and it didn't work – chosen one Jan 09 '21 at 21:03
  • I do not have your hardware, so I cannot verify if it does work or not. Though it compiles successfully. I have updated the code, so please try again. And one issue: You may need to change the polarity of motor, i.e., reverse its power wires connected to the H bridge. (Not the encoder wires!) Once you get it work, you may also need to tune kp value. – msuzer Jan 10 '21 at 07:26