Go Down

Topic: DC motor control with quadrature encoder Arduino mega  (Read 4287 times) previous topic - next topic

nick1992

Hi,

I am using an Arduino mega 2560 to try to rotate a single dc motor with encoder a set number of rotations. I am using a Dual VNH2SP30 Motor Driver Carrier (link at the bottom) and an ASLONG JGY-370B-12V worm gear motor with encoder. I copied code from another post and adapted it to match the pins i was using but i am having some issues.

In the code below i am trying to make the motor do 2 rotations forwards at full speed, 2 rotations backwards at half speed and then stop.

Code: [Select]
// MD03A_Motor_basic + encoder

#define InA1            11                      // INA motor pin
#define InB1            12                      // INB motor pin
#define PWM1            13                      // PWM motor pin
#define encodPinA1      21                      // encoder A pin
#define encodPinB1      20                      // encoder B pin

#define LOOPTIME        100                     // PID loop time
#define FORWARD         1                       // direction of rotation
#define BACKWARD        2                       // direction of rotation

unsigned long lastMilli = 0;                    // loop timing
unsigned long lastMilliPrint = 0;               // loop timing
volatile long count = 0;                        // rotation counter
long countInit;
long tickNumber = 0;
boolean run = false;                            // motor moves

void setup() {
  //Serial.begin(9600); // baud rate
  //Serial.flush();
  pinMode(InA1, OUTPUT);
  pinMode(InB1, OUTPUT);
  pinMode(PWM1, OUTPUT);
  pinMode(encodPinA1, INPUT);
  pinMode(encodPinB1, INPUT);
  digitalWrite(encodPinA1, HIGH);               // turn on pullup resistor
  digitalWrite(encodPinB1, HIGH);
  attachInterrupt(2, rencoder, FALLING);        // 2 is pin 21
}


void loop() {
  moveMotor(FORWARD, 255, 510*2);              // direction, PWM, ticks number
  delay(4000);
  moveMotor(BACKWARD, 128, 510*2);             // 510=360°
  delay(4000);
//Serial.print("countInit : " );                 
//Serial.println(countInit);
 
}

void moveMotor(int direction, int PWM_val, long tick)  {
  countInit = count;    // abs(count)
  tickNumber = tick;
  if(direction==FORWARD)          motorForward(PWM_val);
  else if(direction==BACKWARD)    motorBackward(PWM_val);
}


// ********* Encoder counting ********

void rencoder()  {                                  // pulse and direction, direct port reading to save cycles    NB so this might be the bit that tells if the motor is going forwards or backwards
if (PINB & 0b00000001)   { count++;   }            //if (digitalRead(encodPinB1)==HIGH)   count ++;                     
else                   { count--;  }              // if (digitalRead(encodPinB1)==LOW)   count --;                     
if(run) 
  if((abs(abs(count)-abs(countInit))) >= tickNumber)      motorBrake();
}

// ****Code for forward backward and brake  ****

void motorForward(int PWM_val)  {
  analogWrite(PWM1, PWM_val);
  digitalWrite(InA1, LOW);
  digitalWrite(InB1, HIGH);
  run = true;
}

void motorBackward(int PWM_val)  {
  analogWrite(PWM1, PWM_val);
  digitalWrite(InA1, HIGH);
  digitalWrite(InB1, LOW);
  run = true;
}

void motorBrake()  {
  analogWrite(PWM1, 0);
  digitalWrite(InA1, HIGH);
  digitalWrite(InB1, HIGH);
  run = false;
}


What actually happens is that it does the 2 rotations forwards, pauses to complete the delay, 2 rotations backwards, and then goes into a loop of pausing for 8 seconds then going backwards. Around half way through that 8 second pause, there is a spike in the PWM signal which makes the motor twitch but that is all, I have no idea what is causing this.

I think there is something wrong in the "rencoder" code but if i change it then the motor no longer rotates the specified amount of turns it just rotates for the duration of the delay. How cani make my motor complete the revolutions I want and then stop? I hope to add a second motor once i have accomplished this.

I look forwards to your responses.

Motor Driver: https://www.pololu.com/product/708
Motor:http://jslmotor.en.alibaba.com/product/60248815875-211952029/Electric_12v_Dc_Motor_with_Gear_Reduction_JGY_370B_Worm_Gear_Motor_with_Encoder.html

outsider

Interrupt 2 is pin 19, pin 20 is PD1, PIND,1

http://pighixxx.com/megapdf.pdf

nick1992

Thanks for your response, what does that mean I should do? I don't fully understand the code below and i think it is that which must change along with the attachinterrupt command further up.

Code: [Select]
void rencoder()  {                                  // pulse and direction, direct port reading to save cycles   
if (PINB & 0b00000001)   { count++;   }            //if (digitalRead(encodPinB1)==HIGH)   count ++;                     
else                   { count--;  }              // if (digitalRead(encodPinB1)==LOW)   count --;                     
if(run) 
  if((abs(abs(count)-abs(countInit))) >= tickNumber)      motorBrake();
}


I believe "0b00000001" references a pin from a different type of arduino? and based on the previous reply I should be referencing something other than PINB too? I currently have the encoder wires going into pins 20 and 21 on the Arduino.

MarkT

You only seem to be detecting when to brake in one direction in the encoder ISR.  You need
to tell the ISR what direction and end position are currently appropriate?

You will inevitably overrun of course.

A more powerful approach is to close a servo loop, so that you use a PID loop to set the pwm and
direction given the error signal (desired position less actual position).

The encoder ISR merely keeps the actual position variable live, the PID loop output can be
subject to a limit to give your speed control, or you could arrange the desired position to be
a function of time.

Using a feedback loop like this will mean the position is held actively at a stop, which is more
performant than just braking.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Go Up