- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 12

Thema: Mehr als 2 Servos

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    07.01.2006
    Beiträge
    46

    Mehr als 2 Servos

    Anzeige

    Praxistest und DIY Projekte
    Hallo!

    Ich möchte gerne 6-8 Servos mit einem Atmega 16 steuern. Gibt es irgendwo fertige Routinen, oder Anregungen für sowas, oder hat jemand vielleicht einen Vorschlag? Dabei wäre es gut, wenn die Servosteuerung den Atmega nicht lahmlegen würde, so das auch die eigentliche Aplikation noch darauf laufen kann.

    Dank und Grüße!

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    29.05.2005
    Ort
    Rott am Inn
    Alter
    36
    Beiträge
    373
    Hallo,
    schau dir mal das Beispielprogramm an das kannst du auch auf 6-8 Servos erweitern
    Code:
    '-----------------------------------------------------------------------
    '                         (c) 2001-2005 MCS Electronics
    '                           servo.bas demonstrates the SERVO option
    '-----------------------------------------------------------------------
    
    'Servo's need a pulse in order to operate
    'with the config statement CONFIG Servos we can specify how many servo's we
    'will use and which port pins are used
    'A maximum of 16 Servos might be used
    'The SERVO statements use one byte for an interrupt counter and the TIMER0
    'This means that you can not use TIMER0 anymore
    'The reload value specifies the interval of the timer in uS
    'Config Servos = 2 , Servo1 = Portb.0 , Servo2 = Portb.1 , Reload = 10
    $regfile = "2313def.dat"
    
    Config Servos = 1 , Servo1 = Portb.0 , Reload = 10
    'as an option you can use TIMER1
    'Config Servos = 2 , Servo1 = Portb.0 , Servo2 = Portb.1 , Reload = 10 , Timer = Timer1
    
    
    'we use 2 Servos with 10 uS resolution(steps)
    
    'we must configure the port pins used to act as output
    Config Portb = Output
    
    'finally we must turn on the global interrupt
    Enable Interrupts
    
    'the servo() array is created automatic. You can used it to set the
    'time the servo must be on
    Servo(1) = 10                                               '10 times 10 = 100 uS on
    'Servo(2) = 20                                               '20 times 10 = 200 uS on
    Do
    Loop
    
    Dim I As Byte
    Do
     For I = 0 To 100
       Servo(1) = I
       Waitms 1000
     Next
    
     For I = 100 To 0 Step -1
     '  Servo(1) = I
       Waitms 1000
     Next
    Loop
    End

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    09.08.2004
    Ort
    Potsdam
    Beiträge
    190
    Wenn Du die Ausgänge der Ports im nacheinander per Software ansteuerst kannste ohne Probleme 9 Servos ansteuern und hast noch 2ms für andere Dinge Zeit.
    Oder Du nimmst die Hardware-PWM. Ich hab damit schon etwas rumgefrickelt, bin aber mit der Auflösung noch nicht so ganz zufrieden.

  4. #4
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    30.07.2005
    Beiträge
    569
    Wie wäre es, die Suchfiunktion dieses Forums zu bemühen ?
    Diese Problematik würde nämlich schon zich mal angesprochen.

  5. #5
    Benutzer Stammmitglied
    Registriert seit
    07.01.2006
    Beiträge
    46
    Danke für den Tip, aber so wie ich das verstanden habe, unterstützt Bascom direkt nur 2 Servos. Mir ist das Prinzip der Servoanstuerung zwar grundsätzlich klar, ich bin aber nicht so fit mit dem Atmega, und Bascom, das ich mir jetzt auf die Schnelle zutrauen würde, eine entsprechende Ansteuerung zu basteln.

    Prinzipell stelle ichs mir so vor, das die Servosteuerung in einem Timerinterrupt abgearbeitet wird und die Aplikation im Hauptprogramm läuft - sollte es aus irgendeinem Grund umgekehrt besser sein wärs natürlich auch ok.

    Im Timerinterrupt müsste jeder Servo etwa alle 20ms, oder so oft nötig seine individuelle Impulsdauer verpasst bekommen.

    @e-fan: Kannt Du mir ein Stück Quelltext geben, aus dem ersichtilich ist, wie Du die Servos ansteuerst?









    Zitat Zitat von franzl
    Hallo,
    schau dir mal das Beispielprogramm an das kannst du auch auf 6-8 Servos erweitern
    Code:
    '-----------------------------------------------------------------------
    '                         (c) 2001-2005 MCS Electronics
    '                           servo.bas demonstrates the SERVO option
    '-----------------------------------------------------------------------
    
    'Servo's need a pulse in order to operate
    'with the config statement CONFIG Servos we can specify how many servo's we
    'will use and which port pins are used
    'A maximum of 16 Servos might be used
    'The SERVO statements use one byte for an interrupt counter and the TIMER0
    'This means that you can not use TIMER0 anymore
    'The reload value specifies the interval of the timer in uS
    'Config Servos = 2 , Servo1 = Portb.0 , Servo2 = Portb.1 , Reload = 10
    $regfile = "2313def.dat"
    
    Config Servos = 1 , Servo1 = Portb.0 , Reload = 10
    'as an option you can use TIMER1
    'Config Servos = 2 , Servo1 = Portb.0 , Servo2 = Portb.1 , Reload = 10 , Timer = Timer1
    
    
    'we use 2 Servos with 10 uS resolution(steps)
    
    'we must configure the port pins used to act as output
    Config Portb = Output
    
    'finally we must turn on the global interrupt
    Enable Interrupts
    
    'the servo() array is created automatic. You can used it to set the
    'time the servo must be on
    Servo(1) = 10                                               '10 times 10 = 100 uS on
    'Servo(2) = 20                                               '20 times 10 = 200 uS on
    Do
    Loop
    
    Dim I As Byte
    Do
     For I = 0 To 100
       Servo(1) = I
       Waitms 1000
     Next
    
     For I = 100 To 0 Step -1
     '  Servo(1) = I
       Waitms 1000
     Next
    Loop
    End

  6. #6
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    30.07.2005
    Beiträge
    569
    Zitat Zitat von badamtam
    Danke für den Tip, aber so wie ich das verstanden habe, unterstützt Bascom direkt nur 2 Servos. Mir ist das Prinzip der Servoanstuerung zwar grundsätzlich klar, ich bin aber nicht so fit mit dem Atmega, und Bascom, das ich mir jetzt auf die Schnelle zutrauen würde, eine entsprechende Ansteuerung zu basteln.
    Die ist zwar sachon in Bascom drin, aber tu dir keinen Zwang an.

    Mit etwas Forensuche wirst du sicherlich auch entsprechende Codebeispiele finden ...
    Damit du das nich alleine machen musst, hilft dir dabei die Suchfunktion des Forums

    Und das Bascom nur 2 Servos direkt unterstützt halte ich übrigens für ein Gerücht.

    hrei hat sich dazu schonmal geäußert ... siehe hier

    In seinem Quelltext steht im übrigen ... up to 14 Servos ... also von demher.

    Grüße,
    da Hanni.

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von Dirk
    Registriert seit
    30.04.2004
    Ort
    NRW
    Beiträge
    3.803

    6 bis 8 Servos

    Hallo badamtam,

    ich hänge dir 'mal meine Servo10.LIB zur Ansteuerung von 10 Servos mit einem 2313 mit 4 MHz an.
    Prinzipell stelle ichs mir so vor, das die Servosteuerung in einem Timerinterrupt abgearbeitet wird und die Aplikation im Hauptprogramm läuft - sollte es aus irgendeinem Grund umgekehrt besser sein wärs natürlich auch ok.

    Im Timerinterrupt müsste jeder Servo etwa alle 20ms, oder so oft nötig seine individuelle Impulsdauer verpasst bekommen.
    Genau das macht meine Lib. Du kannst die sicher an den M16 anpassen!

    Code:
    copyright    = Dirk O.
    comment      = Ansteuerung von 10 Servos
    libversion   = 2.00
    date         = 17.06.2006
    statement    = ------------------------------------
    statement    = Muss alle 20ms in einer Interrupt- !
    statement    = Service-Routine ausgeführt werden. !
    statement    = Geeignet für 1-10 MHz Taktfrequenz !
    statement    = ------------------------------------
    
    [Servo10]
    ;Anschluss der 10 Servos:
    .equ PORTB    = $18   ;Portb des AT90S2313, ATtiny2313
    .equ PINB0    = 0     ;Servo1
    .equ PINB1    = 1     ;Servo2
    .equ PINB2    = 2     ;Servo3
    .equ PINB3    = 3     ;Servo4
    .equ PINB4    = 4     ;Servo5
    .equ PINB5    = 5     ;Servo6
    .equ PINB6    = 6     ;Servo7
    .equ PINB7    = 7     ;Servo8
    .equ PORTD    = $12   ;Portd des AT90S2313, ATtiny2313
    .equ PIND5    = 5     ;Servo9
    .equ PIND6    = 6     ;Servo10
    
    ;Register für die 10 Servo-Positionen:
    .def Pos1     = r16
    .def Pos2     = r17
    .def Pos3     = r18
    .def Pos4     = r19
    .def Pos5     = r20
    .def Pos6     = r21
    .def Pos7     = r22
    .def Pos8     = r23
    .def Pos9     = r24
    .def Pos10    = r25
    
    .def Temp     = r26
    .def Position = r27
    
    ;BASCOM-Variablen:
    ; Servoleftpos  -> BYTE für den linken Anschlag (1..255, 0=256)
    ;                   Impuls 0,6ms -> 1/4/8/10 MHz: 14/ 59/119 /149
    ;                   Impuls 0,8ms -> 1/4/8/10 MHz: 19/ 79/159 /199
    ;                   Impuls 1,0ms -> 1/4/8/10 MHz: 24/ 99/199 /249
    ; Servorightpos -> BYTE für den rechten Anschlag (0..255)
    ;                   Impuls 1,0ms -> 1/4/8/10 MHz: 28/111/182*/227*
    ;                   Impuls 1,2ms -> 1/4/8/10 MHz: 33/133/218*/---
    ;                   Impuls 1,4ms -> 1/4/8/10 MHz: 39/156/255*/---
    ;                    Zu *: Mit eingefügter Verzögerung (s.u.!) 
    ; Servopos(10)  -> BYTE-Array für die 10 Servo-Positionen
    ;                   (0..Servorightpos)
    
    Servo10:                      ;Alle 20ms (Timer 50Hz)
    ;Impuls für alle 10 Servos starten:
    ; Der Abstand von 2 Zyklen zwischen den sbi-Befehlen orientiert sich am
    ; notwendigen Abstand der cbi-Befehle beim Beenden der Impulse (s.u.!).
      sbi PORTB,PINB0             ;Servo1 high
     *lds Pos1,{Servopos}         ;2+
      sbi PORTB,PINB1             ;Servo2 high
     *lds Pos2,{Servopos+1}
      sbi PORTB,PINB2             ;Servo3 high
     *lds Pos3,{Servopos+2}
      sbi PORTB,PINB3             ;Servo4 high
     *lds Pos4,{Servopos+3}
      sbi PORTB,PINB4             ;Servo5 high
     *lds Pos5,{Servopos+4}
      sbi PORTB,PINB5             ;Servo6 high
     *lds Pos6,{Servopos+5}
      sbi PORTB,PINB6             ;Servo7 high
     *lds Pos7,{Servopos+6}
      sbi PORTB,PINB7             ;Servo8 high
     *lds Pos8,{Servopos+7}
      sbi PORTD,PIND5             ;Servo9 high
     *lds Pos9,{Servopos+8}
      sbi PORTD,PIND6             ;Servo10 high
     *lds Pos10,{Servopos+9}
    
    ;Impulsdauer (0,6..1ms) linker Anschlag:
    ; Starten und Beenden des Impulses brauchen zusammen 46 (40 + 6) Zyklen
    ; plus Verzögerung Servoleftpos * 40 Zyklen (10us bei 4 MHz) ergibt eine
    ; Impulsdauer linker Anschlag von (Servoleft * 10 + 11,5) us bei 4 MHz.
    ; Servoleftpos kann für eine bestimmte Impulsdauer so berechnet werden:
    ;  Servoleftpos = Impulsdauer (us) * Taktfrequenz (MHz) / 40 - 1,15
     *lds Temp,{Servoleftpos}     ;+2=40 Linker Anschlag
    Delay0:
      call Wait37                 ;37+
      dec Temp                    ;1
      brne Delay0                 ;+2=40
      nop
    
    ;Beenden des Impulses (nach 0..1,4ms) je nach Position:
    ; Die kompl. Schleife für alle 10 Servos besteht im Mittel aus 36 Zyklen.
    ; Damit beträgt die max. Auflösung 9us bei 4 MHz. Bei einer Impulsdauer
    ; von 1ms sind dann z.B. 111 Servo-Positionen (1000 / 9) ansteuerbar.
    ; Servorightpos kann für eine bestimmte Impulsdauer so berechnet werden:
    ;  1/ 4 MHz: Servorightpos = Impulsdauer (us) * Taktfrequenz (MHz) / 36
    ;  8/10 MHz: Servorightpos = Impulsdauer (us) * Taktfrequenz (MHz) / 44
      ldi Position,255            ;1+
    Nextpos:
      inc Position                ;1 Nächste Position (0..Servorightpos)
      cp Pos1,Position            ;1
      brne Next2                  ;1
      cbi PORTB,PINB0             ;+2=6 Servo1 low
    Next2:
      cp Pos2,Position            ;1+
      brne Next3                  ;2
      cbi PORTB,PINB1             ;Servo2 low
    Next3:
      cp Pos3,Position
      brne Next4
      cbi PORTB,PINB2             ;Servo3 low
    Next4:
      cp Pos4,Position
      brne Next5
      cbi PORTB,PINB3             ;Servo4 low
    Next5:
      cp Pos5,Position
      brne Next6
      cbi PORTB,PINB4             ;Servo5 low
    Next6:
      cp Pos6,Position
      brne Next7
      cbi PORTB,PINB5             ;Servo6 low
    Next7:
      cp Pos7,Position
      brne Next8
      cbi PORTB,PINB6             ;Servo7 low
    Next8:
      cp Pos8,Position
      brne Next9
      cbi PORTB,PINB7             ;Servo8 low
    Next9:
      cp Pos9,Position
      brne Next10
      cbi PORTD,PIND5             ;Servo9 low
    Next10:
      cp Pos10,Position
      brne Next11
      cbi PORTD,PIND6             ;Servo10 low
    Next11:
      ;call Wait8                  ;Nur für 8/10 MHz: + 8 Zyklen!
     *lds Temp,{Servorightpos}    ;Rechter Anschlag
      cp Temp,Position            ;Anschlag erreicht?
      brne Nextpos                ;+2=32(40 b. 8/10 MHz) Nein -> weiter
    ;Impuls sicherheitshalber für alle Servos beenden!
    ; (Nur nötig für Servopos(n) > Servorightpos!)
      ldi Temp,0
      out PORTB,Temp              ;Servo1..8 low
      cbi PORTD,PIND5             ;Servo9 low
      cbi PORTD,PIND6             ;Servo10 low
    Wait8:
      ret
    
    Wait37:                       ;29 + 4 (call) + 4 (ret) = 37 Zyklen
      call Wait8                  ;8+
      call Wait8                  ;8
      call Wait8                  ;8
      nop
      nop
      nop
      nop
      nop                         ;+1=29
      ret
    [end]
    
    ;---------------------------------------------------------------------------
    Servo10 muss in einer ISR in Bascom alle 20 ms aufgerufen werden:
    Tim0_isr: 'alle 20ms
    Timer0 = Startwert
    'Impulse für die 10 Servos ausgeben:
    Call Servo10
    Return

    Die Ports deines M16 must du neu anpassen!

    Gruß Dirk

  8. #8
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    30.07.2005
    Beiträge
    569
    Hmm ... nichts gegen deine sicherlich gut funktionierende lib ...

    Nur, wenn ich das richtig übersehe wird die Servoansteuerung komplett in einer ISR abgearbeitet ...

    d.H. alle 20 ms wird der Programmablauf dafür für 2 ms unterbrochen ... Eigentlich ist dieses eher recht ineffizient, vor allem dann wenn der µC noch etwas anderes machen soll ....

    Des weiteren sind die Servopositionen doch:
    1 ms = links,
    1.5 ms = mitte
    2 ms = rechts

    oder täusche ich mich da sosehr ????

  9. #9
    Erfahrener Benutzer Robotik Einstein Avatar von Dirk
    Registriert seit
    30.04.2004
    Ort
    NRW
    Beiträge
    3.803

    Servo10.lib

    Hallo Hanni,

    nichts gegen deine sicherlich gut funktionierende lib ...
    ... jo, funktioniert gut.

    d.H. alle 20 ms wird der Programmablauf dafür für 2 ms unterbrochen ... Eigentlich ist dieses eher recht ineffizient, vor allem dann wenn der µC noch etwas anderes machen soll ....
    ... ja, das stimmt. Andererseits sind 18 von 20ms (d.h. tatsächlich 90%) frei für's Hauptprogramm, das reicht bei mir, wenn da nichts zeitkritisches mehr stattfindet.

    Des weiteren sind die Servopositionen doch:
    1 ms = links,
    1.5 ms = mitte
    2 ms = rechts
    Ja, genau. Da die Servos aber stark streuen, habe ich einen Rahmen von 0,6..2,4ms vorgesehen, den man aber nicht ausnutzen muss.

    Gruß Dirk

  10. #10
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    30.07.2005
    Beiträge
    569
    Nunja, das kann man halten wie ein Dachdecker
    Ich zumindest würde es nicht so realisieren, zumal bei mir meistens noch "wichtigere" Dinge so nebenbei laufen.

    Im übrigen könntest du deinen Assemblercode noch etwas optimieren ... zumindest in der resultierenden Codegröße .. da die Laufzeit an sich bei deinem speziellem Fall eher Wurst ist.

    Anstatt :
    Code:
    Nextpos:
      inc Position                ;1 Nächste Position (0..Servorightpos)
      cp Pos1,Position            ;1
      brne Next2                  ;1
      cbi PORTB,PINB0             ;+2=6 Servo1 low
    Next2:
      cp Pos2,Position            ;1+
      brne Next3                  ;2
      cbi PORTB,PINB1             ;Servo2 low
    Next3:
      cp Pos3,Position
      brne Next4
      cbi PORTB,PINB2             ;Servo3 low
    Next4:
      cp Pos4,Position
      brne Next5
      cbi PORTB,PINB3             ;Servo4 low
    Next5:
      cp Pos5,Position
      brne Next6
      cbi PORTB,PINB4             ;Servo5 low
    Next6:
      cp Pos6,Position
      brne Next7
      cbi PORTB,PINB5             ;Servo6 low
    Next7:
      cp Pos7,Position
      brne Next8
      cbi PORTB,PINB6             ;Servo7 low
    Next8:
      cp Pos8,Position
      brne Next9
      cbi PORTB,PINB7             ;Servo8 low
    könnte man das ganze auch wie folgt schreiben:

    Code:
    Nextpos:
      inc Position                ;1 Nächste Position (0..Servorightpos)
      cp Pos1,Position            ;1
      ror temp
    
      cp Pos2,Position            ;1+
      ror temp
    
      cp Pos3,Position
      ror temp
    
      cp Pos4,Position
      ror temp
    
      cp Pos5,Position
      ror temp
    
      cp Pos6,Position
      ror temp
    
      cp Pos7,Position
      ror temp
    
      cp Pos8,Position
      ror temp
    
      out PORTB, temp

    aus:
    Code:
      sbi PORTB,PINB0             ;Servo1 high
     *lds Pos1,{Servopos}         ;2+
      sbi PORTB,PINB1             ;Servo2 high
     *lds Pos2,{Servopos+1}
      sbi PORTB,PINB2             ;Servo3 high
     *lds Pos3,{Servopos+2}
      sbi PORTB,PINB3             ;Servo4 high
     *lds Pos4,{Servopos+3}
      sbi PORTB,PINB4             ;Servo5 high
     *lds Pos5,{Servopos+4}
      sbi PORTB,PINB5             ;Servo6 high
     *lds Pos6,{Servopos+5}
      sbi PORTB,PINB6             ;Servo7 high
     *lds Pos7,{Servopos+6}
      sbi PORTB,PINB7             ;Servo8 high
     *lds Pos8,{Servopos+7}
      sbi PORTD,PIND5             ;Servo9 high
     *lds Pos9,{Servopos+8}
      sbi PORTD,PIND6             ;Servo10 high
     *lds Pos10,{Servopos+9}
    könnte man im übrigen das folgende machen:

    Code:
     *lds Pos1,{Servopos}         ;2+
     *lds Pos2,{Servopos+1}
     *lds Pos3,{Servopos+2}
     *lds Pos4,{Servopos+3}
     *lds Pos5,{Servopos+4}
     *lds Pos6,{Servopos+5}
     *lds Pos7,{Servopos+6}
     *lds Pos8,{Servopos+7}
     *lds Pos9,{Servopos+8}
     *lds Pos10,{Servopos+9}
     ldi temp, 0xff
     out PORTB, temp
     in temp, PORTD
     ori temp, 0b01100000
     out PORTD, temp
    Warum das auch so geht findest du übrigens hier: Instruktion Set

    Sicherlich mag dir das vielleicht etwas unnötig erscheinen, allerdings macht es im Zweifelsfall neben ein paar gesparten Bytes eben auch einen gewissen Zeitfaktor aus (welcher ja in deinem Beispiel eh unrelevant ist).


    Grüße,

    da Hanni.

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen