Programming The Low-Voltage Dual Serial Motor Controllers

I recently bought a low-voltage dual serial motor controller, for use with the baby orangutan and the tamiya double gearbox. The user’s guide includes examples for programming in basic but I was wondering how one could program it in C, I’m assuming you need to connect the serial in to an out on the orangutan and then send commands through that output, but I don’t know what commands to send…

An example would probably suffice, I can learn pretty easily. Any help would be greatly appreciated.

Here’s a simple C example that sets up the hardware USART on the Baby Orangutan. It assumes that you’re running on the external 20MHz oscillator, and sets the baud rate to 9600bps. It then transmits a sample motor controller command, which you’ll probably want to turn into a separate function.

#define F_CPU 20000000//CPU clock
#define MYUBRR 129//USART config for 9600bps=(F_CPU/16/BAUD)-1, rounded

#include <avr/io.h>

void USART_Init(unsigned int ubrr){//Initialize USART hardware & protocol settings
	UBRR0H=(unsigned char)(ubrr>>8);//set buad rate
	UBRR0L=(unsigned char) ubrr;
	UCSR0B=(1<<TXEN0);//enable transmitter
	UCSR0C=(3<<UCSZ00);//Set frame format for 8bit with 1 stop
}

void USART_Trans (unsigned char data){//Transmit a byte of data over USART
	while(!(UCSR0A&(1<<UDRE0)));//wait for previous transmition to complete
	UDR0=data;
}

int main(){
	USART_Init(MYUBRR);

	USART_Trans(0x80);//start byte
	USART_Trans(0);//device type=serial motor controller
	USART_Trans(0x01);//motor number & direction (motor 0 fwd)
	USART_Trans(127);//full speed

	while(1);//infinite loop

	return 0;
}

You’ll need your Baby Orangutan and your motor controller to share a common ground, and to connect the Orangutan’s hardware TX pin (PD1) to the motor controller’s TTL level serial input pin (pin 4 on your motor controller, labeled “SER” on the silkscreen on the back, not “SERIN”). After that, you’re off to the races!

-Adam

I uploaded the code successfully, but the controller isn’t doing anything. It is connected to vcc and ground on the orangutan and a motor is plugged in, but nothing happens. No motor led and no motion.

Spoke too soon. Figured it out… Wiring, ugh.

With the code, I’m wondering how I would make a two motor configuration that goes forward and reverse depending on a sensors value. I have the sensor code, but I’m a little shaky on the motor end, are some of those four lines only declared once… or what?

int main(){
	USART_Init(MYUBRR);

	USART_Trans(0x80);//start byte
	USART_Trans(0);//device type=serial motor controller
	USART_Trans(0x01);//motor number & direction (motor 0 fwd)
	USART_Trans(127);//full speed

	while(1);//infinite loop

	return 0;
}

You always have to send four bytes at a time. The first two are always the same, a start byte for the Pololu serial protocol (0x80) and a device identification byte for Pololu serial motor controllers (0). The third byte represents the motor number and direction: motor number2 + 1 for forward, 0 for reverse. So to command motor 2 forward, your third byte would be 5 (22+1). To command motor 1 in reverse, your third byte would be 2 (2*1+0). The final byte is the speed, from 0 (stopped) to 127 (full speed).

So, you could build a motor command function that looked something like this:

void motorCommand(unsigned char motorNumber, unsigned char direction, unsigned char speed){
	USART_Trans(0x80);//start byte
	USART_Trans(0);//device type=serial motor controller
	USART_Trans(motorNumber*2+direction);//motor number & direction
	USART_Trans(speed);//speed
}

If you wanted to get a little fancier and check that you were generating valid commands, you could do something like this:

void motorCommand(unsigned char motorNumber, unsigned char direction, unsigned char speed){

	unsigned char motorCmd=motorNumber*2+direction;
	if(motorCmd>127){
		return;//invalid motor number+direction
	}

	if(speed>127){
		speed=127;//check motor speed in range
	}

	USART_Trans(0x80);//start byte
	USART_Trans(0);//device type=serial motor controller
	USART_Trans(motorCmd);//motor number & direction
	USART_Trans(speed);//speed
}

Does that make more sense?

-Adam

O.K. I got that working but… when I turn it on, the one motor spins for a little while and then quits and the other one continues. Here’s a look at the code. If I Unplug and replug the power it works again for a while then quits.

/***********************************************************************************
*This program was written by Matt Books to control a two wheeled balancing robot. 
*An accelerometer measures tilt in ADC6, and a motor driver is connected to 
*Version 0.1
*August 21, 2008
***********************************************************************************/

#include <avr/io.h>
#include "device.h"
#include <util/delay.h>

#include "analog.h"

#define MYUBRR 129

int direction;	//Global direction variable

int speed();
void driveRight(unsigned char spd, unsigned char direction);
void driveLeft(unsigned char spd, unsigned char direction);

void USART_Init(unsigned int ubrr)		//Initialize USART hardware & protocol settings
{
	UBRR0H=(unsigned char)(ubrr>>8);	//set buad rate
	UBRR0L=(unsigned char) ubrr;
	UCSR0B=(1<<TXEN0);					//enable transmitter
	UCSR0C=(3<<UCSZ00);					//Set frame format for 8bit with 1 stop
}

void USART_Trans (unsigned char data)	//Transmit a byte of data over USART
{
	while(!(UCSR0A&(1<<UDRE0)));		//wait for previous transmition to complete
	UDR0=data;
}

int main(void)
{
	USART_Init(MYUBRR);
	analog_init();

	for (;;)
	{			
		driveRight(speed(), direction);	//set Right Motor speed and direction
		driveLeft(speed(), direction);	//set Left Motor speed and direction
	}

	return 0;
}

int speed()
{
	int spd;
	
	spd = analog8(6); //read accelerometer 
	
	if (spd > 127)		//If tilt is past 90, set motors to drive forward
		direction = 1;
	else if (spd < 127)	//If tilt is below 90, set motors to drive reverse
		direction = 0;
	
	if (direction == 1)	//If driving forward
		spd = spd - 127;//Subtract 127 to make motors drive slowly when vertical and faster as it leans
	if (direction == 0)	//If driving backwards
		spd = 127 - spd;//Subtract FROM 127 to "" ""
	
	return spd;
}

void driveRight(unsigned char spd, unsigned char direction)
{
	USART_Trans(0x80);//start byte
	USART_Trans(0);//device type=serial motor controller
	USART_Trans(0*2+direction);//motor number & direction
	USART_Trans(spd);//speed
}

void driveLeft(unsigned char spd, unsigned char direction)
{
	USART_Trans(0x80);//start byte
	USART_Trans(0);//device type=serial motor controller
	USART_Trans(1*2+direction);//motor number & direction
	USART_Trans(spd);//speed
}

Two possibilities come to mind.

My first guess is that you might be having motor noise issues. The Tamiya motors are VERY NOISY. Do you have small capacitors right at the motor leads (as described on page 4 of the user guide). Keeping the motor wires short, fat, and in twisted pairs can also really help. What are you using for your motor power supply and your logic power supply?

I would also be interested to know if you see this effect if you send both motors each a single speed command and then let them run. You might consider adding a short delay (a millisecond or two). I doubt this is your issue though.

Any luck?

-Adam

I’ve been putting that off for a while, thanks for reminding me! I soldered on some caps and twisted the wires and all seems good now. Thanks. Now I just gotta build a chassis and get it to balance (again).