Drive-Brake Operation for VNH5019

Hello

Beginner here. Noted that the VNH5019 dual_vnh5019_motor_driver_shield.pdf (911.9 KB) motor shield can be configured to drive-brake operation. Currently the equipment I’m using is a 6v,3.3aH lead acid battery from unicell, an Arduino Uno(328P) and the 2 motors are from Pololu - 47:1 Metal Gearmotor 25Dx64L mm LP 6V with 48 CPR Encoder (No End Cap). I have connected the jumper ON from page 10 of the PDF attached. Searching past forums got me useful info but raises slightly more questions for a beginner like myself.


According to the user guide of the VNH5019 motor shield, it states clearly that I will have to connect physically a jumper wire of both MxPWM pins to Vcc and simply provide PWM to MxINA/B pins. Below is the edits I’ve made to the library for my needs.

The edits are assuming:

  1. I will not be moving in reverse direction.
  2. No need for current sense pins.
  3. Drive-Brake

My main question is whether I have done the changes to enable drive-brake operation properly. Is it even possible? Would like to seek clarification on this. Thanks in advance.

DualVNH5019MotorShield.cpp

#include "DualVNH5019MotorShield.h"

// Constructors ////////////////////////////////////////////////////////////////

DualVNH5019MotorShield::DualVNH5019MotorShield()
{
  //Pin map
  _INA1 = 2; // pin operates at ~490Hz
  _INB1 = 4; // pin operates at ~490Hz
  _EN1DIAG1 = 6;
  //_CS1 = A0; 
  _INA2 = 7; // pin operates at ~490Hz
  _INB2 = 8; // pin operates at ~490Hz
  _EN2DIAG2 = 12;
  //_CS2 = A1;
}

// DualVNH5019MotorShield::DualVNH5019MotorShield(unsigned char INA1, unsigned char INB1, unsigned char EN1DIAG1, unsigned char CS1, 
                                               // unsigned char INA2, unsigned char INB2, unsigned char EN2DIAG2, unsigned char CS2)
// {
  // //Pin map
  // //PWM1 and PWM2 cannot be remapped because the library assumes PWM is on timer1
  // _INA1 = INA1;
  // _INB1 = INB1;
  // _EN1DIAG1 = EN1DIAG1;
  // _CS1 = CS1;
  // _INA2 = INA2;
  // _INB2 = INB2;
  // _EN2DIAG2 = EN2DIAG2;
  // _CS2 = CS2;
// }

// Public Methods //////////////////////////////////////////////////////////////
void DualVNH5019MotorShield::init()
{
// Define pinMode for the pins and set the frequency for timer1.

  pinMode(_INA1,OUTPUT);
  pinMode(_INB1,OUTPUT);
  pinMode(_PWM1,INPUT);
  pinMode(_EN1DIAG1,INPUT);
  //pinMode(_CS1,INPUT);
  pinMode(_INA2,OUTPUT);
  pinMode(_INB2,OUTPUT);
  pinMode(_PWM2,INPUT);
  pinMode(_EN2DIAG2,INPUT);
  //pinMode(_CS2,INPUT);
  #if defined(__AVR_ATmega168__)|| defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__)
  // Timer 1 configuration
  // prescaler: clockI/O / 1
  // outputs enabled
  // phase-correct PWM
  // top of 400
  //
  // PWM frequency calculation
  // 16MHz / 1 (prescaler) / 2 (phase-correct) / 400 (top) = 20kHz
  TCCR1A = 0b10100000;
  TCCR1B = 0b00010001;
  ICR1 = 400;
  #endif
}
// Set speed for motor 1, speed is a number betwenn -400 and 400
void DualVNH5019MotorShield::setM1Speed(unsigned int speed)
{
   // if (speed < 0)
  // {
    // speed = -speed;  // Make speed a positive quantity
    // reverse = true;  // Preserve the direction
  // }
  if (speed > 400)  // Max PWM dutycycle
    speed = 400;
  // #if defined(__AVR_ATmega168__)|| defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__)
  // OCR1A = speed;
  // #else
  // analogWrite(_PWM1,temp); // default to using analogWrite, mapping 400 to 255
  // #endif
  if (speed == 0)
  {
    analogWrite(_INA1,0);   // Make the motor brake immediately no
    analogWrite(_INB1,0);   // matter which direction it is spinning.
  }
  // else if (reverse)
  // {
    // analogWrite(_INA1,0);
    // analogWrite(_INB1,speed * 51 / 80);
  // }
  else
  {
    analogWrite(_INA1,speed*51/80);
    analogWrite(_INB1,0);
  }
}

// Set speed for motor 2, speed is a number betwenn -400 and 400
void DualVNH5019MotorShield::setM2Speed(unsigned int speed)
{
  // if (speed < 0)
  // {
    // speed = -speed;  // make speed a positive quantity
    // reverse = true;  // preserve the direction
  // }
  if (speed > 400)  // Max 
    speed = 400;
  // #if defined(__AVR_ATmega168__)|| defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__)
  // OCR1B = speed;
  // #else
  // analogWrite(_PWM2,temp); // default to using analogWrite, mapping 400 to 255
  // #endif 
  if (speed == 0)
  {
    analogWrite(_INA2,0);   // Make the motor brake immediately no
    analogWrite(_INB2,0);   // matter which direction it is spinning.
  }
  // else if (reverse)
  // {
    // analogWrite(_INA2,0);
    // analogWrite(_INB2,speed * 51 / 80);
  // }
  else
  {
    analogWrite(_INA2,speed*51/80);
    analogWrite(_INB2,0);
  }
}

// Set speed for motor 1 and 2
void DualVNH5019MotorShield::setSpeeds(unsigned int m1Speed, unsigned int m2Speed)
{
  setM1Speed(m1Speed);
  setM2Speed(m2Speed);
}

// Brake motor 1, brake is a number between 0 and 400
void DualVNH5019MotorShield::setM1Brake(unsigned int brake)
{
  if (brake > 400)  // Max brake
    brake = 400;
  // #if defined(__AVR_ATmega168__)|| defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__)
  // OCR1A = brake;
  // #else
  // analogWrite(_PWM1,temp); // default to using analogWrite, mapping 400 to 255
  // #endif
  analogWrite(_INA1, 400);
  analogWrite(_INB1, 400);
}

// Brake motor 2, brake is a number between 0 and 400
void DualVNH5019MotorShield::setM2Brake(unsigned int brake)
{
  if (brake > 400)  // Max brake
    brake = 400;
  // #if defined(__AVR_ATmega168__)|| defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__)
  // OCR1B = brake;
  // #else
  // analogWrite(_PWM2,temp); // default to using analogWrite, mapping 400 to 255
  // #endif
  analogWrite(_INA2, 400);
  analogWrite(_INB2, 400);
}

// Brake motor 1 and 2, brake is a number between 0 and 400
void DualVNH5019MotorShield::setBrakes(unsigned int m1Brake, unsigned int m2Brake)
{
  setM1Brake(m1Brake);
  setM2Brake(m2Brake);
}

// Return motor 1 current value in milliamps.
// unsigned int DualVNH5019MotorShield::getM1CurrentMilliamps()
// {
  // // 5V / 1024 ADC counts / 144 mV per A = 34 mA per count
  // return analogRead(_CS1) * 34;
// }

// // Return motor 2 current value in milliamps.
// unsigned int DualVNH5019MotorShield::getM2CurrentMilliamps()
// {
  // // 5V / 1024 ADC counts / 144 mV per A = 34 mA per count
  // return analogRead(_CS2) * 34;
// }

// Return error status for motor 1 
unsigned char DualVNH5019MotorShield::getM1Fault()
{
  return !digitalRead(_EN1DIAG1);
}

// Return error status for motor 2 
unsigned char DualVNH5019MotorShield::getM2Fault()
{
  return !digitalRead(_EN2DIAG2);
}

EDIT 1:

Strangely enough, I have stumbled upon other similar posts. According to this post PWM based speed controlling is not possible of VNH5019 with Arduino MEGA, seems that I’ll only be able to in some hybrid mode(which is fine by me) @nathanb. According to the same post @Claire, mentioned compensation by software, if it’s possible may I enquire further on this?

Hello.

The PDF you attached is an outdated version of our user’s guide for the shield and it appears that there is some outdated information in it. How were you referred to it? You can find the most current version of the user’s guide on the “Resources” tab of the board’s product page.

Generally, it is not practical to operate this driver in a pure drive-brake cycle as the switching time can be too high.

Have you gotten the motors to move using motor shield yet? If so, have you observed the non-linear behavior we discuss in the forum post you mentioned or any other problems? Can you post pictures here that show how you have everything connected including any soldered connections you made?

-Nathan

As part of a project, the ash02a was the revision that we were given and the accompanying user guide. I should add we were instructed NOT to make any modifications whether it be adding some capacitor or resistor(supervisors are not flexible on this unfortunately).

Should I use the most current version regardless of the revision anyways?

If that is the case, how then can I achieve a pseudo state or close to that state without it being in full Drive-Coast

Yes I have observed this behavior and no problems as of now other than the fact that one motor is slower than the other(yes due to manufacturing, no 2 items are ever the same). Odd thing is that for the slower motor setSpeed(50) does not work for that motor- but I think this is a separate issue.

I’ll be sure to post them here once I get around to it later.

Thanks again for the reply and looking forward to anything else you can share.

The top board is just a simple power regulator board that was provided.

Thanks for letting me know where you got that from. I wanted to make sure we are not providing any active links to the old user’s guide on our site.

You should use the latest version of our documentation. The largest change between the ash02a and ash02b boards is the addition of pass-throughs for the four new pins on the Arduino Uno R3. Generally speaking, most users should not notice any other differences between the two shield versions; details can be found in the “Differences between board revisions” section of the user’s guide.

You should not need to use any jumper wires to use the driver with that library. If you added any, you should probably remove them.

Our library for the motor shield operates the driver in either Drive/Coast (the setMxSpeed() functions) or Brake/Coast mode (the setMxBrake() functions). Section 2.4 of the VNH5019 datasheet describes the state of the H-bridge in the driver for the different states of the control input pins. The edits you made to the setMxBrake() will probably cause the INA and INB pins to be high (although 400 is not in the range of valid values to pass into the Arduino analogWrite() function), which will connect both leads together (at Vcc) and brake the motor, however this is not much different than calling the unmodified functions with a brake value of 400. You can write your own functions to toggle the input pins to the appropriate states described in the datasheet, but you should be aware that (as described in Table 8 of the datasheet) the transition time of the high side FETs that switch the connection between the motor leads and Vcc is much longer (and requires a much lower switching frequency) than switching the low side FETs using the PWM pin.

If you want to precisely control the speed of your motors with the hardware you have, we recommend using the unmodified library, monitoring the speed of your motors using feedback from the encoders on them, and setting the duty cycle of the motor drivers using something like a PID algorithm. In addition to compensating for the non-linearity of the driver’s output, this could also compensate for varying loads and the manufacturing differences in the motors performance.

-Nathan