Wednesday, 6 April 2011

Servo board controller - parallel not serial

Many moons ago, we put together a multiple channel servo controller which generated a lot of interest on YouTube.

As part of the newly-relaunched NerdClub website, it made sense to write a few posts about how the all-new 20 channel controller works. Kits will be made available to anyone who just wants to get their hands on a working servo board, without the need to puzzle out all the clever code.

For this board, we're using the trusty old PIC 18F4550 microcontroller. You can use the lower-voltage 18LF version of this chip too, but we're sticking with the 5V version (see schematics later on).

Many people have asked how we managed to get beyond the theoretical limit of 8 servos on a 20ms pulse. For anyone not familiar with servo control, the way a servo works is it receives a signal of between 1ms and 2ms in duration (1ms = extreme left position, 2ms = extreme right). This signal has to be repeated every 20ms.



In practice, a servo signal is usually between 0.8ms and 2.4ms in length. Allowing for up to 2.5ms per servo, and repeating each signal every 20ms, this means we can send 20/2.5 = 8 signals one after the other, before having to return to the first servo to repeat the whole process all over again.



This is where we challenged the assumption that the servo signals have to all be sent serially (one after the other). We took the "parallel" approach - we turn on all servo pins at the same time, then compare the current time (in milliseconds) from the on signal start, to an array of "off values". Every time the current timer exceeds the "off value", the corresponding output pin is turned off.

Let's say we've an array of three off values:
servooff[1]=1000
servooff[2]=1500
servooff[3]=2000

We turn on all three servo pins at the same time, and start a timer running.
During the main code loop, we compare the current running timer value (converted into milliseconds) against each of the three off values. When the running timer exceeds 1000, we send servo pin one low (turn off the servo signal). This is the same as a 1ms servo signal (which sets servo one to the extreme left position). After the timer exceeds 1500 (1.5ms) servo pin 2 goes low (servo two is set to the mid-position) and after the running timer exceeds 2000 (2ms) servo pin 3 goes low (setting servo three to the extreme right position).

Because the signals need to repeat every 20ms, we now have 18ms of hanging around before we reset the running timer and turn on all servo pins again.
(in fact, these 18ms are used for other processing such as receiving and processing user input, getting data from an SPI eeprom chip and so on).

Using this "parallel" method of processing the servo signals, we can have many more than just eight servos. We stopped at 20 because our PIC microcontroller has 40 pins - 4 are used for power and USB, 5 for SPI clocking an eeprom chip, a few push-button inputs, serial comms (send and receive) and we decided to leave a couple of spares.


Parallel method of controlling servo signals - all are turned on at the same time, and switched off at different times (between 0.8ms and 2.4ms after being switched on).

2 comments:

  1. If the period resolution is T and there is a servo with periodo nT in the list, would this work if the next servo pin is to be toggled in the nT+1 period?

    ReplyDelete
  2. I'm not sure I understand the question. I don't really know what period resolution means, but by using the parallel approach, there's no such thing as "next servo pin".
    All servo pins are controlled at the same time. So at 0ms, all pins go high. Let's say all servos are centred - at 1.5ms, all pins go low. Now between 2ms and 20ms, the mcu can get on with other tasks (unlike in serial where you're dealing with one servo at a time, one after the other).

    At 20ms, all pins go high again, and at 21.5ms, all go low. Between 22ms and 40ms, the mcu is idling (or can be used to do other stuff).

    If you want to move one servo full left, assuming 1ms=full left and 2ms=full right, we end up with: at 40ms all pins go high. At 41ms, the one servo pin goes low. At 41.5ms, all other pins go low.

    There's no "next pin" and I'm not sure what the "period" bit of the question relates to.
    Strictly speaking, there is a small resolution to work within; but it's nanoseconds during 0ms-2ms the mcu is constantly comparing the current timer value to an array of up to 20 (or more) "off" times so there might be a tiny, tiny delay between when a servo pin should go low and when it actually happens - but there's more delay in the gearing of the servo than in the mcu controller so it's treated as negligible.

    ReplyDelete