PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ansteuerung Servo mit Servo Fkt. oder mit PWM?



cosanostra
03.07.2007, 14:43
Hallo,

ich habe schon einige Threads gelesen und bin mir unschlüssig, ob die SERVO Funktion in Bascom die beste Möglichkeit zur Ansteuerung eines Servos darstellt.

Grundsätzlich sollte die Steuerung der Servos auch über PWM funktionieren, jedoch habe ich noch eine Unwissenheitslücke:
Wie kann ich in PWM Mode den Zähler einschränken, damit ich genau auf meine gewünschte Trägerfrequenz komme.
Quarz 3686400 Hz, Prescale 64, 10bit, Zielfrequenz=50Hz bekomme ich nach 575 Zähler (Formel: fziel=fclk/(2*prescaler*(1+Zähler))

Den Timer allein kann ich zb.: mit einem Interrupt vorstellen, damit ich die Frequenz erhalte.
Wie macht man das jedoch bei PWM? Kann ich hier auch einen Interrupt festlegen und den Timer vorstellen?
Beiliegend findet ihr meinen unvollständigen Code, bitte gebt mir eine Empfehlung, was besser ist und ob man es eventuell so programmieren könnte.
Lg


' 0 sind Eingänge; 1 sind Ausgänge
' digitaler EIngang Pullup Widerstand ergibt 0 wenn Spannung anliegt
' PortB3 Endschalter Schloss-Servo nicht verriegelt
' PortB4 Endschalter Sperrelemt offen
' PortB5 Endschalter Sperrelemt geschlossen
' PortC0 Antriebsmotor ein/aus Relais
' PortC1 Ansteuerung Relais Umschalter für Antriebsmotor
' (dreht sich links..schließen bei 0 und rechts..öffnen bei 1)
' PortC2 Relais Schalten für Servo Antrieb 0..aus/ 1..ein
' PortC3 Analoger Eingang Messung Spannungsabfall, ob Servo dreht oder nicht
' PortB1 PWM Signal für Servowinkelsollsignal

$regfile = "m8def.dat"
$crystal = 3686400 'externer Quarz

Config Adc = Single , Prescaler = Auto 'Analoger Eingang eingeschalten
Start Adc

Config Timer1 = Pwm , Pwm = 10 , Compare A Pwm = Clear Down , Prescale = 1
On Timer1 Timerroutine:
Enable Timer1
Start Timer1
Enable Interrupts
Pwm1a = 741 '7 Zähler entspricht ca. 40° Servobewegung



Dim X As Bit

Ddrb = &B00000111 'Alle unbenützten Eingänge auf Pullup Widerstand gesetzt
Portb = &B11111000

Ddrc = &B00000111
Portc = &B11111000



Do

'HAuptprogramm

Loop


Timerroutine:
Timer1 = 735 '50HZ entspricht 575 Schritte, Start TIMER1 bei 1023-(575+1)/2=735

Return



End

Torsten_G
03.07.2007, 17:44
Hallo und herzlich willkommen hier im Forum!

Zur Servo-Ansteuerung würde ich Dir den Pulseout-Befehl empfehlen, ist in der Bascom-Hilfe gut beschrieben. Pulseout belegt keinen Timer, keinen Interrupt und ist auf beliebige PIN´s anwendbar.

(Hardware)PWM ist auf bestimmte Pins beschränkt unf frisst einen Timer, der Servo-Befehl arbeitet für meinen Geschmack zu grobmotorisch und verbraucht ebenfalls einen Timer.

Du brauchst nicht zwingend die 50Hz einzuhalten.
Meiner (praktischen) Erfahrung nach interessieren sich die Servos lediglich für die Pulslänge, so kann man auch mit höherer Frequenz arbeiten. Keine Ahnung, wo die Untergrenze liegt, da hatte ich bislang keine Probleme. Letztens sagte einer, minimum 10ms... am besten ausprobieren.
Nur viel länger als 20ms (=50Hz) sollte die Pause zwischen den Pulsen nicht sein, sonst verlieren die Servos an Stellkraft.

Grüße

Torsten

cosanostra
04.07.2007, 12:59
Hallo Torsten,

danke, das werde ich gleich mal ausprobieren!

Lg
Reinhard

AndiDC
08.11.2007, 15:45
Hi,
hast Du ein Beispiel, wie der Pulseout Befehl mit einem Servo funktioniert?
Ich bekomme das leider nicht hin.

Danke!

Torsten_G
13.11.2007, 12:47
Hallo Andi,

hatte erst jetzt Deinen Beitrag entdeckt...

Ein Beispiel kannst Du gerne haben:


'************************************************* *****
'Projekt: Atmel-Programmierung für Einsteiger
'
'Prozessor: ATMega 8-16
'Bascom-Version: 1.11.8.1
'
'Auswertung für Graupner Nautic Expert Baustein
'Ansteuerung von Servos über Schalterpositionen
'
'Version: 1.0
'
'Hardware:
'R/C-Kanal an D.2 (INT0)
'LED an C.0
'Servos an C.1...C.4
'
'15.01.2007 T. Gietenbruch
'
'************************************************* *****

'================================================= =====
'System-Einstellungen
'================================================= =====
'Definition für Mega 8
$regfile "m8def.dat"

'Angabe der Taktfrequenz (8Mhz)
$crystal = 4000000

'================================================= =====
'Konfigurationen
'================================================= =====

'Konfiguration der I/O-Ports´s
Ddrc = 11111111
Ddrd = 11110000

'Konfiguration des Timer1
Config Timer1 = Timer , Prescale = 1

'Konfiguration des INT0
'Interrupt bei jedem Flankenwechsel (0->1 und 1->0)
Config Int0 = Change

'================================================= =====
'Deklarationen
'================================================= =====

Dim N As Byte
Dim N_old As Byte
Dim Location As Byte
Dim Signals As Byte
Dim Reading As Bit
Dim Rc_value(10) As Word
Dim Error As Bit
Dim Sync_detect As Bit
Dim X As Word
Dim Switch_up As Byte
Dim Switch_dn As Byte
Dim Sync_ok As Bit
Dim Cycle_done As Bit
Dim Switchhold As Byte
Dim Number As Byte
Dim Watchcat As Word
Dim Servowert_1 As Word
Dim Servowert_2 As Word
Dim Servowert_3 As Word
Dim Servowert_4 As Word

'================================================= =====
'Konstanten
'================================================= =====
Const Sync_lowlimit = 8000
Const Sync_highlimit = 9000
Const Switch_lowlimit = 4000
Const Switch_highlimit = 7900

Const Servo1_up_pos = 1000
Const Servo1_nt_pos = 1500
Const Servo1_dn_pos = 2000

Const Servo2_up_pos = 1200
Const Servo2_nt_pos = 1300
Const Servo2_dn_pos = 2000

Const Servo3_up_pos = 2000
Const Servo3_nt_pos = 1800
Const Servo3_dn_pos = 1000

Const Servo4_up_pos = 1500
Const Servo4_nt_pos = 2000
Const Servo4_dn_pos = 1000

'================================================= =====
'Initialisierungen
'================================================= =====

'Zuweisung der Interrupt-Service-Routinen
On Timer1 Rc_error
On Int0 Rc_read
'Timer-Freigabe
Enable Timer1
Stop Timer1

'Ports initialisieren
Portc = &B11111111

'Freigabe der Interrupt-Routinen
Enable Int0
Enable Interrupts

'================================================= =====
'Synchronisationsschleife
'================================================= =====
Syncronize:
Signals = 1
N = 1
Sync_detect = 0
X = 0

'Rücksetzen aller Schaltersignale
For X = 0 To 7
Switch_up.x = 0
Switch_dn.x = 0
Next X

X = 0

'Warten auf ersten Synchronisationswert
While Sync_detect = 0
Wend

N = 2
Sync_detect = 0

'Warten auf zweiten Synchronisationswert
'Begrenzt durch Zählschleife
While X < 5000 And Sync_detect = 0
Incr X
Wend

'Auswertung des Synchronisationsergebnisses
If X < 5000 And Rc_value(1) > Sync_lowlimit And Rc_value(2) > Sync_lowlimit Then
N = 3
Signals = 10
Else
Goto Syncronize
End If

Watchcat = 0

'================================================= =====
'Hauptprogramm-Schleife
'================================================= =====
Do

'Auswertung der gelesenen Werte (im Block)
If Cycle_done = 1 And Reading = 0 And Error = 0 Then
Cycle_done = 0
'Überprüfung der Synchronisationssignale
If Rc_value(1) > 8000 And Rc_value(2) > 8000 And Error = 0 Then
Sync_ok = 1
Else
Sync_ok = 0
Goto Syncronize
End If

'Aktualisierung der Schaltersignale
If Sync_ok = 1 Then
For X = 3 To Signals
Number = X - 3
'Schalter nach oben betätigt
If Rc_value(x) > 7000 And Rc_value(x) < 7900 Then
If Switchhold.number = 0 Then
Switchhold.number = 1
Toggle Switch_up.number
End If
'Schalter nach unten betätigt
Elseif Rc_value(x) > 4000 And Rc_value(x) < 5500 Then
If Switchhold.number = 0 Then
Switchhold.number = 1
Toggle Switch_dn.number
End If
'Schalter in Mittelstellung
Else
Switchhold.number = 0
Switch_up.number = 0
Switch_dn.number = 0
End If
Next X

'Zuweisen der Servopositionen
If Switch_up.0 = 1 And Switch_dn.0 = 0 Then
Servowert_1 = Servo1_up_pos
Elseif Switch_up.0 = 0 And Switch_dn.0 = 1 Then
Servowert_1 = Servo1_dn_pos
Else
Servowert_1 = Servo1_nt_pos
End If
If Switch_up.1 = 1 And Switch_dn.1 = 0 Then
Servowert_2 = Servo2_up_pos
Elseif Switch_up.1 = 0 And Switch_dn.1 = 1 Then
Servowert_2 = Servo2_dn_pos
Else
Servowert_2 = Servo2_nt_pos
End If
If Switch_up.2 = 1 And Switch_dn.2 = 0 Then
Servowert_3 = Servo3_up_pos
Elseif Switch_up.2 = 0 And Switch_dn.2 = 1 Then
Servowert_3 = Servo3_dn_pos
Else
Servowert_3 = Servo3_nt_pos
End If
If Switch_up.3 = 1 And Switch_dn.3 = 0 Then
Servowert_4 = Servo4_up_pos
Elseif Switch_up.3 = 0 And Switch_dn.3 = 1 Then
Servowert_4 = Servo4_dn_pos
Else
Servowert_4 = Servo4_nt_pos
End If

End If
End If

'Watchdog
If N = N_old Then
Incr Watchcat
If Watchcat > 5000 Then Goto Syncronize
Else
N_old = N
Watchcat = 0
End If
Loop

'Programmende (nur formal)
End


'================================================= =====
'ISR für INT0 - Signalfolge lesen
'================================================= =====
Rc_read:
'Den Timer starten mit steigender Flanke
If Reading = 0 And Pind.2 = 1 Then
Start Timer1
Reading = 1
'Den Timer stoppen mit fallender Flanke
Else
Stop Timer1
Rc_value(n) = Timer1
Timer1 = 0
Reading = 0
'Setzen der Servopositionen
If Sync_ok = 1 Then
Pulseout Portc , 1 , Servowert_1
Pulseout Portc , 2 , Servowert_2
Pulseout Portc , 3 , Servowert_3
Pulseout Portc , 4 , Servowert_4
Else
Portc.1 = 0
Portc.2 = 0
Portc.3 = 0
Portc.4 = 0
End If
'Validierung des gelesenen Wertes
If Rc_value(n) < 4000 Or Rc_value(n) > Sync_highlimit Then Goto Rc_error
'Prüfung auf Sync-Signal
If N < 3 And Rc_value(n) > Sync_lowlimit And Rc_value(n) < Sync_highlimit Then
Sync_detect = 1
End If
'...wenn die Synchronisation fertig ist
If Signals > 2 Then
Incr N
End If
If N > Signals Then
N = 1
Cycle_done = 1
End If
'Statusanzeige an C.0
Toggle Portc.0
End If
'Error-Bit rücksetzen
Error = 0
Return

'================================================= =====
'ISR für Timer1 - Fehlerhandling
'================================================= =====
Rc_error:
'Error-Bit setzen
Error = 1
Reading = 0
Stop Timer1

Return

Das Programm kommt aus dem Modellbau und wertet die Signale eines Graupner NauticExpert-Moduls aus. Damit werden dann vier Servos in vorgegebene Positionen gefahren.

Anwendung ist die Getriebe- und Sperrdifferentilansteuerung eines Allrad-Wedico-Trucks.

Die Hardware wird direkt am Empfänger angeschlossen, die ISR der Signalauswertung (rc_read) nutze ich gleichzeitig zur Aktualisierung der Pulseouts.

"Runterbrechen" auf ein einfaches Beispiel müsstest Du es Dir bitte selbst... O:)

Grüße

Torsten

MeckPommER
13.11.2007, 14:05
Zur Servo-Ansteuerung würde ich Dir den Pulseout-Befehl empfehlen, ist in der Bascom-Hilfe gut beschrieben. Pulseout belegt keinen Timer, keinen Interrupt und ist auf beliebige PIN´s anwendbar.

Nur aus Neugierde meine Nachfrage:
Wenn dieser Befehl keinen Timer und keinen Interrupt verwendet, wie erzeugt er dann z.b. einen Impuls von 1,5ms Länge? Legt er den Portpin auf High, wartet dann so lange und setzt ihn dann wieder auf Low?
Wenn das so sein sollte, dann erkauft man sich einen gesparten Timer durch eine enorme Zeitverschwendung beim Erzeugen des Pulses. Nur das Ansteuern eines einzigen Servos würde den µC dann ja schon zu 5-10% auslasten.

Falls ich mich irre ... einfach weiterlesen und mich nicht beachten ^^

EDIT: den Bascom-Befehl für die Servos kann man wirklich vergessen, wenn man mit den Servos nicht grade Pinoccio in der Folge "me & xtc" steuern möchte ;-)

Torsten_G
13.11.2007, 22:37
Hallo,

nein, Pulseout wartet nicht.
Wie das genau funzt, entzieht sich aber leider meiner Kenntnis - da wären jetzt mal die Hardcore-Bascomer gefragt... :-k

Gruß

Torsten

AndiDC
14.11.2007, 10:28
Hallo Torsten!
Vielen Dank für den Quellcode, das Runterbrechen sollte ich hinbekommen!
Kannst Du ungefähr sagen, wieviel genauer deine Variante im Vergleich zum normalen Servo Befehl ist?
Danke!

roboterheld
14.11.2007, 11:26
....nein, Pulseout wartet nicht.....

natürlich, der wartet so lange bis der puls draussen ist.

weiterhin steht in der bascombschreibung wie lange mindestens ein pulse läuft. es kann für manche steuerungen zu lange dauern.

pwm ist präziser und noch feinfühliger für den servo. der servo kann dadurch noch genauer positioniert werden.

mfg