Folks:
I requested sample PWM code for the Orangutan well over a year ago, but judging from the lack of response and seeing similar requests from others, I conclude that Pololu engineers are unable to support their products with software. The hardware is nice, though!
So, users need to support themselves. I’ve spent some time puzzling over the documentation and design, which led to the following motor routines. The forward and reverse actions (brake vs. coast) are not the same because of the H-bridge and the Orangutan design, but the code seems to work OK. See notes below. To achieve the same PWM mode for forward and reverse, PB.1 and PB.2 will need to be disconnected from the output compare registers and handled separately in the code.
This code should work on the baby Orangutan (which I just purchased) but I haven’t tested it. The delay loops and PWM clock divider will need to be changed.
Corrections/suggestions would be appreciated. Note that posting removes tabs. Email me if you want the tabbed source.
Cheers, Jim
/*
** ORANGUTAN from pololu
** PWM for atmega8/LB1836M motor controller by Jim Remington
** sjames_remington _at_ yahoo.com
** WinAVR
*/
#include <avr/io.h>
/*
** Delays
*/
#define F_CPU 1000000UL
#include <util/delay.h>
#define Delay( x ) _delay_loop_2( x )
// above, x is uint16
/*
** PWM_Init - Set up the pwm ports (PORT B1=IN1, B2=IN3, D5=IN2, D6=IN4)
*/
void pwm_init( void )
{
DDRB |= (1<<1) | (1<<2);
DDRD |= (1<<5) | (1<<6);
TCCR1A = 0xF1; // 8 bit pwm phase correct
TCCR1B = 0x01; // clock/1. clock/8 works too (0x02).
OCR1A = 0;
OCR1B = 0;
}
/*
** pwm_set - Set the two PWM speeds. Each ranges from -255 to 255
** assumes left motor = PB.2 and PD.6, right = PB.1 and PD.5.
If direction of travel is wrong, switch motor leads (but see note below on asymmetry of PWM modes)
Truth Table for LB1836 controller from data sheet.
IN1/3 IN2/4 MODE
---- ----- ----
1 0 forward
1 1 brake (both outputs low)
0 1 reverse
0 0 coast (both outputs off =high impedance?)
*/
void pwm_set( int left_speed, int right_speed )
{
if ( right_speed < 0 ) { // If the right speed is negative
PORTD |= _BV(5); //IN2=1
TCCR1A |= _BV(COM1A0); //COM1A1 is 1, set COM1A0=1. Result: OC1A=IN1=0 on upcount, =1 on compare match
OCR1A = -right_speed; //(this should be reverse on upcount, brake on compare match)
}
else { //if right speed is positive
PORTD &= ~_BV(5); //IN2=0
TCCR1A &= ~_BV(COM1A0); //COM1A1 is 1, set COM1A0=0. Result: OC1A=IN1=1 on upcount, =0 on compare match
OCR1A = right_speed; //(this should be forward on upcount, coast on compare match)
}
if ( left_speed < 0 ) { // If the left speed is negative
PORTD |= _BV(6); //IN4=1
TCCR1A |= _BV(COM1B0); //COM1B1 is 1, set COM1B0=1. Result: OC1B=IN3=0 on upcount, =1 on compare match.
OCR1B = -left_speed; //(this should be reverse on upcount, brake on compare match)
}
else { // If the left speed is positive
PORTD &= ~_BV(6); //IN4=0
TCCR1A &= ~_BV(COM1B0); //COM1B1 is 1, set COM1B0=0. Result: OC1B=IN3=1 on upcount,=0 on compare match.
OCR1B = left_speed; //(this should be forward on upcount, off on compare match)
}
/* NOTE ASYMMETRY of forward and reverse PWM modes!
In preliminary tests with a mini-sumo rig using the LB1836 to directly drive two servo motors,
little difference between "brake" and "coast" modes could be detected.
However, reverse travel seemed to be a bit smoother and the motors responded more uniformly to identical
PWM setpoints. Need to test average current draw in the two modes
*/
}
/*
** MAIN. Exercise left and right motors.
** ramp up and down, forward and back
*/
int main(void)
{
unsigned int i,j;
pwm_init();
while(1)
{
for(i=1;i<256;i++)
{
pwm_set(i,i);
Delay(5000); //20000 cycles
}
for(i=255;i>0;i--)
{
pwm_set(i,i);
Delay(5000);
}
for(i=1;i<256;i++)
{
pwm_set(-i,-i);
Delay(5000); //20000 cycles
}
for(i=255;i>0;i--)
{
pwm_set(-i,-i);
Delay(5000);
}
}
return 0;
}