24 servo motors

Introduction

As I wanted to make a walking machine, I needed to control more than 18 servo motors. I first use a 68hc11 but I never make it work for more than 8 servos because I found only one port (8 bits...) that had the right electrical caracteristics. The I tried with the at90s2313 and every thing worked fine! With one Atmel I controle 12 servos (13 should have also been possible).

Program

Here is the idea of the board and the program:
The at90s2313 has 1 serial port, 2 timers and 13 IOs. For my board I use only 12 IOs, that will drive the servos. The first timer drives 8 servos and the second one4 servos.
Here is the time diagram for the timer that drives 4 servos:


A servo is drived by sending a pulse of 1 ms to 2 ms every 20ms on the data wire (white or yellow). It is possible to send servo pulse for 8 servos one after each other. So for my program,
1) when the timer overflow interruption is raised, the pin corresponding to servo 1 is set to VCC and the timer overflow is set to the pulse width.
2) when the second timer overflow occures, servo 1 pulse is stopped, servo 2 pulse start and timer overflow is set to servo 2 pulse width.
3) same as 2)
4) same as 2)
5) servo 4 pulse is stopped. To have a pulse period of 20ms, the timer is set to wait a longer time. As the pulse period is not very important for the precision of the servo position, this waiting time can be set to constant even if servo pulse are non constant.

I use the serial port to send orders to the IC: set servo position+enable servo, disable servo. To drive 24 servos, I just have created a loop on serial port:
PC-Tx -> IC1-Rx, IC1-Tx -> IC2-Rx, IC2-Tx -> PC-Rx

Communication protocol

Send 2 bytes on serial port:
--------------------------------------------------------------------------------------
| Board ID2 | Board ID1 | Board ID0 | Set servo Pos | addr3 | addr2 | addr1 | addr 0 |
--------------------------------------------------------------------------------------
-----------------------------------------------------------------
| data7 | data6 | data5 | data4 | data3 | data2 | data1 | data0 |
-----------------------------------------------------------------
Set servo Pos= 0=> set enableMask, mask = data,
Set servo Pos= 1=> set servo pos using data
if addr3==0, data = mask for lower(<8) servo ids else higher servo ids(>=8)

The 3 bits higher bits of the first byte are the id of the micrcontrolleur you are talking to. As there is only 2 microtcontrolers values are 000 and 001 (only Board ID0 is useful). If you want to send an order to a servo which id is less or equal to 11, send 000 else 001.
The fourth bit: "Set servo Pos" is used to select the kind of command to send to the servo:
- send the servo to a given position Set servo Pos=1
- disable/enable the power on the servo so it is controled or not: Set servo Pos = 0
Then you have 4 bits (the lower ones) to select the servo you want to set the position of. There are 16 posibilities but only the 12 first one are useful as there are only 12 servos per microcontroller.

If (Set servo Pos=1) then the second byte defines the pwm value for the servo it should be between 190 and 240.
For example :
to set the position of servo 0 to 0xEF send 0x10 0XEF
to set the position of servo 10 to 0xDA send 0x1A 0xDA
to set the position of servo 12 to 0xDA send 0x30 0xDA
to set the position of servo 13 to 0xDA send 0x31 0xDA

If you want to enable/disable the power of a motor it is a little bit more complicated:
The first 4 bits of the first byte have the same meaning. Then the comand allows you to enable/disable 8 servo in one command. If addr3=0 then the second byte will set the enable/disable mask for servos [0-7] of the microcontroller you have selected. If addr3=1 it is for servos [8-11].
The second byte contains the mask value to enable/disbale 4 or 8 servos. Each bit set to one means that you want to enable the corresponding servo.
For example:
- if you want to enable servo 0 and disable all other servos
0x00 0x01 (<= enable servo 0 and disable servos 1 to 7)
0x08 0x00 (<= disable servos 8 to 11)
0x20 0x00 (<= disable servos 12 to 19)
0x28 0x00 (<= disable servos 19 to 23)

- if you want to enable servo 13 and disable all other servos
0x00 0x00 (<= disable servos 1 to 7)
0x08 0x00 (<= disable servos 8 to 11)
0x20 0x02 (<= enable servo 13 and disable servos 12 and 14 to 19)
0x28 0x00 (<= disable servos 19 to 23)

- if you want to enable servo 19 and disable all other servos
0x00 0x00 (<= disable servos 1 to 7)
0x08 0x00 (<= disable servos 8 to 11)
0x20 0x80 (<= enable servo 19 and disable servos 12 to 18)
0x28 0x00 (<= disable servos 19 to 23)

Board Schematic


To connect it to a PC, use a max232.

Download

Assembler source code using AVR studio + control program for PC (Visual C++): servo24.zip