Posts by Programmiersklave

    Bewegung ohne Zielpunkt,

    Ist nicht vorgesehen. Es gibt keinen "fahr erstmal los, dann schaun mer mal"-Befehl.

    Die Ansatz von Whitey impliziert, dass Du den weitest möglichen Punkt als Ziel setzt und über Interrupt(!) vor dem Erreichen abbrichst.

    Der Ansatz vom Robonaut sagt: fahr exakt einen Millimeter, und guck dann noch mal. (Mit jeweils anhalten, ohne geht es nicht.)


    Dann ist manchmal noch die dritte Möglichkeit gegeben, einen weiter entfernten Zielpunkt anzusteuern und einfach gegen einen mechanischen Anschlag zu fahren und dann über die Motorenmomente oder Achsströme ein Limit zu setzen.


    Gibt für alle Lösungen Anwendungsgebiete. Die klassische Suchfahrt, die auf einen Sensor reagiert, wird nach dem ersten Fall programmiert. Schließlich muss ja auch abgesichert sein, dass das Signal evtl. nicht kommt oder sowas.

    Irgendwelche Rangierhilfen für Bediener im Automatikbetrieb mache ich manchmal nach der zweiten Methode.

    Die dritte Art hilft beim Einfädeln mechanischer Ungenauigkeiten, verzichtet aber komplett auf externe Sensoren.


    Natürlich kann man, beliebig komplex, alles kombinieren.


    -


    Wenn ich richtig mitgezählt habe, dann ist das schon Dein dritter Thread zu dieser Fragestellung. Es hilft wohl nichts, Du wirst Dich mit Interrupts beschäftigen müssen.... :) ist aber nicht so schlimm, echt jetzt.

    Bei solchen Fummeleien und wenn die zeitliche Vorgabe eben nicht so genau sein muss lasse ich Hintergrundtasks gerne im Takt arbeiten. Die ungebremste SPS.SUB kommt ja nicht beliebig oft durch, sondern recht zuverlässig in 12ms. Oder man bremst sie halt aus mit einer definierten Wartezeit.... jedenfalls hat man dann einen Taktgeber, den man in jedem Durchlauf einen Step hochzählen lassen kann, situationsabhängig, und zurücksetzen. Man kann Zähler ja auch kaskadieren, damit man nicht so schnell überläuft...

    Beim Abfragen der Zählvariablen natürlich nie auf Gleichheit prüfen, ist klar.


    Natürlich ist das zeitlich ungenauer als die Verwendung der Timer, aber in vielen Fällen bequemer und durchschaubarer. Allerdings: man wird öfter in Verlegenheit kommen, Flanken von Signalen abfragen zu müssen, d. h., dass man nicht das eigentliche Signal verwendet, sondern den Vergleich mit seinem Zustand im letzten Zyklus. Das kann man aber in zwei Funktionen schön auslagern. Bei kritischen Überschneidungen muss man auch die Signale, die man verwerten will, vorher in einem Rutsch in Variablen abbilden, sonst kann es während der Abarbeitung innerhalb eines Zyklus' zu Problemen kommen...


    Naja, das klingt jetzt doch komplizierter als eigentlich gedacht, aber kommt halt drauf an, wie oft man das machen muss. Zwei, drei $Timer sind easy, da braucht man das Konzept eher nicht, aber bei mehr ist diese Taktlösung gar nicht so schlecht.


    Grüße,

    Michael

    Ist aber nichts anderes als das, was Windows auch macht, und funktioniert eigentlich immer, mit den bekannten Einschränkungen. Jeder weiß, dass man es nicht darf, und jeder macht es trotzdem.


    lukelukeluke : Kommt der Hänger denn erst, wenn Du dieses Verzeichnis wie im Bild öffnen willst oder allgemein beim Aufbau des Dateibrowsers von der wurzel aus? Eigentlich ist das im Bild ja nur der Vorgang, der immer kommt, wenn man versucht, ein Verzeichnis anzeigen zu lassen. Nur hier eben mit einem Timeout-Fehler.

    Unter anderem nimmt der "Explorer" ja auch *.zip-Dateien auseinander und stellt sie im Bereich "Archive" dar. Irgendeine Datei kann eben nicht angezeigt werden, warum auch immer. Ich würde im Weiteren jetzt alles aus dem Zugriffsbereich des Explorers rausschieben und nach und nach wieder reinholen. Wird ja eine bestimmte Datei sein, die irgendwie vermurkst ist, oder ein Symlink, oder irgendwas Böses.

    Das wird mit KUKA gar nichts zu tun haben, sondern ist eher ein Windows-Problem. Hast Du mal versucht, nur mit dem "richtigen" Windows-Explorer (lokal) das fragliche Verzeichnis anzeigen zu lassen?


    Grüße,

    Michael

    Was mir gerade noch einfällt: manche Editoren haben einen eingebauten Eifer, Codierungsprobleme selbst umgehen zu wollen. UltraEdit z. B. kann man locker dazu überreden, in den Dateikopf ein Unicode-BOM zu schreiben. Das sieht man dann natürlich nicht, wenn man dieselbe Datei mit demselben Editor wieder öffnet, stört aber die KRC vor dem &COMMENT ... etc. ungemein.

    Sehen kann man das mit dem primitiven Windows-Editor.


    Grüße,

    Michael

    Für's nächste mal mit Telnet drüber schauen. Dann siehst Du die Anzahl Bytes / Words sofort.

    Dies war mir bis jetzt auch unbekannt. Kannst Du das bitte ansatzweise präzisieren bzw. weiterführende Infos verlinken?

    Obwohl ich unter diversen Linuxen verschiedene Systeme headless betreibe bin ich noch nie auf den Gedanken gekommen, dass ich auch auf den KUKA mit 'nem CLI zugreifen könnte... oder wie war das gemeint? Bzw. und weiter: welches Kommandozeilenprogramm guckt da auf dem Bus?


    Grüße,

    Michael

    KRL möchte JEDE Variable deklariert haben, allein schon, um den Geltungsbereich festzulegen. Sollte man in Sprachen, die grundsätzlich Deklarationen verlangen, irgendwo auf Stellen treffen, wo das nicht nötig zu sein scheint, sollte man es trotzdem tun, außer die Daten sind offensichtlich vordeklariert.


    Die Namenskonvention "P"-> "XP" bei durch Inline-Formulare geteachten Punkten ist ein Artefakt aus alter Zeit, weil "P.+" nur ein Meta-Name ist, hinter dem mehrere unabhängige Datenstrukturen verwaltet werden. In "XP.+" liegt dann der FRAME. KRL schleppt einige dieser faulen Kompromisse mit sich rum, die entstanden sind, als Speicher noch rar und teuer war und man nicht genau wusste, wo es enden sollte. Muss man einfach hinnehmen.


    Grüße,

    Michael

    Sometimes these kind of issues are related to improper interrupts or triggers (I.E. an interrupt occurs more oftenly than could be handled by the trap routine or something like that.) or recursions. Recursive procedure / function calls are generally possible in KRL, but normally without reasonable use cases in robot applications and mostly generated accidentally.


    Regards

    Michael

    Philipp, mir hat es anfangs in der Praxis immer geholfen, die Sache möglichst zu fragmentieren, und jedes besch... Byte oder doch wenigstens die Words einzeln zu betrachten, besonders dann, wenn es kompliziert wird.

    Ich kopiere Dir mal auszugsweise ein Beispiel aus einer realen Anlage hier drunter, vielleicht siehst Du dann, was gemeint ist. Die Kommentare standen übrigens genau so drin.... aber lies erstmal unterhalb des Beispiels weiter.



    Guck mal zuerst auf den letzten Block. Ich hab da Ausgänge, und zwar digital 10 Byte, ab Byte 25. Das ist Ausgang $OUT[201] bis [280]. Die sind auf dem Busgerät ab Byte 8 verfügbar.

    Dann habe ich separat noch 4 weitere Doppelbytes. Das Busgerät schickt die davor, deswegen gehen die von 0 bis 6 auf der rechten Seite, in zweier-Abständen. Die hole ich mir paarweise von den Doppelbytes 50..51, 52..53, 54..55 und 56..57. (Bedient werden die von einer Soft-SPS, die auf dem Kuka läuft, der Robbi selbst hat damit nichts zu schaffen, aber hier rein mussten sie dennoch. Das wären rein technisch die Ausgänge ab $OUT[401] aufwärts, und man kann die Signale sogar sehen, wenn man in der EA-Ansicht dorthin blättert auf dem KCP.)


    Vielleicht kannst Du Dir sinngemäß eine Theorie ableiten, wie das bei den Eingängen läuft, bei denen die rechte Seite mit "10" beginnt, das ist Devnet-Gerät 10.


    Und dann gibt's ganz oben noch einen ganz simplen Block, wo einfach alles blockweise durchgeschossen wird, auf einem sehr hohen Bereich ab $IN/OUT[1105], was Byte 138 entspricht. Aber auf ein anderes Busgerät mit der Adresse 12. 8 Bytes breit, das macht exakt 64 Signale jeweils.


    Hier hatte ich damals immer Doppelbytes verwendet. ... INB (mit "B"), und dann Faktor "x2". Warum nicht Words? Ganz einfach: so konnte ich's besser kapieren. Und die SPS kommt mir ja auch immer mit Bezeichnungen wie "22.7", wo ich dann umrechnen muss: Byte 22, Bit 7, +1 für die Zählung, die bei 1 anfängt, macht 184.

    Und man kann mal eben was rauskommentieren oder verschieben, wenn man das braucht.


    Noch was: in der devnet.ini kann man "debug" einschalten, dann macht er ein Logfile irgendwo hin im Log-Ordner. Das ist zwar nicht sooo hilfreich, aber bringt gelegentlich die Erleuchtung.


    Grüße,

    Michael

    Die Tools haben momentan die gleiche Orientierung, sind nur gegenüber dem Flansch-Y um 183,6 mm verschoben. Somit müsste der Roboter einfach nur linear 183,6mm zur Seite fahren, um den anderen Greifer zu benutzen, und gar nichts drehen.

    Wenn er trotzdem was dreht, dann ist der Punkt anders geteacht bzw. programmiert.

    Wenn das andere Tool eine andere Ausrichtung hat, dann müsstest Du die natürlich eingeben um das gewünschte Ergebnis zu erhalten.

    Aber Vorsicht: bei exakt 180° Verdrehung kannst Du nicht sicher sein, dass der Roboter immer in dieselbe Richtung dreht. Und bei flexiblen Positionen kann es ebenfalls zu Überraschungen kommen, wenn der Robbi meint, andersherum schwenken sei sinnvoller, auch wenn die Tools nicht 180 Grad verschieden sind. Die Überraschungen hauen dann erst um sich, wenn der nächste PTP-Punkt kommt...


    Grüße,

    Michael

    Hi Philipp,

    ja, wenn man das zum ersten Mal sieht, könnte man durchdrehen.


    Paar Erklärungen, mehr grundsätzlich:

    In den einzelnen Ini-Dateien für die Busse werden die Parameter der Busse an sich festgelegt. Z. B. bei Dir, wenn Du DeviceNet hast, in der devnet.ini, siehe Martins Beispiel. Da müssen dann die Mac-Ids der Teilnehmer rein, können ja mehrere sein.


    In der iosys.ini werden dann die dadurch zugänglichen physischen Signale auf den Bussen auf logische Bytes in der KRC gemapped. INB, OUTB usw. stehen jeweils für 8 Bit, INW und OUTW für jeweils 16 Bit. Die kleinste Einheit ist ein Byte, also 8 Signale (Bit.) Wenn Du nur die digitalen EA verwendest, macht es keinen Unterschied, ob Du 2 INB nimmst oder 1 INW .


    Die Zählung fängt dort bei 0 an, d. h. OUTB0 mappt auf die ersten 8 Ausgänge, die beim KUKA aber im Ausgangsarray wiederum bei 1 anfangen. Das heisst: $OUT[1] bis $OUT[8]. Links vom "=" steht die logische Zuordnung, rechts steht die physische. Der Job besteht jetzt darin, die physischen Signale auf dem Bus zu finden, deren Bitbreite zu wissen, und dann dort sinnvoll den logischen Signalen zuzuordnen. Das Ärgerliche ist vielleicht, dass die Bitbreite des Busteilnehmers nicht immer offensichtlich ist, es ist immer ein Vielfaches von 8, deshalb der Faktor. Benutzt man "W", dann sind's Vielfache von 16. Manche Koppler schicken z. B. ungefragt noch ein Diagnosebyte mit, das man zwar nicht braucht, aber was auf dem Bus bemerkt wird. Und wenn's nicht stimmt, sagt die KRC: geht nicht.


    Irgendwo im Menü findet man was mit "E/A-Treiber rekonfigurieren", das muss nach jeder Änderung in Obigem einmal gemacht werden.


    Wenn Du dann alles fertig konfiguriert hast und die Signale durchgereicht werden, dann kannst Du mit der "SIGNAL"-Definition (z. B. ) in der $config.dat auch noch optional Namen vergeben, die kann man dann im Programm verwenden. Und die sieht man dann aber immer noch nicht in der E/A-Liste, die man über das Menü aufrufen kann sondern müssen da noch einmal extra eingegeben werden. (Oder bei "Langtexte" exportiert/importiert werden.)


    Grüße,

    Michael

    Ich rede nicht von sicherheitsrelevanten Funktionen.

    Ich auch nicht.


    aber es ist sicherer als reiner Code im Anwenderprogramm

    Nein, jedenfalls nicht bei Verwendung kartesischer Zonen (Quader, Kugel, Zylinder). Das wollte ich nur anmeckern, da ich es oft genug schon anders gesehen habe.


    Szenario 1, eher unwahrscheinlich, aber nicht unmöglich, weil zumindest was den Bediener angeht schon selbst erlebt:

    Robbi steht auf dem zonenüberwachten Punkt. Bediener kommt her, will in bester Absicht was machen, Bewegungsart steht auf "Umorientieren". Bediener rudert mit Steuerknüppel um den aktiven TCP, das ist der, der beim Anfahren dieses Punktes aktiv war. Der Ausgang der Zonenüberwachung steht eisern auf 1. Bediener findet, dass der Roboter sich heute eher komisch bewegt, gibt auf, lässt alles so stehen und startet nach - bumm.


    Szenario 2, mir selbst schon passiert:

    ConfL und ConfJ arbeiten modal. Bei Abarbeitung einer Bearbeitungsroutine mit abgeschalteter Konfigurationsüberwachung bleibt irgendwas stecken. Der Bediener löst das Problem lokal und übergeht den nachfolgenden Teil der Bearbeitung, indem er den Programmzeiger direkt auf den zonenüberwachten Punkt setzt und anfährt. Der Ausgang wird 1. Leider hat der Bediener aber übersehen, dass bei der normalen Bearbeitung sich die Handachsen unter der Achse 4 wegbewegt hätten und die Handachsenkonfiguration jetzt, durch das versetzte Anfahren, auf dem Kopf steht. Bediener startet nach - bumm.


    Szenario 3, hab' ich auch schon mal gesehen:

    Beim Hochfahren des Systems geht irgendwas schief und die Ereignisroutine, die die Weltzonen definiert, wird nicht vollständig abgearbeitet. Infolgedessen wird auch kein Ausgang gesetzt. Der Fehler wird quittiert, jemand versucht, die Maschine zu starten. Das selbstbewusste Roboterprogramm hat zwar den Manipulator in der Homeposition, ist aber drauf dressiert, immer dann, wenn der Home-Ausgang wie jetzt nicht da ist, erst eine automatische Homefahrt zu versuchen. Die ebenfalls etwas zu selbstbewusste SPS hingegen kommt zu eigenen Schlüssen und hat nie daran gedacht, dass der Roboter so etwas tun wollen könnte und stellt ihm mal eben einen Antrieb in den Weg - bumm.


    Da bin ich mit einem durchdachten CJointT besser dabei.


    Grüße,

    Michael

    Ein Target mit einer Ist-Position auf Gleichheit vergleichen zu wollen find' ich einen reichlich verwegenen Plan.


    Was aber in diesem Anwendungsfall ginge wäre sowas wie IF (Distance(p_temp,p_fass) < 0.1) oder so, je nach Genauigkeit, wobei Vorsicht angebracht ist, da man dann auch bei anderer Konfiguration oder auch nur Orientierung ein positives Ergebnis erhält.


    Was erfahrungsgemäß sehr sicher geht ist die Verwendung von CJointT und CalcJointT, um dann aus der Summe der Quadrate der einzelnen Achswinkelabstände die Wurzel zu ziehen, und diese dann mit einem recht kleinen Wert vergleichen.


    Grüße,

    Michael

    Der Rücksprung geht so, als wäre die unterbrochene Routine normal zu Ende. Nur, wenn Du noch weitere verschachtelte Ebenen mit Aufrufen dazwischen hast, dann so, als wären die dann auch zu Ende.


    Du kannst auf alle Daten zugreifen, die im selben Modul liegen, also im zur *.src gehörigen *.dat. Oder Du musst mit dem Schlüsselwort GLOBAL arbeiten.


    Und Du kannst auch weitere Routinen aufrufen. Wichtig ist halt, dass Du im Hinterkopf behältst, dass Du noch im Interrupt bist, und dort irgendwann wieder rauskommst, und dass Du währenddessen für Interrupts mit geringerer Priorität taub bist.


    Auf GOTO würde ich an Deiner Stelle lieber verzichten, ich hab' keine Ahnung ob man überhaupt mit GOTO aus nem Interrupt kommt. Hört sich jedenfalls an wie kontrollierte Selbstzerstörung.


    Grüße,

    Michael

    Hm, WaitUntil u. WaitDi wird im Vorlauf abgearbeitet; wenn die Bedingung stimmt, dann geht er mit Zone drüber. Ist halt nur etwas undefiniert, wo er dann stehenbleibt, wenn die Bedingung NICHT zutrifft, er ist aber innerhalb der Zone. Ausser man verwendet \InPos, dann endet er immer auf dem Punkt, auch wenn man mit Zone programmiert.


    Ausgänge kriegt man mit MoveXDo bzw. komplexere Aufgaben mit MoveXSync ganz gut in den Griff. Unabhängige MultiMove-Roboter verriegeln wir hauptsächlich über programmierte Kollisionsbereiche, wo auf PERS (als taskübergreifend) zurückgegriffen wird. Der Trick ist halt da, dass man sich als Task entweder selbst blockiert oder sofort dem anderen sagt, was man gerne für sich selbst reserviert hätte.


    Man muss "in der Mitte" dann halt ein wenig mehr "fuzzy" programmieren. Nach dem "Schrittkettensignal" und vor der nächsten Bedingungsprüfung noch ein paar Bahnpunkte haben in Richtung "home" oder was immer man damit meint.


    Oder habe ich Deine Frage mißverstanden?


    Grüße,

    Michael