PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Servo zuckelt bei timer1_irq aber nicht bei waitms ...



Willa
22.10.2007, 15:12
Hi!
Ich bin ganz neu in der Materie und habe ein Problem: Ein Servo soll per Sinus angesteuert werden. Es ist ein Futaba s9253 (mit das schnellste was es gibt) angeschlossen am RN-Control v1.4.
Das ganze soll später eine Art Schlagflugroboter ansteuern, dessen Aerodynamik dann vermessen wird. Deswegen ist präzision hier einigermaßen wichtig.
Hier erstmal der Quellcode der nicht richtig funktioniert:


$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32

$crystal = 16000000
$baud = 9600



Config Servos = 1 , Servo1 = Portb.3 , Reload = 10
Config Portb = Output


Config Timer1 = Timer , Prescale = 8
On Timer1 Timer_irq
Enable Interrupts
Enable Timer1

Dim I As Integer
Dim J As Single
Dim X As Single
Dim Sinx As Single
Dim Erst As Single
Dim Zweit As Single
Dim Dritt As Integer
Dim Vorerst As Single
Const Pi = 3.14159265358979
Const 2pi = 6.28318530717958


For I = 500 To 300 Step -10 'sound PORTD.7 , Länge , Frequenz
Sound Portd.7 , 10 , I
Next I
Waitms 180
For I = 500 To 300 Step -10
Sound Portd.7 , 10 , I
Next I
For I = 300 To 500 Step 5
Sound Portd.7 , 12 , I
Next I


J = 0.02 * Pi

Do
Sinx = Sin(x) 'X wird im Timer_irq immer um "J" erhöht
Vorerst = Sinx + 1 'die variable "Vorerst" schwankt sinusförmig zwischen o und 2
Erst = Vorerst * 50 'Hochskalieren der Werte, so dass sie zw. 60 und 160 sinusförmig schwanken
Zweit = Erst + 60
Dritt = Round(zweit) 'und nochmal runden, man weiss ja nie...
Servo(1) = Dritt 'servo 1 und servo 2 stellen
'Print Servo(1)
'Delay 'ins terminal schreiben welche werte die servos haben
Loop

Timer_irq: 'hat eine Frequenz von 31Hz
Timer1 = 1020
If X < 2pi Then 'x wird um J erhöht solange x kleiner als 2 Pi, ansonsten x = 0
X = X + J
Else
X = 0
End If
Return


Der timer_irq schlägt mit 31 Hz zu und erhöht eine Variable X immer ein bischen, dann wird sinus X ausgerechnet und an das Servo gesendet. Dabei passiert aber folgendes (Video):

http://www.youtube.com/watch?v=yEjPdcdpZC4

DSas servo folgt zwar prinzipiell dem Sinus, zuckelt aber öfters mal auf irgendwelche undefinierten positionen und macht dann wieder weiter. Das sieht man auch im Terminal wenn man Servo(1) printed. Zwischendurch stehen da mal ganz wilde Zeichenkombinationen oder falsche zahlen.

Folgender Code funktioniert. dort wird die Variable X einfach im Main-Loop erhöht, danach gibts immer 2ms pause damit das ganze nicht zu schnell läuft.

Im Schlagflugroboter muss das servo aber am ende mit einer bestimmten frequenz laufen. Außerdem bewegt es sich dann nicht mehr per einfacher sinusfunktion sondern bewegt sich etwas komplizierter. Und wenn ich das ohne Timer1 mache, dann habe ich doch keine garantie mehr dafür dass das servo mit der richtigen geschwindigkeit läuft? Bzw. wann das Servo wie schnell läuft hängt dann davon ab wie schnell der AtMega32 die funktionen berechnen kann, oder?

Also hier der funktionierende Code ohne timer1_irq


$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32

$crystal = 16000000
$baud = 9600



Config Servos = 1 , Servo1 = Portb.3 , Reload = 10
Config Portb = Output


'Config Timer1 = Timer , Prescale = 8
'On Timer1 Timer_irq
Enable Interrupts
'Enable Timer1

Dim I As Integer
Dim J As Single
Dim X As Single
Dim Sinx As Single
Dim Erst As Single
Dim Zweit As Single
Dim Dritt As Integer
Dim Vorerst As Single
Const Pi = 3.14159265358979
Const 2pi = 6.28318530717958


For I = 500 To 300 Step -10 'sound PORTD.7 , Länge , Frequenz
Sound Portd.7 , 10 , I
Next I
Waitms 180
For I = 500 To 300 Step -10
Sound Portd.7 , 10 , I
Next I
For I = 300 To 500 Step 5
Sound Portd.7 , 12 , I
Next I


J = 0.002 * Pi

Do
Sinx = Sin(x) 'X wird im Timer_irq immer um "J" erhöht
Vorerst = Sinx + 1 'die variable "Vorerst" schwankt sinusförmig zwischen o und 2
Erst = Vorerst * 50 'Hochskalieren der Werte, so dass sie zw. 60 und 160 sinusförmig schwanken
Zweit = Erst + 60
Dritt = Round(zweit) 'und nochmal runden, man weiss ja nie...
Servo(1) = Dritt 'servo 1 und servo 2 stellen
'Print Servo(1)
'Delay 'ins terminal schreiben welche werte die servos haben


If X < 2pi Then 'x wird um J erhöht solange x kleiner als 2 Pi, ansonsten x = 0
X = X + J
Else
X = 0
End If

Waitms 2

Loop


Und hier das Video, das Servo läuft schön regelmässig:

http://www.youtube.com/watch?v=Wcj16WOxGcg

Meine Frage daher: Was kann ich machen damit im timer_irq quasi die "Zeitvariable" hochzählt und im Hauptprogramm mit dieser Variablen eine Funktion ausgerechnet wird? Und diese Funktion sollte ein Servo ansteuern OHNE dass das so komisch durch die Gegend zuckelt.... Für eure Hilfe wäre ich sehr dankbar!
Viele Grüße,
William

T.J.
22.10.2007, 20:57
Ich vermute mal spontan, das durch irgendwas ein Interrupt ausgelöst wird und du deswegen sporadische Fehlwerte hast. Überprüf das mal

Willa
28.10.2007, 17:17
ich habe das Problem gelöst indem ich $hwstack = 64 statt 32 groß gemacht habe.
Außerdem muss der timer_irq jetzt nur noch rechnen:
x=x+1
und x ist als byte deklariert. anscheinend kommt der at32 besser mit solchen zahlen zurecht. Im Forum "Vorstellungen+Bilder von fertigen Projekten/Bots" werde ich gleich ein Thread mit Video zum fertigen "Roboter" erstellen...
Viele Grüße,
William