2017-09-12 1 views
1

Ich versuche, die Geschwindigkeit von zwei DC-Motoren mit einem Arduino Uno und Encoder, die an die Motoren angeschlossen sind, zu steuern.Gleichstrommotor mit Encoder

Ich habe einen Code geschrieben, um zu überprüfen, ob sich die Position des Encoders ändert und dementsprechend die Geschwindigkeit der Motoren berechnet.

verwendet Ive this website für den Code:

ich Probleme habe, wenn die Differenz zwischen der neuen Position des Gebers zu berechnen und der alten Position des Gebers. Aus irgendeinem Grund steigt dieser Unterschied, obwohl die Geschwindigkeit gleich bleibt.

Dies ist mein Code so weit:

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

Die beiden, wenn Aussagen gemacht werden, nur zu prüfen, ob die Geber richtig funktionieren. In der ersten if-Anweisung versuche ich die Geschwindigkeit zu berechnen.

Ich würde mich über jede Rückmeldung freuen.

Vielen Dank.

EDIT:

ich Theres eine Encoder-Bibliothek fand heraus, das alles viel einfacher macht.

so jetzt sieht mein Code wie folgt aus:

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

Ich bin immer noch Probleme mit meinem „B“ Motor, die Berechnung ist noch in weiter Ferne aus irgendeinem Grund haben.

Motor "A" funktioniert

Antwort

1

Ein paar Probleme, einschließlich einer Division-durch-Null-Fehler in der Schleife(). Dieser Scan verursacht einen Reset Ihres Controllers. Überprüfen Sie immer den Wert des Divisors, wenn Sie eine Division durchführen!

Mit nur positive Übergänge reduziert unnötig die Auflösung der Messwerte von 2.

Der Arduino ist eine 8-Bit-Controller ... ein int Lesen erfordert mehrere Anweisung, das heißt, Sie Interrupts, bevor ein int zu lesen, die geändert hat deaktivieren sollte durch eine Interrupt-Routine. Andernfalls werden merkwürdige Sprünge im vakue-Lesevorgang auftreten. Dies ist in der Regel wie folgt geschehen:

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

In Ihrem Fall ein einziger Byte-Wert zu speichern Bewegung wahrscheinlich genug ist, mit einem Reset aller 30 ms, soll dies Ihnen eine Höchstgeschwindigkeit von 255 Impulsen/30ms = 8500 Impulse/Sekunde oder 1275000 U/min für einen 24-Bit-/Drehgeber. :) In diesem Fall müssen Interrupts für eine Lesung nicht deaktiviert werden.

mit einem Messwert pro 30 ms, 1 Tick/30 ms = 33 Tick/Sekunden oder 85 RPM. Es ist ein bisschen hoch für Bewegung. Je nach Anwendung müssen Sie möglicherweise die Messwerte mitteln.

Auch der Algorithmus, den Sie verwenden, wird definitiv nicht funktionieren. Der Hauptgrund ist, dass die Verzögerung zwischen Lesevorgängen und Anpassungen zu gering ist. Die meisten Messwerte werden Null sein. Sie werden auf das Problem stoßen, wenn Sie die println() -Aufrufe entfernen. Ich empfehle eine Stimulation von mindestens 30 ms zwischen den Messungen. Je nach Anwendung können 100 ms etwas besser funktionieren.Eine Variable float für den Durchschnitt der Geschwindigkeit wird definitiv helfen.

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

Der Code-Encoder Lesung scheint furchtbar komplex ...

#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

Hallo Michael Danke für die Antwort, habe ich versucht, die Änderungen zu übernehmen Sie gesagt, aber ich immer noch falsche Ergebnisse zu erhalten. Wenn ich die if-Anweisung mit der Zeitdifferenz über 30 verwende, bekomme ich nur ein paar Ergebnisse (inakrete Ergebnisse) und die Ergebnisse stoppen aus irgendeinem Grund. – user7792712

+0

Ich habe eine Bearbeitung mit dem neuen Code hinzugefügt – user7792712