arduino - Controlling DC motor using encoder -


i'm trying control speed of 2 dc motors using arduino uno , encoders connected motors.

i've written code check whether there's change in position of encoder , according calculate velocity of motors.

ive used this website code:

i'm having problems when calculating difference between new position of encoder , old position of encoder. reason difference keeps going though speed stays same.

this code far:

#define pwmleft 10 #define pwmright 5 #define in1 9 #define in2 8 #define in3 7 #define in4 6  //motor int motorspeeda = 100; static int pina = 2; // our first hardware interrupt pin digital pin 2 static int pinb = 3; // our second hardware interrupt pin digital pin 3 volatile byte aflag = 0; // let's know when we're expecting rising edge on pina signal encoder has arrived @ detent volatile byte bflag = 0; // let's know when we're expecting rising edge on pinb signal encoder has arrived @ detent (opposite direction when aflag set) volatile long encoderpos = 0; //this variable stores our current value of encoder position. change int or uin16_t instead of byte if want record larger range 0-255 volatile long oldencpos = 0; //stores last encoder position value can compare current reading , see if has changed (so know when print serial monitor) volatile long reading = 0; //somewhere store direct values read our interrupt pins before checking see if have moved whole detent  //motor b static int pinc = 12; // our first hardware interrupt pin digital pin 2 static int pind = 33; // our second hardware interrupt pin digital pin 3 volatile byte cflag = 0; // let's know when we're expecting rising edge on pina signal encoder has arrived @ detent volatile byte dflag = 0; // let's know when we're expecting rising edge on pinb signal encoder has arrived @ detent (opposite direction when aflag set) volatile long encoderposb = 0; //this variable stores our current value of encoder position. change int or uin16_t instead of byte if want record larger range 0-255 volatile long oldencposb = 0; //stores last encoder position value can compare current reading , see if has changed (so know when print serial monitor) volatile long readingb = 0;  int temppos; long vel; unsigned long newtime; unsigned long oldtime = 0;  void setup() {   //motor   pinmode(pina, input_pullup); // set pina input, pulled high logic voltage (5v or 3.3v cases)   pinmode(pinb, input_pullup); // set pinb input, pulled high logic voltage (5v or 3.3v cases)   attachinterrupt(0, pina, rising); // set interrupt on pina, looking rising edge signal , executing "pina" interrupt service routine (below)   attachinterrupt(1, pinb, rising); // set interrupt on pinb, looking rising edge signal , executing "pinb" interrupt service routine (below)   //motor b   pinmode(pinc, input_pullup); // set pina input, pulled high logic voltage (5v or 3.3v cases)   pinmode(pind, input_pullup); // set pinb input, pulled high logic voltage (5v or 3.3v cases)   attachinterrupt(0, pinc, rising); // set interrupt on pina, looking rising edge signal , executing "pina" interrupt service routine (below)   attachinterrupt(1, pind, rising);   serial.begin(9600); // start 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 read pin values   reading = pind & 0xc; // read 8 pin values strip away pina , pinb's values   if(reading == b00001100 && aflag) { //check have both pins @ detent (high) , expecting detent on pin's rising edge     encoderpos --; //decrement encoder's position count     bflag = 0; //reset flags next turn     aflag = 0; //reset flags next turn   } else if (reading == b00000100) bflag = 1; //signal we're expecting pinb signal transition detent free rotation   sei(); //restart interrupts }  void pinb(){   cli(); //stop interrupts happening before read pin values   reading = pind & 0xc; //read 8 pin values strip away pina , pinb's values   if (reading == b00001100 && bflag) { //check have both pins @ detent (high) , expecting detent on pin's rising edge     encoderpos ++; //increment encoder's position count     bflag = 0; //reset flags next turn     aflag = 0; //reset flags next turn   } else if (reading == b00001000) aflag = 1; //signal we're expecting pina signal transition detent free rotation   sei(); //restart interrupts }  void pinc(){   cli(); //stop interrupts happening before read pin values   readingb = pind & 0xc; // read 8 pin values strip away pina , pinb's values   if(readingb == b00001100 && cflag) { //check have both pins @ detent (high) , expecting detent on pin's rising edge     encoderposb --; //decrement encoder's position count     dflag = 0; //reset flags next turn     cflag = 0; //reset flags next turn   } else if (readingb == b00000100) dflag = 1; //signal we're expecting pinb signal transition detent free rotation   sei(); //restart interrupts }  void pind(){   cli(); //stop interrupts happening before read pin values   readingb = pind & 0xc; //read 8 pin values strip away pina , pinb's values   if (readingb == b00001100 && dflag) { //check have both pins @ detent (high) , expecting detent on pin's rising edge     encoderposb ++; //increment encoder's position count     dflag = 0; //reset flags next turn     cflag = 0; //reset flags next turn   } else if (readingb == b00001000) cflag = 1; //signal we're expecting pina signal transition detent 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;   }     } 

the 2 if statements made check encoders working properly. in first if statement i'm trying calculations of velocity.

i appreciate feedback.

thank you.

edit:

i found out theres encoder library makes lot easier.

so code looks this:

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

i still having problems "b" motor, calculation still way off reason.

motor "a" works fine

a couple of issues, including divide 0 error in loop(). scan cause reset of controller. check value of divisor when doing division!

using positive transitions unnecessarily reduces resolution of readings 2.

the arduino 8bit controller... reading int requires multiple instruction, means should disable interrupts before reading int that's modified interrupt routine. failure cause odd jumps in vakue read. done this:

//... nointerrupts(); int copyofvalue = value;   // use copy work with. interrupts(); //... 

in case, single byte value enough store movement, reset every 30 ms, should give top speed of 255 pulses/30ms = 8500 pulses/second or 1275000 rpm 24 ticks/turn encoder. :) in case, no need disable interrupts reading.

with 1 reading per 30ms, 1 tick /30ms = 33 tick/seconds, or 85 rpm. it's bit high motion. may need average readings, depending on application.

also, algorithm using not work. main reason delay between reads , adjustments small. readings of zero. run problem when removing println() calls. suggest pacing of @ least 30 ms between readings. 100 ms may work bit better, depending on application. using float variable speed average help.

void loop() {   //...   if(oldencpos != encoderpos) {     newtime = millis();     temppos = encoderpos - oldencpos;     vel = temppos / (newtime - oldtime);   // <--  if newtime == oltime => divide zero.     //...   }    //... } 

the encoder reading code seems awfully complex...

#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;        // difference, mask     if (delta == 1)                           // delta either 1 or 3        ++encpos1;    else        --encpos1;    encval1 = c;                              // keep reading next time.    encpos1 += delta;                         // position.    // no need call sei() }  setup() {   pinmode(pina, input_pullup);   pinmode(pinb, input_pullup);    // initial value   encvala  = digitalread(pina) ? 0b01 : 0;   encvala += digitalread(pinb) ? 0b10 : 0;    // use digitalpintointerrupt() map interrupts pin #   // ask interrupt on change, 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 have reasonable value.     {         unsigned char pos = encpos1;         signed char delta = pos - oldpos;          speed = 1000 * delta) / (time - oldtime);  // signed ticks/s          encpos1 -= pos;  // reset using subtraction, don't miss out                           // on encoder pulses.         oldtime = time;     } } 

Comments

Popular posts from this blog

angular - Ionic slides - dynamically add slides before and after -

minify - Minimizing css files -

Add a dynamic header in angular 2 http provider -