Can the Orangutan SVP-324 control 4 motors?

In the specs I read that there are dual TB6612FNG motor drivers on board the SVP-324. However, it seems like they can only drive one bidirectional motor each, but at twice the ratings of the driver as a standalone chip. Can this be modified so that I can use the motor drivers to run 2 motors apiece and 4 motors total?

Hello, Drebis.

While each TB6612FNG is capable of driving two motors, we have tied their inputs and outputs together on the Orangutan SVP so they can only drive one motor. It would be extremely difficult or impossible to modify the SVP to get 4 motor outputs from the on-board motor drivers.

Instead, I suggest that you buy a dual motor driver, such as the TB6612FNG Dual Motor Driver Carrier and control it using free PWM outputs and I/O lines on the SVP. Pins PB3 and PB4 are PWM outputs for Timer 0, so you can use those.

–David

Thanks, I actually happen to have bought the TB6612FNG motor driver carrier before, so I will try this out! I appreciate your help.

OK so now I am trying to use the Timer0 to control the motor driver carrier Item #713, which is the carrier for the TB6612FNG.

I hooked the motor leads to A01 and A02, B01 and B02.
I used the Vadj from the SVP-324 and stuck it on Vmot on the carrier, turning the pot so the Vadj was near 7 V (Vin is 7.2V).
SVP-324 Vcc (5V) to Standby and Vcc on the carrier
grounds where indicated

PB3 to PWMA
A4 to AIN1
A5 to AIN2

PB4 to PWMB
A6 to BIN1
A7 to BIN2

Then I cribbed this code:

// pwm0-only
//
// Tom Benedict


// This set of motor PWM routines uses TIMER0, an 8-bit timer with
// dual PWM output.  The output compare signals for TIMER0, OC0A
// and OC0B are tied to PB3 and PB4 respectively.
//
//
// The documentation for the TB6612FNG gives the following output
// for each combination of IN1 and IN2 (or IN3 and IN4):
//
//  IN1		IN2		Function
//  ------	------	--------------------
//  0		0		Coast
//	1		0		CW
//  0		1		CCW
//  1		1		Brakes
//
// Since OC0A and OC0B are tied to PB3 and PB4, we can use them to
// send a pulse-width modulated signal to motors A and B.  But there's
// a catch (there always is):



#define F_CPU 20000000UL

#include <pololu/orangutan.h>  
#include <avr/io.h>

// We're not using delays for driving the motors, but so we can
// pause for a couple of seconds during the demo to show things are
// working.  If you're going to use this motor code for your own
// purposes, you probably won't need this #include.
#include <util/delay.h>


// The PWM motor code does a lot of bit fiddling in timer control
// registers.  I've made an effort in the comments to explain WHAT
// is going on.  But I haven't gone overboard in explaining HOW.
// If you read through this and wonder what loading TCCR0A with
// 2 << COM0A0, please read the data sheet for the processor you're
// using.  Atmel actually has very good datasheets with lots of
// examples.  The chapters on the timers are well written and will
// fill in all the gaps I'm leaving.


// Initialize timer 0 to do PWM for our motors:
void pwm0_init(void)
{
	// Set Timer Control Register 0 A for PWM on both OC0A and OC0B,
	// with both set to clear on compare match, and set at bottom.  
	// This is how we want things for forward rotation.  We'll set on 
	// compare match with clear at bottom for reverse.  Waveform 
	// generation mode is set to fast PWM from 0x00 to 0xFF (mode 3):

	TCCR0A = (2 << COM0A0) | (2 << COM0B0) | (3 << WGM00);

	// Set Timer Control Register 0 B to set a clock prescale of 256
	// This sets a PWM frequency of Clock / 256 / 256 or:
	// Orangutan:		122.07031250 Hz
	// Baby-Orangutan:	305.17578125 Hz
	// Prescale of 256 is mode 4.

	TCCR0B = (4 << CS00);

	// We're in PWM mode, so no need of interrupts:

	TIMSK0 = 0;

	// Enable output on PB4 and PB3 so we get our PWM outputs on the
	// TB6612FNG motor driver inputs: GOING TO SEND IT TO PWMA AND PMWMB

	DDRB |= (1 << PB4);
	DDRB |= (1 << PB3);

	// Enable output on PB1 and PB2 so we can set those bits to get 
	// directional control on the other inputs on the TB6612FNG:

	DDRA |= (1 << PA4); //AIN1
	DDRA |= (1 << PA5); //AIN2
	DDRA |= (1 << PA6); //BIN1
	DDRA |= (1 << PA7); //BIN2

	// Set our waveforms to zero for the time being:  (Zero speed.)

	OCR0A = 0;
	OCR0B = 0;
}

// Motor A uses PA4 and PA5 as well as PB3-> PWMA
void pwm0_a(int speed)
{
	clear();
	print_long(speed);
	if (speed > 0)
	{
		// Forward

		// PA4 PA5 = HL needed for CW rotation
		
		PORTA |= (1 << PA4);
		PORTA &= ~(1 << PA5);

		// Clear compare mode for PWM0A and set to clear on compare
		// match, set at bottom:
		TCCR0A = (TCCR0A & ~(3 << COM0A0)) | (2 << COM0A0);
		// Set our PWM duty cycle
		OCR0A = speed;
	}	
	if (speed == 0)
	{
		// Disconnect PWM from 0C0A:
		TCCR0A &= ~(3 << COM0A0);
		// Set PA$ and PA% to LL to coast
		PORTA &= ~(1 << PA4);
		PORTA &= ~(1 << PA5);
		// No PWM duty cycle to set
	}
	if (speed < 0)
	{
		// Reverse

		// Set to PA4 PA5 to LH for CCW rotation

		PORTA &= ~(1 << PA4);
		PORTA |= (1 << PA5);

		// Clear compare mode for PWM0A and set to set on compare
		// match, clear at bottom:
		TCCR0A = (TCCR0A & ~(3 << COM0A0)) | (3 << COM0A0);
		// Set our PWM duty cycle
		OCR0A = -speed;
	}
}

// Motor B uses PA6 and PA7 with PB4 going to PWMB
void pwm0_b(int speed)
{
	if (speed > 0)
	{
		// Forward

		// A6 A7 = H L
		PORTA |= (1 << PA6);
		PORTA &= ~(1 << PA7);

		// Clear compare mode for PWM0B and set to clear on compare
		// match, set at bottom:
		TCCR0A = (TCCR0A & ~(3 << COM0B0)) | (2 << COM0B0);
		// Set our PWM duty cycle
		OCR0B = speed;
	}	
	if (speed == 0)
	{
		// Disconnect PWM from 0C0A:
		TCCR0A &= ~(3 << COM0B0);

		// Set outputs to zero to coast
		PORTA &= ~(1 << PA6);
		PORTA &= ~(1 << PA7);
		
		// No PWM duty cycle to set
	}
	if (speed < 0)
	{
		// Reverse

		// A6 A7 = L H
		PORTA &= ~(1 << PA6);
		PORTA |= (1 << PA7);

		// Clear compare mode for PWM0B and set to set on compare
		// match, clear at bottom:
		TCCR0A = (TCCR0A & ~(3 << COM0B0)) | (3 << COM0B0);
		// Set our PWM duty cycle
		OCR0B = -speed;
	}
}

void pwm0_a_brake(void)
{
	// Set motor speed to zero (turns off PWM):
	pwm0_a(0);
	// Enable both PA4 and PA5 to hit the brakes (POWER HUNGRY):
	PORTA &= ~(1 << PA4);
	PORTA &= ~(1 << PA5);
}

void pwm0_b_brake(void)
{
	// Set motor speed to zero (turns off PWM):
	pwm0_b(0);
	// Enable both PA6 and PA7 to hit the brakes (POWER HUNGRY):
	PORTA &= ~(1 << PA6);
	PORTA &= ~(1 << PA7);
}


// That's really it for the motor stuff.  The only other subroutine
// is a delay routine that will let us pause for a couple of seconds.
// Almost all the example code will have this routine in it.

// Delay for N seconds
void delay_sec(unsigned char sec)
{
	unsigned int cycles;

	// Delay 25ms at a time (38.4ms is the most we can delay with a
	// 20MHz processor, unfortunately.  See the delay.h include file
	// for more info.)

	for(cycles = 0; cycles < (sec * 40); cycles ++)
	{
		_delay_ms(25);
	}
}

// And now for our main routine:

int main(void)
{
	// Make sure all our registers are clear
	DDRD |= 1 << DDD1;
	DDRB = 0;
	DDRC = 0;
	DDRD = 0;

	// Make sure all our pull-up resistors are clear
	PORTB = 0;
	PORTC = 0;
	PORTD = 0;

	// Initialize the timer0 PWM system:

	pwm0_init();

	// Motors are stopped when we initialize them, so there's
	// no need to do that after the init routine.

	// The endless loop

	for(;;)
	{
	

		// Both motors full forward
			pwm0_a(150);
		pwm0_b(150);
		delay_sec(2);


		// Coast to a stop
		
		pwm0_a(0);
		pwm0_b(0);
		delay_sec(5);




		// Both motors full reverse
		
		pwm0_a(-255);
		pwm0_b(-255);
		delay_sec(2);


		// Brake to a stop
		
		pwm0_a_brake();
		pwm0_b_brake();
		delay_sec(5);


	}

	// We never get here, but return a zero if we ever do.
	return(0);
}

I tried to run it, and I varied the speed for forward just to see if it would help, but nada from the motors, and no voltage changes on A01 A02 etc.

ANy hints as to what I am forgetting to change? I appreciate any help you could give me, thanks.

I plugged 5V into PWMA, and the motor will go forwards and backwards, so my problem is definitely in the PWM portion of the code. Any pointers?

I looked at your PWM code but couldn’t spot anything wrong. You could simplify it a lot and that might reveal the bug. I’m not sure if that delay_sec function actually works.

–David

Have you gotten this code to work yet?
I’m trying to control 4 motors with my Orangutan X2, 2 on the motor controller that comes with it and two on another motor controller (the exact same kind).
I still have to figure out how to connect my second motor controller PWM to the correct place on the X2 but it seems like PB3 is used for the LCD screen and PB4 for something else.

Hello.

PB4 is a free pin; we break it out to the center of the board. If you are not using the LCD screen, you should be able to use PB3 as a PWM output as well. Alternatively, you could use the available PD4 and PD5 pins that use Timer1 or PD6 and PD7 pins that use Timer2 to generate PWM signals. For more information about the Orangutan X2 and a schematic of the board, you can refer to the Orangutan X2 quick-start guide.

- Jeremy

That helps a lot since I am using the LCD screen the D pins on the other two clocks will be helpful. I do need to find how to code the PWM signals through those pins still. All the information in the quickstart, Orangutan X2 Commands and avr library doesn’t seem to help with that.

You might refer the OrangutanMotors library to see how the Orangutan SVP (which also uses an ATmega1284P) uses the timers to generate PWM signals. (The Orangutan X2 uses an auxiliary process to generate PWM signals.) You can find the source code for our Orangutan controller in the “src” folder in the Pololu AVR Library.

- Jeremy