首页 > 解决方案 > 如何使用旋转编码器控制电机

问题描述

我想使用旋转编码器控制电机的精度。

例如,我想将电机移动到任意一侧,例如 70 度,并使用旋转编码器返回其原始位置。我写了一个代码,但是这个代码电机不会移动,除非旋转编码器移动。

二手零件

代码:

// 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; 




} 

标签: griddb

解决方案


  1. 需要用 PWM 信号驱动 H 桥 PWM 引脚,将 PWM 引脚拉高会导致电机全速旋转,不适合位置控制。
  2. 您需要将编码器引脚连接到硬件定时器(在计数器模式下)以提高控制性能,否则您可能无法在高电机速度下获得编码器值。当然,编码器信号经过特殊编码,因此您可能需要先对其进行解码,然后再对其进行计数。请谷歌它以获取更多信息。
  3. 您需要使用 P、PI 或 PID 控制器(在软件中)来有效控制电机位置。我将举一个 P 控制的例子,一旦你开始工作,你可以检查更高级的一个(PI 或 PID)。
  4. 避免在高速循环中调用 Serial.print 东西,它会降低性能。

您可以找到以下代码作为起点(虽然它没有经过测试)。

// 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; 
}

推荐阅读