0

Multi-channel servo controller

Posted by Chris on Sunday, May 10, 2009 in , , ,
So here's the first working version of multi-channel, USB (and serial) driven servo controller. It's by no means complete, and for some reason, my servos only move 45 degrees either side of the zero point but the theory behind it seems to work.

Here's what happens, in a nutshell:
Unlike other multiple servo controllers, this one does not activate the servo pins in sequence (which, incidentally on a 20Mhz crystal limits you to 8 servos, maximum).
This controller switches on all servo pins at the same time, and uses timer1 to decide when each servo pin should be switched off.
Since all pins are on for the first 1ms, and are turned off during the second millisecond, this keeps 3-20ms (9/10ths) of the processing time free for data processing and other tasks (give or take a few nanoseconds for some basic time-keeping checks).

Using the same layout as my earlier USB project you can get some results quite quickly. Set your board out according to the schematic and drop the code (below) onto the PIC18F2455.

Attaching your servo signal wire to pin RB0 should move the servo to the zero position. RB1 should move the servo to one extreme, pin RB2 to the other. (in fact, if you look at the code, you should see that pins RB3-7 also move the servo to the same angle as RB1.

I'm still working on fine-tuning the code and experimenting with other servos.
I'm using a Hextronic HXT900 servo which doesn't appear to move through the full 180 degrees. The half-way signal does appear to put the servo into the centre position. However, when sending signals to move the servo to its extremes, it only moves 45 degrees in each direction, rather than the full 90.
I'm not sure whether this is a software issue, or whether it's particular to this servo model. Results of any further investigations will be posted here in time!

Oshonsoft PICBasic listing for 18F2445

Define CLOCK_FREQUENCY = 20
Define CONFIG1L = 0x24
Define CONFIG1H = 0x0c
Define CONFIG2L = 0x3e
Define CONFIG2H = 0x00
Define CONFIG3L = 0x00
Define CONFIG3H = 0x81
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

'PORTA.0 is feature LED
'PORTA.1 is i/o LED
'these can be removed if necessary

declarations:
Dim ax As Byte
Dim i As Byte
Dim j As Byte
Dim t As Byte
Dim svh(16) As Byte
Dim svl(16) As Byte

usbcrap:
UsbSetVendorId 0x1220
UsbSetProductId 0x1234
UsbSetVersionNumber 0x1122
UsbSetManufacturerString "www.nerdclub.co.uk"
UsbSetProductString "Multiple servo USB controller"
UsbSetSerialNumberString "1111111111"
UsbOnIoInGosub usbonioin
UsbOnIoOutGosub usbonioout
UsbOnFtInGosub usbonftin
UsbOnFtOutGosub usbonftout

init:
AllDigital
Config PORTA = Output
Config PORTB = Output
T1CON = 0 'set all bits to zero

startusb:
PORTA.0 = 1 'turn on an output so we can see the pic is running
UsbStart
PORTA.0 = 0 'turn off output once USB has set up

startup:
'set the value for timer1 to count up to
'(count to 5000 = 1ms: highbyte=5000/256, lowbyte=5000 mod 256)
CCPR1H = 19
CCPR1L = 136

'to allow a 0-100% range, sv(0-15) can take the value 0-100
'(we multiply these up by 50 as the values are received, to give
'a range of 0-5000, which is 0ms to 1ms).
'these are some example values to test the middle and extreme
'ranges of the servo controller on pins 0,1,2

svh(0) = 9
svl(0) = 196

svh(1) = 0
svl(1) = 0

svh(2) = 19
svl(2) = 136

'1011 = special event interrupt, clear timer etc.
CCP1CON.CCP1M3 = 1
CCP1CON.CCP1M2 = 0
CCP1CON.CCP1M1 = 1
CCP1CON.CCP1M0 = 1

'PIR1.CCP1IF = 0 'clear any "bogus" reading
T1CON.TMR1ON = 1 'enable timer1

t = 0

loop:

  If t = 1 Then
    'turn on all servo outputs for 1ms
    PORTB = 0xff
    PORTA.0 = 1 'led to show timer is running
  Else
      If t = 2 Then
      'this is where outputs get turned off. Because there may
      'be a delay in processing this loop, we compare the actual
      'value held in Timer2 and if it's greater than our servo-off
      'value (0-100% multipled by 50) then turn that pin off

      If TMR1H > svh(0) Then PORTB.0 = 0
      If TMR1H = svh(0) And TMR1L >= svl(0) Then PORTB.0 = 0

      If TMR1H > svh(1) Then PORTB.1 = 0
      If TMR1H = svh(1) And TMR1L >= svl(1) Then PORTB.1 = 0

      If TMR1H > svh(2) Then PORTB.2 = 0
      If TMR1H = svh(2) And TMR1L >= svl(2) Then PORTB.2 = 0

    Else
      'turn off the servo outputs for the duration 3ms to 14ms (and 0ms-1ms)
      PORTB = 0x00
      PORTA.0 = 0 'turn off timer led

      'service the USB port for data
      UsbService

      'check to see if we've had two bytes of serial data
      If i = 0 Then
        'Hserget i
      Else
        If j = 0 Then
          'Hserget j
        Else
          'parse the two byte instruction and update the servo-off
          'values as necessary, then reset i and j to zero
          i = 0
          j = 0
        Endif

      Endif
    Endif
  Endif

   'check for CCP1 interrupt flag (even if interrupts are not
   'on, you can poll this flag to see if an event has occurred)
   'this really needs to be in an interrupt routine so that the timer
   'is kept as up-to-date as possible
   If PIR1.CCP1IF = 1 Then
     t = t + 1
     PIR1.CCP1IF = 0

     If t > 14 Then
       t = 0

       'reset the timer to exactly zero
       '(so if there's been a delay switching on, we're back in sync
       'when it comes to switching the signal off, otherwise there
       'might be a bit of judder as the time period between on and off
       'may differ by a few thousandths of a millisecond)
       TMR1L = 0
     Endif

   Endif

Goto loop

End


usbonftout:
Toggle PORTA.0
Return


usbonftin:
'we've received some data in the feature report
Return


usbonioout:
Toggle PORTA.1
Return


usbonioin:
'we've received some data on the data i/o, so
'update the necessary servo high and low byte values
'to get the selected servo to move to its new position

Return


0 Comments

Post a Comment

whos.amung.us

Copyright © 2009 .Nerd Club All rights reserved. Theme by Laptop Geek. | Bloggerized by FalconHive Supported by Blogger Templates.