|
Antwort |
Registriert seit: 9. Dez 2005 Ort: Kandel 408 Beiträge |
#31
Du bekommst damit niemals eine exakt diagonale Bewegung hin, du bewegst deine Achsen immer getrennt.
Noch dazu kommt: Der langsamste Motor bestimmt die Geschwindigkeit. Und die ist niemals die von dir erwartete. Der Grund: Du arbeitest blockierend und mit Verzögerung. Dafür habe ich meine Zeitscheiben. Geplant ist folgendes: Zu einer (linearen) Bewegung gibt es für jede Achse folgenden Datensatz: - Anzahl zu erledigender Schritte - Anzahl der zu wartenden Zeitscheiben zwischen zwei Schritten (Geschwindigkeitsfaktor) - Zeitscheibenzähler Jede Zeitscheibe wird der Zähler dekrementiert und dann geprüft, ob er null ist. Für alle Achsen, bei denen dies der Fall ist, werden getoggelt. Dann wird der Zähler wieder zurückgesetzt auf den Startwert, die Anzahl der zu erledigenden Schritte um eins reduziert, bis diese Anzahl schließlich bei null angekommen ist. Wenn alle Achsen ihre Zielposition erreicht haben, wird der nächste Job geladen. @RS232: Im Moment noch gar keine. Die Firmwareentwicklung steht im gerade im Vordergrund, sobald die Firmware so weit ist, dass sie ein Gegenstück braucht, entsteht dieses langsam. Google und die Suchfunze spucken aber diverse Möglichkeiten aus. mfG & Happy Coding Markus
Markus
|
Zitat |
Registriert seit: 7. Nov 2004 639 Beiträge |
#32
Zitat:
Du bekommst damit niemals eine exakt diagonale Bewegung hin, du bewegst deine Achsen immer getrennt.
Aber ist natürlich schon eine schlechte Lösung, das ist mir schon klar! Das mit den Zeitscheiben (=Timer?!) habe ich so halbwegs verstanden... aber diese 3 Zeitscheiben-Prozeduren müssen doch genau gleichzeitig ausgeführt werden, da bräuchte es doch Threads?! Das begreife ich irgendwie nicht. Du kannst ja auch nicht bei allen 3 Schrittmotoren exakt im gleichen Moment einen Schritt ausführen oder, eine minimale Verzögerung zwischendrin hast du doch immer? Naja...also sobald du mal ein bisschen Code zum angucken hast, wäre ich sehr froh wenn du den mal posten könntest. Ich denke, ich probiere jetzt auch mal mit den Übertragungsroutinen zu beginnen. Wenn ich grad Zeit habe schaue ich auch mal wie die Timer so funktionieren... Zur RS232: Jo hab da schon paar Sachen gefunden, ich verwendete bisher eine Komponente dafür (TApdComPort). Da gibts dann ein PutChar(), PutString() und ein PutBlock(Word). Bräuchte ich da wohl PutBlock (genügt ein Word für das ganze Telegramm)? mfg Urban |
Zitat |
Registriert seit: 9. Dez 2005 Ort: Kandel 408 Beiträge |
#33
Mir ist dieser Beitrag im Forum aufgefallen, diese Form der Ansteuerung schaut doch ganz nett aus, oder?
Zur "gleichzeitigen" Ansteuerung: Der Trick besteht darin, dass ich erst berechne, welche Motoren bewegt werden müssen. Diese sind bei mir alle am PortB angeschlossen, ich kann also mit einer einzigen Zuweisung alle nötigen Pins toggeln. Wie du bereits erraten hast, findet dieser Teil komplett in der Timer-ISR statt. Ich hatte mir zuerst Gedanken über die Programmstruktur gemacht und dann mit den Bresenham-Routinen angefangen. Daraufhin habe ich das Kommunikationsprotokoll und die dazugehörigen Routinen so entworfen, dass alle anderen (zu diesem Zeitpunkt ja noch nicht existenten) Module damit arbeiten können. Im Moment optimiere ich meine Bresenham-Berechnungen "etwas", bei Kreisen mit einem Radius von weniger als ~30000 Schritten schafft der µC ~65k Punkte + Fifo-Zuweisung in einer Sekunde, allerdings ohne Positionskontrolle. Als nächstes kommt dann vermutlich zuerst einmal das Motor-Management oder der G-Code-Interpreter, das muss ich erst noch sehen. Das wird dann vermutlich auch der Teil der für dich interessanter ist. mfG Markus
Markus
|
Zitat |
Registriert seit: 7. Nov 2004 639 Beiträge |
#34
okay, ich hab mal was zusammengekritzelt...
Delphi-Quellcode:
hast du dir das in ungefähr so vorgestellt?
var
Befehl_vorhanden, Maschine_Bereit: boolean; Schritte_X, Schritte_Y, Schritte_Z, Geschwindigkeitsfaktor_X, Geschwindigkeitsfaktor_Y, Geschwindigkeitsfaktor_Z, GF_Down_X, GF_Down_Y, GF_Down_Z: Integer; procedure main; // die Hauptprozedur des Programmes begin Alles_Initialisieren; // z.B. die Serielle Schnittstelle initialisieren, Pins auf Ausgang schalten usw. begin Endlosschleife // Läuft ewigs durch, hört nie auf =) RS232_Senden_Empfangen; // Siehe weiter unten if Befehl_Vorhanden and Maschine_Bereit then // Wenn ein Befehl vorhanden ist und kein Fräsvorgang in arbeit ist... Befehl_auswerten; // ...wird der Befehl ausgewertet (siehe weiter unten) end; end; procedure RS232_Senden_Empfangen; begin Buffer_mit_Empfangsdaten_füllen; // Was in der Zwischenzeit empfangen wurde, wird in den Buffer geladen If Buffer_voll then // wenn der Buffer voll ist... Sende_Wartebefehl_an_PC; //... wird dem PC mitgeteilt dass er warten muss mit der Übermittlung If Buffer_leer then // Wenn der Buffer leer ist... begin Befehl_vorhanden := false; // Wird die Variable auf false gesetzt... Sende_Bereit_an_PC; // ...und dem PC mitgeiteilt dass er wieder Daten senden soll end else Befehl_vorhanden := true; // Wenn der Buffer nicht leer ist, wird die Variable auf true gesetzt end; procedure Befehl_auswerten; // Wertet den Empfangenen Befehl aus begin Buffer_auslesen; // Der Empfangsfuffer der RS232 wird ausgelesen Buffer_splitten(Startbyte, Message_Size, Command_Byte, Payload, Command_Byte, Checksumme, Stopbyte); // Das Telegramm wird in die einzelnen bestandteile zerlegt // Startbyte usw überprüfen... Case Command_Byte of // Wenn der Befehl... Kalibrieren: Prozedur_Kalibrieren(Payload); // ...eine Kalibrierung ankündigt, wird diese ausgeführt G-Code: Run_G-Code(Payload); //...ein G-Code ankündigt, wird dieser weiterverarbeitet End; end; procedure Run_G-Code(Payload: G-Code); // Der Empfangene G-Code wird verarbeitet begin Befehl_auslesen; // Liest aus dem Payload heraus, ob M0, M1, G00, G01 usw. Case Payload.Befehl of // Enthält "M0", "G00" usw. M0: ... ; M1: ... ; ... G00: Fahre_Zu_Position(Payload.X, Payload.Y, Payload.Z, schnell); // Die Fräse muss schnell an die angekündigte Position fahren G01: Fahre_Zu_Position(Payload.X, Payload.Y, Payload.Z, schnell); // Die Fräse muss an die angekündigte Position fahren ... end; end; procedure Fahre_Zu_Position(X, Y, Z, Geschwindigkeit); // Die Position X, Y, Z wird mit der entsprechenden Geschwindigkeit angefahren begin Maschine_Bereit := false; // Damit Keine zweite Befehlsauswertung stattfinden kann Schritte_X := X - Istposition_X; // Die Differenz zwischen Soll- und Istposition ermitteln Schritte_Y := Y - Istposition_Y; Schritte_Z := Z - Istposition_Z; Geschwindigkeitsfaktor_X_berechnen; // Die Wartezeit zwischen den einzelnen Pins ein-/ausschalten berechnen Geschwindigkeitsfaktor_Y_berechnen; Geschwindigkeitsfaktor_Z_berechnen; GF_Down_X := Geschwindigkeitsfaktor_X; // Variable setzten GF_Down_Y := Geschwindigkeitsfaktor_Y; GF_Down_Z := Geschwindigkeitsfaktor_Z; timer_X_Intervall := Geschwindigkeit; // Den Intervall für die Geschwindigkeit timer_Y_Intervall := Geschwindigkeit; timer_Z_Intervall := Geschwindigkeit; timer_X_aktivieren; // Die Timer werden aktiviert timer_Y_aktivieren; timer_Z_aktivieren; end; procedure Timer_x; // 3 Mal das "selbe" für X, Y, Z) begin GF_Down_X := GF_Down_X - 1; // Die Wartezeit wird immer eines weniger if GF_Down_X = 0 then // Wenn die Wartezeit gleich Null ist... begin If Pin_Ein then // ...Wird der Takt-Pin getoggelt Pin_aus else Pin_ein; GF_Down_X := Geschwindigkeitsfaktor_X; // ...wird die Wartezeit wieder heraufgesetzt Schritte_X := Schritte_X - 1; // ...wird die Anzahl zu erledigender Schritte verringert If Schritte_X = 0 then // Wenn alle Schritte ausgeführt wurden... begin Timer_X_deaktivieren; // ...wird der Timer_X deaktiviert If (Schritte_Y = 0) and (Schritte_Z = 0) then //...und wenn alle Schritte (X, Y, Z) ausgeführt wurden... Maschine_Bereit := true; //...wird die Bereitschaft auf true gestellt damit der nächste Befehl verarbeitet werden kann end; end; end; Soll natürlich nur den Ablauf darstellen, ich programmier den µC natürlich nicht in Delphi^^ mfg Urban |
Zitat |
Registriert seit: 9. Dez 2005 Ort: Kandel 408 Beiträge |
#35
Zitat von urbanbruhin:
okay, ich hab mal was zusammengekritzelt...
... hast du dir das in ungefähr so vorgestellt? Soll natürlich nur den Ablauf darstellen, ich programmier den µC natürlich nicht in Delphi^^ Für das Senden/Empfangen von Kommandos gibt es zwei FiFos und zwei Prozeduren. Die für das Senden erstellt das Kommandotelegramm an den PC und speichert es in den Fifo. Das Übertragen übernimmt (oh Überraschung) ein Interrupt, der beim Füllen des TX-Puffers aktiviert wird und bei leerem Puffer deaktiviert wird (Für alle Kenner: Es handelt sich um den UDRE-Interrupt (USART Data Register Empty)). Beim Empfangen ist es ähnlich, der Receive-Interrupt schaufelt die Daten in den Fifo und setzt intern verschiedene Warn-Flags für einen fast vollen oder vollen RX-Fifo. Die fürs Empfangen zuständige Prozedur tritt erst hier auf den Plan und wird in der Main-Schleife angepollt. Sie prüft Schritt für Schritt die ankommenden Bytes durch. Der Trick ist, dass nicht wie bei dir ein Kommando auf einmal ausgelesen wird, sondern es gibt eine Statusvariable für die verschiedenen Zustände. Die Zerlegung findet dann Schrittweise in einer State-Machine statt (Case-Selektor anhand der Statusvariable), wenn ein Schritt durch ist, schaltet er den nächsten aktiv. Die Dekodierung erfolgt deshalb schrittweise, weil in der Zwischenzeit sonst keine weiteren Punkte berechnet werden können. Dazu aber nun. Das war der Kommunikationsteil, nun die Auswertung und Ansteuerung. Für ankommende G-Codes gibt es bei der Kommando-Dekodierung im entsprechenden Schritt eine Subroutine, die den (vereinfachten) G-Code aus der Payload dann in die intern verwendete Struktur überführt und in einen G-Code-Fifo packt. Nach der Kommando-Dekodierung wird die G-Code-Dekodierung aufgerufen, die entweder einen G-Code dekodiert und in den Ansteuerungs-Fifo abspeichert, oder aber komplexe G-Codes (Kreis!) oder Steuerungs-G-Codes (u.a. die M-Befehle) direkt verarbeitet. Die Motorsteuerung selbst findet im bereits erklärten Timer-Interrupt statt und kann bereits von Natur aus Linien zeichnen, da zu jeder Achse die Parameter der zurückzulegenden Schritte sowie die Geschwindigkeit festgelegt werden. Das Verhältnis der Geschwindigkeiten zueinander bestimmt die Richtung der Linie, die Schrittzahl die Länge. Die Berechnung der Schritte findet ZUSAMMEN in einem Timer-Interrupt statt, dort werden dann die Pins gewackelt. Ist ein solcher Task abgearbeitet, wird der nächste Datensatz aus dem Ansteuerungs-Fifo geholt. Kreise werden "einfach" als Linien mit höchstens einem Schritt je Achse abgelegt, was zwar häufige FiFo-Operatinen zufolge hat, es aber ermöglicht, ein durchgängiges Konzept zu verwenden. Gleichzeitig erfordert es aber auch, dass die Kreisberechnungen, die nun in der Main-Schleife stattfinden, häufig genug den FiFo auffüllen können. Deshalb muss die Kommando-Dekodierung aufgeteilt werden, um den FiFo auf gar keine Fall leerlaufen zu lassen. Die Berechnung erfolgt also möglichst unabhängig von den Interrupts, die ISRs können relativ kurz bleiben, eine zeitnahe Reaktion ist so gewährleistet. mfG Markus
Markus
|
Zitat |
Registriert seit: 7. Nov 2004 639 Beiträge |
#36
okay, jetzt ist mir einiges klarer geworden
Zitat:
Nach der Kommando-Dekodierung wird die G-Code-Dekodierung aufgerufen, die entweder einen G-Code dekodiert und in den Ansteuerungs-Fifo abspeichert, oder aber komplexe G-Codes (Kreis!) oder Steuerungs-G-Codes (u.a. die M-Befehle) direkt verarbeitet.
Ausserdem kann ich mir unter dem FIFO in der Praxis noch nichts vorstellen... Benutzt du dafür eine Variable, ein Array? Oder wie sieht das aus? Und kann der Ansteuerungs-FIFO nicht überfüllt werden, wenn eine kreisberechnung ausgeführt wird? Werde später dann mal meinen "Code" nochmal überarbeiten, ich finde sowas irgendwie noch nützlich. Erstens ist es eine gute Vorlage wenn ich mit dem programmieren beginne, und zweitens kann ich ohne grosse Worte mitteilen wie ich mir den Ablauf vorstelle Ach ja, also bei der kommunikationsgeschichte komm ich noch nicht 100% nach, aber das liegt daran dass ich das Grundprinzip der seriellen Datenübertragung noch nicht ganz verstanden habe, also in welcher Form ich die Daten empfange usw. Werde mal schauen ob ich da was gutes zum lesen finde... Gruss Urban |
Zitat |
Registriert seit: 9. Dez 2005 Ort: Kandel 408 Beiträge |
#37
Zitat von urbanbruhin:
okay, jetzt ist mir einiges klarer geworden
Zitat:
Nach der Kommando-Dekodierung wird die G-Code-Dekodierung aufgerufen, die entweder einen G-Code dekodiert und in den Ansteuerungs-Fifo abspeichert, oder aber komplexe G-Codes (Kreis!) oder Steuerungs-G-Codes (u.a. die M-Befehle) direkt verarbeitet.
Tatsächlich ist es so, dass es verschiedene Steuerkommandos gibt, die sich verschiedenartig auswirken. Ein Wartezeitbefehl hindert mich nicht daran, schon das nächste Kommando vorzuberechnen, auch ein M3 (Frässpindel Drehrichtung Uhrzeigersinn einschalten) vermutlich nicht, je nach dem wo diese Kommandos interpretiert und umgesetzt werden, und ob eine serielle Abarbeitung garantiert ist. Unter Umständen muss der Interpreter seine Arbeit aber auch unterbrechen, z.Bsp. bei einem Werkzeugwechsel-Befehl (außer du hast das Geld, dir diese Mechanik einzubauen ). In diesem Falle steuern die Motoren ihre Zielposition an und gehen dann, mangels neuer Befehle, auf Standby. Klar ist auf jeden Fall, dass eine serielle Abarbeitung der G-Codes GARANTIERT sein muss.
Zitat von urbanbruhin:
Ausserdem kann ich mir unter dem FIFO in der Praxis noch nichts vorstellen...
Benutzt du dafür eine Variable, ein Array? Oder wie sieht das aus? Und kann der Ansteuerungs-FIFO nicht überfüllt werden, wenn eine kreisberechnung ausgeführt wird? Die praktische Umsetzung erfolgt anhand eines Lese- und eines Schreibzeigers, kommt ein Datensatz, wird er geschrieben und der Schreibzeiger eins erhöht. Zudem wird der Counter der die Anzahl der Bytes im Puffer angibt ebenfalls hochgezählt. Beim Auslesen wird das gelesen, worauf der Lesezeiger gerade zeigt, danach wird dieser eine Speicherstelle weitergeschoben und dann der Counter um eins runtergezählt. Erreicht einer der Zeiger das Ende des Arrays, wird er auf das erste Element zurückgesetzt. So kann man das Array unendlich lange mit Daten befüllen und wieder auslesen, man sollte nur darauf achten, dass man seine eigenen Daten nicht überschreibt oder liest wo es nichts gibt (dafür der Counter). Die Kreisberechnung wird natürlich nur aufgerufen, wenn der FiFo noch ausreichend Platz hat. Die Kreisberechnung liefert bei einem Aufruf immer den nächsten Punkt zurück, daraufhin muss dann noch geprüft werden, ob mit diesem Schritt das Ziel dann erreicht ist oder eben nicht. Meine FiFo-Implementation verhindert ferner ein Überlaufen, ist dieser voll wird ein false (0 bei C) zurückgegeben
Zitat von urbanbruhin:
Ach ja, also bei der kommunikationsgeschichte komm ich noch nicht 100% nach, aber das liegt daran dass ich das Grundprinzip der seriellen Datenübertragung noch nicht ganz verstanden habe, also in welcher Form ich die Daten empfange usw. Werde mal schauen ob ich da was gutes zum lesen finde...
Ein ATMega (also auch dein M128) hat einen zweistufigen Eingangspuffer. Der vor dir verborgene Teil enthält die Bits, die gerade empfangen werden. Sobald ein Byte "voll" ist, landet es im UDRn, dem USART Data Register n (wobei n beim Mega128 null oder eins sein kann, der M128 hat nämlich zwei USARTs). An dieser Stelle kann ein Interrupt aufgerufen werden, der die Daten in eine Variable deiner Wahl transportiert, oder du pollst deinen UART auf neue Daten und blockierst dabei die Ausführung anderer Dinge.
Markus
|
Zitat |
Registriert seit: 7. Nov 2004 639 Beiträge |
#38
also ich hab jetzt nochmal kurz an meinem "code" gearbeitet. fehlt natürlich noch sehr vieles, hab einfach mal angefangen den code abzuändern.
Delphi-Quellcode:
naja, ist bestimmt nocht nicht so wie du dir das vorstellst, aber ich geh jetzt erstmal schlafen^^
var
Befehl_vorhanden, Maschine_Bereit: boolean; Schritte_X, Schritte_Y, Schritte_Z, Geschwindigkeitsfaktor, GF_Down_X, GF_Down_Y, GF_Down_Z: Integer; Sende_FiFo, Empfangs_FiFo, G-Code_FiFo: Array; procedure main; // die Hauptprozedur des Programmes begin Alles_Initialisieren; // z.B. die Serielle Schnittstelle initialisieren, Pins auf Ausgang schalten usw. begin Endlosschleife // Läuft ewigs durch, hört nie auf =) If Empfangs_FiFo_leer then // Wenn der Buffer leer ist... begin Befehl_vorhanden := false; // Wird die Variable auf false gesetzt... RS232_Senden(Warte_auf_Befehl); // ...und dem PC mitgeiteilt dass er wieder Daten senden soll end else Befehl_vorhanden := true; // Wenn der Buffer nicht leer ist, wird die Variable auf true gesetzt If Empfangs_FiFo_voll then // wenn der Buffer voll ist... RS232_Senden(PC_muss_warten); //... wird dem PC mitgeteilt dass er warten muss mit der Übermittlung Befehl_auswerten; // ...wird der Befehl ausgewertet (siehe weiter unten) if Befehl_Vorhanden and Maschine_Bereit then // Wenn ein Befehl vorhanden ist und kein Fräsvorgang in arbeit ist... Run_G-Code; end; end; procedure RS232_Senden(Sendedaten); begin Sende_FiFo_mit_Sendedaten_füllen; // Was in der Zwischenzeit empfangen wurde, wird in den Buffer geladen // Der Sende_FiFo wird wieder geleert sobald die Übertragung per Interrupt stattgefunden hat end; procedure RS232_Empfangen; // Wird per Interrupt ausgelöst (Sobald etwas empfangen wird) begin Empfangs_FiFo_mit_Empfangsdaten_füllen; // Was in der Zwischenzeit empfangen wurde, wird in den Empfangs_FiFo geladen end; procedure Befehl_auswerten; // Wertet den Empfangenen Befehl aus begin Empfangs_FiFo_auslesen; // Der Empfangsfuffer der RS232 wird ausgelesen Empfangs_FiFo_splitten(Startbyte, Message_Size, Command_Byte, Payload, Command_Byte, Checksumme, Stopbyte); // Das Telegramm wird in die einzelnen bestandteile zerlegt // Startbyte usw überprüfen... Case Command_Byte of // Wenn der Befehl... Kalibrieren: Prozedur_Kalibrieren(Payload); // ...eine Kalibrierung ankündigt, wird diese ausgeführt G-Code: G-Code_FiFo_hinzufügen(Payload); //...ein G-Code ankündigt, wird dieser in den G-Code_FiFo geschrieben End; end; procedure Run_G-Code(G-Code); // Der Empfangene G-Code wird verarbeitet begin Befehl_auslesen; // Liest aus dem Payload heraus, ob M0, M1, G00, G01 usw. Case G-Code.Befehl of // Enthält "M0", "G00" usw. M0: ... ; M1: ... ; ... G00: Fahre_Zu_Position(Payload.X, Payload.Y, Payload.Z, schnell); // Die Fräse muss schnell an die angekündigte Position fahren G01: Fahre_Zu_Position(Payload.X, Payload.Y, Payload.Z, schnell); // Die Fräse muss an die angekündigte Position fahren ... end; G-Code_FiFo_Anweisung entfernen; // Der ausgeführte Befehl wird aus der FiFo entfernt - oder muss man das nicht machen? end; procedure Fahre_Zu_Position(X, Y, Z, Geschwindigkeit); // Die Position X, Y, Z wird mit der entsprechenden Geschwindigkeit angefahren begin Maschine_Bereit := false; // Damit Keine zweite Befehlsauswertung stattfinden kann Schritte_X := X - Istposition_X; // Die Differenz zwischen Soll- und Istposition ermitteln Schritte_Y := Y - Istposition_Y; Schritte_Z := Z - Istposition_Z; Geschwindigkeitsfaktor_berechnen; // Die Wartezeit zwischen den einzelnen Pins ein-/ausschalten berechnen GF_Down_X := Geschwindigkeitsfaktor; // Variable setzten GF_Down_Y := Geschwindigkeitsfaktor; GF_Down_Z := Geschwindigkeitsfaktor; timer_Intervall := Geschwindigkeit; // Den Intervall für die Geschwindigkeit timer_aktivieren; // Der Timer wird aktiviert end; procedure Timer; begin GF_Down_X := GF_Down_X - 1; // Die Wartezeit wird immer eines weniger GF_Down_Y := GF_Down_Y - 1; GF_Down_Z := GF_Down_Z - 1; if GF_Down_X = 0 then // Wenn die Wartezeit gleich Null ist... begin If Pin_X_Ein then // ...Wird der Takt-Pin getoggelt Pin_X_aus else Pin_X_ein; GF_Down_X := Geschwindigkeitsfaktor; // ...wird die Wartezeit wieder heraufgesetzt Schritte_X := Schritte_X - 1; // ...wird die Anzahl zu erledigender Schritte verringert end; if GF_Down_Y = 0 then // Wenn die Wartezeit gleich Null ist... begin If Pin_Y_Ein then // ...Wird der Takt-Pin getoggelt Pin_Y_aus else Pin_Y_ein; GF_Down_Y := Geschwindigkeitsfaktor; // ...wird die Wartezeit wieder heraufgesetzt Schritte_Y := Schritte_Y - 1; // ...wird die Anzahl zu erledigender Schritte verringert end; if GF_Down_Z = 0 then // Wenn die Wartezeit gleich Null ist... begin If Pin_Z_Ein then // ...Wird der Takt-Pin getoggelt Pin_Z_aus else Pin_Z_ein; GF_Down_Z := Geschwindigkeitsfaktor; // ...wird die Wartezeit wieder heraufgesetzt Schritte_Z := Schritte_Z - 1; // ...wird die Anzahl zu erledigender Schritte verringert end; If (Schritte_X = 0) and (Schritte_Y = 0) and (Schritte_Z = 0) then //wenn alle Schritte (X, Y, Z) ausgeführt wurden... begin Maschine_Bereit := true; //...wird die Bereitschaft auf true gestellt damit der nächste Befehl verarbeitet werden kann Timer_deaktivieren; // ...wird der Timer deaktiviert end: end; mfg Urban EDIT: hab den code noch kurz bisschen abgeändert |
Zitat |
Registriert seit: 9. Dez 2005 Ort: Kandel 408 Beiträge |
#39
Ich schmier mal schnell einen Pseudo-Pseudo-Code hin, damit du dich nicht so quälen musst. Du bist nämlich noch ein gutes Stück von mir entfernt.
Es stellt sich aber dennoch die Frage, ob es Sinn macht, meine Gedankengebäude nachzuprogrammieren wenn ich das Konzept noch nicht einmal vollständig durchdacht habe. Noch ein Hinweis zu deiner Maschine_Bereit Sache: Sinn und Zweck der Fifos ist es doch gerade, DAS unnötig zu machen. Die Maschine soll nahtlos ihren Job abarbeiten, ohne beim PC immer nerven zu müssen. Die CNC baut sich einen FiFo auf und arbeitet DEN schrittweise ab. Der PC selbst soll möglichst wenig mit allem zu tun haben, was Verzögerungen bewirkt, optimal ist es, wenn die Motion-Control schon nach dem letzten Schritt "weiß" wo sie als nächstes hinfährt, dieses Element aus dem Motion-Fifo holt und beim nächsten Timer-Interrupt einfach weiterarbeiten kann.
Delphi-Quellcode:
mfG
var rx_fifo, tx_fifo, gcode_fifo, motion_fifo : TFifo;
var rx_errors, decode_state : byte; procedure main; //alles hat einen anfang begin while (true) do begin command_decode; //kommandodekodierung gcode_preprocessor; //g-code-interpretierung; end; end; procedure rs232_receive; begin if not rx_fifo.add(rx_register) then rx_errors := rx_errors or FEHLERCODE_FÜR_VOLLEN_FIFO; else begin if rx_fifo.size-5 < rx_fifo.count then rx_errors := rx_errors or WARNCODE_FÜR_FAST_VOLLEN_FIFO; end; end; procedure rs232_transmit; var out_buf : byte; begin if tx_fifo.get(@out_buf) then tx_register = out_buf else disable_rs232_transmit_interrupt; end; procedure command_decode; begin case decode_state of wait_for_startflag : //eingangsfifo nach startflag durchsuchen und bei gefundenem startflag die nächste stufe scharfschalten read_message_size : //sobald ein byte gekommen ist, als message_size interpretieren + nächsten schritt aktivieren receiving_telegram : //warten (nachsehen, danach funktion verlassen wenn nicht alles da) bis alle angekündigten bytes da sind, danach nächster schritt check_stopflag : //prüfen ob das telegramm tatsächlich da ein ende hat wo es eines haben sollte, wenn ja: weiter check_cmd_code : //doppelten commandocode prüfen, weiter wenn ok, check_sum : //checksumme prüfen, weiter wenn ok launch_parser : //payload an den parser übergeben, z.bsp für gcode rst_wait_stopflag : //wenn ein fehler aufgetreten ist, überspringen wir hier solange eingehende bytes, bis ein stopflag dabei ist, danach schritt eins scharfschalten if rx_errors <> 0 then //irgendwann beim dekodieren oder empfangen ist ein fehler aufgetreten, das teilen wir dem master mit begin if transmit_command(receive_error,@rx_errors,sizeof(rx_errors)) then rx_errors := 0; //transfer erfolgreich, wir können den fehler löschen. end; end; procedure gcode_preprocessor; begin //mach was sinnvolles mit dem gcode, abhängig vom aktuellen zustand berechnungen anstelle, neue codes aus dem gcode_fifo entnehmen und interpretieren und dann in den motion_fifo einfügen oder oder end; procedure timer1_interrupt; begin //zu toggelnde pins ermitteln //toggeln //distanzen updaten etc. //zurücktoggeln //wenn job done, neuen nachladen oder in idle-mode gehen end; Markus
Markus
|
Zitat |
Registriert seit: 7. Nov 2004 639 Beiträge |
#40
Zitat:
Es stellt sich aber dennoch die Frage, ob es Sinn macht, meine Gedankengebäude nachzuprogrammieren wenn ich das Konzept noch nicht einmal vollständig durchdacht habe.
Ich will ja auch nicht einfach nur deinen Code 1:1 abschreiben, doch beim Grundgerüst komme ich ohne Hilfe wohl nirgens hin, und wenn ich das habe kann ich vermutlich den Rest relativ selbständig machen. Und wenn dein Konzept aus irgendeinem Grund nicht funktionieren würde, dann wäre das auch halb so wild weil ich auch so schon einiges lernen konnte! Und danke für deinen "Code"! Vielleicht werde ich dieses Wochenende mal mit dem Programmieren beginnen... Ach ja, hast du deine Schrittmotorplatinen (L297/L298) selbst gemacht? Ich hab nämlich mal 3 Platinen mit der "Direct-Toner"-Methode gemacht, doch nur eine davon war nach langem nachbessern funktionstüchtig Danach hatte ich die Schnauze voll von dem riesen Aufwand, und hab mal nach Platinen-Ätz-Service gesucht. Da hab ich aber gemerkt dass das vom Preis her überhaupt nicht in Frage kommt. Also wenn du deine Platinen selbst gemacht hast, würdest du auch für ein bisschen Geld nochmal 3 von diesen machen? mfg Urban EDIT: Ich habe ja mal was von Threads geschrieben. Nun hab ich in der Hilfedatei des C-Controls mal bisschen gelesen, und ich würde meinen dass das eigentlich eine gute Sache ist für diese Anwendung. z.B. Das Senden/Empfangen der RS232 kann man doch sehr gut in einem Thread plazieren denke ich mal. Und vielleicht auch deine "command_decode"-Prozedur. Naja, wenn ich schon die Möglichkeit habe, Threads zu benutzen, sollte ich es mir wohl auch zu nutzen machen |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |