Mist ...
... sieht wirklich so aus, als müßte man noch was deichseln ;):lol: :lol: :lol:Zitat:
.... läuft das Teil nun besser als erwartet.
Mit herzlichen Glückwünschen
Searcher
Druckbare Version
So, hier nochmal der Code für ein einzelnes Servo auf dem kleineren Attiny45. Die Berechnung der Servogeschwindigkeit musste nochmals komplett überarbeitet werden, da beim Attiny45 nur 8-Bit Timer zur Verfügung stehen. Da sich der Kleine nicht mit mehreren RC Signalen rumschlagen muss, war es (fast) kein Problem, die entsprechende Berechnung umzugestalten.
mfg
Robert
Code:'===============================================================================
'Single Baggerarmsteuerung V3
'
'RC Eingang 1 an Pin 7 (PB2, INT0)
'Poti 1a an Pin 2 (PB3, ADC3)
'Poti 1b an Pin 3 (PB4, ADC2)
'Servo 1 an Pin 6 (PB1) Baggerarmservo
'===============================================================================
$regfile = "attiny45.dat"
$crystal = 8000000 'FuseBit CKDIV8 deaktivieren
$hwstack = 40
$swstack = 40
$framesize = 50
'-------------------------------------------------------------------------------------------------
'Timer konfigurieren
'-------------------------------------------------------------------------------------------------
Tccr1 = &B00000111 'Timer1 für RC-Signal Einlesung wird gestartet (Prescale 64) (geht beim Attiny45 nicht mit "Config"!)
Config Timer0 = Timer , Prescale = 64 'Timer0 für Servoausgabe, Wert 125 entspricht 1ms, Wert 250 entspricht 2ms
On Timer0 Servoausgabe Nosave 'Register werden manuel in der ISR gesichert
Enable Timer0
'-------------------------------------------------------------------------------------------------
'Interrupt-Service-Routinen konfigurieren und freigeben
'-------------------------------------------------------------------------------------------------
Config Int0 = Change 'beim Flankenwechsel an PB2/INT0 (RC Eingang) Int0 auslösen und in die Subroutine springen
Enable Int0
On Int0 Rc_eingang_1 Nosave 'Register werden manuel in der ISR gesichert
Enable Interrupts
'-------------------------------------------------------------------------------------------------
'Poti-Eingänge konfigurieren
'-------------------------------------------------------------------------------------------------
Config Adc = Single , Prescaler = Auto
Start Adc
'-------------------------------------------------------------------------------------------------------------
'Konstanten definieren
'-------------------------------------------------------------------------------------------------------------
Const Jitterausgleich = 2 'Wert in µs um den sich gemessene Impulslaenge aendern darf/muss, bevor Servo gestellt wird
Const Rc_min = 122 'Minimaler RC-Wert für die Berechnungen (Werte zwischen 120 - 125 sinvoll)
Const Rc_max = 253 'Maximaler RC-Wert für die Berechnungen (Werte zwischen 250 - 255 sinvoll)
'-------------------------------------------------------------------------------------------------------------
'Variablen definieren
'-------------------------------------------------------------------------------------------------------------
Dim Rc_signal_1_start As Byte
Dim Rc_signal_1_stop As Byte
Dim Rc_signal_1_stop_flag As Byte
Dim Impulslaenge_1 As Byte
Dim Impulslaenge_1_alt As Byte
Dim Impulslaengenaenderung As Integer 'wird nur einmal gebraucht, da nur Hilfswariable
'Variablen für Servowegsbegrenzung
Dim Poti_1a As Word
Dim Poti_1b As Word
Dim Limit_1a As Byte
Dim Limit_1b As Byte
'Variablen für Berechnungen
Dim Berechnung_1 As Byte
Dim Berechnung_1a As Byte
Dim Servospeed As Byte
Dim Zeit_1 As Byte
Dim Zeit_2 As Word
'Variablen für Servoausgabe
Dim Kanal As Byte
Dim Servoausgabe_1 As Byte
'-------------------------------------------------------------------------------------------------
'Einigen Variablen Werte zuweisen
'-------------------------------------------------------------------------------------------------
Kanal = 1
Berechnung_1a = 187 'Servo erst mal auf Mittelstellung
'-------------------------------------------------------------------------------------------------------------
'Ein- und Ausgang festlegen
'-------------------------------------------------------------------------------------------------------------
Ddrb = &B00000010 'PB1 wird Ausgang, restlicher PortB bleibt Eingang
'======================================================
'Hauptprogramm
'======================================================
Do
'RC Impulslänge berechnen und Grenzwerte festlegen
If Rc_signal_1_stop_flag = 1 Then 'Bearbeitung nur, wenn ISR Pulsende gefunden hat
Disable Int0 'Mögliche Korruption durch ISR vorbeugen
Impulslaenge_1 = Rc_signal_1_stop - Rc_signal_1_start
Enable Int0
Rc_signal_1_stop_flag = 0
Impulslaengenaenderung = Impulslaenge_1_alt - Impulslaenge_1 'SW-Hysterese
If Abs(impulslaengenaenderung) >= Jitterausgleich Then
Impulslaenge_1_alt = Impulslaenge_1
Berechnung_1 = Impulslaenge_1
If Berechnung_1 > Rc_max Then Berechnung_1 = Rc_max
If Berechnung_1 < Rc_min Then Berechnung_1 = Rc_min
End If
End If
'Berechnung der Servogeschwindigkeit und Servostellung
If Berechnung_1 < 182 And Berechnung_1a > Rc_min Then
Servospeed = Berechnung_1 - Rc_min 'ergibt Werte zwischen 0 (schnell) und 61 (langsam)
Zeit_1 = 61 - Servospeed 'inventieren (0=langsam, 61=schnell)
Zeit_2 = Zeit_2 + Zeit_1
If Zeit_2 > 200 Then
Decr Berechnung_1a
Zeit_2 = 0
End If
End If
If Berechnung_1 > 193 And Berechnung_1a < Rc_max Then
Servospeed = Rc_max - Berechnung_1
Zeit_1 = 61 - Servospeed 'inventieren
Zeit_2 = Zeit_2 + Zeit_1
If Zeit_2 > 200 Then
Incr Berechnung_1a
Zeit_2 = 0
End If
End If
'Potis abfragen und Werte für Servolimits berechnen
Poti_1a = Getadc(3)
Poti_1a = Poti_1a / 25 '1024 / 25 = 41, ergibt ca 30% Wegbegrenzung
Limit_1a = 255 - Poti_1a
Poti_1b = Getadc(2)
Poti_1b = Poti_1b / 25
Limit_1b = 120 + Poti_1b
'RC Signal auf Limitwerte begrenzen
If Berechnung_1a > Limit_1a Then 'zu hohe Werte abfangen
Berechnung_1a = Limit_1a
End If
If Berechnung_1a < Limit_1b Then 'zu kleine Werte abfangen
Berechnung_1a = Limit_1b
End If
'Finale Berechnungen an Servoausgabe übergeben, Servoausgabe_x zum direkten Laden in TCNT0 vorbereiten (Cmd Load umgangen)
Servoausgabe_1 = 256 - Berechnung_1a 'Baggerarmservo
Loop
'======================================================
'ISR
'======================================================
Rc_eingang_1:
$asm
push r17 'Register auf Stack sichern
sbis pinb , 2 'Skip next Instr if PINBx = 1
rjmp Puls_ende1 'Springe Puls_ende
in r17 , tcnt1 'Timer1 Wert holen
sts {Rc_signal_1_start} , r17 'Speichere Timer1 nach Rc_signal_1_start
rjmp ende1 'Springe zum Ende
Puls_ende1:
in r17 , tcnt1 'Timer1 Wert holen
sts {Rc_signal_1_stop} , r17 'Speichere Timer1 nach Rc_signal_1_stop
ldi r17 , 1
sts {Rc_signal_1_stop_flag} , r17 'Setze Flag zur Bearbeitung von Impulslaenge in Hauptschleife
Ende1:
pop r17 'Register vom Stack zurückholen
$end Asm
Return
Servoausgabe:
$asm
push r16 'Register auf Stack sichern
in r16,sreg 'Statusregister holen und halten
push r17 'Register auf Stack sichern
lds r17 , {kanal} 'hole Kanalnummer
cpi r17 , 1 'check Kanal und ...
brne LABEL_KANAL_2 '... "wenn nicht gleich" verzweige zum nächsten Kanal
sbic portB , 1 'Skip next instr. wenn PORTA.0 = 0 ist
rjmp label_1 'Springe zum LOW-setzen des Servosignals
sts {kanal} , r17 'Sichere Kanalnummer
lds r17 , {Servoausgabe_1} 'Hole aufbereiteten Pulslängenwert für Timer0
Out Tcnt0 , R17 'Setze Timer0 mit Pulslängenwert
sbi portB , 1 'Setze Servosignal HIGH
rjmp Ende_isr 'Springe zum Ende der ISR
Label_1:
cbi portB , 1 'Setze Servosignal nach LOW
inc r17 'Erhöhe Kanalnummer
'Pausenauffüllung
'Pausenanfang
sts {kanal} , r17 'Sichere Kanalnummer
ldi r17 , &B00000101 'CS00 und CS02 für prescaler 1024 in Timer0 vorbereiten
Out Tccr0b , R17 'Timer0 läuft mit 128µs Auflösung
ldi r17 , 162 'Wert für ca 12ms bis zum nächsten OVF (162=256-94) bei prescaler 1024
Out Tcnt0 , R17
rjmp Ende_isr 'Springe zum Ende der ISR
'Pausenende
Label_kanal_2: 'Bearbeitung von Kanal 2 (Pausenende)
ldi r17 , &B00000011 'CS00 und CS01 für prescaler 64 in Timer0 vorbereiten
Out Tccr0b , R17 'Timer0 läuft wieder mit 8µs Auflösung
ldi r17 , 1 'Kanalnummer auf 1 setzen
sts {kanal} , r17 'Sichere Kanalnummer
Ende_isr:
pop r17 'Register vom Stack zurückholen
Out Sreg , R16 'Statusregister zurückspeichern
pop r16 'Register vom Stack zurückholen
$end Asm
Return
Hallo zusammen,
ich habe mit großer Aufmerksamkeit diesen Thread gelesen und wollte das Forum bitte mir bei meinem Vorhaben zu unterstützen diesen Code für einen Arduino Nano (ATME328p) umzuschreiben.
Ich habe schon mal begonnen, komme aber nicht wirklich weiter.
Im Anhang meine ersten Versuche den Code von R2D2 Bastler umzuschreiben.
Ich denke, das nicht soviele Änderungen notwendig wären?
Vielen Dank
VG
Tom
na wirklich niemand Zeit sich den Code mal anzusehen?
komme wirklich nicht weiter...
Hallo Seacher,
danke für deine Antwort.
Ja Kompilieren lässt sich der Code, nur wenn ich diesen auf den Arduino spiele, funktioniert nur der Teil, wo die Servos auf die Mittelstellung fahren.
Die Steuerung reagiert nicht auf die Empfängereingangssignale.
Ich hab auf D4 ein Empfängersignal und auf D8 einen Servo. Die Potis habe ich nicht angeschlossen, kannes daran liegen?
Anbei nochmal der Code, hier habe ich nochmal die Eingangs und Ausgangsports angepasst.
VG
Tom
Nochmals der Code
Hallo Tony,
ich kann nicht so genau überblicken welchen Einfluß die Potis haben. Ich habe damals praktisch nur die ASM Routinen gemacht und R2D2 hat das dann auf seinen Bagger angewendet. Wenn du keine Potis angeschlossen hast, würde ich statt des Getadc() Konstanten verwenden, die am Programmanfang zum Testen mit Werten zwischen 0 und 1023 belegt werden.Zitat:
Ich hab auf D4 ein Empfängersignal und auf D8 einen Servo. Die Potis habe ich nicht angeschlossen, kannes daran liegen?
D4 bzw D8 sagt mir nichts. Das sind Arduino Bezeichnungen und ich vertraue Dir, das du die Servos schon richtig angeschlossen hast? Mittelstellung funktioniert ja.
Sehr wichtig sind jedoch die Timereinstellungen. Dein ATMega328p läuft mit 16MHz. Das Programm war aber für 8MHz ausgelegt. Auf den ersten Blick erscheint mir das nicht angepaßt, da die Timer mit den gleichen Prescalern wie für 8MHz laufen? Hab im Augenblick nicht die Ruhe, das im einzelnen jetzt durchzugehen. Da müßtest Du nochmal schauen.
Möchtest Du da auch einen Bagger o.ä. betreiben oder zu was brauchst Du das. Die Potis waren, glaub ich, nur zur Wegbegrenzung um keinen Knoten in den Baggerarm zu bekommen ... oder so :) Die Variablen sollten aber mit irgendwas initialisiert werden oder die Limitberechnung komplett rausgenommen werden.
Gruß
Searcher
Hallo Searcher,
danke für die Antwort. Ja ich würde gerne ebenfalls einen Bagger betreiben damit, da mir das ständige Halten der Steuerknüppel auf den Zeiger geht :-)
Okay das mit den Timern habe ich nicht bedacht, werde mich dahinter klemmen. Ich versuche mal deine gesamten Ratschläge durch.
D4 und D8 sind in der Tat die Belegung für den Arduino. Anbei ein Pin Mapping des Arduino.
http://christianto.tjahyadi.com/wp-c...14/11/nano.jpg
Nach diesem Pin Mapping bin ich vorgegangen.
VG
Tom
- - - Aktualisiert - - -
Hallo Searcher,
also wirklich weiter bin ich nicht bekommen, also wenn du mal ne ruhige Minute hättest :-)
VG
Hallo Tom,
das Programm auf 16MHz umzuschreiben ist nicht so einfach, weil der Timer0 nicht den passenden Prescaler bietet. Er sollte mit 8µs Auflösung laufen. Wird der µC mit 16MHz getaktet, läuft Timer0 mit 4µs und schafft dann als 8Bit Timer (256*4µs=1024µs) nicht den Servoimpulsbereich von 1000µs bis 2000µs. EDIT: ODER DOCH ??? Einfacher den µC mit 8MHz laufen zu lassen Der nächste Prescaler wäre 256. Dann würde der Timer bei 16MHz mit 16µs Auflösung laufen, was mir zu grob erscheint. Es wäre wermutlich eine leicht ruckelige Bewegung die Folge.
Man kann aber den µC fürs erste ohne HW Eingriff verlangsamen. Das sollte im Register CLkPR zu machen sein.
Gleich nach dem Header im Bascomprogramm nach Framesize und vor Timerkonfiguration diese beiden Zeilen einfügen:
Dann sollte der ATMega328 nur noch mit 8MHz laufen und keine weiteren Eingriffe im Programm fürs Timing nötig sein. Falls möglich die Taktfrequenz mal überprüfen. Ich habe das selbst noch nicht in der Praxis durchgeführt. Laut Simulator sollte es aber hinhauen (Der zweite Registerzugriff muß innerhalb von 4 Taktzyklen nach Setzen des CLKPCE Bits abgeschlossen sein.)Code:Clkpr = &B1000_0000 'CLKPCE Bit hight zum clock devision bit change enable
Clkpr = &B1000_0001 'clock devision bit für division by 2
Gruß
Searcher
Hallo Searcher,
also hab es so eingefügt wie du beschrieben hast. Das Servo zuckt jetzt nicht mehr so stark wie vorher.
Leider reagiert es kein bisschen auf irgendwelche Empfängersignale.
Ich habe das Servo auf einen Digital-Pin D8 (PB0, PCINT0) gelegt und das Empfänger Signal auf D4 (PD4, PCINT20); Stromversorgung des Empfängers (REX 5MPD) erhält dieser über das Board. Als Sender ist einer Graupner Sender MC-20 35Mhz im Einsatz.
Neben dem Arduino Nano habe ich noch ein Pin Board verbaut mit externe Stromversorgung (5V). Komisch ist das mit der externen Stromversorgung ein weiteres Servo am Empfänger nicht arbeitet, aber mit der USB Versorgung am Arduino schon.
Meine Vermutung ist, dass die Eingangssignal des Empfängers schon gar nicht passen?
Danke für deine Hilfe bisher.
VG
- - - Aktualisiert - - -
ach ja und die Servos fahren anscheinend nicht in die Mittelstellung, sonder in die Endstellung, besser gesagt würden gerne darüber hinaus fahren wollen.
Irgendwie strange die Sache.
OK, scheint zu wirken.
Portpinanpassungen in Baggersteuerung_V23_ATmel_V3.bas scheinen OKZitat:
Leider reagiert es kein bisschen auf irgendwelche Empfängersignale.
Ich habe das Servo auf einen Digital-Pin D8 (PB0, PCINT0) gelegt und das Empfänger Signal auf D4 (PD4, PCINT20);
Dazu kann ich nichts sagen. Das Programm erwartet an seinen Eingängen Impulse von ca 1ms bis ca 2ms. Müssen nicht nacheinander eintreffen, können auch parallel ankommen.Zitat:
Stromversorgung des Empfängers (REX 5MPD) erhält dieser über das Board. Als Sender ist einer Graupner Sender MC-20 35Mhz im Einsatz.
Na ja, Servos können viel Strom ziehen und damit übrige Elektronik, die an der gleichen Stromversorgung hängt durcheinander bringen. Wäre ein eigenes Thema. Zum Testen würd ich erstmal die Servos über ein eigenes Netzteil versorgen. GND Verbindung von der externen Stromversorgung zum Arduino aber nicht vergessen.Zitat:
Neben dem Arduino Nano habe ich noch ein Pin Board verbaut mit externe Stromversorgung (5V). Komisch ist das mit der externen Stromversorgung ein weiteres Servo am Empfänger nicht arbeitet, aber mit der USB Versorgung am Arduino schon.
Da kann ich nu nix zu sagen. Kann man denn da die Servosignalleitung nicht direkt anschließen? Da mußt Du schon sicher sein, was da raus kommt.Zitat:
Meine Vermutung ist, dass die Eingangssignal des Empfängers schon gar nicht passen?
Poste nochmal das aktuelle Programm und ich schau nochmal - aber heute wahrscheinlich nicht mehr. Du könntest erstmal alles auskommentieren bis auf Servosignal lesen und Servosignal ausgeben. Die ganzen Veränderungen, Limits usw. brauchst du erstmal zum Testen nicht. Es muß erst Lesen des/der Signal und Ausgeben der Signale funktionieren.
Gruß
Searcher
Hallo Searcher,
also anbei nochmal das Programm.
Ich werde deine Vorschläge nochmal testen. Die Empfängersignale kommen bestimmt zwischen 1ms und 2ms. Die Servos kommen ja damit klar.
Aber mit Bestimmtheit kann ich es nicht sagen.
Also schönen Abend noch.
VG
Dann ist es gut.
Oaahhh, genau wie ich.Zitat:
Aber mit Bestimmtheit kann ich es nicht sagen.
Ich sehe gerade, daß du online bist. Das ich mir heute früh Deine letzte Version aus Post #53 herunter geladen habe, sagt nichts über darüber aus ob ich Dir früh auch eine Antwort geben kann. Es ist Ostern und ich muß schauen was sie Hasen machen. :lol:
Gruß
Searcher
Also schönen Abend noch.
VG[/QUOTE]
- - - Aktualisiert - - -
Leider nicht :( Die Pinchangeinterrupts können so nicht richtig ablaufen.
Die Anweisung zB PCMSK1.PCINT20=1 sollte im Maskenregister PCMSK1 den PCINT20 freigeben. Es gibt den PCINT20 dort aber nicht beim ATMega328 (Datenblatt). Der ist im PCMSK2.
Danach versuchst Du PD4 mit PCINT21 freizugeben. Darf nicht sein, da PCINT21 im gleichen PCMSK2 Register liegt wie PCINT20 (PD4) . Die Pinchangeinterrupts werden für Gruppen von Portpins ausgelöst. PCINT0 für PB0 bis PB7 (im PCMSK0 den jeweiligen Pin freigeben und mit ENABLE PCINT0 den Interrupt freigeben) das Gleiche für PC8 bis PC14 im PCMSK1 und ENABLE PCINT1. Bischen verwirrend, da PCINT einmal für einen der 3 Pinchangeinterrupts und einmal für den Portpin verwendet wird.
Beim Vergeben der Eingänge mußt du also drauf achten, daß die zugehörigen PCINTS in verschiedenen PCMSK Registern liegen. PD2 (als INT0 kann erstmal bleiben so wie ich das im Augenblick sehe, da der INT Interrupt unabhängig von den PCINT Interrupt ist - wenn sie nicht gerade gleichzeitig verwendet werden sollen, was ja bei dir nicht der Fall ist)
So, das wars fürs Erste. Später im Programm werden noch Interruptflags manuell gelöscht. Dazu dann mehr, wenn Du eine neue Verteilung der Eingänge hast. Wie siehts bei der Stromversorgung aus?
Gruß
Searcher
Hallo Searcher,
also ich habe deine Änderungen angepasst, zumindest hoffe ich alle Änderungen richtig gemacht zu haben. Macht Sinn mit den unterschiedlichen Register. Wenn man sich den ursprünglichen Code ansieht, erkennt man das die Eingänge auch auf unterschiedlichen Registern hängen.
Das mit Stromversorgung habe ich auch gelöst.
Was meinst du mit den Manuellen Flags?
Da war ich einen Augenblick nicht ganz bei der Sache. Es gibt die Anweisung "Set Tifr1.ocf1b", die ein Interruptflag löscht. Ist aber hier nicht das Problem.
Im Augenblick finde ich keinen Fehler mehr bei den Portanpassungen im Programm :confused: Sieht für mich jetzt erstmal gut aus. Timing sollte mit dem Clockdevision by 2 auch klar gehen.
Im Header hast Du als Kommentar zB soetwas:
'RC Eingang 1 an Pin 3 (PC0, PCINT8 ) Stick 1 (Aileron)
'RC Eingang 2 an Pin 6 (PB4, PCINT4) Stick 2 (Elevator)
'RC Eingang 3 an Pin 5 (PD2, INT0) Betriebsmode
Mir ist die Nummerierung nicht klar. Nach Deinem Link mit der Zuordnungstabelle stimmen die Pinnummern im Header nicht mit den lila Nummern in der Arduinoskizze überein. Da könnte der HW-Anschluß vom Empfänger zum Arduinoeingang nicht mehr stimmen. Würd ich also nochmal überprüfen bzw Kommentae aktualisieren.
Eigentlich fällt mir nichts mehr ein. Wenn nichts geht, mit dem RC_MAX, RC_MIN, Potiwerten spielen, oder versuchen die ganzen Pulsbeeinflussungen im Programm rauszunehmen und schauen ob die Pulse dann durchgeschleift werden. Es gibt da auch noch eine Betriebswahl:
"If Berechnung_3 < 187 Then 'falls der Betriebswahlkanal unter Mittelstellung ist, ..."
hab ich auch noch nicht näher betrachtet.
Bin auf Weiteres von Dir gespannt ...
Gruß
Searcher
Hallo Searcher,
ja der Header hat nicht mehr gestimmt. Habe das angepasst. siehe nachfolgend:
'================================================= ==============================
'BAGGER Steuerung V23
'
'RC Eingang 1 an Pin A0 (PC0, PCINT8) Stick 1 (Aileron)
'RC Eingang 2 an Pin D12 (PB4, PCINT4) Stick 2 (Elevator)
'RC Eingang 3 an Pin D2 (PD2, INT0) Betriebsmode
'Poti 1a an Pin A5 (PC5, ADC5)
'Poti 1b an Pin A4 (PC4, ADC4)
'Poti 2a an Pin A3 (PC3, ADC3)
'Poti 2b an Pin A2 (PC2, ADC2)
'twe: Servo 1 an Pin D8 (PB0, PCINT0) Baggerarmservo
'twe: Servo 2 an Pin D9 (PB1, PCINT1) Baggerarmservo
'twe: Servo 3 an Pin D10 (PB2, PCINT2) Kettenantrieb
'twe: Servo 4 an Pin D11 (PB3, PCINT3) Kettenantrieb
'
'================================================= ==============================
Die Frage welche ich noch habe, oder wo ich mir unsicher bin ist bei den Ein- und Ausgängendefinition
'-------------------------------------------------------------------------------------------------------------
'Ein- und Ausgang festlegen
'-------------------------------------------------------------------------------------------------------------
Ddrb = &B00001111 'twe: PB0, PB1, PB2, PB3 werden Ausgänge, restlicher PortB bleibt Eingang
Ddrc = &B00000000 'twe: PortC bleibt Eingang
Ddrd = &B00000000 'twe: PortD bleibt Eingang
Stimmt das so? Musste das um die Ports D erweiteren.
Anbei nochmal der ganze Code.
Ja, stimmt so. Eine 1 im entsprechenden Bit von entsprechendem DDR Register :) bedeutet Pin als Ausgang konfiguriert.
Der ATMega belegt nach Reset alle Register mit Defaultwerten. Beim DDRx sind das Nullen. Man müßte also Nullen nicht Schreiben, wenn man Eingänge haben möchte. "Ddrd = &B00000000" wäre unnötig, dient aber auf jeden Fall der Klarheit eines Programmes.
Gruß
Searcher
PS: Ich lad mir das letzte Programm nochmal und versuche daraus, wie von mir obenvorgeschlagen, ein Durchschleifprogramm zu machen. Wird heute und morgen aber sicher nichts mehr.
Hallo Searcher,
danke für deinen Vorschlag. Ich werde jetzt alles nochmal komplett neu anschließen und mit dem print - Befehl versuchen zu ergründen, was vom Empfänger eigentlich ankommt.
Denn ich denke da ist der Fehler begraben.
An sich ist das Programm sehr nachvollziehbar, zumindest bis ich zu den asm Routinen komme. :-) Sind ja wie ich verstanden habevon Dir selbst geschrieben, oder?
VG
Tom
Ich habe in meinen Anfangszeiten, als ich noch kein Oszilloskop besaß, mit einem Soundkartenoszilloskop solche Signale beobachten können. Hab leider keine Unterlagen mehr dazu, läßt sich aber im INET finden. Signal an Soundkarte-Soundin, Freeware Oszilloskop gestartet und mit viel Phantasie erahnt was vorgeht. Manche Audioaufnahmeprogramme können Waveformen auch sichtbar machen :confused:
Ja, die ASM Teile sind von mir.Zitat:
An sich ist das Programm sehr nachvollziehbar, zumindest bis ich zu den asm Routinen komme. :-) Sind ja wie ich verstanden habevon Dir selbst geschrieben, oder?
Zum Messen des Impulses am Eingang wird bei einem (PCINT) in die entsprechende Interruptroutine gesprungen.
Dort wird mit "sbis pinC , 0" festgestellt ob der PCINT Flankenwechsel nach high oder low ging.
Es wird entsprechend verzweigt und der Timer1 ausgelesen und gesichert zur Nachbearbeitung im Hauptprogramm.
War der Pin low, ist der Impuls zu Ende und es wird noch ein Flag gesetzt um dem Hauptprogramm mitzuteilen, das jetz die Impulslänge berechnet werden kann.
Servoausgabe:
Die Servoimpulse für alle Servos werden nacheinander ausgegeben. Der Interrupt ...
Fotsetzung folgt später, Sorry.
Gruß
Searcher
Hallo Searcher,
danke für die Infos über asm. Du kein Ding is heute eh schon spät und vorallem Sonntag :-)
Interessant ist, dass ich den RC_Signal 1 eigentlich sehr gute Werte zwischen 2201 und 3812 bekomme.
RC_Signal 2 kommt ziemlicher Quark an.
1647 Impulslaenge_2
1649 Impulslaenge_2
1649 Impulslaenge_2
1846 Impulslaenge_2
2924 Impulslaenge_2
6182 Impulslaenge_2
7473 Impulslaenge_2
8853 Impulslaenge_2
10579 Impulslaenge_2
38714 Impulslaenge_2
40492 Impulslaenge_2
16675 Impulslaenge_2
1035 Impulslaenge_2
1649 Impulslaenge_2
1649 Impulslaenge_2
2256 Impulslaenge_2
2972 Impulslaenge_2
3574 Impulslaenge_2
3987 Impulslaenge_2
irgendwie stimmt da etwas nicht.
VG
Fortsetzung:
Servoausgabe:
Die Servoimpulse für alle Servos werden nacheinander ausgegeben und der Timer0 mit seinem Overflow Interrupt
zum Abmessen der Zeiten verwendet.
Die Servoimpulslänge für jeden Kanal wird vom Hauptprogramm in den Variablen "Servoausgabe_1" bis "Servoausgabe_4" als Vorladewert (Servoausgabe_1 = 256 - Berechnung_1a) abgelegt.
Tritt die ISR "Servoausgabe" zum erstenmal auf, wird Kanal 1 bearbeitet.
Die ISR wird durch den Timer0 Overflow Interrupt aufgerufen.
Der Vorladewert für den ersten Kanal wird geholt und der Timer0 damit geladen und der Portpin für Servo auf high gesetzt - Pulsbeginn. (Durch Abfrage des Zustandes des Portpins wird auf Puls beginnen oder Puls beendene entschieden)
Nach Erreichen des nächsten Overflowinterrupts, die Zeit wird ja durch den Vorladewert bestimmt, wird das Servosignal nach low gesetzt - Pulsende.
Dann wird die Kanalnummer noch erhöht und gleich der nächste Kanal bearbeitet mit Vorladewert holen und Pin für Pulsbegin auf high. Ablauf wie für Kanal 1.
So werden 4 Ausgabekanäle ausgegeben und dann eine Ausgabepause gemacht um die ca. 50Hz für Servopulsfrequenz zu erreichen.
Die "Pausenanfang" und "Pausenende" Instruktionen am Ende der ISR machen die ca. 20ms Folgen für die Servopulse. Wurden alle 4 Kanäle abgearbeitet/ausgegeben (ca 2ms * 4 = 8ms), wird eine Pause von 12ms auch durch temporäre Veränderung des Prescalers gemacht, damit weniger Interrupts auftreten und dadurch die Messung der Eingänge nicht so sehr gestört werden kann. Die 50Hz Ausgabe zu den einzelnen Servos ist etwas abhängig von den Pulslängen. Da die Genauigkeit von 50Hz aber nicht so kritisch sind, haben wir die damals vernachlässigt.
Gruß
Searcher
PS:)Bild hier Bild hier Sonst würde etwas nicht stimmen. Bild hierZitat:
irgendwie stimmt da etwas nicht.
Viel Erfolg beim testen. Bis dann.
Hallo Searcher,
also nach langem hin und her, habe ich jetzt zumindest erreicht, dass der Servo verfährt und auf die Eingangssignale des Empfängers hört.
Ich habe die Codezeile: "Shift Berechnung_1 , Right , 3" und "Shift Berechung_1, Right, 4" umgeändert. Hierdurch wird das Eingangssignal des Empfängers von Neutral 2950 auf min 137 und max 236 umgerechnet; damit funktioniert es :-)
Das Servo reagiert jetzt eigentlich richtig, nur verfährt es in einem sehr kleinen Bereich, ziwschen den Werten "Signal Servoausgabe 2" (= MinPosition) und "Signalausgabe 60" (= MaxPosition Servo, sogar der harte Endanschlag des Servos). Den Prescaler des Timers0 auf 8 zu reduzieren, brachte nur einen Geschwindigkeitszuwachs aber keine Veränderung der Neutralposition und des Arbeitsbereichs des Servo.
Interessant ist auch, dass das Eingangssignal des Empfängers immer kurzzeitig auf 24000 springt, wodurch die Berechnungen immer um 1 springen und damit das Servo langsam in die Minposition (Servoausgabe_1= 2) verfährt und dort verharrt. Ist aber wohl nur ein Filterproblem, welches sich sicherlich einfach lösen lässt.
Ich sehen im Moment keine Lösung für den geringen Verfahrbereich. Kann das am Timing für den Servo (asm Schnittstelle) liegen? Prescaler und Pausenzeiten vielleicht?
Wenn ich an der Fernsteuerung den Arbeitsbereich erweitere, oder den Nullpunkt verschiebe, erreiche ich nichts. Da die Variable Servoausgabe_1 ja begrenzt ist.
Servoausgabe = 256 - Berechnung_1a
Vielleicht hast du noch eine Idee. Dacht mir vielleicht dass es schon an der Demo Version von Bascom liegt, diese gibt ja maximal 4KB große Dateien frei, die *.bin Datei hat aber nur 3,44KB, sollte also i.O. sein.
VG
Tom
Anbei nochmal der gesamte Code
Hab ich gesehen und darf aber nicht sein :) Die Division hab ich wieder rückgängig gemacht. Siehe weiter unten - Es gab Problem mit dem Takt von 16MHz.
Man müßte genau wissen, was der Empfänger wirklich schickt. Servosignale sollen nur zwischen 1000µs und 2000µs lang sein. Ich gehe immer von 500µs bis 2500µs aus.Zitat:
Interessant ist auch, dass das Eingangssignal des Empfängers immer kurzzeitig auf 24000 springt, wodurch die Berechnungen immer um 1 springen und damit das Servo langsam in die Minposition (Servoausgabe_1= 2) verfährt und dort verharrt. Ist aber wohl nur ein Filterproblem, welches sich sicherlich einfach lösen lässt.
Den Takt in Ordnung bringen und schauen ob das Durchschleifen paßt. Siehe unten.Zitat:
Ich sehen im Moment keine Lösung für den geringen Verfahrbereich. Kann das am Timing für den Servo (asm Schnittstelle) liegen? Prescaler und Pausenzeiten vielleicht?
Wenn ich an der Fernsteuerung den Arbeitsbereich erweitere, oder den Nullpunkt verschiebe, erreiche ich nichts. Da die Variable Servoausgabe_1 ja begrenzt ist.
Servoausgabe = 256 - Berechnung_1a
Vielleicht hast du noch eine Idee.
Ich nutze auch die Demoversion 2.0.7.5. Ist in Ordung und kann die Programmgröße noch händeln.Zitat:
Dacht mir vielleicht dass es schon an der Demo Version von Bascom liegt, diese gibt ja maximal 4KB große Dateien frei, die *.bin Datei hat aber nur 3,44KB, sollte also i.O. sein.
Hier fängt "unten" an: ;)
Ich habe das Programm zum Durchschleifen von 3 Eingängen auf 3 Ausgänge verändert und mit einem Mega88A mal getestet.
Das veränderte Programm "BaggerDurchschleif_V23_ATmel_V3_mega328.bas", lauffähig auf 16MHz ATMega328p ist im Anhang.
Soweit ich noch alles zusammenbekomme gibt es folgende Veränderungen:
1. Änderung bei der Clockdevision. Zweites CMD muß "Clkpr = &B0000_0001" sein, sonst wird das nix. (Bisher gab es dadurch bei 16MHz schon ein Problem weil es nicht gewirkt hat) $crystal ist noch auf 16000000. Dadurch, daß nach dem Heruntersetzen des Taktes der µC ja nur mit 8MHz läuft, wäre es vielleicht richtiger auch den $crystal Wert auf 8000000 zu setzten. Sollte aber im gegenwärtigen Programm keine Auswirkung haben, da keine WAIT Anweisungen oder so vorhanden sind. Es gibt allerdings deine PRINT Anweisung. Wenn der µC dann tatsächlich mit 8MHz läuft und $crystal noch auf 16000000 steht, geht die Ausgabe über UART dann wahrscheinlich nicht mehr.
2. Die RC_Min und RC_max Werte angepaßt um Ausgabepulsbereich zu erweitern.
3. Auskommentierung von allen Pulsveränderungen bis auf den Jitterausgleich. Das Durchschleifen getestet mit 3 Eingängen und 3 Ausgängen so gut es ich es mit einem Simulator durch einen Attiny44 auf die Schnelle hinbekommen habe. Läuft!
Die Zeilen mit den Auskommentierungszeichen sind an den hash Zeichen (##########..) erkennbar. Die Zeilen einfach wieder rausnehmen.
4. Anmerkung: Gemessen wird im Programm mit einer Auflösung von 1µs. Die Ausgabepulse werden mit einer Auflösung von 8µs ausgegeben. Divisionen durch 16 auf 8 rückgängig gemacht. (Jitterausgleich - funktioniert/wirkt laut R2D2, ich konnte das noch nicht testen - Jitter ist eventuell Ursache nur für Servozittern - zuletzt dran drehen, wenn sonst keine Ursache auszumachen ist)
5. An Zeilen mit "srch" im Kommentar hab ich auch noch gewerkelt.
6. Programm enthält noch auskommentierte Zeilen für meinen ATMega88A.
7. Die ASM Teile und Portanpassungen von Dir wurden nicht verändert.
So, und nun darfst Du Dich wieder auslassen.
Gruß
Searcher
Hallo Searcher,
so endlich Wochenende und wieder mehr Zeit für das Projekt. :-)
Also ich habe deinen Code getestet und wirklich vielen Dank funktioniert sehr sehr gut.
Ich habe dann noch die andere Teile wieder aktiviert |) und die gleichen Phänomene waren wieder da.
If Tifr1.ocf1a = 1 And Berechnung_1 < 182 Then
Set Tifr1.ocf1a 'Interruptflag löschen
Servospeed = Berechnung_1 - Rc_min
Servospeed = Servospeed * 500 'eine Einheit in Servospeed macht 1µs Wartezeit
If Servospeed < 1000 Then Servospeed = 1000 'Sicherheitszeit 1000µs damit bei kleinen Werten kein kompletter timer rundlauf bis zum nächsten
'comparematch abgewartet werden muß. Länger sollte auch eine Runde in der Hauptschleife nicht dauern.
Ocr1a = Tcnt1 + Servospeed 'Setzen von OCR1A damit nach Servospeed ein Compare Match auftritt
Decr Berechnung_1a
End If
Das Servo fährt in die Mittelstellung, wenn ich nun den Hebel auslenke fährt das Servo in die richtige Richtung aber die Geschwindigkeit bleibt in der jeder Situation die Selbe.
Wenn ich die Fernsteuerung loslasse, fährt der Servo langsam in eine Endposition, da wieder das Eingangssignal kurzzeitig auf über 40000 geht.
Meine Vermutung ist jetzt, dass der Teil Tifr1.ocf1a dafür verantwortlich sein muss, da hier anscheinend der Interrupt gelöscht wird, was vermutlich das Phönomen auslöst.
Ganz habe ich diesen Codeteil auch nicht verstanden, den der Befehl "Decr" sagt nicht über die Geschwindigkeit aus und ist doch vom Takt der Berechnung abhängig.
Wenn jetzt von 187 rückwärts gezählt wird, dann doch genau in dem Takt wie die Berechnung läuft, oder täusche ich mich da jetzt gewaltig?
Vg
Tom
Hallo Tom,
ehrlich gesagt bereitet es mir Mühe das Verhalten bei Dir theoretisch nachzuvollziehen.
1. Die folgenden 4 Zeilen mußten auch noch raus. Hast Du aber vermutlich gemacht.
Code:Servoausgabe_1 = 256 - Berechnung_1 'srch Baggerarmservo 1,
Servoausgabe_2 = 256 - Berechnung_2 'srch Baggerarmservo 2
Servoausgabe_3 = 256 - Berechnung_3 'srch Fahrservo oder ESC 1
'Servoausgabe_4 = 256 - Berechnung_4 'srch Fahrservo oder ESC 2
2. Ich versuche das mal zu erklären. Wie gesagt, ich habe keine Testumgebung mit Servos dazu. Getestet hat das R2D2 Bastler.
"If Berechnung_3 < 187 Then 'falls der Betriebswahlkanal unter Mittelstellung ist, ist Fahrbetrieb"
Welcher Betrieb ist bei Dir eingestellt? Im Baggerbetrieb ...
Im Else Zweig (Baggerbetrieb) kommt erst das Interruptflaglöschen zum Tragen.Code:'--------------------------------------------------
'BAGGERETRIEB
'--------------------------------------------------
If Tifr1.ocf1a = 1 And Berechnung_1 < 182 Then
Set Tifr1.ocf1a 'Interruptflag löschen
Servospeed = Berechnung_1 - Rc_min
Servospeed = Servospeed * 500 'eine Einheit in Servospeed macht 1µs Wartezeit
If Servospeed < 1000 Then Servospeed = 1000 'Sicherheitszeit 1000µs damit bei kleinen Werten kein kompletter timer rundlauf bis zum nächsten
'comparematch abgewartet werden muß. Länger sollte auch eine Runde in der Hauptschleife nicht dauern.
Ocr1b = Tcnt1 + Servospeed 'Setzen von OCR1A damit nach Servospeed ein Compare Match auftritt
Decr Berechnung_1a
End If
Der Timer1 läuft mit einer Auflösung von 1µs (1Mhz Takt)
In Berechnung_1 steht die Sollpulslänge, eingelesen vom Input, von dem 1. Servo in 8µs Einheiten.
Steht da zB 150 drin, bedeutet das, daß Servopulslänge für Servo1 soll 150*8µs = 1200µs werden
Servo1 soll also nach Position 1200 gebracht werden.
Servo1 steht aber auf Position, die in Berechnung_1a drinsteht.
Es wird Berechnung_1a decrementiert, da Berechnung_1 < 182 ist.
Würde Berechnung_1 zwischen 182 und 193 liegen (Fernsteuer vermutlich in neutral? ), würde nichts passieren.
Die Abfrage wird für Servo1 immer dann ausgeführt, wenn der Comparematch1A auftritt.
Die Abfrage wird für Servo2 immer dann ausgeführt, wenn der Comparematch1B auftritt.
Servospeed = Berechnung_1 - Rc_min (Servospeed = 150 - 122 = 28 )
Servospeed = Servospeed * 500 (Servospeed = 28 * 500 = 14000)
Ocr1b = Tcnt1 + Servospeed (Ocr1b = Tcnt1 + 14000) Hier werden 14000µs bis zum nächsten Auftreten des Comparematches eingstellt.
(Fehler? müßte Ocr1a = Tcnt1 + Servospeed sein, es sind also 14000µs (14ms), bis der Servo wieder ein 8µs Schritt durch decr Berechnung_1a macht)
Da keine Interruptserviceroutine für die Compare-Matches benutzt wird, die die Interruptflags automatisch löschen würde, müssen die Flags mit "Set Tifr1.ocf1a" bzw Set "Tifr1.ocf1b" "von Hand" gelöscht werden.
Die zusätzliche Verwendung des Timer1 als Zeitgeber durch Abfragen der Comparematchinterruptflags wurden gemacht um die Hauptschleife möglichst wenig aufzuhalten. Kann mich noch erinnern, daß ein Durchlauf sehr sehr weit unter den 1000µs war. Dein "Print" könnte da jetzt was ändern!
Der Timer1 wird hier also nur als Zeitgeber für langsames Verfahren der Servos benutzt, da diese sonst so schnell es ihnen möglich ist ihre Sollposition anfahren würden. Sieht beim Baggerarm dann wohl nicht so gut aus. Ich weiß leider auch nicht - sieht mir nicht so aus - daß da eine Rampe (langsames Anfahren und schneller werden bzw umgekehrt geht) - weiß auch nicht wie die Fernsteuerung geht ... ???
Im o.g. Teil müßtest Du mal OCR1B gegen OCR1A tauschen - scheint mir ein Fehler zu sein. k.A. ob das Absicht ist.
Gruß
Searcher
Hallo Searcher,
also gestern habe ich dann noch die Lösung gefunden und hab dann heute deine Vermutung gelesen.
Jup es war der "Print" Befehl der alles aufgehalten hat. :-)
Danke trotzdem für die Erklärung der Funktionen Tifr1.ocf1b. Ich war dann heute gleich so beflügelt vom Erfolg, dass ich das Ganze noch um einen weiteren Servo erweitert habe.
Ich habe einfach den letzten PIN-Change Interrupt ausgewählt PCINT2 und damit funktioniert es auch ganz gut.
Nur leider ist es so, dass der CompareMatch im Timer1 (hoffe liege da richtig) nur Compare Match A und B kann und C nicht möglich ist.
Daher meine Frage ob ich jetzt, damit alle drei Servos gleichzeitig verfahren werden können ich einen dritten Timer (Timer 2) aufmachen muss??
Anbei nochmal der Code erweitert um den dritten Servo. Ich habe den Compare Match einfach kopiert, was ich wohl nicht machen darf?
Den dritten Servo habe ich so gelegt, das PCMSK0, PCMSK1 und PCMSK2 auf unterschiedlichen Pins liegen und sich nicht stören sollten.
Der Servo 4 ist über den Befehl Berechnung_4 = 255 ausgehebelt, somit kommt der nicht in die Quere.
Wie gesagt es funktionieren alle drei sehr gut, 1 und 2 lassen sich gleichzeitig bewegen, also ruckelfrei, nur 3 fährt nur wenn 1 oder 2 stehen.
If Tifr1.ocf1a = 1 And Berechnung_3 < 182 Then
Set Tifr1.ocf1a
Servospeed = Berechnung_3 - Rc_min
Servospeed = Servospeed * 500
If Servospeed < 1000 Then Servospeed = 1000 'Sicherheitszeit
Ocr1a = Tcnt1 + Servospeed
Decr Berechnung_3a
End If
If Tifr1.ocf1a = 1 And Berechnung_3 > 193 Then
Set Tifr1.ocf1a
Servospeed = Rc_max - Berechnung_3
Servospeed = Servospeed * 500
If Servospeed < 1000 Then Servospeed = 1000 'Sicherheitszeit
Ocr1a = Tcnt1 + Servospeed
Incr Berechnung_3a
End If
Meine Überlegung war jetzt einen weiteren Timer 2 aufzumachen um hier die beiden weiteren Compare Matches A und B verwenden zu können?
Würde das so funktionieren, oder gibt es hier einen eleganteren Weg?
VG
Tom
Hört sich ja prima an, gratuliere. (Ab jetzt dran denken, da kann was nicht stimmen :) :lol: )
Was sagt das Datenblatt? Comparematch C gibt es hier nicht! Timer1 ist jetzt auch reichlich ausgenutzt und man muß anfangen aufzupassen, damit er nicht überlastet wird und unrund läuft :)Zitat:
Nur leider ist es so, dass der CompareMatch im Timer1 (hoffe liege da richtig) nur Compare Match A und B kann und C nicht möglich ist.
Ja, gute Idee. Vorher war das ja nicht möglich, da der ATTiny84, für den das Programm ja ursprünglich war, nur zwei Timer hat.Zitat:
Daher meine Frage ob ich jetzt, damit alle drei Servos gleichzeitig verfahren werden können ich einen dritten Timer (Timer 2) aufmachen muss??
Na ja, die Comparematches sind den Servos zugeordnet und müssen für jedes Servo unabhängig sein. Die Abhängigkeit hast du ja bemerkt, indem Servo3 nur läuft wenn die anderen stehen. Dann wird das Interruptflag nicht gelöscht und steht noch für Servo3, das damit dann arbeiten kann.Zitat:
Anbei nochmal der Code erweitert um den dritten Servo. Ich habe den Compare Match einfach kopiert, was ich wohl nicht machen darf?
Das sollte OK sein. Werd später nochmal in Dein Programm schauen.Zitat:
Den dritten Servo habe ich so gelegt, das PCMSK0, PCMSK1 und PCMSK2 auf unterschiedlichen Pins liegen und sich nicht stören sollten.
Ja, ich denke, das es mit Timer2 funktionieren sollte. Weiß jetzt nicht, ob es was besseres geben würde. Eigentlich gibt es ja immer zig Möglichkeite. Timer2 läßt sich aber am einfachsten in das bestehende Programm einfügen. Ein CONFIG TIMER2 Kommando. Ausrechnen wie die Zeiten nach dem set tifr2.ocf2a sein müssen und analog zu den bestehenden Codezeilen anpassen.Zitat:
Wie gesagt es funktionieren alle drei sehr gut, 1 und 2 lassen sich gleichzeitig bewegen, also ruckelfrei, nur 3 fährt nur wenn 1 oder 2 stehen.
If Tifr1.ocf1a = 1 And Berechnung_3 < 182 Then
Set Tifr1.ocf1a
Servospeed = Berechnung_3 - Rc_min
Servospeed = Servospeed * 500
If Servospeed < 1000 Then Servospeed = 1000 'Sicherheitszeit
Ocr1a = Tcnt1 + Servospeed
Decr Berechnung_3a
End If
If Tifr1.ocf1a = 1 And Berechnung_3 > 193 Then
Set Tifr1.ocf1a
Servospeed = Rc_max - Berechnung_3
Servospeed = Servospeed * 500
If Servospeed < 1000 Then Servospeed = 1000 'Sicherheitszeit
Ocr1a = Tcnt1 + Servospeed
Incr Berechnung_3a
End If
Meine Überlegung war jetzt einen weiteren Timer 2 aufzumachen um hier die beiden weiteren Compare Matches A und B verwenden zu können?
Würde das so funktionieren, oder gibt es hier einen eleganteren Weg?
Gruß
Searcher
Hallo Searcher,
ich hab jetzt den Timer 2 eingefügt:
onfig Timer1 = Timer , Prescale = 8 'Timer für Einlesen RC Signale
Start Timer1
Config Timer2 = Timer , Prescale = 8 'Timer für Einlesen RC Signale
Start Timer2
Config Timer0 = Timer , Prescale = 64 'Timer für Servoausgabe, Wert 125 entspricht 1ms, Wert 250 entspricht 2ms
Enable Timer0
On Timer0 Servoausgabe Nosave
und den unteren Teil habe ich folgendermaßen geändert
If Tifr2.ocf2a = 1 And Berechnung_3 < 182 Then
Set Tifr2.ocf2a
Servospeed = Berechnung_3 - Rc_min
Servospeed = Servospeed * 500
If Servospeed < 1000 Then Servospeed = 1000 'Sicherheitszeit
Ocr2a = Tcnt2 + Servospeed
Decr Berechnung_3a
End If
If Tifr2.ocf2a = 1 And Berechnung_3 > 193 Then
Set Tifr2.ocf2a
Servospeed = Rc_max - Berechnung_3
Servospeed = Servospeed * 500
If Servospeed < 1000 Then Servospeed = 1000 'Sicherheitszeit
Ocr2a = Tcnt2 + Servospeed
Incr Berechnung_3a
End If
Das Ergebnis dieser Änderung ist, dass das dritte Servo deutlich zu schnell fährt. Aber ich kann alle drei Servos gleichzeitig betätigen.
Vermutlich fehlt es jetzt nur am Timing. Ich habe in der Doku versucht zu verstehen, wie der Timer 2 funktioniert. Den Prescaler habe ich gleich gelassen wie bei Timer1.
Anbei noch mal der geänderte Code.
VG
Thomas
Es geht schon mal was\\:D/. Aber ganz so einfach ist es doch nicht. Der Timer2 ist ein 8-Bit Timer und das OCR2A Register hat auch nur 8 Bit. Wenn man da 14000, wie im obigen Beispiel bei Timer1, aufaddiert, läuft der nicht nur einmal über, was er machen darf/soll, sondern gleich mehrfach und ist so nicht mehr einfach handhabbar.
Man muß also drauf achten, daß der Wert Servospeed für Servo3 einen Wert von 255 nicht übersteigt bzw die Zeit nicht kürzer als die Sicherheitszeit von 1000µs = 1ms wird.
Wenn man den Timer2 mit Prescaler 1024 betreibt, braucht er für einen kompletten Durchlauf:
8000000Hz/1024 = 7812,5Hz 1/7812,5Hz = 0,000128s 8Bit Timer = 256 Werte -> 0,000128s * 256 = 0,032768s
Die längste Zeit, die zwischen zwei 8µs Bewegungen (Decr Berechnung_3a) von Servo3 liegt, können ungefähr 0,032768s sein.
Die kürzeste Zeit soll eben die Sicherheitszeit sein, die dann 1000µs / 128µs = 8 Einheiten lang ist:
If Servospeed < 8 Then Servospeed = 8 'Sicherheitszeit
Berechnung_3 liegt ja irgendwo zwischen 182 und RC_Min (120)
Servospeed = Berechnung_3 - Rc_min (zwischen 0 und 62)
Damit man jetzt in etwa auf gleiche Verzögerung wie bei Timer1 kommt, wird mit 4 multipliziert.
Servospeed = Servospeed * 4 (zwischen 0 und 248 (0 * 4 bzw 62 * 4))
Könnte dann so aussehen ...
Die Steuerung bzw Langsamfahrt für Servo3 wird aber viel rauher sein ??? Bin gespannt ...Code:Config Timer2 = Timer , Prescale = 1024
If Tifr2.ocf2a = 1 And Berechnung_3 < 182 Then
Set Tifr2.ocf2a
Servospeed = Berechnung_3 - Rc_min
Servospeed = Servospeed * 4
If Servospeed < 8 Then Servospeed = 8 'Sicherheitszeit
Ocr2a = Tcnt2 + Servospeed
Decr Berechnung_3a
End If
'Für INCR Berechnung_3a analog ...
Start Timer ist nicht notwendig. Spart Code und Timer werden durch Angabe von Prescaler im CONFIG TIMER Kommando gestartet.
Keine Gewähr, ich könnte mich sicherlich irgendwo verrechnet haben :( Die Richtung sollte aber stimmen. Die Verzögerung der Servofahrt hat R2D2 Bastler, soweit ich mich erinnern kann, ausprobiert.
Viel Erfolg beim Endspurt
Gruß
Searcher
Hallo Searcher,
also ich habe den Code so ausprobiert und wie Du schon vermutet hast reagiert der 3.Servo etwas rauer. Ich habe auch festgestellt, dass es aber sehr abhängig vom Servotyp ist.
Im Moment verwende ich nur analoge Servos, ich werde morgen noch einen digitalen Servo ausprobieren.
Was mir aufgefallen ist, dass die Servogeschwindigkeit sehr linear ist; Ganz habe ich es auch noch nicht verstanden, wie ich hier eine eher exponentiellere Kennlinie fahren könnte.
Damit meine ich bei kleineren Ausschlägen ein schnelleres Ansprechverhalten.
Dann hätte ich noch eine Verständnisfrage, ganz ist mir noch nicht klar warum die Rechenzeit 8µs beträgt. Wodurch wird dies bestimmt, durch den Timer 1?
Das Problem mit der externen Stromversorgung lag übrigens an einem zu schwachen Netzteil, welches zwar mit 5Volt bezeichnet ist, 8Volt anzeigt unbelastet, aber durch den Spannugnswandler auf dem IO Board nur irgendwas mit 4.2V liefert. Ein 12V Netzteil brachte die Lösung :-)
Aber ansonsten funktioniert es sehr sehr gut. Habe noch ein wenig mit den Werten hier und da gespielt, aber meistens habe ich es verschlimmbessert :-) Wie immer:-)
Ich mach mich morgen noch daran, den Deltabetrieb, d.h. Umschaltung auf Kettenantrieb einzuarbeiten, damit das auch wieder funktioniert.
Mal sehen wie ich das mit den Potis gedeichselt bekomme, denke das werde ich rausmachen, da ein Code schneller gebaut ist, als mit den Potis rumspielen.
Dann fehlt noch das Einschalten von LEDs, dann gehts an den Umbau des Baggers. Der Umbau sollte eine schneller Sache sein, da hab ich eher Heimspiel :-)
VG
Thomas
Meinst Du diese 8µs?
Die 8µs kommen vom Timer0. Der läuft ja durch seinen Prescaler von 64 mit 125000Hz. 1/125000Hz = 8µs.Zitat:
Zitat von Searcher
Alle 8µs schaltet der Timer also einen Schritt weiter - erhöht sein Register TCNT0 um eins weiter bis 255 wo es dann beim nächsten Schritt auf 0 gesetzt wird (überläuft) und ab da wieder den Berg rauf schreitet. Weil er damit die Zeiten für die Pulsbreite der Servos macht, kann die Pulsbreite nur in Schritten mit 8µs verändert werden. Puls kann also ein Vielfaches von 8 lang sein (8µs, 16µs, 32µs ....) aber nicht 5µs, 17µs etc. Wenn also Berechnung_3a um eins verändert wird, wird die Pulslänge von Servo3 um 8µs, eben die kleinst mögliche für Timer0 abmeßbare Zeiteinheit, verändert. *keuch* *lufthol*
Ich sollte nicht soviel schreiben. Je mehr man schreibt, desto mehr Mist kann dabei rauskommen :)
Also allgemein bekommt ein Servo eine Sollposition durch die Pulsbreite seine Servosignals mitgeteilt. Das Servo versucht nun mithilfe seiner eingebauten Elektronik und dessen Eigenschaften die Sollposition so schnell wie möglich zu erreichen. (Da gibt es schon Unterschiede zwischen den verschiedenen Typen)
Um den Lauf des Servos von "außen", also durch das Programm zu verlangsamen wird nicht die Endsollposition übermittelt, sondern eine Pulsweite, die nur wenig von der vorherigen abweicht. Das Servo fährt also nicht zur Endposition siondern ein kleines Stück dorthin (In unserem Fall ein Stück, daß eine 8µs Pulsweitenveränderung ausmacht). Nach einer Weile wird die Pulsweite wieder ein Stück in Richtung Endsollweite verändert - das Servo macht wieder einen kleinen Schritt. Die Geschwindigkeit des Servos hängt also von diesen "Weilen" ab, die zwischen den Pulsweitenveränderungen in Richtung Sollpulsweite liegt.
Die "Weile" also die Zeit, die zwischen den Veränderungen vergeht, wird hier mit Timer1 bzw Timer2 bestimmt. Jedesmal, wenn die Zeit abgelaufen ist (Das Interruptflag steht) wird zB Berechnung_3a verändert.
Man könnte sich auch andere Methoden einfallen lassen. Ich meine, es gab mal zu Beginn des threads, eine bzw mehrere Variablen, die immer mit jedem Durchlauf der Hauptschleife hochgezählt wurden und bei einem bestimmten Wert ein Servo ein Stück weitergeschaltet hatten. Damit könnte man Servo3 wieder weniger "rauh" bekommen. Oder sich andere Methoden einfallen lassen ....
Exponetielle Geschwindigkeitsverläufe oder Rampen - Gehirnschmalz zum Erzeugen der Zeiten zwischen den Servoimpulsveränderungen stecken. Ich kann aber heute und demnächst vermutlich nicht :lol: :lol: :lol:
Genau, erstmal die Basis schaffen, ich bin beim Daumen drücken.Zitat:
Ich mach mich morgen noch daran, den Deltabetrieb, d.h. Umschaltung auf Kettenantrieb einzuarbeiten, damit das auch wieder funktioniert.
Mal sehen wie ich das mit den Potis gedeichselt bekomme, denke das werde ich rausmachen, da ein Code schneller gebaut ist, als mit den Potis rumspielen.
Dann fehlt noch das Einschalten von LEDs, dann gehts an den Umbau des Baggers. Der Umbau sollte eine schneller Sache sein, da hab ich eher Heimspiel :-)
Gruß
Searcher
Hallo Fachleute
Ich nutze den Code von #64 auf einem Arduino nano, das Programm funktioniert einwandfrei!!
Ich möchte nun wenn der Baggerarm Servo gegen einen Taster fährt das Servo Stoppen und erst bei einem Richtungswechsel des Fernsteuer Signales das Servo wieder freigeben.
(evtl. könnte man mit einem Transistor den Plusspannung des Servos unterbrechen oder gibt es noch bessere Möglichkeiten??)
Für eine Antwort möchte ich mich jetzt schon Bedanken !
Ich entschuldige mich dafür, dass ich seit Jahren nicht mehr hier war. :(
Auch wenn es für eine Antwort auf die Frage von pocketpcuser schon einige Jahre zu spät ist, antworte ich trotzdem (vielleicht sucht ja mal jemand anderes nach genau dieser Lösung).
Einem Servo die Betriebsspannung zu nehmen ist keine gute Idee. Das Servo verliert seine Haltekraft. Zudem reagieren manche Servos sehr nachtragend, wenn die Versorgungsspannung wegfällt, aber die Impulse des Empfängers weiter anliegen.
Im Code wäre es recht einfach gewesen, einen Endschalter für ein bestimmes Servo zu integrieren. In den Zeilen 299 bis 334 werden unter anderem die Servostellungen berechnet. Dies passiert mit den Zeilen:
In diesen Zeilen wird die jeweilige Stellung von Servo 1 oder Servo 2 nach rechts oder links verschoben.Code:Decr Berechnung_1a
Incr Berechnung_1a
Decr Berechnung_2a
Incr Berechnung_2a
Wenn nun z.B. die Linksbewegung des Servos 1 mit einem Endschalter begrenzt werden soll, liese sich das mit lediglich 3 Programmzeilen bewerkstelligen.
Vor der Hauptschleife den Endschalter einrichten mittels:
Code:Endschalter Alias Pinx.y ' Pin festlegen, an dem der Endschalter angeschlossen wird
Portx.y = 1 ' PullUp an dem Pin einschalten
Im jeweiligen Berechnungsblock (abhängig von Servo und Richtung) dann z.B. folgende Änderung durchführen:
Code:' Decr Berechnung_1a <--- diese Zeile ersetzen durch...
If Endschalter = 1 then Decr Berechnung_1a ' Nur ausführen, wenn Endschalter nicht betätigt ist
Nun würde das Servo nur solange in die entsprechende Richtung bewegt werden können, solange der Endschalter (oder besser gesagt der EndTASTER) nicht betätigt ist.
Sobald der Baggerarm den Taster betätigt (am Endschalter-Pin liegt dann Masse an), würde die Variable "Berechnung_1a" nicht mehr weiter decreased -> Das Servo bleibt stehen.
Danke für Die INFO.
Auf diese Lösung bin ich dann auch gekommen.