Friday, December 28, 2007

Motor Control (Part 2)

Ok, well, if I get any of this wrong let me know. I haven't spent a lot of time in the AVR ATmega8 data sheets, and have only skimmed through this AVR PWM tutorial, but here goes...

Among the other things you can do, PWM-wise, you can create phase-correct PWM signals using a 16-bit counter, which is what the developer did who wrote the motor control example program (he said so in the comments). The long and short of it is that you use Timer1 (TCNT1), two Output Compare Registers (OCR1A and OCR1B). Two timer counter control registers (TCCR1A and TCCR1B) control TCNT1 and how the waveform generation operates.

The developer set TCCR1A to 0x0A2 (10100011). From the data sheet:
TCCR1B is set to 0x01. Here's the info on that from the data sheet:
So, the relevant settings being made are:

// Clear OC1A/B on Compare Match (set output low)
COM1A1 = 1; COM1A0 = 0;
COM1B1 = 1; COM1B0 = 0;

// Select clk/1 as source, no prescaling
CS12 = 0; CS11 = 0; CS10 = 1;

// Waveform Gen Mode 3, Phase-correct, 10-bit
WGM13 = 0; WGM12 = 0; WGM11 = 1; WGM10 = 1;

The data sheet gives you the truth tables for COM1B and WGM bits as they affect operation of the waveform generation. The example program's comments claimed it was setting Mode 2, Phase-corrected 9-bit but that is in contrast to the data sheet. Odd. At any rate, that takes care of the mode and configuration of the PWM.

Now, OCR1A and OCR1B are set to whatever desired value to achieve a particular duty cycle. Then TCNT1 is reset and off we go. The OCR1A/B registers are continually compared to TCNT1 and when there's a match, the corresponding Output Compare Pin (OC1A / PB1 and OC1B / PB2) is dropped low.
A lower compare value in OCR1A means more frequent drop-outs on the OC1A pin, thus a lower duty cycle, while a higher compare value means higher duty cycle. (At least that is how it works conceptually, but there are details I haven't tackled, yet)

In the example program (motor_test2.c) from Microrobot, the motor_init() function sets all this up (I've tweaked it a little to hopefully make more sense -- but take the comments with a grain of salt):

Distilling all this to the most fundamental information: to make the motors drive forward, basically do this after the init routine above:

OCR1AH=1; OCR1AL=100;
OCR1BH=1; OCR1BL=100;

The OC1A/B output pins go through the NAND gates mentioned previously and ultimately to input Pin1 and Pin2 of the Sanyo LB1630 bi-directional motor controller. It appears to always be the case that Pin1 = ~Pin2.
So how, exactly, do we get the motors to go reverse and forward simply by setting the high byte of OCR1A/B to 0x01... ?

I think we are always alternating between forward/reverse signals and we are essentially inverting the duty cycle for 0x00..0xFF (getting a reverse signal more often than a forward signal) versus 0x100..0x1FF (getting a forward signal more than a reverse signal). That means at 0x00, the motor is getting forward/reverse equally, which explains why the motors buzz at this setting. It also means we aren't saving a lot of energy by using PWM.

Also confusing is whether we are really using a 9- or 10-bit counter. Maybe I'll solve these mysteries in part 3.

Meanwhile I've managed to get the bot to do some very stupid, basic obstacle avoidance. So I am making some progress towards building a maze-solving bot.

No comments:

Post a Comment