|
The SSC-32
outputs are connected to shift registers, which are under
control of an AVR ATMega8 processor running at 14.7456 MHz. Each
shift register controls a bank of 8 outputs, numbered Bank 0
through Bank 3. Bank 0 contains outputs 0-7, Bank 1 contains
outputs 8-15, etc. The shift registers are driven by the SPI
(Serial Peripheral Interface) hardware of the ATMega8, clocked
at the maximum rate of 7.3728 MHz. Every time the processor
needs to change an output, it sends the byte representing an
entire bank to the appropriate shift register. Using optimized
assembly code, the processor is able to update the outputs as
fast as every 1.5 microseconds.
The servo
pulses are output one bank at a time. The 20 millisecond update
period is divided as follows:
* 0.0 - 2.5 ms: Bank 0 pulses
* 2.5 - 5.0 ms: Bank 1 pulses
* 5.0 - 7.5 ms: Bank 2 pulses
* 7.5 - 10.0 ms: Bank 3 pulses
* 10.0 - 20.0 ms: no pulses
The pulse
outputs are handled by an Interrupt Service Routine (ISR), so
other processing can happen continuously in the background. An
interrupt occurs at the beginning of a bank output interval to
turn on all of the outputs that are enabled in the bank. Then, 8
more interrupts occur, one to turn off each output in the bank.
If two or more edges occur very close together, they will be
combined into the same interrupt. The process repeats every 20
milliseconds.
Received
characters from the UART are also handled by an ISR, which
places the characters into a queue for later processing. The
background task removes received characters from the queue and
acts upon them. As servo positions, speeds, and move times are
received, they are collected into a table. When a carriage
return character is received, the processor goes through the
table and updates the servo target positions and speeds. The
move speed for each servo is calculated so that all the servos
start and end simultaneously. The following rules determine the
speed of the move:
1. All servos involved in the move start and end at the same
time.
2. If a speed is specified for a servo, that speed will not be
exceeded during the move.
3. If a time is given for the move, then the move will take at
least that long.
4. The move will be as fast as possible, without violating the
first 3 rules.
In order to
follow these rules, the processor looks at the current position,
target position, and speed (if any) for each servo. The
combination of the distance to be moved and the speed implies a
time for the move, which will generally be different for each
servo. In addition, there might be a time specified for the
entire move. For the actual move time, the processor uses the
longest time of all the times calculated. It then re-calculates
the speed for each servo based on the actual move time. All of
the calculations are performed using precision arithmetic, in
order to minimize rounding errors.
In addition to
handling received characters, the background task also updates
the pulse widths for servos that are moving. It does this by
adding a value to the pulse width every 20 milliseconds. This
continues until the actual pulse width is equal to the target
pulse width. The value added to the pulse width depends on the
speed of the move; the higher the speed the faster the pulse
width changes. The value added to the pulse width can be
positive or negative, depending on whether the pulse width needs
to increase or decrease. |