griddb - 如何使用旋转编码器控制电机
问题描述
我想使用旋转编码器控制电机的精度。
例如,我想将电机移动到任意一侧,例如 70 度,并使用旋转编码器返回其原始位置。我写了一个代码,但是这个代码电机不会移动,除非旋转编码器移动。
二手零件
- 带变速箱的直流电机
- arduino 巨型
- 防弹少年团 7960
- 编码器旋转
代码:
// 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;
}
解决方案
- 需要用 PWM 信号驱动 H 桥 PWM 引脚,将 PWM 引脚拉高会导致电机全速旋转,不适合位置控制。
- 您需要将编码器引脚连接到硬件定时器(在计数器模式下)以提高控制性能,否则您可能无法在高电机速度下获得编码器值。当然,编码器信号经过特殊编码,因此您可能需要先对其进行解码,然后再对其进行计数。请谷歌它以获取更多信息。
- 您需要使用 P、PI 或 PID 控制器(在软件中)来有效控制电机位置。我将举一个 P 控制的例子,一旦你开始工作,你可以检查更高级的一个(PI 或 PID)。
- 避免在高速循环中调用 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;
}
推荐阅读
- asp.net - Docusign dotnet 4.7 示例
- python - 是否有一个 python 模块可以一次绘制多个一个像素宽的点?
- ios - 如何正确删除 SnapshotListeners?
- ruby-on-rails - 如何在 ruby on rails 中重新创建 db 文件
- javascript - jquery-3.5.1.js:4055 错误数据表无法读取未定义的属性“aDataSort”
- c# - 将 IEnumerable 转换为 ObservableCollection
- javascript - 将条件返回为 1 和 -1 的最短方法是什么
- c# - 在 .NET Core 中使用自定义绑定 Web 服务
- sql - 通过 ODBC 的 SQL 事件
- android - Flutter:在无状态小部件中“查找已停用小部件的祖先是不安全的”