2017-09-12 12 views
1

私は、Arduino Unoとモータに接続されたエンコーダを使用して2つのDCモータの速度を制御しようとしています。エンコーダを使用してDCモータを制御する

私はエンコーダの位置に変化があるかどうかをチェックし、それに基づいてモータの速度を計算するコードを書いています。エンコーダの新しい位置とエンコーダの古い位置との差を計算するときに、私は問題を抱えている

は、アイブ氏は、コードのためthis websiteを使用しました。何らかの理由で、たとえスピードが同じであっても差が上がり続ける。

これは、これまでの私のコードです:

#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文では、私は速度の計算をしようとしています。

フィードバックに感謝します。

ありがとうございます。

EDIT:

私が見つけたが、すべてが非常に簡単になりエンコーダライブラリをtheresの。

ので、今私のコードは次のようになります。私はまだ私の「B」モーターとの問題を抱えています

#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); 
    } 
} 

、計算が何らかの理由で道まだオフです。

モーターは、 "A" はループでゼロ除算エラーを含む問題の罰金

答えて

1

カップルを、作品()。このスキャンはコントローラのリセットを引き起こします。除算を行うときは常に除数の値をチェックしてください!唯一のポジティブトランジションを使用して

が不必要に2

して測定値の解像度を低減Arduinoのは、8ビットコントローラです... intを読むと、あなたが変更されていますintを読む前に割り込みを無効にする必要がありますを意味し、複数の命令が必要です割り込みルーチンによって実行されます。そうしないと、読み込み中に奇妙なジャンプが発生します。これは通常、次のように行われます:あなたのケースでは

//... 
NoInterrupts(); 
int copyOfValue = value; // use the copy to work with. 
interrupts(); 
//... 

、単一バイト値はリセットして、店舗の動きに十分な可能性があるごとに30ミリ秒、これはあなたに255パルス/ 30msでの= 8500の最高速度を与える必要がありますパルス/秒または12ティック/ターンエンコーダの場合は1275000 rpmです。 :)その場合、読み取りのために割り込みを無効にする必要はありません。

30ミリ秒ごとに1つの読み取り、1ティック/ 30ミリ秒= 33ティック/秒、または85 RPMです。モーションのために少し高いです。あなたのアプリケーションに応じて、平均値を読み取る必要があるかもしれません。

また、使用しているアルゴリズムは間違いなく機能しません。主な理由は、読み込みと調整の間の遅延が小さすぎるということです。ほとんどの読み取り値はゼロになります。 println()呼び出しを削除するときに問題が発生します。私は読書の間に少なくとも30ミリ秒のペーシングをお勧めします。アプリケーションによっては、100msが少し良くなるかもしれません。速度平均に変数floatを使用することは間違いなく役立ちます。

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

コードを読んで、エンコーダがひどく複雑なようだ...返信用

#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; 
    } 
} 
+0

こんにちはマイケルのおかげで、私はあなたが言った変更を適用しようとしたが、私はまだ間違った結果を取得します。私は、もしstatemtnを使って、30を越える時間差があるならば、私はいくつかの結果を得ることができません。そして、何らかの理由で結果が停止します。 – user7792712

+0

Iveは新しいコードで編集を追加しました。 – user7792712

関連する問題