Society of Robots - Robot Forum

Software => Software => Topic started by: frank26080115 on February 26, 2009, 12:08:59 PM

Title: I wrote code for a servo controller
Post by: frank26080115 on February 26, 2009, 12:08:59 PM
http://frank.circleofcurrent.com/servo_controller.php (http://frank.circleofcurrent.com/servo_controller.php)

This is an 8 channel serial servo controller.

Specs and Usage

It's performance depends on it's clock source. Running at 5V, it can use a 20 MHz clock source maximum, which would give it 0.05 microsecond resolution. At 3.3V, it can use its internal 8 MHz clock and have a resolution of 0.125 microsecond.

Individual channels can be enabled or disabled with a command and then a bit-mask. To ensure safe operation, the controller will start with all channels disabled. The pulse widths and pulse period should be set before enabling any channels.

The pulse period is adjustable, but keep in mind that it works by adding a delay after the final enabled channel is pulsed. All channels that are enabled will be pulsed, so the period can be longer that what the user has set to ensure all channels gets pulsed.

The command set is very simple, one command byte followed by its parameters. To set the pulse width of a channel, send the channel number (1 to 8), then two bytes representing the pulse width as a 16 bit integer, send the upper 8 bits first. To enable/disable channels, send a 0x09 then send a byte with each bit representing a channel, the value of bit 0 determines the status of channel 1, bit 7 determines the status of channel 8, a value of 1 means enabled and 0 means disabled. To set the pulse peroid, send 0x0A, then send a 32 bit integer representing the period length, send the upper 8 bits first. Sending a 0x00 as a command byte will do nothing and there are no parameters. This is useful because if you disconnect the serial port in the middle of a command, sending four 0x00 will cause the servo controller to wait for a new command no matter what stage of the process you were in.

The baud rate is automatically detected, upon resetting the servo controller, two bytes must be detected with the first byte being 0x00 for proper detection. You should still use a baud rate that works with your clock source, check the ATtiny2313 datasheet for the best baud rate and frequency combinations.

A neat feature of the way that the command set works and the automatic baud rate detection is that it's guaranteed to work if you send four 0x00 before any commands, the commands can be chained together after the four 0x00.

Project is compiled by AVR-GCC in AVR Studio, WinAVR is needed. Schematic is drawn in EAGLE. Please note that you need to compile this yourself first if you are not using the default 8 MHz clock source. You may also want to modify the schematic to suit your own application.

How It Works

The 16 bit timer interrupt is used. To ensure accuracy, TCNT1 is never modified, and the first thing that's done in the interrupt is to update the output port. The next pulse width is fetched from an array and the alarm is set, the index of the array is incremented until it reaches the next enabled channel, or it is determined that it is the last channel. After the last channel is pulsed, the remaining delay is calculated using the sum of all the previous pulses. The delay is split into the number of overflows needed and the remainder. The delay is executed like a channel would be except no pin is actually pulsed.

The AVR loops until a command is found. If it's a 0x00 command, then no parameters are needed and it loops again. If it's a valid command, it is executed as specified. The timer is started when at least one channel is enabled and it is stopped when the command disables all channels.

The automatic baud rate detection uses the input capture feature of the 16 bit timer. When there is a falling edge on the serial port, the input capture module takes a time stamp. The number of counts between two rising edges when two 0x00 bytes are sent is equal to the time it takes for 10 bits to be sent. The count is divided by 10, then by 16, then decremented, which would give a value to be used for the UBRR register. quadrotor helicopter.
Title: Re: I wrote code for a servo controller
Post by: Admin on March 20, 2009, 12:57:18 AM
I see its for the ATtiny2313.

If I were to put this onto the Axon, how much modification you think I'd need to do?

(note: I haven't looked at the code yet, but strongly considering adapting it)
Title: Re: I wrote code for a servo controller
Post by: frank26080115 on March 20, 2009, 07:06:51 AM
should be simple, it takes the number of clock ticks to pulse from an array, the main program loop is just something that waits for commands and places data into the array, just re-define your port names and get rid of the command part, then you can have your application place values into the same array.
Title: Re: I wrote code for a servo controller
Post by: Webbot on March 21, 2009, 09:05:28 AM
Nice one. I like the automatic baud rate detection. The servo control aspect is the same concept as used in 'servos.h/c' of AVRlib which I have experimented with. The only issue I have found with this timer technique is if you embed it into an app that uses lots of other interrupt routines - the interrupts cause the servo pulses to be not quite exact so you can get some small juddering of the servos. Hard to get around that though (other than hardware PWM) since you cannot disable the global interrupts as for 8 servos you may spend 16ms with all interrupts disabled.
 
Title: Re: I wrote code for a servo controller
Post by: frank26080115 on March 21, 2009, 10:19:52 AM
I have another method that guarantees timing even if multiple interrupts are enabled. It requires a serial to parallel shift register, and using the hardware compare output pins of the timer as the shift clock, timing is guaranteed because those pins are toggled by hardware and not interrupt routines.
Title: Re: I wrote code for a servo controller
Post by: Webbot on March 21, 2009, 12:27:17 PM
I have another method that guarantees timing even if multiple interrupts are enabled. It requires a serial to parallel shift register, and using the hardware compare output pins of the timer as the shift clock, timing is guaranteed because those pins are toggled by hardware and not interrupt routines.

Tell me more! Have you a schematic for the hardware? Would be interested to check it out.
Title: Re: I wrote code for a servo controller
Post by: frank26080115 on March 21, 2009, 12:36:01 PM
No I don't have a schematic, but you should be able to figure out how it works if you think about how a serial to parallel shift register works, place a bit in the first bit location, and every time you pulse the clock pin, that bit will shift to the next pin, thus beginning to pulse the pin latched to that bit location, on the next shift, the pulse will end and the pulse for the next pin begins.

Since AVR timers usually have two compare outputs, you can have 16 servos working at once with 4 GPIO pins, 2 shift register chips, and 1 timer

I believe 74LS164 is a good chip for the job