Help with pro mini and TB6612FNG motor driver

Hi All

Am new to this forum and Arduino so forgive me if some of my questions seem strange.
I am trying to build a project that has a requirement for up to 8 motor / power functions, for this i have chose the pro mini as i have size constraints on my model.
So i have been searching forums etc and found some code by Duane B i believe who is a member here, his code is using interrupts to read signals from an rc reciever and then output through one of the other channels.
Now where i have got so far is i can serial monitor read the 3 channels i have setup and i want these to feed to a TB6612FNG motor controller so i can drive my motors with forward and reverse, this is where my problem is i am really unsure what i need to connect from my pro mini to the motor controller to get the motors to work.
Have been trying many configurations but i cannot find anything online the clearly explains it, i am sure once i get it once it will all make sense.
Anyway if anyone on here has expericenced this issue as i have i would really be greateful for some help.

Regards
Mike.

Your description of what you are trying to do seems to be all jumbled up. Try again, starting at the inputs and working all the way down to the outputs. And don't forget to describe the machine you are trying to make. Keep in mind that we can't see your workbench and the only info we have is what you tell us.

Post a link to the datasheet for the motor driver.

Post a link to the datasheet for your motors.

Post your program and tell us what it actually does and what you want it to do that is different.

...R

Hi Robin

Really appreciate you coming back to me and apologies for my jumbled message i do realise i am giving very little info but wanted to get a dialog going and hopefully be able to flush out the details as we go.
So what am i trying to do.

As i said this is a project in progress but basically i want to start by just getting the following code link from Duane B's blog :

I have loaded the code up to my arduino pro mini and have managed to get the serial monitor reading the 3 channels.
Now my next issue is i want to connect up my TN6612FNG motor controller to the pro mini and get the output signal being processed by the above code to run my motor (the motor is a simple micro motor like this one :

problem is i am unsure what connections etc i am supposed to make from the pro mini to the motor controller, surely it is not just the output wire to the pwm of the controller (accepting that i have the power already setup on the controller ) ?

I hope that makes more sense , as you no doubt have guess i am a totally new entrant to the arduino scene and totally appreciate i might have jumped a few steps on but i can undestand the code part it is the electronic wiring parts i am struggling with, just so you know i have a turnigy tx and rx setup hence why i want to read rx input signals and use this to control my model.

My setup at moment is all on a breadboard so i can get a single motor working and i plan to build from there.

Regards
Mike.

This hookup guide should help you to connect the TB6612FNG if that is the version you have. If it isn't then you're on your own since you apparently don't want to provide links to whatever it is you are talking about.

Steve

EireGobra:
problem is i am unsure what connections etc i am supposed to make from the pro mini to the motor controller, surely it is not just the output wire to the pwm of the controller (accepting that i have the power already setup on the controller ) ?

You failed to post the most important info - the link to the motor driver you want help with. Happily @slipstick has done the job for you (be sure to thank him).

As far as I can see for each motor you need two digital pins for direction control and one PWM pin for speed.

...R

Hi Both

@Slapstick : thanks for posting link i thought i had added it to be honest but apparently not, i had already been over this one actually.

I guess my issue here is i am trying to use Duane B’s code from the link i provided but his code has changed the input/output for the mini pro

Basically the code is taking inputs from the reciever on
#define THROTTLE_IN_PIN 8
#define STEERING_IN_PIN 9
#define AUX_IN_PIN 10

And then creating circuits on the arduino to output on the following which does notwork with the diagram for wiring up the TB6612FNG

// Assign your channel out pins
#define THROTTLE_OUT_PIN 5
#define STEERING_OUT_PIN 6
#define AUX_OUT_PIN 7

Thanks for your help anyway i will keep looking possibly need to get code that will do what is sufficient for what i want it may be possible this code is not fitting with the hookup between the pro mini and the TB66 motor controller.

Regards
Mike.

EireGobra:
And then creating circuits on the arduino to output on the following which does notwork with the diagram for wiring up the TB6612FNG

// Assign your channel out pins
#define THROTTLE_OUT_PIN 5
#define STEERING_OUT_PIN 6
#define AUX_OUT_PIN 7

That is meaningless without a diagram to show how you have connected the motor driver.

My suspicion is that the code you are working with assumes there is a servo or ESC (which is controlled like a servo) attached to each of those pins.

Post the latest version of your program.

…R

Hi Robin

I expect you are right i have just rebuilt my breadboard with the setup from the TB661 site and uploaded the suggested code, it works find and cycles both motors on a forward and reverse cycle.

This is the original code i was working off
#include <PinChangeInt.h>

//MultiChannels
//
// rcarduino.blogspot.com
//
// A simple approach for reading three RC Channels using pin change interrupts
//
// See related posts -
// http://rcarduino.blogspot.co.uk/2012/01/how-to-read-rc-receiver-with.html
// http://rcarduino.blogspot.co.uk/2012/03/need-more-interrupts-to-read-more.html
// http://rcarduino.blogspot.co.uk/2012/01/can-i-control-more-than-x-servos-with.html
//
// rcarduino.blogspot.com
//

// include the pinchangeint library - see the links in the related topics section above for details
#include <PinChangeInt.h>

#include <Servo.h>

// Assign your channel in pins
#define THROTTLE_IN_PIN 8
#define STEERING_IN_PIN 9
#define AUX_IN_PIN 10

// Assign your channel out pins
#define THROTTLE_OUT_PIN 5
#define STEERING_OUT_PIN 6
#define AUX_OUT_PIN 7

// Servo objects generate the signals expected by Electronic Speed Controllers and Servos
// We will use the objects to output the signals we read in
// this example code provides a straight pass through of the signal with no custom processing
Servo servoThrottle;
Servo servoSteering;
Servo servoAux;

// These bit flags are set in bUpdateFlagsShared to indicate which
// channels have new signals
#define THROTTLE_FLAG 1
#define STEERING_FLAG 2
#define AUX_FLAG 4

// holds the update flags defined above
volatile uint8_t bUpdateFlagsShared;

// shared variables are updated by the ISR and read by loop.
// In loop we immediatley take local copies so that the ISR can keep ownership of the
// shared ones. To access these in loop
// we first turn interrupts off with noInterrupts
// we take a copy to use in loop and the turn interrupts back on
// as quickly as possible, this ensures that we are always able to receive new signals
volatile uint16_t unThrottleInShared;
volatile uint16_t unSteeringInShared;
volatile uint16_t unAuxInShared;

// These are used to record the rising edge of a pulse in the calcInput functions
// They do not need to be volatile as they are only used in the ISR. If we wanted
// to refer to these in loop and the ISR then they would need to be declared volatile
uint32_t ulThrottleStart;
uint32_t ulSteeringStart;
uint32_t ulAuxStart;

void setup()
{
Serial.begin(9600);

Serial.println(“multiChannels”);

// attach servo objects, these will generate the correct
// pulses for driving Electronic speed controllers, servos or other devices
// designed to interface directly with RC Receivers
servoThrottle.attach(THROTTLE_OUT_PIN);
servoSteering.attach(STEERING_OUT_PIN);
servoAux.attach(AUX_OUT_PIN);

// using the PinChangeInt library, attach the interrupts
// used to read the channels
PCintPort::attachInterrupt(THROTTLE_IN_PIN, calcThrottle,CHANGE);
PCintPort::attachInterrupt(STEERING_IN_PIN, calcSteering,CHANGE);
PCintPort::attachInterrupt(AUX_IN_PIN, calcAux,CHANGE);
}

void loop()
{
// create local variables to hold a local copies of the channel inputs
// these are declared static so that thier values will be retained
// between calls to loop.
static uint16_t unThrottleIn;
static uint16_t unSteeringIn;
static uint16_t unAuxIn;
// local copy of update flags
static uint8_t bUpdateFlags;

Serial.println(unThrottleIn);

// check shared update flags to see if any channels have a new signal
if(bUpdateFlagsShared)
{
noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables

// take a local copy of which channels were updated in case we need to use this in the rest of loop
bUpdateFlags = bUpdateFlagsShared;

// in the current code, the shared values are always populated
// so we could copy them without testing the flags
// however in the future this could change, so lets
// only copy when the flags tell us we can.

if(bUpdateFlags & THROTTLE_FLAG)
{
unThrottleIn = unThrottleInShared;
}

if(bUpdateFlags & STEERING_FLAG)
{
unSteeringIn = unSteeringInShared;
}

if(bUpdateFlags & AUX_FLAG)
{
unAuxIn = unAuxInShared;
}

// clear shared copy of updated flags as we have already taken the updates
// we still have a local copy if we need to use it in bUpdateFlags
bUpdateFlagsShared = 0;

interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on
// as soon as interrupts are back on, we can no longer use the shared copies, the interrupt
// service routines own these and could update them at any time. During the update, the
// shared copies may contain junk. Luckily we have our local copies to work with :slight_smile:
}

// do any processing from here onwards
// only use the local values unAuxIn, unThrottleIn and unSteeringIn, the shared
// variables unAuxInShared, unThrottleInShared, unSteeringInShared are always owned by
// the interrupt routines and should not be used in loop

// the following code provides simple pass through
// this is a good initial test, the Arduino will pass through
// receiver input as if the Arduino is not there.
// This should be used to confirm the circuit and power
// before attempting any custom processing in a project.

// we are checking to see if the channel value has changed, this is indicated
// by the flags. For the simple pass through we don’t really need this check,
// but for a more complex project where a new signal requires significant processing
// this allows us to only calculate new values when we have new inputs, rather than
// on every cycle.
if(bUpdateFlags & THROTTLE_FLAG)
{
if(servoThrottle.readMicroseconds() != unThrottleIn)
{
servoThrottle.writeMicroseconds(unThrottleIn);
}
}

if(bUpdateFlags & STEERING_FLAG)
{
if(servoSteering.readMicroseconds() != unSteeringIn)
{
servoSteering.writeMicroseconds(unSteeringIn);
}
}

if(bUpdateFlags & AUX_FLAG)
{
if(servoAux.readMicroseconds() != unAuxIn)
{
servoAux.writeMicroseconds(unAuxIn);
}
}

bUpdateFlags = 0;
}

// simple interrupt service routine
void calcThrottle()
{
// if the pin is high, its a rising edge of the signal pulse, so lets record its value
if(digitalRead(THROTTLE_IN_PIN) == HIGH)
{
ulThrottleStart = micros();
}
else
{
// else it must be a falling edge, so lets get the time and subtract the time of the rising edge
// this gives use the time between the rising and falling edges i.e. the pulse duration.
unThrottleInShared = (uint16_t)(micros() - ulThrottleStart);
// use set the throttle flag to indicate that a new throttle signal has been received
bUpdateFlagsShared |= THROTTLE_FLAG;
}
}

void calcSteering()
{
if(digitalRead(STEERING_IN_PIN) == HIGH)
{
ulSteeringStart = micros();
}
else
{
unSteeringInShared = (uint16_t)(micros() - ulSteeringStart);
bUpdateFlagsShared |= STEERING_FLAG;
}
}

void calcAux()
{
if(digitalRead(AUX_IN_PIN) == HIGH)
{
ulAuxStart = micros();
}
else
{
unAuxInShared = (uint16_t)(micros() - ulAuxStart);
bUpdateFlagsShared |= AUX_FLAG;
}
}

I think i need to go back to basics even though the code above is easy to follow and add new stuff to i am not sure if it will do what i require, i will look into the esc’s and using them.

Regards
Mike.

To make it easy for people to help you please modify your post and use the code button </> so your code looks like this and is easy to copy to a text editor.

I had assumed you would have already read How to use the Forum

Your code is too long for me to study quickly without copying to a text editor.

Also please use the AutoFormat tool to indent your code for easier reading.

…R

Hi Robin

Apologies i did read the how to but have to admin not all the way and missed this code section , so lets try again using the code tags.

Hopefully i have got it right this time.

//MultiChannels
//
// rcarduino.blogspot.com
//
// A simple approach for reading three RC Channels using pin change interrupts
//
// See related posts - 
// http://rcarduino.blogspot.co.uk/2012/01/how-to-read-rc-receiver-with.html
// http://rcarduino.blogspot.co.uk/2012/03/need-more-interrupts-to-read-more.html
// http://rcarduino.blogspot.co.uk/2012/01/can-i-control-more-than-x-servos-with.html
//
// rcarduino.blogspot.com
//

// include the pinchangeint library - see the links in the related topics section above for details
#include <PinChangeInt.h>

#include <Servo.h>

// Assign your channel in pins
#define THROTTLE_IN_PIN 8
#define STEERING_IN_PIN 9
#define AUX_IN_PIN 10

// Assign your channel out pins
#define THROTTLE_OUT_PIN 5
#define STEERING_OUT_PIN 6
#define AUX_OUT_PIN 7

// Servo objects generate the signals expected by Electronic Speed Controllers and Servos
// We will use the objects to output the signals we read in
// this example code provides a straight pass through of the signal with no custom processing
Servo servoThrottle;
Servo servoSteering;
Servo servoAux;

// These bit flags are set in bUpdateFlagsShared to indicate which
// channels have new signals
#define THROTTLE_FLAG 1
#define STEERING_FLAG 2
#define AUX_FLAG 4

// holds the update flags defined above
volatile uint8_t bUpdateFlagsShared;

// shared variables are updated by the ISR and read by loop.
// In loop we immediatley take local copies so that the ISR can keep ownership of the 
// shared ones. To access these in loop
// we first turn interrupts off with noInterrupts
// we take a copy to use in loop and the turn interrupts back on
// as quickly as possible, this ensures that we are always able to receive new signals
volatile uint16_t unThrottleInShared;
volatile uint16_t unSteeringInShared;
volatile uint16_t unAuxInShared;

// These are used to record the rising edge of a pulse in the calcInput functions
// They do not need to be volatile as they are only used in the ISR. If we wanted
// to refer to these in loop and the ISR then they would need to be declared volatile
uint32_t ulThrottleStart;
uint32_t ulSteeringStart;
uint32_t ulAuxStart;

void setup()
{
  Serial.begin(9600);
  
  Serial.println("multiChannels");

  // attach servo objects, these will generate the correct 
  // pulses for driving Electronic speed controllers, servos or other devices
  // designed to interface directly with RC Receivers  
  servoThrottle.attach(THROTTLE_OUT_PIN);
  servoSteering.attach(STEERING_OUT_PIN);
  servoAux.attach(AUX_OUT_PIN);

  // using the PinChangeInt library, attach the interrupts
  // used to read the channels
  PCintPort::attachInterrupt(THROTTLE_IN_PIN, calcThrottle,CHANGE); 
  PCintPort::attachInterrupt(STEERING_IN_PIN, calcSteering,CHANGE); 
  PCintPort::attachInterrupt(AUX_IN_PIN, calcAux,CHANGE); 
}

void loop()
{
  // create local variables to hold a local copies of the channel inputs
  // these are declared static so that thier values will be retained 
  // between calls to loop.
  static uint16_t unThrottleIn;
  static uint16_t unSteeringIn;
  static uint16_t unAuxIn;
  // local copy of update flags
  static uint8_t bUpdateFlags;

  Serial.println(unThrottleIn);

  // check shared update flags to see if any channels have a new signal
  if(bUpdateFlagsShared)
  {
    noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables

    // take a local copy of which channels were updated in case we need to use this in the rest of loop
    bUpdateFlags = bUpdateFlagsShared;
    
    // in the current code, the shared values are always populated
    // so we could copy them without testing the flags
    // however in the future this could change, so lets
    // only copy when the flags tell us we can.
    
    if(bUpdateFlags & THROTTLE_FLAG)
    {
      unThrottleIn = unThrottleInShared;
    }
    
    if(bUpdateFlags & STEERING_FLAG)
    {
      unSteeringIn = unSteeringInShared;
    }
    
    if(bUpdateFlags & AUX_FLAG)
    {
      unAuxIn = unAuxInShared;
    }
     
    // clear shared copy of updated flags as we have already taken the updates
    // we still have a local copy if we need to use it in bUpdateFlags
    bUpdateFlagsShared = 0;
    
    interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on
    // as soon as interrupts are back on, we can no longer use the shared copies, the interrupt
    // service routines own these and could update them at any time. During the update, the 
    // shared copies may contain junk. Luckily we have our local copies to work with :-)
  }
  
  // do any processing from here onwards
  // only use the local values unAuxIn, unThrottleIn and unSteeringIn, the shared
  // variables unAuxInShared, unThrottleInShared, unSteeringInShared are always owned by 
  // the interrupt routines and should not be used in loop
  
  // the following code provides simple pass through 
  // this is a good initial test, the Arduino will pass through
  // receiver input as if the Arduino is not there.
  // This should be used to confirm the circuit and power
  // before attempting any custom processing in a project.
  
  // we are checking to see if the channel value has changed, this is indicated  
  // by the flags. For the simple pass through we don't really need this check,
  // but for a more complex project where a new signal requires significant processing
  // this allows us to only calculate new values when we have new inputs, rather than
  // on every cycle.
  if(bUpdateFlags & THROTTLE_FLAG)
  {
    if(servoThrottle.readMicroseconds() != unThrottleIn)
    {
      servoThrottle.writeMicroseconds(unThrottleIn);
    }
  }
  
  if(bUpdateFlags & STEERING_FLAG)
  {
    if(servoSteering.readMicroseconds() != unSteeringIn)
    {
      servoSteering.writeMicroseconds(unSteeringIn);
    }
  }
  
  if(bUpdateFlags & AUX_FLAG)
  {
    if(servoAux.readMicroseconds() != unAuxIn)
    {
      servoAux.writeMicroseconds(unAuxIn);
    }
  }
  
  bUpdateFlags = 0;
}


// simple interrupt service routine
void calcThrottle()
{
  // if the pin is high, its a rising edge of the signal pulse, so lets record its value
  if(digitalRead(THROTTLE_IN_PIN) == HIGH)
  { 
    ulThrottleStart = micros();
  }
  else
  {
    // else it must be a falling edge, so lets get the time and subtract the time of the rising edge
    // this gives use the time between the rising and falling edges i.e. the pulse duration.
    unThrottleInShared = (uint16_t)(micros() - ulThrottleStart);
    // use set the throttle flag to indicate that a new throttle signal has been received
    bUpdateFlagsShared |= THROTTLE_FLAG;
  }
}

void calcSteering()
{
  if(digitalRead(STEERING_IN_PIN) == HIGH)
  { 
    ulSteeringStart = micros();
  }
  else
  {
    unSteeringInShared = (uint16_t)(micros() - ulSteeringStart);
    bUpdateFlagsShared |= STEERING_FLAG;
  }
}

void calcAux()
{
  if(digitalRead(AUX_IN_PIN) == HIGH)
  { 
    ulAuxStart = micros();
  }
  else
  {
    unAuxInShared = (uint16_t)(micros() - ulAuxStart);
    bUpdateFlagsShared |= AUX_FLAG;
  }
}

Regards
Mike.

You need 3 Arduino pins for each TB6612 channel. For 8 motors, that's 24 pins. One PWM pin per motor. I don't think a Pro Mini has that many.

You can reduce the pins by tying some of the TB6612 pins to HIGH or LOW. It depends on how much control you want to have over each motor. If you only want to control start/stop then you can do it with 1 pin and no PWM. That may be useful if it's just driving lights or something.

Hi MorganS

Thanks for your reply , unfortunately i need full control for the motors, am wondering if there is anyway i can use the pro mini for pwm control only ?, i guess this is not possible unless i used and ESC for each motor and just used the promini to output pwm signals , this would be too expensive thought i would think if i had to buy an ESC for each of my required motors.

Do you know if it is possible to use two pro mini's and within the code do some work to control which was getting the signal ?

I am only introducing myself to arduino so still learning, it looks though i can only at max possibly control 3 motors via adruino if i require full forward and reverse functions ?

Regards
Mike.

The Adafruit motor shield uses these same drivers with a PWM 'helper chip'. It only uses the I2C interface (2 pins) on the Arduino for up to 64 motors.

You could buy the shield or copy the schematic into your own custom PCB.

Hi MorganS

Thanks for the info i think copying the schematic at the moment is a step too far for me, but the Adafruit motor shield looks interesting, what i am not understanding is can this be programmed like the arduino mini pro or do i need another arduino board to allow me to code logic into it ?

I see it is stackable to build up the motors but it is not compatible with the mini pro it appears ?

The shield format is kind of large compared to a Pro Mini. You may be able to find an ebay seller with the same motor driver thing on smaller boards. Or you just put wires between the Pro Mini and the relevant pins on the motor shield.

So would I be correct in assuming that all the pro mini would be used for is generating the pwm signals from the receiver to the shield ?
am just trying to get my head around how to work it ..
Managed to get my transmitter / receiver working with one motor using pulseln but am going to now try using interrupt code as pulseln from what I hear is not really good ..
But I definitely see I have issues as it looked like I will only get to run one mother controller with one pro mini ..so might have to look at a larger bird or alteratively I look at making my own esc controllers ..

If you're using the Adafruit motor shield then the Pro Mini doesn't use PWM. The helper chip does that. You just send it commands over I2C. Download the library and have a look at how you talk to the library.

The shield is several times larger than it needs to be. The actual working components take up less than half of the area. The connector pins for the Uno size Arduino are large. It should be possible to find the same functionality on smaller boards.