Hallo, ich entwickle ein Anlagensteuerprogramm unter Windows XP in C, welches unter anderem auch SPS-Funktionalitäten für den CAN-Bus enthält. Ich muss also alle auflaufenden, für das Programm relevante CAN-Frames lesen und verarbeiten. Die Daten laufen in Form von üblichen CAN-Frames (ID, Länge, 8 Datenbytes) auf. Ich gleiche jedes einzelne PDO mit dem vorher empfangenen PDO (gleicher ID) ab und betrachte bei abweichendem Inhalt eines Datenbytes jedes weitere Bit einzeln. Da es sich fast nur um Digitale I/O-Signale (also ein Bit) handelt, erzeugt jedes eintreffende Frame ein Aufruf von "pdo_input(int id, int byte, int bit, int status)". So erkenne ich z.B. die Meldung eines Näherungsschalters. Es sind mittlerweile sehr viele Kanäle vorhanden, also ist die Funktion pdo_input entsprechend groß. In der Funktion gibt es dann verschiedene switch-case / if-Strukturen, die für jede Bitänderung eine Reaktion auslösen. Insgesamt funktioniert dieses System sehr gut. Es laufen aber sehr viele Daten auf, die entsprechend schnell verarbeitet werden müssen. Wenn nur eine Bitfunktion irgendwo in der pdo_input-Funktion ein Delay von <10ms auslöst, gibt es schon massive Heartbeat-Probleme. Ich würde die Funktion gerne in Form eines Threades ausführen, damit der gleiche Thread mehrfach gleichzeitig ausgeführt werden kann. So schläft nicht gleich der ganze Lesezyklus, weil ein Tastersignal ein kurzes Delay aufruft. Natürlich ist das nicht üblich an diese Stelle ein Delay für Steuerungszwecke zu setzen, dazu habe ich weitere Funktionen, es soll aber trotzdem so sein, dass ein kurzer Aussetzer nicht alle weiteren Frames verschwinden oder stark verzögern lässt. Wäre das eine sinnvolle Vorgehensweise? Wie löst ihr dieses Problem? Hier noch ein paar Daten: ca. 10 CAN-Knoten, ~100 Digitale I/O's, ~20 Analogsignale (je 2-4 byte), 500kBit/s Grüße vom hansi
Sowas im Einzelbitverfahren loesen zu wollen ist unrealistisch. Und Delays gibt es eh nicht. Gab es noch nie. Dazu ist zu sagen, ein PC war noch nie eine Echtzeit Maschine. Ich wuerd da alles in Hardware auslagern. Eigentlich macht man die beschriebene Funktionalitaet mit Threads, ein PC ist dann aber trotz 3GHz schnell am Ende, denn ein Taskswitch ist ein Riesenaufwand. Eine Zustandsmaschine ist da viel effizienter. Und weswegen muss das alles auf einem PC laufen ?
Rumpel, der Stilz ist grad nicht da. schrieb: > Delays gibt es eh nicht. Gab es noch nie. War auch nur beispielhaft für etwas, was etwas Zeit in Anspruch nehmen kann. Beispielsweise die Aktualisierung eines Anzeigeelementes auf der GUI. Rumpel, der Stilz ist grad nicht da. schrieb: > Eine Zustandsmaschine ist da viel effizienter. Und weswegen muss das > alles auf einem PC laufen ? Warum denn nicht? Das ganze läuft im universitären Umfeld aus Forschungsmaschine. Nebenbei gibt es einige Messaufgaben, Visualisierung, ggf. Ankopplung an andere Softwarekomponenten. Deshalb muss es ein PC sein. Es gibt ja auch z.B. die CoDeSys-Soft-SPS auf einem PC, EtherCAT Automatisierungen laufen fast ausschließlich auf IPCs. Der Einzige Unterschied ist, dass ich nicht die EN 61131-"Sprachen" verwende, sondern mir ein eigenes Programm baue, in dem die Automatisierung läuft. Zur Echtzeit: Ist glaube nicht nicht wichtig für meine Anwendung. Kurz noch zum strukturellem Aufbau des Automatisierungsteils: 1. Automatikprogramm wird mit automatik(0) gestartet. (0) ist der Startparameter für die Ablauffolge. 0 Ist dabei ein Sprungpunkt in einer switch-Anweisung 2. In 'case 0' steht z.B. Zylinder_vor. Ein Zylinderwarteflag wird gesetzt. 3. pdo_input meldet, dass der Zylinder vorne ist (Näherungsschalter) ==> wenn Zylinderwarteflag, dann task(1) 4. ......
Also, mit einem PC so etwas zu machen, ist vollkommen in Ordnung und auch kein Problem. Richtig, TwinCat von Beckhoff läuft auch auf allen möglichen Windows-Varianten, ob CE, XP, 7 usw. Allerdings eben immer relativ tief im System als Echtzeit-Task. Aber egal, vermutlich liegt es an Deiner Programm-Struktur. Du solltest vielleicht IO (Can), SPS-Funktionalität und Visualisierung voneinander trennen. Keine Ahnung was für eine CAN-Karte Du hast und wieviel sie puffern kann. Aber vom Prinzip solltest Du das wie ein normales SPS-System aufbauen: a.) Eine Task, höchste Priorität, macht nur IO (CAN) und baut aus den einzelnen Bit-Nachrichten ein "virtuelles" Prozessabbild zusammen und beantwortet aus diesem Prozessabbild auch CAN-Bus-Anfragen. b.) Eine zweite Task, mittlere Priorität wird zyklisch aufgerufen, und darin programmierst Du die SPS-Funktionalität, genau so zyklisch wie sonst mit IEC61131-3, nur eben in C++ anstatt ST. (Eine Kopie des Input-Prozessabbildes am Zyklusbegin erstellen und Output-Prozessabbild am Zyklusende der IO-Task übergeben.) c.) Eine dritte Task, normale Priorität, macht den ganzen Visualisierungskram, Diese Task kann dann beliebig komplexe Funktionen des Betriebssystem aufrufen und Datei-IO etc. machen.
Est leider ueblich im universitaeren Umfeld etwas selbst machen zu wollen, was man als zu teuer oder als nichtpassend betrachtet. Das ergebnis ist dann ein schlecht dokumentiertes unzuverlaessiges Gepfriemel. Wenn man noch einen Schritt weitergeht, dh etwas haebn will, das nicht funktioniert und viel gekostet hat, nimmt man National Instruments.
@Troll: Ganz ehrlich, Deine Antwort verstehe ich nicht. Es geht um eine relativ einfache Folgeautomatik mit vielen Digitalkanälen, so etwas wurde früher mit Schützsteuerungen realisiert und funktionierte super. Warum sollte man dafür 1000% überdimensionierte fertig-SPS'en einbauen, die alles verkomplizieren? Letztendlich ist die Schnittstelle vom PC-Programm zur Peripherie das CAN-Frame. Es ist simpel aufgebaut, und im vergleich zu anderen Feldbussen, wie z.B. Profibus, Profinet, EtherCAT, etc. kann man sehr einfach das Protokoll verstehen und die Frame-Inhalte interpretieren. Wenn ich einen Kanal setzen möchte, sende ich einen Frame, die ankommenden Frames werden empfangen und ausgewertet. Es geht mir auch primär nicht darum, ob so was gut ist, oder nicht, sondern wie ich das Problem mit dem Multitasking/Multithreading löse. Den Vorschlag von Automatisierer (Gast) finde ich schon gar nciht schlecht, allerdings möchte ich es nicht zyklisch machen, sondern rein Ereignisorientiert. Deshalb habe ich auch einen Thread, in dem eine CAN_Read-Funktion steht. Der Thread "steht" so lange, bis ein Frame kommt, was dann ausgewertet wird. Da es ein Thread ist, kann das restliche Programm weiterlaufen, wenn kein Frame kommt, und dieser eine Thread steht. Ich überlege ähnliches auch zu tun, wenn eine Bitänderung kommt. Ist soetwas denn völlig unüblich udn unrealistisch?? Zu ni: richtig, kostet viel, aber falsch: funktioniert sehr gut! Allerdings ohne Fertiglösungen wie LabVIEW, sondern frei programmiert in C. Das ganze dann integriert in mein Steuerprogramm. Unter Anderem deshalb übrigens auch komplett frei programmiert....
Hallo > @Troll: Ganz ehrlich, Deine Antwort verstehe ich nicht. Das ist nur einer, der Angst hat, das jemand mit open source SPSen das Geschäft kaputtmacht. ;O) > Den Vorschlag von Automatisierer (Gast) finde ich schon gar nciht > schlecht, allerdings möchte ich es nicht zyklisch machen, sondern rein > Ereignisorientiert. Der Vorschlag, von Automatisierer ist auch das einzig wahre. Ereignisorientiert ist aber seeehr aufwändig und kompliziert und dadurch bei größerem Umfang schnell langsam bzw. ohne garantierbare Maximalzeiten und Fehleranfällig.
anderer Troll schrieb: > Ereignisorientiert ist aber seeehr aufwändig und kompliziert ok, dann verstehen wir beide "ereignisorientiert" vielleicht etwas unterschiedlich. Ich meine damit, dass ich im Programm einen Thread laufen habe, der bei der Funktion canRead (Daten von der PCI-CAN-Karte abholen) stehen bleibt, bis ein Frame kommt, was dann auseinander gepflügt wird. Da ich es noch nie zyklisch probiert habe, würde ich es mir sicherer und sparender vorstellen, es nicht zyklisch zu machen, denn wenn ein Eingang kommt, wird gepfüft (if), ob dieser Eingang jetzt gerade erwartet wird. Der Automatikzyklus geht dann durch einen Sprung in automatik(int teilschritt) weiter. Zyklisch müsste ich ja in jedem Durchlauf prüfen, ob der Eingang gerade erwartet wird, und dann trotzdem in meine automatik(int teilschritt)-Funktion springen. Realisierst Du auch eine Folgeautomatik mit Sprüngen in eine Funktion, die meiner automatik(int teilschritt)-Funktion ähnelt mit Hilfe von switch-case? Habe das irgendwann mal übernommen und seit dem immer wieder in neuen Anlangen verwendet.
Hallo, der Einwand von Troll mit der inkompatiblen Selbstbaulösung ist teilweise berechtigt. Für deine beschriebene Aufgabe gibt es aber bereits eine Teillösung. Das System nennt sich EPICS (http://www.aps.anl.gov/epics/) und hat eine beachtliche Verbreitung vor allem im universitären Umfeld. Das Grundgerüst für eine Steuerung und eine definierte Schnittstelle hast du damit. Zusammen mit SNL (http://www-csr.bessy.de/control/SoftDist/sequencer/index.html) kannst du damit die Ablaufsteuerung sehr einfach und flexibel erstellen und ändern. Auch Programme wie LabVIEW können auf EPICS ohne Aufwand zugreifen. Die CAN-Bus Auslese musst du deshalb trotzdem noch schreiben, allerdings ist es in der Dokumentations beschreiben, was wie dafür gebraucht wird. Das System ist nicht perfekt, es lässt sich aber recht brauchbar mit arbeiten und durch die über 20 Jahre Entwicklung des Systems sind auch quasi keine Fehler im Basisquellcode mehr enthalten. Visualisierungen des und Bedieneroberflächen lassen sich z.B. mit CCS (http://cs-studio.sourceforge.net/) per Drag and Drop sehr schnell erstellen (wir verwenden die NSLS2 Version). Gruß Kai
2 Vorbemerkungen: a) da die c't von gestern es grade brachte: stell sicher dass es nicht nur auf WinXP läuft, das kriegt in nem Jahr absolut garkeine Patches mehr. b) Der Hinweis auf ein bestehendes System ist gut, macht die Wartbarkeit durch andere leichter und dürfte viele deiner Probleme schon gelöst haben. Ein Betriebssystem mit Echtzeitfähigkeiten hat vermutlich auch Vorteile. Leider habe ich bei deinen Erklärungen ein paar Probleme, man merkt dass du tief im System steckst, wir nur leider nicht ;) Ich habe auch ein bisschen den Eindruck, dass du zu sehr "in quelltext" denkst und dir über die große Struktur noch eher wenig Gedanken gemacht hast (sorry falls das nicht stimmt) Mal ein Haufen fragen, die dir hoffentlich beim strukturieren helfen und uns dabei, das Problem zu verstehen. hansi schrieb: > Wenn nur > eine Bitfunktion irgendwo in der pdo_input-Funktion ein Delay von <10ms > auslöst, gibt es schon massive Heartbeat-Probleme. Was bedeutet "Heartbeat-Probleme"? Erwarten andere Systemkomponenten Rückmeldungen? Wovon hängen diese ab? Warum sollte in der input-Funktion ein Delay auftreten? Was macht die alles? Passt dein Problem überhaupt in einen Automaten "ordentlich"? hansi schrieb: > Da ich es noch nie zyklisch probiert habe, würde ich es mir sicherer und > sparender vorstellen, es nicht zyklisch zu machen, denn wenn ein Eingang > kommt, wird gepfüft (if), ob dieser Eingang jetzt gerade erwartet wird. Und was wenn der nicht erwartet wird? Darf das nicht passieren -> Fehlerfall? Oder was passiert sonst mit der Information?
asdf schrieb: > Leider habe ich bei deinen Erklärungen ein paar Probleme, man merkt dass > du tief im System steckst, wir nur leider nicht ;) das hatte ich schon vermutet. Ich werde in den nächsten Tagen das Prinzip mal skizzieren und meine "ereignisgesteuerte" SPS vorstellen. asdf schrieb: > Ich habe auch ein > bisschen den Eindruck, dass du zu sehr "in quelltext" denkst und dir > über die große Struktur noch eher wenig Gedanken gemacht hast (sorry > falls das nicht stimmt) ist schon richtig. Ich denke in diesem Fall wirklich verschärft in Ansi-C und überlege, wie ich es programmiere, welche Funktion was aufruft und wo deklariert ist. Ist so, so habe ich mit all dem angefangen und C gelernt.... Bin halt kein "typischer" SPSler ;-) asdf schrieb: > Was bedeutet "Heartbeat-Probleme"? Erwarten andere Systemkomponenten > Rückmeldungen? Wovon hängen diese ab? > Warum sollte in der input-Funktion ein Delay auftreten? Was macht die > alles? Passt dein Problem überhaupt in einen Automaten "ordentlich"? Mit Heartbeat meine ich den CAN-Heartbeat. Es gibt eine Komponente, die alle 100ms ein Bit toggelt, und ich passend zwischen den Eintreffen der Bits antworten muss. In Ruhe läuft das ganze. Mache ich z.B. den Firefox auf und scrolle ein wenig, läuft zwar das Programm noch, aber der CAN-Teilnehmer steigt aus, da das Heartbeat zu spät kam. Ich müsste also irgendwie den Funktionen/Threads in meinem Programm eine höhere Priorität geben..... asdf schrieb: >> Da ich es noch nie zyklisch probiert habe, würde ich es mir sicherer und >> sparender vorstellen, es nicht zyklisch zu machen, denn wenn ein Eingang >> kommt, wird gepfüft (if), ob dieser Eingang jetzt gerade erwartet wird. > Und was wenn der nicht erwartet wird? Darf das nicht passieren -> > Fehlerfall? Oder was passiert sonst mit der Information? Mit dieser Information passiert nichts. In diesem Beispiel setze ich ein Ventil, dadurch setzt sich ein Zylinder in Bewegung (die Zylinderbewegung kann z.B. 4 Sekunden dauern). D.h. das Programm wartet ab Schalten des Ventils auf Ankunft des Zylinders (Eingang). Das ist quasi nur dazu, damit nicht wilde Dinge passieren, wenn der Zylinder unerwartet vorne ist.
Ich habe jetzt eine grobe Übersicht meines Programmes aufgemalt. Ich hoffe, es wird einigermaßen verständlich, wie ein automatischer Ablauf bei mir funktioniert. Ein Problem ist natürlich, wenn bit_changed oder ablauf aus irgendeinem Grund kurz haken sollte, steht auch die Auswerteschleife für ungelesene Frames. Vielleicht werden die SPS-Experten dieses Vorgehen für Schrott, oder Müll halten, ich bin aber insgesamt relativ zufrieden und würde andere C-Programmierer mal um ihre Meinung bitten. Natürlich stehen Teilabläuft mit Delay() in einem getrenntem Thread, damit Delay wartet, aber da es nur ein Thread ist, läuft der Rest weiter. Der Haupt-Thread geht aber natürlich nicht weiter, wenn eine durch den Thread aufgerufene Funktion steht. Anders wäre es, wenn bit_changed auch ein Thread wäre, der idealerweise auch mehrfach zur gleichen Zeit aufgerufen werden kann.
position bei ablauf ist der "Fortschritt 'in %'" des Automatik-Ablaufes. Jeder Teilschritt ist im switch-case-Konstrukt als case dargestellt.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.