Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arduino 用编码器控制直流电机_Arduino_Encoder - Fatal编程技术网

Arduino 用编码器控制直流电机

Arduino 用编码器控制直流电机,arduino,encoder,Arduino,Encoder,我试图用Arduino Uno和与电机相连的编码器来控制两个直流电机的速度 我已经写了一个代码来检查编码器的位置是否有变化,并据此计算电机的速度 我使用了以下代码: 我在计算编码器的新位置和旧位置之间的差异时遇到问题。由于某种原因,即使速度保持不变,差异也会继续增大 这是我目前的代码: #define pwmLeft 10 #define pwmRight 5 #define in1 9 #define in2 8 #define in3 7 #define in4 6 //MOTOR A i

我试图用Arduino Uno和与电机相连的编码器来控制两个直流电机的速度

我已经写了一个代码来检查编码器的位置是否有变化,并据此计算电机的速度

我使用了以下代码:

我在计算编码器的新位置和旧位置之间的差异时遇到问题。由于某种原因,即使速度保持不变,差异也会继续增大

这是我目前的代码:

#define pwmLeft 10
#define pwmRight 5
#define in1 9
#define in2 8
#define in3 7
#define in4 6

//MOTOR A
int motorSpeedA = 100;
static int pinA = 2; // Our first hardware interrupt pin is digital pin 2
static int pinB = 3; // Our second hardware interrupt pin is digital pin 3
volatile byte aFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte bFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile long encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255
volatile long oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile long reading = 0; //somewhere to store the direct values we read from our interrupt pins before checking to see if we have moved a whole detent

//MOTOR B
static int pinC = 12; // Our first hardware interrupt pin is digital pin 2
static int pinD = 33; // Our second hardware interrupt pin is digital pin 3
volatile byte cFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte dFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile long encoderPosB = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255
volatile long oldEncPosB = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile long readingB = 0;

int tempPos;
long vel;
unsigned long newtime;
unsigned long oldtime = 0;

void setup() {
  //MOTOR A
  pinMode(pinA, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
  pinMode(pinB, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
  attachInterrupt(0, PinA, RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
  attachInterrupt(1, PinB, RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below)
  //MOTOR B
  pinMode(pinC, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
  pinMode(pinD, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
  attachInterrupt(0, PinC, RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
  attachInterrupt(1, PinD, RISING);
  Serial.begin(9600); // start the serial monitor link
  pinMode (in1, OUTPUT);
  pinMode (in2, OUTPUT);
  pinMode (in3, OUTPUT);
  pinMode (in4, OUTPUT);
  digitalWrite (8, HIGH);
  digitalWrite (9, LOW); //LOW
  digitalWrite (7, LOW); //LOW
  digitalWrite (6, HIGH);
  pinMode (pwmLeft, OUTPUT);
  pinMode (pwmRight, OUTPUT);
}

void PinA(){
  cli(); //stop interrupts happening before we read pin values
  reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values
  if(reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
    encoderPos --; //decrement the encoder's position count
    bFlag = 0; //reset flags for the next turn
    aFlag = 0; //reset flags for the next turn
  } else if (reading == B00000100) bFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
  sei(); //restart interrupts
}

void PinB(){
  cli(); //stop interrupts happening before we read pin values
  reading = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values
  if (reading == B00001100 && bFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
    encoderPos ++; //increment the encoder's position count
    bFlag = 0; //reset flags for the next turn
    aFlag = 0; //reset flags for the next turn
  } else if (reading == B00001000) aFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
  sei(); //restart interrupts
}

void PinC(){
  cli(); //stop interrupts happening before we read pin values
  readingB = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values
  if(readingB == B00001100 && cFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
    encoderPosB --; //decrement the encoder's position count
    dFlag = 0; //reset flags for the next turn
    cFlag = 0; //reset flags for the next turn
  } else if (readingB == B00000100) dFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
  sei(); //restart interrupts
}

void PinD(){
  cli(); //stop interrupts happening before we read pin values
  readingB = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values
  if (readingB == B00001100 && dFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
    encoderPosB ++; //increment the encoder's position count
    dFlag = 0; //reset flags for the next turn
    cFlag = 0; //reset flags for the next turn
  } else if (readingB == B00001000) cFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
  sei(); //restart interrupts
}

void loop(){
  analogWrite(pwmLeft, motorSpeedA);
  analogWrite(pwmRight, motorSpeedA);
  if(oldEncPos != encoderPos) {
    newtime = millis();
    tempPos = encoderPos - oldEncPos;
    vel = tempPos / (newtime - oldtime);
    Serial.println(tempPos);
    oldEncPos = encoderPos;
    oldtime = newtime;
    delay(250);
  } 
  if(oldEncPosB != encoderPosB) {
    Serial.println(encoderPosB);
    oldEncPosB = encoderPosB;
  }    
}
这两个if语句只是为了检查编码器是否正常工作。在第一个if语句中,我试图计算速度

如果有任何反馈,我将不胜感激

多谢各位

编辑:

我发现有一个编码器库,它使一切都变得容易得多

现在我的代码如下所示:

#include <Encoder.h>
#define pwmLeft 10
#define pwmRight 5
Encoder myEncA(3, 2);
Encoder myEncB(13, 12);
unsigned long oldtimeA = 0;
unsigned long oldtimeB = 0;
int speedA = 100;
int speedB = 130;

void setup() {
  Serial.begin(9600);

  digitalWrite (8, HIGH);
  digitalWrite (9, LOW); //LOW
  digitalWrite (7, LOW); //LOW
  digitalWrite (6, HIGH);

  pinMode (pwmLeft, OUTPUT);
  pinMode (pwmRight, OUTPUT);
}

long oldPositionA  = -999;
long oldPositionB  = -999;

void loop() {

  analogWrite(pwmLeft, speedA);
  analogWrite(pwmRight, speedB);

  long newPositionA = myEncA.read();
  long newPositionB = myEncB.read();
  if ((newPositionA != oldPositionA) || (newPositionB != oldPositionB)) {
    unsigned long newtimeA = millis ();
    long positionA = newPositionA - oldPositionA;
    long positionB = newPositionB - oldPositionB;
    long velB = (positionB) / (newtimeA - oldtimeA);
    long velA = (positionA) / (newtimeA - oldtimeA);
    oldtimeA = newtimeA;
    oldPositionA = newPositionA;
    oldPositionB = newPositionB;
    Serial.println(velB);
  }
}
#包括
#定义pwmLeft 10
#定义pwmRight 5
编码器myEncA(3,2);
编码器myEncB(13,12);
无符号长oldtimeA=0;
无符号长oldtimeB=0;
int speedA=100;
int speedB=130;
无效设置(){
Serial.begin(9600);
数字写入(8,高);
digitalWrite(9,低);//低
digitalWrite(7,低);//低
数字写入(6,高);
pinMode(pwmLeft,输出);
pinMode(pwmRight,输出);
}
长oldPositionA=-999;
长oldPositionB=-999;
void循环(){
模拟写入(pwmLeft、speedA);
模拟写入(pwmRight、speedB);
long newPositionA=myEncA.read();
long newPositionB=myEncB.read();
如果((新位置A!=旧位置A)| |(新位置B!=旧位置B)){
无符号长newtimeA=millis();
长位置A=新位置A-旧位置A;
长位置B=新位置B-旧位置B;
long velB=(位置B)/(新时间A-旧时间A);
长velA=(位置A)/(新时间A-旧时间A);
oldtimeA=新Timea;
旧位置A=新位置A;
旧位置B=新位置B;
序列号println(velB);
}
}
我的“B”电机仍有问题,由于某些原因,计算结果仍有偏差


电机“A”工作正常

有几个问题,包括回路中的零除错误()。此扫描会导致控制器复位。进行除法运算时,请始终检查除数的值

仅使用正转换不必要地将读数的分辨率降低2

Arduino是一个8位控制器。。。读取
int
需要多条指令,这意味着您应该在读取由中断例程修改的
int
之前禁用中断。否则将导致vakue读数出现奇数跳变。这通常是这样做的:

//...
NoInterrupts();
int copyOfValue = value;   // use the copy to work with.
interrupts();
//...
在您的情况下,单字节值可能足以存储移动,每30毫秒重置一次,这将为您提供255个脉冲/30毫秒=8500个脉冲/秒或1275000 rpm的最高速度(对于24次/圈编码器):在这种情况下,无需为读取禁用中断

每30毫秒读取一次读数,1滴答/30毫秒=33滴答/秒,或85转/分。这对运动来说有点高。根据您的应用,您可能需要计算平均读数

此外,您使用的算法肯定不起作用。主要原因是读取和调整之间的延迟太小。大多数读数为零。删除println()调用时会遇到问题。我建议读数之间至少间隔30 ms。100毫秒可能会更好一些,这取决于您的应用程序。使用
float
变量作为平均速度肯定会有所帮助

void loop()
{
  //...
  if(oldEncPos != encoderPos) {
    newtime = millis();
    tempPos = encoderPos - oldEncPos;
    vel = tempPos / (newtime - oldtime);   // <--  if newtime == oltime => divide by zero.
    //...
  } 
  //...
}

嗨,Michael,谢谢你的回复,我尝试了应用你所说的更改,但仍然得到不正确的结果。如果我使用时间差大于30的If语句,我只会得到一些结果(不准确的结果),结果会因为某种原因停止
#define PIN_A  2  // encoder bit 0
#define PIN_B  3  // encoder bit 1

volatile char encVal1;
volatile unsigned char encPos1;  // using char 

void OnEncoder1Change()
{
   char c = (digitalRead(pinA) ? 0b01 : 0)
          + (digitalRead(pinB) ? 0b10 : 0);  // read
   char delta = (c - encVal1) & 0b11;        // get difference, mask

   if (delta == 1)                           // delta is either 1 or 3
       ++encPos1;
   else
       --encPos1;
   encVal1 = c;                              // keep reading for next time.
   encPos1 += delta;                         // get position.
   // no need to call sei()
}

setup()
{
  pinMode(pinA, INPUT_PULLUP);
  pinMode(pinB, INPUT_PULLUP);

  // get an initial value
  encValA  = digitalRead(pinA) ? 0b01 : 0;
  encValA += digitalRead(pinB) ? 0b10 : 0;

  // use digitalPinToInterrupt() to map interrupts to a pin #
  // ask for interrupt on change, this doubles .
  attachInterrupt(digitalPinToInterrupt(PIN_A), OnEncoder1Change, CHANGE);  
  attachInterrupt(digitalPinToInterrupt(PIN_B), OnEncoder1Change, CHANGE);


  //...
}

unsigned char oldTime;
unsigned char oldPos;
int speed;
void loop()
{
    unsigned char time = millis();

    if (time - oldTime > 30)        // pace readings so you have a reasonable value.
    {
        unsigned char pos = encPos1;
        signed char delta = pos - oldPos;

        speed = 1000 * delta) / (time - oldTime);  // signed ticks/s

        encPos1 -= pos;  // reset using subtraction, do you don't miss out 
                         // on any encoder pulses.
        oldTime = time;
    }
}