next up previous
Next: Finished Product Up: Actual Implementation Previous: Oops

Servo Control

BB3 uses two dedicated pins controlled by a hardware timer to generate the signal required to control two RC servos. This approach is superior to the software based approach used by other robot controllers.

JP1 (the one to the left) is controlled by OC1A, while JP2 (the one to the right) is controlled by OC1B.

OC1A and OC1B are controlled by timer 1. Since most servos can handle a control pulse every 20ms, it makes sense to set the period of pulses at 20ms or longer. To do so, the clock of timer 1 must be slow enough so the period is 20ms or longer.

To do this, the clock should be divided by 8. This can be done by setting CS12, CS11 and CS10 to 010. This means for each second, timer 1 clocks at 200kHz. 20ms at this frequency means 40,000 clock ticks.

This means we need to use mode 14 (fast PWM with ICR1 as the top) of the timer as illustrated in table 47. This means WGM13, WGM12, WGM11 and WGM10 should all be set 1, 1, 1 and 0, respectively. ICR1 should to set to 40,000.

In the fast PWM mode, COM1A1 and COM1A0 should be set to 11 or 10. You can choose one way or the other. The difference is polarity. It is more intuitive (for me, anyway) to use the first portion of a period for the on (high) portion. This polarity means you need to choose 10 for COM1A1 and COM1A0 (and similar for COM1B1 and COM1B0).

The bottom line is that TCCR1A should be set to binary 10100010. TCCR1B should be set to binary 00011010.

In order to set the 16-bit registers, software must write to the high byte first, then the low byte. This is due to the design of including a temporary high register so the update of 16-bit registers is synchronized.

The first 16-bit register to set is TCNT1. It should be reset to zero initially. The second 16-bit register to set is ICR1. It should be set to 40,000 for a period of 20ms. Both of these 16-bit registers only need to be set once for initialization.

The other two 16-bit registers, OCR1A and OCR1B, controls the duty cycle of the servo pulses.

The following code should initialize timer 1:

output(TCNT1H,0);
output(TCNT1L,0);
output(ICR1H,40000 >> 8);
output(ICR1L,40000 & 0xff);
output(TCCR1A,0xa2);
output(TCCR1B,0x1a);

The pins connected to OC1A and OC1B are, by default, input pins. To make them output pins, use the following statement:

output(DDRD, input(DDRD) | 0x30);

The center position of a servo requires a 2ms pulse. This translates to 4000 clock cycles. This means it is best to initialize the compare registers as follows:

output(OCR1AH,4000 >> 8);
output(OCR1AL,4000 & 0xff);
output(OCR1BH,4000 >> 8);
output(OCR1BL,4000 & 0xff);

To make the servo go fast in one direction, substitute 3000 instead of 4000. To make the servo go fast in the other direction, substitute 5000 instead of 4000.

A simple but complete program to initialize BB3 to output a center signal to both servo connectors is located at http://www.drtak.org/src/bb3/servo1.c.


next up previous
Next: Finished Product Up: Actual Implementation Previous: Oops
Tak Auyeung 2003-07-21