Tutorial KinematicController/de

Einleitung
Diese Anleitung beschreibt, wie man eine einfache Kinematiksteuerung aus ein paar Zeilen Python-Kode erstellt, die mit Baugruppen des Arbeitsbereiches Assembly3 verwendet werden kann.

Jeder Texteditor kann zum Erstellen von Kode genutzt werden. Mein Favorit ist Atom, aber FreeCADs eingebauter Editor funktioniert auch bestens.

Die folgenden Kode-Beispiele können kopiert, in eine leere Textdatei eingefügt und dann unter einem selbstgewählten Namen als oder * abgespeichert werden.

Grundstruktur
Die Grundstruktur besteht aus einer Hauptfunktion und einer Weiche, an der überprüft wird, ob das Makro als Behälter für Klassen, Methoden usw. verwendet wird oder ob es eigenständig läuft. Nur die zweite Möglichkeit startet die Hauptfunktion. Noch ist diese Funktion leer.

Randbedingungen zum Antreiben finden
Die Randbedingungen zum Antreiben (Antriebe) sind Objekte in einem FreeCAD-Dokument. Sie müssen markiert sein, um gefunden zu werden.

Für diese Steuerung muss das Suffix an das Label eines Antriebs  angehängt werden. Es kann zur Verdeutlichung mit einem oder  abgetrennt werden, da nur geprüft wird ob das Label auf  endet.

Eine Funktion, der das Dokumentobjekt übergeben wird und die eine Liste von Antrieben zurück gibt, wird diese Arbeit erledigen.

Die Hauptfunktion lädt das aktive Dokument in die Variable  und ruft im Anschluss die Funktion   (Antriebs-Randbedingungen finden) auf und übergibt den Inhalt von. Die zurückgegebene Liste wird in die Variable abgelegt, die dann überprüft wird, ob sie wenigstens ein Element enthält. Wenn das der Fall ist, wird die Liste im Ausgabefenster angezeigt.

Das Makro bis hierhin...

Steuerungsfenster
Das Steuerungsfenster ist aus Qt-Widgets (window gadgets ~ Fenstergelöt) aufgebaut, einem Hauptfenster und einigen Ein- und Ausgabe-Widgets.

Alle Widgets müssen importiert werden, bevor sie verwendet werden können, aber sie können als ein kompletter Satz importiert werden.

Hauptfenster
Für das Hauptfenster sieht die Import-Zeile so aus:

Das Hauptfenster, genannt, ist ein Klassenobjekt, das eine Instanz des -Widgets ist.

Es enthält zwei init-Methoden. initialisiert das neue Klassenobjekt, verarbeitet eingehende Variablen und startet, die alle Widgets innerhalb des Hauptfensters verwaltet.

Um ein einzelnes Steuerungsfenster zu starten, wird eine Instanz dieser Klasse namens erstellt, mit  (dem Dokumentobjekt) und  (dem ersten Element auf der Liste der Antriebe), die an diese Instanz übergeben wurden. Schließlich öffnet die Methode der Klasse das Dialogfenster.

Um mehr als eine Antrieb zu verwenden, muss die Liste der Antriebe durchgesehen werden und für jedes Element der Liste eine Instanz erstellt werden, der das jeweilige Element übergeben wird.

Diese Zeilen ersetzen den Ausgabebefehl im else-Abschnitt der Hauptfunktion.

Hinweis: Das Zusammenstellen einer (Fensterliste) erlaubt es alle Fenster auf einmal zu starten. (Ich kann dieses Verhalten bisher nicht erklären...)

Lässt man das Makro laufen, erstellt es ein sauberes, leeres Dialogfenster, das auf Widgets wartet.



Das Makro bis hierhin...

Parameter setzen
Nun ist es Zeit die Methode zu befüllen:

The actuator to be used is the first item in the actuators list. (The list contains a single item now, but, if the controller can handle more than one driving constraint in the future, it may hold more.) ((Dieser Abschnitt ist veraltet und muss im Original überarbeitet werden. Das vollständige Makro weiter unten ist korrekt.))

Methode getDriverType
Für spätere Verwendung muss die Art des Antriebs ermittelt werden, Winkel, Abstand oder Länge (Angle, Distance, Length), daher muss eine Methode namens (Finde den Antriebstyp) definiert werden.

Diese Methode überprüft, ob die Art der gegebenen Randbedingung in einer der Listen zu finden ist, und gibt zurück, welche Art Maß zu steuern ist

Es wird angenommen, dass der Antrieb im Kinematikdokument korrekt markiert wurde und funktioniert, wenn er von Hand geändert wird. In diesem Falle ist es nicht nötig geometrische Randbedingungen wie Colinear oder PointsCoincidence herauszufiltern (aber hier wäre die Stelle es zu tun...)

Fenstereigenschaften
Die Fenstergröße wird über seine Größt- und Kleinstmaße festgelegt. Verwendet man jeweils dieselben Werte, wird eine konstante Größe festgelegt

Im Titel findet sich der Name des Antriebs und ob es sich um einen Winkel, einen Abstand oder eine Länge handelt. Schließlich wird das Fenster angewiesen über allen anderen Fenstern (sichtbar) zu bleiben.

Weitere Parameter setzen
Im nächsten Schritt wird der Wert des Antriebs ausgelesen und die Start- und Endwerte abhängig von der Antriebsart gesetzt.

Ein Abstand kann nicht negativ sein und exakt null verwirrt den Gleichungslöser, daher wird der Startwert auf 0,001 gesetzt. Winkel akzeptieren negative Werte und erhalten symmetrische Werte. (Ob Längen negative Werte akzeptieren, muss noch abschließend festgestellt werden...)

Die Einheiten müssen gespeichert werden, bis die Werte am Ende an die Eigenschaften der Randbedingungen zurückgegeben werden. Abstände und Längen benötigen Werte mit Einheiten.

Der Umgang mit Einheiten und die Darstellung der Werte als Zeichenketten in einigen Widgets erfordert es häufig Zahlen in Zeichenketten und wieder zurück zu verwandeln.

Um die Parameter zu vervollständigen, wird ein Wert für die Anzahl von Schritten vorgegeben, die berechnet werden solle, wenn die Bewegung automatisch erfolgt; und wenn der Umschalter auf  gesetzt ist, wird bei jedem Schritt der Bewegung ein Bild aufgenommen.

Label
Nun werden drei Label(-Widgets) hizugefügt, um Start-, End-, sowie den aktuellen Wert anzuzeigen

Zuerst muss die Klasse importiert werden, d. h. die Import-Liste muss, wie hier gezeigt wird, ergänzt werden:

Zurück in der Methode fügt man folgendes ein:

Die Platzierung erfolgt mit der ererbten Methode. In diesem Falle wird die Beschreibung eines Rechtecks verwendet (X-Position, Y-Position, Breite, Höhe)

Die ersten und dritten Zeilen könnten zusammengefasst werden, wird aber aus Gründen der Übersichtlichkeit nicht empfohlen.

Startet man das Makro aus einem Kinematikdokument heraus, erhält man ein Dialogfenster wie dieses:



Das Makro bis hierhin...

Schieberegler
Um den aktuellen Wert auf jede mögliche Zahl zwischen Start- und Endwert einzustellen, würde ein Schieberegler passen.

Zuerst muss die Klasse importiert werden, d. h. die Import-Liste muss, wie hier gezeigt wird, ergänzt werden:

Zurück in der Methode fügt man folgendes direkt nach dem Labels-Abschnitt ein:

Der Schieberknopf wird mit der Methode platziert. Sein Wert muss aus dem aktuellen Wert und dem Schrittverhältnis berechnet werden. Das Schrittverhältnis muss immer berechnet werden, wenn sich der Start- oder Endwert ändert, daher wird eine weitere Methode hinter der Methode eingefügt.

Ein Verhältnis zu verwenden anstatt die Kleinst- und Größtwerte des Schiebereglers zu verändern, hat den Vorteil einer feineren Auflösung für kleinere Werte.

Und nach diesem kommt eine weitere Methode, die festlegt, was zu tun ist, wenn sich die Position des Schiebers bzw. der Wert des Schiebereglers ändert. Die Methode wird von der Methode  aufgerufen, die auch den Wert des Schhiebereglers als Variable übergibt.

Sie berechnet den aktuellen Wert erneut aus der Schieberposition, überschreibt den Text des Labels und ändert die Eigenschaft der Randbedingung unter Beachtung der Art des Antriebs.

Wird der Befehl gestartet, beginnt der Gleichnungslöser die Bestandteile der Baugruppe dem geänderten Wert entsprechend neu anzuordnen.

Das Dialogfenster mit dem Schieberegler sollte so aussehen und ist jetzt bereit eine Bewegung zu steuern.



Es kann ein Dialogfenster für jedes geöffnete Dokument gestartet werden; sie beeinflussen sich nicht gegenseitig.

Texteingabefelder
Um Start- und Endwerte zu ändern kann man ein Line-Edit-Widget verwenden.

Zuerst muss die Klasse importiert werden, d. h. die Import-Liste muss, wie hier gezeigt wird, ergänzt werden:

Zurück in der Methode fügt man folgendes zwischen Labels- und Slider-Abschnitt ein:

Die Eingabefelder zeigen die voreingestellten Start- und Endwerte an. Sie sind aber erst komplett, wenn auch Methoden hinzugefügt werden, die die geänderten Werte verarbeiten. Das erledigen die Methoden  und, die zwischen den Methoden  und  eingefügt werden.

Beide wandeln die erhaltene Zeichenkette in eine Fließkommazahl und ändern den Startwert  bzw. Endwert und das dazugehörige Label. Danach wird der Schieber aktualisiert.

Das Dialogfenster mit den Texteingabefeldern sollte so aussehen und ist jetzt bereit den Bereich einer Bewegung zu ändern:



Das Makro bis hierhin...

Bewegung
um einen Zusammenbau in Bewegung zu setzen benötigt man:
 * Schaltflächen, die eine Bewegung in die gewünschte Richtung auslösen.
 * Ein Eingabefeld, um die Anzahl der schritte zu verändern, für schnellere oder fließendere Bewegungen.
 * Ein Optionsfeld (Checkbox), um das Erstellen einer Bildfolge zu aktivieren.

Vorwärts- und Rückwärts-Schaltflächen
Damit sich die Bauteile automatisch bewegen, werden zwei Schaltflächen benötigt, die die Bewegungen auslösen, eine in Richtung der Startposition und eine in Richtung der Endposition. Diese beiden und eine zum Schließen verwenden das Widget.

Kleinere Baugruppen werde etwas zu schnell berechnet und zeigen eher Sprünge anstatt einer fließenden Bewegung. Um sie zu verlangsamen wird die Methode des Moduls  verwendet, das zuerst importiert werden muss.

Ein weiterer Import und ein weiteres Widget:

Zurück in der Methode fügt man folgendes nach dem Slider-Abschnitt ein:

Die Methoden, die gedrückte Schaltflächen bearbeiten sind, , und. Sie werden nach der Methode eingefügt.

Die Methode ruft die ererbte Methode  auf, die nur das Dialogfenster schließt und damit das Makro beendet.

Beide Methoden und  zählen die verbleibenden Schritte, die noch zu gehen sind, bis man die gewünschte Position erreicht und berechnen die Schrittlänge entsprechend der Anzahl der Schritte. Zu diesem Zeitpunkt wird die voreingestellte Anzahl von zehn Schritten beibehalten.

Jede Runde in der While-Schleife erhöht/verringert den aktuellen Wert und aktualisiert den Schieber, wodurch im Hintergrund ausgelöst wird (siehe Absatz Schieberegler).

Wenn keine Schritte mehr übrig sind, wird der Schieber auf die erste bzw. letzte Position gesetzt, nur für den Fall, dass Rundungsfehler aufgetreten sind.

Das Dialogfenster mit den Schalflächen sollte so aussehen und kann jetzt einen Zusammenbau mit 10 Schritten auf die gewünschte Position bewegen:



Das Makro bis hierhin...

Anzahl der Schritte
Die Voreinstellung ist so gewählt, dass man einen schnellen Eindruck erhält, ob sich der Zusammenbau wie erwartet bewegt, ohne zu viel Rechenzeit zu verbrauchen.

Wenn die Bauteile eher springen als sich fließend zu bewegen, oder wenn winkelbasierte Antriebe Problemen bereiten, wenn der Unterschied zwischen zwei Winkeln zu groß ist, dann kann beides durch das Erhöhen der Anzahl der Schritte behoben werden.

Und ein weiteres Line-Edit-Widget wird verwendet, um die Anzahl der Schritte zu ändern (eingesetzt hinter den schon vorhandenen Line-Edit-Widgets):

Die zugehörige Methode füllt nur den Parameter  mit dem eingegebenen Wert. Sie wird nach der Methode eingefügt.

Das Dialogfenster, das in der Lage ist, die Anzahl der Schritte zu ändern sollte so aussehen:



Bildfolge
Sobald die Bewegung der Bauteile den Erwartungen entspricht, kann bei jedem Schritt ein Bild aufgenommen werden. Aus der entstandenen Bildfolge kann eine kurze GIF-Animation erstellt werden.

Um diese Funktionalität einzubauen, wird das Widget und ein Verzeichnis zum Speichern der Bilder gebraucht.

Ein weiterer Import und ein weiteres Widget:

Zurück in der Methode fügt man folgendes nach dem Slider-Abschnitt ein:

Die Methode synchronisiert den Parameter  und die Anzeige des Aktivierungshäkchens.

Um die Ausgabeparameter festzulegen wird die Methode verwendet:

First the image path has to be adapted to your OS; the last part is the image name without current number and file tag. This must be done manually for now.

Then follow file tag to finish the image name, image height and width, and how the background should be filled ( (3D view background),, , or ).

To always have a 3 digit number leading zeros have to be prefixed to the counter parameter.

Finally the scripted version of the command Std ViewScreenShot is used to take a picture based on the mentioned parameters.

Still no pictures taken!?! No problem, as this method doesn't get called yet, and so we need to insert a call in the while loop of and. Right after we insert this line:

Now the macro should be ready to control an assembly and to take pictures for an animated gif.

The final version of the dialog window:



Und schließlich das ganze Makro

Nicht vergessen den Pfad in der Ausgabemethode output anzugeben!

Ein paar Schwachstellen

 * Die Numerierung der Bildfolge ist umgekehrt, da die Variable steps_left (verbleibende Schritte) heruntergezählt wird.
 * Das Bildverzeichnis und der Name des Bildes sind im Makro hinterlegt (hard-coded).
 * Mehrfach geöffnete Steuerungsfenster sind nicht synchronisiert.