Control unlimited servos at the same time


Closed Thread
Results 1 to 8 of 8

Hybrid View

  1. #1
    Join Date
    Sep 2005
    Posts
    19

    Default Control unlimited servos at the same time

    I have an idea to control lots of (>10) servos from a PIC at the same time.

    Normaly everbody would choose this way to control multiple servos:

    High Ch1pin 'Or pulseout pin,ch1
    Pause ch1
    low Ch1pin

    High Ch2pin
    Pause ch2
    low Ch2pin

    High Ch3pin
    Pause ch3
    low Ch3pin

    This is uneffecient, and its also limits the maximum servo number
    becasuse a servo needs to update its position in every 18ms (19mS) (~50Hz).
    When using this technic we must run allover every signal sendout.
    Its limited to max ~11 servos (@50Hz)

    Here is the normal way to send out control signals:
    http://kepfeltoltes.hu/view/060913/O...toltes.hu_.gif

    There is a another solution, when we set High all Ch pins
    and give out a pause command, length of the first pause is the lowest ch time ,after the pause, Low the smallest ch pin.
    Then we have to figure out wich is the next lowest ch,then subtract the previous ch from this.
    We get a delta time. Give pause out for delta time, then Low the second lowest ch pin. Then search for the third lowest ch, subtrack the previous ch, pause delta time,low pin, search for the 4th lowest... and all over for all n servos.

    Here is the Faster way:
    http://kepfeltoltes.hu/view/060913/M...toltes.hu_.gif

    we have ch1,ch2,ch3,ch4,ch5,ch6,...ch(n) VAR byte 'for 8bit control
    ch1 is RB0,ch2 is RB1 ............

    1, High all servo pins (RB0,RB1....)
    2, find the smallest ch
    3, pause for smallest ch time
    4, low smallest ch pin

    5, find next! smallest ch
    6, subtract the previous from it
    7, pause for delta time
    8, low the ch pin
    9, goto 5

    it would be very nice when we could put in a loop (for,repeat,while)

    The limits of the servo number is really just the pin number of the microcontroller

    Some idea for the structure, to find the lowest ch:

    '---------
    For i=0 to (# of the servos)

    Select case Ch# 'current servo
    case is > ch1
    ..?
    case is > ch2
    ..?
    case is > ch3
    ..?
    .
    .
    .
    End select

    Next i
    '--------
    of course its not so simple, but please help me how to code this.
    Thx

  2. #2
    blainecf's Avatar
    blainecf Guest


    Did you find this post helpful? Yes | No

    Default excellent thinking process!

    I love to see people analyzing problems, breaking them down into their core components, and discovering that things don't have the limitations previously thought. (i.e. the limitation was really me, not the hardware!)

    I'm thinking a gotcha on this is the amount of calculation and decisions being made. And, obviously, things (servo positioning) will change over time.

    So, you have calculations, optimizing the data for an algorithm, and allowing for something to signal changes.

    The good news: things won't be changing that often (especially when viewed from MCU mhz perspective), or at least you hope that's the case (see below).

    Let's say, for the sake of argument, that you were to create three parallel arrays. One array for priority, one for on-time, and one for off-time. Then make an algorithm that will step through the arrays and set the pins accordingly.

    The first array functions like a database index, so, rather than (re-)sorting your arrays everytime something changes, you just change the index.

    A problem you'll run into is when managing multiple waveforms of different frequencies, you'll have to use something like a least-common-denominator concept to artificially time-slice/time-share. Hard to explain without a bunch of math; but simply draw a few different square waves of different frequencies on a whiteboard, one-above-the-other. Then, draw vertical lines that represent the action points. Conceptually, you'd need infinite resolution, but engineering is trade-offs, so you'll wind up picking (through calculations or trial-and-error) a minimum time increment to deal with.

    Why? When will you take time to check for changes and then re-calculate the array values.

    ------------------

    Where's the code!!!!!!!!!

    I'll watch this posting to see how things go.

    bcf

  3. #3
    Join Date
    Sep 2005
    Posts
    19


    Did you find this post helpful? Yes | No

    Default

    I think using an indexing is very good idea instead of sorting.
    Its maybe not a problem to recheck the integrity of the index,
    because is still much less time than send out pulses in the oldway
    (it can take SEVERAL mS-s instead of the integrity check which is not a big
    calculation (just comparing) @4Mhz)


    Or does enyone knows that how do manufactures solve this problem to
    control more than 15 servos @same time, from 1 controller, in single tasking.

    Because that is NOT possible to do this with standard servos.

  4. #4
    Join Date
    Oct 2003
    Location
    holland
    Posts
    251


    Did you find this post helpful? Yes | No

    Default

    I made a system with 8 servo output channels and it is easy to make that for more.
    See attachement
    Attached Files Attached Files

  5. #5
    Join Date
    Sep 2005
    Posts
    19


    Did you find this post helpful? Yes | No

    Cool

    I've finished the whole code.
    Its contains of:

    1, A Word[] array:
    its for storing each channel value between 1000-2000uS-> 1-2mS
    Or when using 10bit ADC-> we add ~988 to the adc value

    0-1023
    +988
    988-2011 uS -> 0.98-2mS instead of 1-2mS
    engineering is realy a tread of
    maximum resolution is 16bit because of Word is 16bit.

    you can add many channels as your PIC can handle,
    simply extend the numbers of elements of the A array.
    like A var word[10]

    And you also must change the biggest element number
    at line 31.

    2, B Byte[] array:
    it has the same numbers of elements as A.
    I use this array as an index of the A array.

    On startup I fill it up with [0,1,2,3]
    this index is used for "linking" (or pointing) to the A array.

    3. sorting
    the sorting was do it on the B index array,

    4, temp is just a byte because its temporaly holds
    the value of a the B elements, which is far less then
    255.

    5, send out routine
    high all servo pins
    because the B array is the sorted form of the A
    we can easily obtain the lowest channel value.
    calculate the delta times
    pauseus out the delta times
    and low the lowest channel's pin.

    You can learn more on delta timing on my previous posts.
    and more infos are in the code.
    The whole code is just 283 Word
    and its MAX runoff time is 3mS! (at a channel config of:1000,1435,1140,2000uS)
    when you want to sendout like this: pulseout ch1,ch2,ch3,ch4... itt would took

    5,6mS.!!! So my code is really effecient, especially when you use more channels.

    array setup: http://kepfeltoltes.eof.hu/gallery.p...1158505218.gif
    -------------------------------------------------------------------------

    'startup
    counter var BYTE
    Temp var byte
    A var WORD[4]
    B var byte[4]
    trisa=0
    trisb=0

    for counter=0 to 3 'DONT delete!!!!
    b[counter]=counter 'its for fill B[] on start up
    next counter
    'end of startup

    a[0]=1000 'CH0 'assign any value between 1000-2000uS->1-2mS
    a[1]=1435 'CH1 'in 1uS resolution!
    a[2]=1140 'CH2
    a[3]=2000 'CH3

    'sorting routine (from Melanie)
    'B[0] smallest, B[3] biggest
    counter=0
    SortLoop: 'dont delete this label,its for looping

    If a[b[counter]] > a[b[counter+1]] then
    Temp=b[counter]
    b[counter]=b[counter+1]
    b[counter+1]=Temp
    If counter>0 then counter=counter-2
    endif
    counter=counter+1
    If counter<3 then goto SortLoop
    'end sorting of B index array

    'this was 500-725 uS from start,depend a little on
    'how much sorting was needed

    'next routine will be as long as the biggest ch value
    'max 2mS + some uS

    'Sendout:
    high portb.0 'CH0
    high portb.1 'CH1
    high portb.2 'CH2
    high portb.3 'CH3


    for counter=0 to 3
    pauseus a[b[counter]]-a[b[counter-1]]
    'calc delta times
    'if counter=0 -> a[b[0-1]] -> WILL BE 0, TESTED!
    'so it'll be: Pauseus a[b[counter]]-0 !
    Portb.0(B[counter])=0
    'LOW portb# given back from B
    next counter

    end
    ---------------------

  6. #6
    Join Date
    Sep 2005
    Posts
    19


    Did you find this post helpful? Yes | No

    Default

    Any questions, or ideas?

  7. #7
    Join Date
    Sep 2005
    Posts
    19


    Did you find this post helpful? Yes | No

    Default

    I've fixed an error in the code.
    read comment.

    When at least 2 channels have the same value there will
    be no problems. Because the sorting cycle just changes the
    array when numbers are in wrong place:
    example: 1000 1000 1300 1400

    current test number:1000
    if current number > next number then swap

    but 1000 is not > than 1000
    so it will not change.

    when all ch have the same value:
    1000 1000 1000 1000
    the B array values will be: [0,1,2,3]

    ------------------
    'startup
    counter var BYTE
    Temp var byte
    A var WORD[4]
    B var byte[4]
    trisa=0
    trisb=0

    for counter=0 to 3 'DONT delete!!!!
    b[counter]=counter 'its for fill B[] on start up
    next counter
    'end of startup

    a[0]=1000 'CH0 RB0 'assign any value between ~1000-2000uS->~1-2mS
    a[1]=1430 'CH1 RB1 'in 1uS resolution!
    a[2]=1321 'CH2 RB2
    a[3]=1000 'CH3 RB3

    'sorting routine (from Melanie)
    'B[0] smallest, B[3] biggest
    counter=0
    SortLoop: 'dont delete this label,its for looping

    If a[b[counter]] > a[b[counter+1]] then
    Temp=b[counter]
    b[counter]=b[counter+1]
    b[counter+1]=Temp
    If counter>0 then counter=counter-2
    endif
    counter=counter+1
    If counter<3 then goto SortLoop
    'end sorting of B index array

    'this was 500-725 uS from start,depend a little on
    'how much sorting (swapping) was needed

    'next routine will be as long as the biggest ch value
    'max 2mS + some uS

    'Sendout:
    high portb.0 'CH0
    high portb.1 'CH1
    high portb.2 'CH2
    high portb.3 'CH3


    pauseus a[b[0]] 'for the lowest ch, not for fix ch!
    Portb.0(B[0])=0 'dont change!

    'the above 2 lines cant be inserted into the For cycle,
    'because it will couse for ever loops some times.
    'the reason is counter-1 @counter=0, some times will not be 0 (maybe 255).
    for counter=1 to 3 'for more channel replace 3

    pauseus a[b[counter]]-a[b[counter-1]]
    'calc delta times
    Portb.0(B[counter])=0
    'LOW portb# given back from B
    next counter
    'you need to redesign this send out routine
    'when you reach the max portb port number (1-7)
    'simply copy another FOR cycle
    'for Porta like: For counter 1 to 7
    end

    ---------------

Similar Threads

  1. 16F877 elapsed time control
    By BerkayT in forum mel PIC BASIC Pro
    Replies: 17
    Last Post: - 12th February 2009, 17:23
  2. Code to control 4 LEDs and 2 servos
    By The Master in forum Off Topic
    Replies: 2
    Last Post: - 26th November 2008, 13:33
  3. using a pot to control a time range
    By glkosec in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 17th June 2008, 19:59
  4. Serout2/serin2 Pbp Problem
    By SOMRU in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 11th December 2006, 19:55
  5. Button pressed time control
    By tanero in forum mel PIC BASIC Pro
    Replies: 12
    Last Post: - 15th August 2005, 15:17

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts