![]() ![]() INFO - FAQ - CC2-Forum - CCPro-Forum |
|
Hallo, nachdem ich im Forum mir immer mal wieder nützliche Tips und Tricks geholt habe möchte ich euch mal mein kleines Programm für eine Servosteuerung für bis zu acht Servos vorstellen. Endstanden ist das ganze eigentlich daraus, dass ich meine im Aufbau befindliche Modellbahnanlage über ein PC-Programm in Verbindung mit mehreren Open-Mini/Midi/Macro steuern und abwechslungsreicher gestalten möchte. Die Servosteuerung benötige ich um die "Weichen" von Autokreuzungen zu schalten, ein par Türen zu öffnen/schließen und noch so'n par Gimmigs, einfach um mehr Leben reinzubringen. Ihr benötigt dazu eine Open-Macro, die habe ich gewählt weil ich durch die "Word"-Variablen die Servos, je nach Typ und Drehwinkel bis in ihre Endlagen und einer "theoretischen" Auflösung von bis zu 700-800 Schritten betreiben kann! Leider erfolgt die Ansteuerung von einen, oder mehreren Servos parallel, immer nacheinander, vieleicht hat ja jemand von euch eine Idee wie man unterschiedliche Servos unabhängig positionieren kann. Auch für weitere Anregungen, Fragen und Tips wäre ich euch dankbar, und vor allen ob das Programm auch bei euch läuft. Hier der Quellcode von "ServoansteuerungV1.bas": ' ' Servoansteuerung V1 von bis zu 8 Servos durch Open-Makro ' von Olaf Stermann ' Beginn: 18.05.2010 ' Stand: 24.05.2010 ' ' Beschreibung: ' 8 Servos können über Port9 bis Port16 angesteuert werden. ' Durch die neue Open-Makro (Wordverarbeitung) können die Servos über ' ihren vollen Stellbereich genutzt werden (ausprobieren), ' siehe weitere Beschreibungen in "servov1.iia". ' ' Die Auswahl des Servos erfolgt über ein Bit: Servo1=ON ' Soll der Servo nicht mehr positioniert dann: Servo1=OFF ' Es ist auch möglich mehrere Servos zusammen zu positionieren. ' ' Befehl 1: ServoPositionAbsolut(aaa,bbb) ' aaa = Position (WORD); Bereich ca. 200(Links)-1100(Rechts) je nach Servo ' bbb = Anzahl der Pulse (BYTE); ' Einfache Positionierung auf eine Position. ' Signaldauer = bbb*20ms ' ' Befehl 2: ServoPositionBewegung(aaa,bbb,ccc,ddd) ' aaa = Startposition (WORD); Werte siehe Befehl 1: aaa ' bbb = Zielposition (WORD); Werte siehe Befehl 1: aaa ' ccc = Positionsänderung (BYTE); ' ddd = Anzahl der Pulse (BYTE) pro Positionsänderung ' Positionierung von aaa nach bbb, dabei it es egal ob von links nach ' rechts oder umgekehrt, die Auswertung erfolgt in "servov1.iia". ' Berechnung Signaldauer: ' Signaldauer=((bbb-aaa)/ccc)*ddd*20ms ' Bsp.: ServoPositionBewegung(250,1050,8,5) ' Signaldauer = ((1050-250)/8)*5*20ms = ca. 10 Sekunden ' ' --------------------------------------------------------------------------- 'INCLUDE "om.def" 'Definitionen fuer Open-Micro und Open-Mini 'INCLUDE "omid.def" 'Definitionen fuer Open-Midi INCLUDE "omac.def" 'Definitionen fuer Open-Makro ' --------------------------------------------------------------------------- ' --------------------------------------------------------------------------- ' Definition der Ports der OM ' --------------------------------------------------------------------------- 'define RS232 Port[1] ' RS232-Port 'define RS232_DCD Port[2] ' Datenempfang für PC-Programm aktivieren 'define nc Port[3] ' nicht benutzt 'define RS232_RTS Port[4] ' Datenempfang PC-Programm bereit 'define nc Port[5] ' Bustakt für Daten 'define nc Port[6] ' Datenleitung 'define Servo1 Port[9] ' wird in "ServoV1.iia" definiert 'define Servo2 Port[10] ' wird in "ServoV1.iia" definiert 'define Servo3 Port[11] ' wird in "ServoV1.iia" definiert 'define Servo4 Port[12] ' wird in "ServoV1.iia" definiert 'define Servo5 Port[13] ' wird in "ServoV1.iia" definiert 'define Servo6 Port[14] ' wird in "ServoV1.iia" definiert 'define Servo7 Port[15] ' wird in "ServoV1.iia" definiert 'define Servo8 Port[16] ' wird in "ServoV1.iia" definiert ' --------------------------------------------------------------------------- ' --------------------------------------------------------------------------- ' Definition der Allgemeinen Variabeln ' --------------------------------------------------------------------------- define Servo_Ports_aktive BYTE define Servo1 BIT[1] of Servo_Ports_aktive ' Servo aktivieren define Servo2 BIT[2] of Servo_Ports_aktive ' Servo aktivieren define Servo3 BIT[3] of Servo_Ports_aktive ' Servo aktivieren define Servo4 BIT[4] of Servo_Ports_aktive ' Servo aktivieren define Servo5 BIT[5] of Servo_Ports_aktive ' Servo aktivieren define Servo6 BIT[6] of Servo_Ports_aktive ' Servo aktivieren define Servo7 BIT[7] of Servo_Ports_aktive ' Servo aktivieren define Servo8 BIT[8] of Servo_Ports_aktive ' Servo aktivieren ' --------------------------------------------------------------------------- ' Die Servoroutinen einbinden ' --------------------------------------------------------------------------- INCLUDE "servov1.iia" ' --------------------------------------------------------------------------- ' Das Hauptprogramm ' --------------------------------------------------------------------------- Servo_Ports_aktive=0 'alle Servoports aus InitServo 'Initialisierung der Ports pause 50 #main #Hauptprogramm Servo2=on 'Servo 2 an '------------------------------------------------------------- ' Test: Graupner Servo C507 ' Ermittelte Werte durch Versuche: ' Links=ca.250; Mitte=ca.650; Rechts=ca.1050. ' Drehbewegung = ca.190°. ' Theoretische Auflösung=ca.0,2375°. ' Gemessene Dauer für die Positionsimpulse: ' Links=ca.0,66ms/Mitte=ca.1,66ms/ Rechts=ca.2,66ms '------------------------------------------------------------- 'Mittelstellung: ServoPositionAbsolut(650,20) pause 50 'Linksanschlag: ServoPositionAbsolut(250,20) pause 50 'Mittelstellung: ServoPositionAbsolut(650,20) pause 50 'Rechtsanschlag: ServoPositionAbsolut(1050,20) pause 50 'Bewegung von Rechts nach links (Dauer ca. 2,5s): ServoPositionBewegung(1050,250,8,1) pause 50 'Takten von Links nach Rechts um ca.2° mit Pause von ca.100ms: ServoPositionBewegung(250,1050,8,5) pause 50 ' Fazit: Graupner Servo C507 ' Praktische minimale Auflösung=ca.0,5°-1°, ' da doch bei längerer Taktzeit(Position halten) ein ' leichtes ruckeln im Servo zu spüren ist. '------------------------------------------------------------- 'Servoauswahl: endweder so.... Servo2=off Servo1=on Servo3=on '....oder auch so möglich 'Servo_Ports_aktive=&b00000101 '------------------------------------------------------------- ' Test: Conrad "Billig" Servo von Prafa ' Ermittelte Werte durch Versuche: ' Links=ca.200; Mitte=ca.580; Rechts=ca.960. ' Drehbewegung = ca.185°. ' Theoretische Auflösung = ca.0,2434°. ' Gemessene Dauer für die Positionsimpulse: ' Links=ca.0,53ms/Mitte=ca.1,49ms/ Rechts=ca.2,42ms ' 'Mittelstellung: ServoPositionAbsolut(580,20) pause 50 'Linksanschlag: ServoPositionAbsolut(200,20) pause 50 'Mittelstellung: ServoPositionAbsolut(580,20) pause 50 'Rechtsanschlag: ServoPositionAbsolut(960,20) pause 50 'Bewegung von Rechts nach links (Dauer ca. 2,5s): ServoPositionBewegung(960,200,8,1) pause 50 'Takten von Links nach Rechts um ca.2° mit Pause von ca.100ms: ServoPositionBewegung(200,960,8,5) pause 50 ' Fazit: Conrad "Billig" Servo von Prafa ' Praktische minimale Auflösung=ca.0,5°-1°, ' da doch bei längerer Taktzeit(Position halten) ein ganz ' leichtes ruckeln im Servo zu spüren ist, aber weniger ' als beim Graupner Servo (billigere Bauteile???). '------------------------------------------------------------- Servo1=off Servo3=off 'so kann auch verfahren werden, aber es entstehen kurze 'Aussetzer mit rucklern am Servo 'while ServoHighSignal<960 'ServoHighSignal=ServoHighSignal+20 'ServoPositionAbsolut(ServoHighSignal,4) 'wend goto Hauptprogramm END ' --------------------------------------------------------------------------- ' Die Firmware-Routinen einbinden ' --------------------------------------------------------------------------- 'INCLUDE "OM_FW.pro" und hier der Quellcode von dem eingebundenen Assemblerteil "servov1.iia": ' Assemblermodul: ' Servoansteuerung V1 für 8 Servos über Port 9 bis Port 16 der Open-Macro ' von Olaf Stermann ' Beginn: 18.05.2010 ' Stand: 24.05.2010 ' ' 18.05.2010: ' Erste Puls-/Pausenverhältnisse getestet (Testport=Port[9]). ' Ermittlung der Dauer des 20ms Positionsignals mit OSZI: Puls+Pause=8000. ' Die Pause wird durch "8000-Puls=Pause" gebildet. ' 19.05.2010: ' Testweise mal mit ein par Werten für den Puls (Positionssignal) ' experimentiert und an unterschiedlichen Servos getestet: ' 1. Es ist nicht so kritisch das, dass gesamte Signal genau 20ms haben muß. ' +/- 2 bis 5ms interessieren meist überhaupt nicht, also nicht kritisch. ' 2. Auch die eigentlich "definierten" 1ms bis 2ms Pulsdauer sehen die ' Hersteller nicht so eng. Bei meinen Tests konnte ich bis zu 0,5ms ' für den Linksanschlag und bis zu 2,7ms für den Rechtsanschlag ' messen, dadurch ist es möglich den Servo bis in die Grenzen zu drehen!! ' 21.05.2010: ' Den Positionierbefehl in Positionspuls inkl. der Pause in Takten zerlegt, ' dadurch kann durch einen Aufruf mit der Position und durch die Takte ' die Dauer zur Ansteuerung des Servos festgelegt werden: ' Ansteuerdauer Servo = Takte*Positionssignal(20ms). Die Takte müssen ' so gewählt werden das der Servo seine Position erreicht. ' 22.05.2010: ' Aus meinen Programm für die Infrarotsteuerung des DC-Car-System ' habe ich die Portansteuerung von Port9 bis Port16 übernommen. ' Invertierte Servoports (Invert_Servo_PORT) von "Servo_Ports_aktive" ' eingebunden, somit lassen sich bis zu acht gleiche Servos gleichzeitig ' ansteuern. Es muss jetzt nur noch das entsprechende Servobit von ' "Servo_Ports_aktive" gesetzt werden um den Servo anzusteuern. ' Das setzt natürlich mindesten zwei gleiche Servos mit den ' selben Werten vorraus (Bahnschrankensteuerung,Tür- oder Torsteuerung, ein ' par Bäume umfallen lassen, usw.). ' 23.05.2010: ' Positionssteuerung von X nach Y eingebaut. Die Geschwindigkeit wird ' über die Änderung der Pulslänge und der Anzahl der Takte gebildet. ' So ist quasi eine Geschwindigkeitssteuerung möglich, aber die Werte ' müssen halt ausprobiert werden. Mit verschiedenen Kombinationen ist ' es möglich eine fast Ruckfreie Positionierung des Servos hinzubekommen. ' ' Einschränkungen: ' Leider kann immer nur ein Befehl nacheinander abgearbeitet werden. ' Vieleicht ist es möglich mehrere Servos gleichzeitig unterschiedlich ' zu positionieren (Interruptsteuerung???). ' -------------------------------------------------------------------------- ' -------------------------------------------------------------------------- ' Ports definieren 'DEFINE Servo1 bPTB0 'PTB1 = PORT[9] 'DEFINE Servo2 bPTB1 'PTB2 = PORT[10] 'DEFINE Servo3 bPTB2 'PTB3 = PORT[11] 'DEFINE Servo4 bPTB3 'PTB4 = PORT[12] 'DEFINE Servo5 bPTB4 'PTB5 = PORT[13] 'DEFINE Servo6 bPTB5 'PTB6 = PORT[14] 'DEFINE Servo7 bPTB6 'PTB7 = PORT[15] 'DEFINE Servo8 bPTB7 'PTB8 = PORT[16] DEFINE ServoPORT PTB 'PORTB = BYTEPORT[2] 'EIN/AUS DEFINE ServoDDR DDRB 'DDRB = BYTEPORT[2] 'Richtung ' -------------------------------------------------------------------------- ' Variablen definieren DIM Invert_Servo_PORT BYTE 'Invertierter Servoport für High-Signal DIM ServoTakt BYTE 'Takt=Dauer des Signals (Takt*20ms) DIM ServoTaktZaehler BYTE 'für Abarbeitung des Taktes DIM ServoHighSignal WORD 'Position des Servos DIM ServoLowSignal WORD 'Dauer der Pause DIM StartPos WORD 'Startposition für Bewegung DIM ZielPos WORD 'Zielposition für Bewegung DIM ServoGsw WORD 'Ist eigentlich die Änderung von "ServoHighSignal" DIM ServoGswL BYTE[1] of ServoGsw 'LOW-Byte von "ServoGswL" als Zähler, um 'die Änderung von "ServoHighSignal" zu 'Berechnen DIM ServoRichtung BYTE 'In welche Richtung der Servo dreht bei Bewegung. 'geht sicher auch einfacher ' -------------------------------------------------------------------------- ' Servopositionssignal an den Servoport bilden PROCEDURE ServoPositionsSignal(ZielPos) INLASM #ServoSTART ! lda ServoTakt 'die Taktzyklen (Signaldauer) laden ! sta ServoTaktZaehler 'und als Zähler speichern #ServoPositionBeginn 'Beginn des Signals ! lda Invert_Servo_PORT 'aktivierte Servoports laden; Signal=HIGH ! sta ServoPORT 'und hier setzen '! bset Servo1,ServoPORT 'war zum testen an PORT9 ! nsa 'kleine Pause ! ldhx ServoHighSignal 'die Dauer des HIGH-Impulses laden ! bsr Servo_Verzoegerung 'und in "Servo_Verzoegerung" abarbeiten ! lda #&b00000000 'Alle Servos wieder auf OFF ! sta ServoPORT 'und hier setzen '! bclr Servo1,ServoPORT 'war zum testen an PORT9 ! nsa 'kleine Pause ! ldhx ServoLowSignal 'die Dauer der Pause laden ! bsr Servo_Verzoegerung 'und in "Servo_Verzoegerung" abarbeiten ! dec ServoTaktZaehler 'die Taktzyklen um 1 verringern ! bne ServoPositionBeginn 'wenn >1 dann zurück zu "ServoPositionBeginn" '__________________________________________________________________________ 'Bei Absolutpositionierung ist die Zielposition gleich der Sollposition, 'deswegen erfolgt kein Aufruf der Servobewegung! ! ldhx ServoHighSignal 'Hier das HIGH-Signal (Position) mit der ! cphx ZielPos 'Zielposition vergleichen ! bne ServoBewegung 'nicht im Ziel (Bewegung) "Servo_Verzoegerung" '__________________________________________________________________________ #ServoENDE 'Ablaufende ! rts 'ENDE und zurück #Servo_Verzoegerung 'Hier ist die Verzögerung ! aix #-1 'Verzögerung -1 ! cphx #0 'Vergleich auf 0 ! bne Servo_Verzoegerung 'nicht 0 dann nochmal "Servo_Verzoegerung" ! rts 'zurück zum Aufruf '........................................................................... ' Servobewegung von X nach Y #ServoBewegung ! lda ServoRichtung 'Positionierrichtung laden ! cmp #0 'und vergleichen ! beq ServoLinks 'wenn 0 dann "ServoLinks" (nach Links) 'sonst..... ! lda ServoGswL '.....die Solländerung als Schleifenzähler laden.... #ServoRechts 'Drehrichtung nach Rechts ! ldhx ServoHighSignal 'Puls laden ! aix #1 '+1 ! sthx ServoHighSignal 'Puls speichern ! dbnza ServoRechts 'Schleifenzähler verringern. Wenn gleich NULL dann ! bra ServoLinksEnde 'Drehrichtung nach Links überspringen #ServoLinks 'hier gehts nach links ! lda ServoGswL '.....die Solländerung als Schleifenzähler laden..... #ServoLinks_1 'Drehrichtung nach Links ! ldhx ServoHighSignal 'Puls laden ! aix #-1 '-1 ! sthx ServoHighSignal 'Puls speichern ! dbnza ServoLinks_1 'Schleifenzähler verringern. Wenn gleich NULL dann #ServoLinksEnde 'Ende der Pulsberechnung ! ldhx #7800 'Gesamtdauer Puls laden (hier weniger da Berechnung) ! sub ServoHighSignal 'den Puls abziehen ! sthx ServoLowSignal 'und in die Pause laden ! bra ServoSTART 'wieder zurück "ServoSTART" ! rts 'ENDE END PROCEDURE ' -------------------------------------------------------------------------- ' Servos Initialisieren PROCEDURE InitServo INLASM ! lda #&b00000000 'Alles auf LOW ! sta ServoPORT 'Alle Servoports auf LOW ! lda #&b11111111 'Alle Servoports aktivieren ! sta ServoDDR 'Alle Servoports auf Ausgang und LOW ! lda #&b11111111 'Bitmuster alle ON laden und ! and Servo_Ports_aktive 'mit "Servo_Ports_aktive" invertieren (ON=OFF/OFF=ON) ! sta Invert_Servo_PORT 'und in "Invert_Servo_PORT" abspeichern, Signal=ON ! nsa 'warten... ! nsa 'warten... ! nsa 'warten... ! rts 'Zurück END PROCEDURE ' -------------------------------------------------------------------------- ' Servosteuerung absolut (Position,Impulsanzahl) PROCEDURE ServoPositionAbsolut(ServoHighSignal,ServoTakt) ServoLowSignal=8000-ServoHighSignal 'Pause berechnen und schon mal eintragen ZielPos=ServoHighSignal 'Zielposition auf Positionspuls setzen SYS InitServo 'Initialisierung der Servoports alle auf 0 SYS ServoPositionsSignal(ZielPos) 'Servosignal abarbeiten SYS InitServo 'wieder alle Servoports auf 0 RETURN END PROCEDURE ' -------------------------------------------------------------------------- ' Servosteuerung Bewegung von (Start,Ziel,Wegänderung,Impulsanzahl) PROCEDURE ServoPositionBewegung(StartPos,ZielPos,ServoGsw,ServoTakt) 'Auswertung der Richtung durchführen if StartPos>=ZielPos then 'Start>Ziel dann 'hier die Startposition neu berechnen, durch die innere 'Berechnung "..(StartPos-ZielPos)/ServoGsw.." werden die Kommawerte 'abgeschnitten, dadurch wird die neue Startposition zu einen glatten 'Wert der sich im Ablauf mit der Zielposition auf "GLEICH" auswerten lässt! StartPos=ZielPos+(((StartPos-ZielPos)/ServoGsw)*ServoGsw) ServoRichtung=0 '=negativ Zählen else 'Start<Ziel dann 'wie bei Start>Ziel StartPos=ZielPos-(((ZielPos-StartPos)/ServoGsw)*ServoGsw) ServoRichtung=1 '=positiv Zählen end if ServoHighSignal=StartPos 'Positionspuls eintragen ServoLowSignal=8000-StartPos '1.Pause berechnen und schon mal eintragen SYS InitServo 'Initialisierung der Servoports alle auf 0 SYS ServoPositionsSignal(ZielPos) 'Servosignal abarbeiten SYS InitServo 'wieder alle Servoports auf 0 RETURN END PROCEDURE Bitte gebt mal Rückmeldung, egal mit welchen Ergebnis! Viel Spass beim ausprobieren, Olaf |
Antwort schreiben |