VNH5019 Shield with servo

Hello,

I’m using a Pololu Dual VNH5019 Motor Driver Shield connected to an arduino Uno. On this, i have 2 Pololu motors connected and 1 NRFL2401 module for a remote controller.
I want to control also a Servomotor but it seems that i don’t have any PWM PIN available anymore :frowning:
Is there a solution ?

Regards,

Hi.

This section from our Zumo shield guide on controlling a servo with an Arduino Uno has code for using Timer 2, which should not interfere with the VNH5019 shield.

-Claire

Thanks Claire, i will check this link

Well, this is not exactly my issue :frowning:
The shield is using by default some PINS.
So i only have available the PINS 3, 5, 11 and 13, but all of them are used for the NRFL2401 !
I have no more PWM PIN to use for the servo :frowning:
Is there any clue ?

This is my diagram without the Servo :

Regards,

Can i use the Pin 6 for example ? or is it already used in my case by the shield ?

I tried with the link @Claire provide above.
And i can move the servo with it by using the PIN 6. But in the code, i just can move servo OR motors depending on which initialization is done in last between the “motor init” and the “servo init”.
I guess because the PIN 6 is used for both :frowning:
Can you please to find a way to make working both servo and motors with the shield and the NRF24L01 ? Or it’s just impossible ?

Here is my code for information :

#include "DualVNH5019MotorShield.h"

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>


DualVNH5019MotorShield md; // declaration pour le shield Pololu

// pour Servo //////////////////////
#define SERVO_PIN 6
// This is the time since the last rising edge in units of 0.5us.
uint16_t volatile servoTime = 0;
// This is the pulse width we want in units of 0.5us.
uint16_t volatile servoHighTime = 3000;
// This is true if the servo pin is currently high.
boolean volatile servoHigh = false;
int mapServo = 0;
////////////////////// pour Servo /

void stopIfFault()
{
  if (md.getM1Fault())
  {
    Serial.println("M1 fault");
    while(1);
  }
  if (md.getM2Fault())
  {
    Serial.println("M2 fault");
    while(1);
  }
}

RF24 radio(5, 3); // CE, CSN du module wireless

const byte address[6] = "00001"; // Canal de communication entre les modules wireless

struct Pack
{
  int vX;
  int vY;
  int SW_state;
  int But_state;
  int vX2;
  int vY2;
  int SW_state2;
  int But_state2;
}pack;

int mapX = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println("Dual VNH5019 Motor Shield");
  
  //md.init(); // work only if servoInit() is commented
  servoInit(); // work only if md.init() is commented

  // initialisation pour le module Wireless
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_MIN);

}

void loop()
{ 
  radio.startListening();

while  (radio.available()) {
  radio.read( &pack, sizeof(pack) );
  mapX = map(pack.vX, 0, 1023, -200, 200);
  mapServo = map(pack.vY2, 0, 1023, 1000, 2000);

  servoSetPosition(mapServo);
  delay(20);

//if ((mapX > 20) || (mapX < -20)) {
//  stopIfFault();
//  md.setSpeeds(-mapX,-mapX); // on inverse car le joystick est a l'envers
//  }
//  else {  ////////////////////////////////////////////////////////////////////////////// a l'arret
//    stopIfFault();
//    md.setSpeeds(0,0);
//  }
}

  Serial.print("X droite: ");
  Serial.print(pack.vX);
  Serial.print(" | Y droite: ");
  Serial.print(pack.vY);
  Serial.print(" | Bouton droite: ");
  Serial.print(pack.SW_state);
  Serial.print(" | Push droite: ");
  Serial.print(pack.But_state);
 
  Serial.print(" |||| ");
  Serial.print(" X gauche: ");
  Serial.print(pack.vX2);
  Serial.print(" | Y gauche: ");
  Serial.print(pack.vY2);
  Serial.print(" | Bouton gauche: ");
  Serial.println(pack.SW_state2);
  Serial.print(" | Push gauche: ");
  Serial.print(pack.But_state2);

  //Serial.print("X: ");
  //Serial.print(mapX);
  //Serial.print(" | Y: ");
  //Serial.print(mapY);
  //Serial.print(" | Bouton: ");
  //Serial.println(pack.SW_state);
}

// pour Servo //////////////////////
  // This ISR runs after Timer 2 reaches OCR2A and resets.
// In this ISR, we set OCR2A in order to schedule when the next
// interrupt will happen.
// Generally we will set OCR2A to 255 so that we have an
// interrupt every 128 us, but the first two interrupt intervals
// after the rising edge will be smaller so we can achieve
// the desired pulse width.
ISR(TIMER2_COMPA_vect)
{
  // The time that passed since the last interrupt is OCR2A + 1
  // because the timer value will equal OCR2A before going to 0.
  servoTime += OCR2A + 1;
   
  static uint16_t highTimeCopy = 3000;
  static uint8_t interruptCount = 0;
   
  if(servoHigh)
  {
    if(++interruptCount == 2)
    {
      OCR2A = 255;
    }
 
    // The servo pin is currently high.
    // Check to see if is time for a falling edge.
    // Note: We could == instead of >=.
    if(servoTime >= highTimeCopy)
    {
      // The pin has been high enough, so do a falling edge.
      digitalWrite(SERVO_PIN, LOW);
      servoHigh = false;
      interruptCount = 0;
    }
  } 
  else
  {
    // The servo pin is currently low.
     
    if(servoTime >= 40000)
    {
      // We've hit the end of the period (20 ms),
      // so do a rising edge.
      highTimeCopy = servoHighTime;
      digitalWrite(SERVO_PIN, HIGH);
      servoHigh = true;
      servoTime = 0;
      interruptCount = 0;
      OCR2A = ((highTimeCopy % 256) + 256)/2 - 1;
    }
  }
}
 
void servoInit()
{
  digitalWrite(SERVO_PIN, LOW);
  pinMode(SERVO_PIN, OUTPUT);
   
  // Turn on CTC mode.  Timer 2 will count up to OCR2A, then
  // reset to 0 and cause an interrupt.
  TCCR2A = (1 << WGM21);
  // Set a 1:8 prescaler.  This gives us 0.5us resolution.
  TCCR2B = (1 << CS21);
   
  // Put the timer in a good default state.
  TCNT2 = 0;
  OCR2A = 255;
   
  TIMSK2 |= (1 << OCIE2A);  // Enable timer compare interrupt.
  sei();   // Enable interrupts.
}
 
void servoSetPosition(uint16_t highTimeMicroseconds)
{
  TIMSK2 &= ~(1 << OCIE2A); // disable timer compare interrupt
  servoHighTime = highTimeMicroseconds * 2;
  TIMSK2 |= (1 << OCIE2A); // enable timer compare interrupt
}
  ////////////////////// pour Servo /

Pin 6 is used by the VNH5019 library by default for EN1DIAG. You can see all the default pins the library uses in its DualVNH5019MotorShield.cpp file. You can move the servo pin to another unused pin by changing line 17 of the example code to:

#define SERVO_PIN A2

A2 can be replaced with any pin number that is convenient.

-Claire

So great ! It works perfectly !
I though that I had to use only PIN with a ~ for servo.
Thanks a lot.