Tasks - Parallel, nicht Synchron

  • Hallo zusammen,


    in meinem Kopf sind Tasks zu einem großen geworden. Aufgabenstellung ist folgende:
    Es gibt mehrere Zustände, wichtig ist nur, dass etwas in einer bestimmten Frequenz passiert.
    1) Warten, nix tun und auf Eingabe warten -> Freq1
    2) Irgendwas tun -> Aufhebung von Freq1 (also taskkill)
    3) irgendwohin fahren -> Freq1


    Wenn ich es richtig verstehe arbeitet die CS8C das sequentiell ab. Ich kann jetzt aber doch nicht den Bewegungsbefehl mit 20 Wiederholungen im Code in einer While-Schleife vorsehen, nur damit was anderes mit der Frequenz angesteuert wird? Daher die Überlegung mit tasks zu arbeiten.


    Bewegungsbefehl und "parallel" mit ner Frequenz arbeiten. Das müsste doch gehen, aber ich steh grad aufm Schlauch.


    Beste Grüße

  • ANZEIGE
  • Hallo Odyssee,


    ich verstehe deine Frage(n) und deine Aufgabenstellung nicht :denk: ...


    Vielleicht mal generell:
    Es gibt im System Asynchrontasks (viel Code pro "Zeit", aber nicht Echtzeit) und Synchrontasks (Echtzeit, aber nur verhältnismäßig wenig Code pro "Zeit").
    Alle Fahrbefehle (egal aus welchem Task) werden in den Motionstack (dem Eingangspuffer der Bahnplanung) kopiert und nach und nach durch die Bahnplanung an die Verstärker gefüttert.


    Versuche doch bitte, einem Langsamdenker wie mir dein Problem ein wenig anders näherzubringen :oops:


    Viele Grüße


    Spielkind

  • Heyho,


    es gibt Gründe, warum ich mich den Natur- und nicht den Literaturwissenschaften zugewandt habe ;) Da verstehen mich noch weniger Menschen :lol:


    Kurzbeispiel:
    Fahrbefehl: 600mm lange Raumdiagonale mit 100mm/s => Fahrprogramm braucht 6s mit einem Befehl


    Nebenher soll aber ein Ausgang mit z.B. 20 Hz angesteuert werden => 120 Zyklen die nicht stattfinden, da der Fahrbefehl ja noch läuft und erst nach Ende des Fahrbefehls wieder der Ausgang angesteuert wird. Das fühlt sich nach einer klassischen Brett-Vorm-Kopf-Situation an.



    Irgendwie kommt mir das killen merkwürdig vor. Ich seh grad nicht ganz, wie ich dort eine vernünftige "Parallelität" (oder geschickte sequentielle Ordnung) reinbekomme.


    Gruß vor dem zweiten Kaffee,
    Odyssee

  • Hi Odyssee,


    ach so, nun habe auch ich es verstanden:


    Wie schon vorher geschrieben, werden Fahrbefehle "einfach" an die Bahnplanung (den Motionstack) geschickt. Damit ist für den Programminterpreter der Fahrbefehl erledigt und er kann im Programm weitermachen.
    Im einfachsten Falle könnte dein Programm so aussehen:


    Das obige Schnipsel ist nur zeitlich genau, wenn Du es in einem Echtzeittask aufrufst (also mit taskCreateSync ). Desweiteren wird im obigen Beispiel einfach angenommen, dass der Roboter dann auch fährt. Also Not-Aus, Antriebe Aus, falsche Betriebsart usw. würden den Ausgang endlos weiterblinken lassen.


    Einen völlig anderen Ansatz bekommst Du, wenn Du mit dem Befehl
    $getMoveId() - aus dem Expansion-AddOn, wenn das Betriebssystem < 7.0 ist
    getMoveId() - im Standard-Befehlsumfang, wenn dein Betriebssystem >= 7.0 ist
    arbeitest.


    Damit könnte das Beispiel so aussehen:


    Bei diesem Beispiel könnten alle Zeilen beginnend mit wait(getMoveId() >= nNummer) auch in einem anderen Task laufen.
    Die Fahrbefehle wären also in einem "normalen" Task (taskCreate), die Aktionen, die du bahnbegleitend machen möchtest, würden dann in einem Echtzeittask (taskCreateSync) stattfinden. Die Synchronisierung von Bahnausführung und Aktion geschieht dann über die eindeutige Kennung und getMoveId().


    Viel Erfolg


    Spielkind

    Einmal editiert, zuletzt von Spielkind ()

  • Hallo Spielkind,


    ich versuch es grad nachzuvollziehen, stell mich aber glaub ich zu blöd an.


    Dein Plan sieht so aus:


    start() --> Prozedur mit dem ersten Codeschnipsel als

    Code
    taskCreateSync "tAusgang", 0.05, bTrue, ausgang()


    aufrufen ?


    isEmpty() wäre dann


    Code
    if here(tTool, tKoord) == pZiel
    isEmpty = true
    endif


    nehme ich an?


    Die Doku zu den tasks ist ohne Schulung auch irgendwie dürftig.

  • Hi Odyssee,


    isEmpty() ist ein VAL3-Befehl, kein Programm ...


    Das Program start() sieht so aus:

    Code
    program start()
      begin
        taskCreate "motion",100,motion()
      end


    das Programm motion() sieht so aus:

    Einmal editiert, zuletzt von Spielkind ()

  • Hallo zusammen,


    das ganze entwickelt sich mal wieder zu einer Odyssee.


    Danke für das Beispiel. Ist so direkt einiges verständlicher und auch (fast) lauffähig.


    Anstatt den doAusgang zu triggern müsste ich nur ne Bytefolge über die Serielle Schnittstelle schieben (s. http://www.roboterforum.de/rob…chnittstelle-t8996.0.html)


    Das Fehlerbild welches sich aktuell einstellt ist folgendes:
    Es passiert nichts ;)


    Situation ist folgende:
    Roboter führt Hin- und Rückbewegungen zwischen zwei Punkten aus. Auf der einen Bahn soll die serielle Schnittstelle mit n Hz angesteuert werden. Auf der zweiten nichts passieren. Anstelle von isEmpty() also ne globale Variable eingebaut.


    Fehlerbild:
    Roboter bewegt sich, angesteuertes Gerät ist stumm. Programm beenden.


    Neustarten der Steuerbox des Gerätes und anschließender erneuter Programmaufruf führt zu einer Abfolge von 10-25 Zyklen durch das angesteuerte Gerät, danach wieder ebbe.


    Das hört sich irgendwie an, als würden die Steuerbefehle irgendeinem Speicher auflaufen und dann abgearbeitet werden. Da erst durch den Programmaufruf des Stäubli die Steuereinheit zum Leben erwacht, bevor sie dann wieder schweigt hab ich die CS8C in Vermutung :aufsmaul:


    Irgendwann hat das Ding noch eine Delle :kopfkratz:


    Frustrierter Gruß

  • Hallo Odyssee,


    ich denke mal du musst uns besser über deine Hardware bzw. deine Aufgabe aufklären.
    Ist sie für dein ansteuer Häufigkeit ausgelegt?


    ich würde die Ansteuerung der Ausgänge bzw. Rs232 in eine SynchronTask ausgliedern.


    dann kannst du deine Funktion auch mal ohne Bewegung testen.

  • Hardware ist ne CS8C mit VAL 6.8; Roboter ist ein TX60


    Wie im o.g. Beispiel zu sehen wird das ganze über die serielle Schnittstelle angesteuert.


    Es ist das Beispiel von Spielkind, nur, dass ich anstelle des doAusgang-Wechsels ein Programm aufrufe, welches eine Bitfolge an die Dosiereinheit sendet.


    Die Steuerbox kann die Hz-Zahlen ansteuern. 30 Hz grad mit der gleichen Prozedur getestet.


    Das Programm funktioniert, wenn ich z.B. ein 2D-Raster abfahre und dort bei den Punkten anhalte (waitendmove() ), funktioniert aber nicht, wenn es "nebenher" laufen soll.

  • Programmschnipsel


    Ansteuerung des Gerätes (geraet(nAnzahl)):




    Funktioniert:
    x und y werden durch eine Doppel-Schleife laufen gelassen --> Raster

    Code
    call geraet(1)
          movel(appro(pUrsprung,{x,y,0,0,0,0}),tFlaeche,mRaster)
          waitEndMove()


    Funktioniert interessanterweise auch nur mit waitendmove() ?!


    Funktioniert nicht:
    Beispiel von Spielkind


    start()


    bewegung()


    Situation 1)
    Gerät ist an, Roboter an, Programm wird zum ersten mal gestartet:
    es passiert gar nichts, außer den Bahnkurven


    Situation 2)
    Gerät ist neugestartet, Programm wird neugestartet
    Direkt zu Programmstart arbeitet das Gerät einige Zyklen (10-25) ab, danach wieder Ruhe


    Das ist mir eindeutig zu diffus :bawling:

  • Zwischen den Feiertagen kommt man endlich mal zu was. Delay war in der Tat das Problem, aber eher das delay in der Steuerbox. Ich hab den Controller schon mit einem Steuerbefehl gefüttert, während er noch dabei war sein internes delay zu zählen. Daran hat er sich dann verschluckt und es war Feierabend.


    Danke erneut ans Forum. Jetzt kommt das anpassen der vorhandenen Programme. :eviltongue:

  • Zitat

    Der Fehler ist Tot, es lebe der Fehler!


    Das Ding will mich ärgern ;) aber warum wundert mich das nicht. Ich hab es geschafft mir einen Fehler 41 zu produzieren, sprich er meint, sein Arbeitsspeicher würde für die Task nicht reichen. Das ganze passiert nach einigen selbstaufrufen.


    Programmstruktur:
    start() -> bewegung() -> task -> task -> ... -> start() -> bewegung() -> ...


    start ruft im wesentlichen nur die bewegungsprozedur auf, fährt den Roboter einmal auf Ausgang, wenn er noch nicht da steht, etc. startprozedur halt


    bewegung fährt von Punkt 1 zu Punkt 2. Auf dem Hinweg wird die task in einem Intervall ausgeführt, auf dem Rückweg ist die task gekillt.


    Nach n Durchläufen (>50) kommt dann Fehlercode41 ("Der Ausführungsspeicher ist für die Task unzureichend. Siehe Größe des Ausführungsspeichers. ")


    Sehr merkwürdig. Speichert der irgendwas? Speicher größer machen ist ja nicht das Problem, aber irgendwie hab ich das Gefühl das Problem damit nur nach hinten zu verschieben.



    #######
    edit: Gelöst!


    Ich hab andauernd mit einem call-Befehl die start() wieder aufgerufen und dadurch sukzessiv den Speicher geflutet. Problem gelöst. Jetzt kann es weiter gehen. Bis zum nächsten Problem :danke:

    Einmal editiert, zuletzt von Odyssee ()

Erstelle ein Benutzerkonto oder melde dich an um zu kommentieren

Du musst ein Benutzerkonto haben um einen Kommentar hinterlassen zu können

Benutzerkonto erstellen
Neues Benutzerkonto für unsere Community erstellen. Geht einfach!
Neues Benutzerkonto erstellen
Anmelden
Du hast bereits ein Benutzerkonto? Melde dich hier an.
Jetzt anmelden