Tutorial KinematicController/fr

Introduction
Ce tutoriel décrit comment générer un contrôleur cinématique simple à utiliser avec les assemblages créés avec l'atelier Assembly3 à partir de quelques lignes de code Python.

N'importe quel éditeur de texte peut être utilisé pour coder. Mon choix se porte sur Atom, mais l'éditeur intégré de FreeCAD fonctionne bien aussi.

Les exemples de code suivants peuvent être copiés et collés dans un fichier texte vide, puis enregistrés sous le nom de votre choix comme fichier ou.

Structure de base
La structure de base consiste en une fonction et un commutateur pour vérifier si la macro est utilisée comme un conteneur pour les classes, les méthodes, etc. ou si elle est exécutée seule. Seule la deuxième option lancera la fonction. Cette fonction est vide pour le moment.

Trouver les contraintes pilotes
Les contraintes pilotes sont des objets dans un document FreeCAD. Elles doivent être marquées pour pouvoir être trouvées.

Pour ce contrôleur, le suffixe doit être attaché au label d'une contrainte pilote. Il peut être séparé par un ou  pour plus de clarté, car nous ne vérifierons que si le label se termine par.

Une fonction qui reçoit un objet document et renvoie une liste de contraintes pilotes (les noms dans ce cas) fera l'affaire.

La fonction charge le document actif dans la variable, puis appelle la fonction  et lui transmet le contenu de. La liste retournée est chargée dans qui est ensuite vérifiée pour contenir au moins un élément. Si c'est le cas, la liste est finalement imprimée dans la Vue rapport.

La macro jusqu'à présent...

Panneau de contrôle
Le panneau de contrôle est construit à partir de widgets Qt, une fenêtre principale contenant plusieurs widgets d'entrée/sortie.

Chaque widget doit être importé avant de pouvoir être utilisé, mais ils peuvent être importés en un seul ensemble. La ligne d'importation est placée en haut du fichier.

Fenêtre principale
Pour la fenêtre principale, la ligne d'importation ressemble à ceci :

La fenêtre principale appelée est un objet de classe instancié à partir du widget.

Elle possède deux méthodes init. initialise le nouvel objet de la classe, gère les arguments entrants et lance qui gère tous les widgets de la fenêtre principale.

Pour lancer un seul panneau de commande, une instance, appelée, de cette classe sera créée avec (l'objet document) et  (le premier de la liste des contraintes de conduite) transférés à cette instance. Enfin, la méthode de la classe ouvre la fenêtre de dialogue.

Pour gérer plus d'un contrôleur, nous devons vérifier la liste des contrôleurs et créer une instance pour chaque élément de la liste et transférer l'élément en cours.

These lines replace the command in the else branch of the  function.

Note: Collecting a allows us to launch all panels at once. (I cannot explain this behaviour yet...)

Running the macro will display a clean empty dialog window waiting for widgets:



And the macro so far...

Setting parameters
Now it is time to fill the method:

represents the driving constraint and stores a keyword for its type. The latter is used to choose the correct property with each constraint.

Method getDriverType
For later use we need the driver type (Angle, Distance, Length) and so a method has to be defined:

This method checks if the type of the given constraint can be found in one of the lists, and returns which kind of dimension has to be controlled.

It is assumed that in the kinematic document the driver is marked correctly and working if edited manually. In this case there is no need to filter out geometric constraints such as Colinear or PointsCoincidence (but here would be the place to do so...)

Window properties
The window size is defined by its minimum and maximum dimensions. Using the same values results in a fixed size.

The title shows the driver name and whether its an angle, a distance, or a length. Finally the window is told to stay on top of all windows.

Setting more parameters
The next step is to extract the current value of the driver and set the default start and end values depending on the driver type.

A distance cannot be negative and exactly zero puzzles the solver and so the start value is set to 0.001. Angles accept negative values and get symmetric values. (If lengths accept negative values has to be proven finally...)

The unit suffix must be kept for returning the value to the constraint property in the end. Distances and lengths need values with units.

Dealing with units and displaying values as strings in several widgets requires to convert numbers into strings and back again quite often.

To complete the parameters we set a default number of steps that should be computed when the motion is automated and if the toggle is set to, a picture will be taken with each step of the motion.

Labels
Now three labels are added to display the start, end, and current value.

First the class must be imported i.e. the import list has to be extended like this:

Back in the method we insert:

The placement is done with the inherited method. In this case the description of a rectangle is used (X position, Y position, width, height).

The first and third lines could be combined, but it is not recommended for clarity reasons:

Running the macro with a kinematic assembly document would create a dialog window like this:



And the macro so far...

Slider
To change the current value to any number between start and end value a slider widget would fit.

First the class must be imported i.e. the import list has to be extended like this:

Back in the method and right after the labels section we insert:

The slider button is placed with the method. Its value has to be calculated from the current value and a step ratio. The ratio has to be calculated whenever a start or end value is changed and so we insert another method after the method.

To work with a ratio instead of altering the slider's min and max values has the advantage of a finer resolution for small values.

And after this one comes another method defining what to do when the slider position or the slider value changes. The method is called by the  method which also hands over the slider value as an argument.

It recalculates the current value from the slider position, rewrites the text of the label and changes the constraint property according to the driver type.

Running the command starts the solver to rearrange the assembly parts with the altered value.

The dialog window with the slider should look like this and is ready to control a motion:



We can start a dialog window for any opened document, they won't interfere with each other.

Text entry fields
To set the start and end value we use a line edit widget.

First the class must be imported i.e. the import list has to be extended like this:

Back in the method and between the labels and the slider sections we insert:

The entry fields display the default start and end values. They are not complete until we add the methods to deal with altered entries. This will be done by the methods and  that are inserted between the  and the  methods.

Both convert the received string value to a floating point number and change either or  and the corresponding label accordingly. After that the slider value is updated.

The dialog window with text entry fields should look like this and is ready to change the range of a motion:



And the macro so far...

Motion
To get the assembly in motion we need:
 * Buttons to trigger motion in the desired direction.
 * An input field to alter the number of steps for faster or smoother motions.
 * A check box to indicate if we want to shoot a sequence of images.

Forward and Backward buttons
To move the assembly parts automatically we need two buttons to trigger the motions, one towards the start position and one towards the end position. These two and a close button will use a widget.

Small assemblies compute a bit too fast and show jumps instead of a smooth motion. To slow it down we use the method of the  module which has to be imported first.

Another import and another widget:

Back in the method we insert the buttons after the slider section:

The methods dealing with pressed buttons are, , and. They are inserted after the method.

The method invokes the inherited method  which just closes the dialog window and thereby ends the macro.

Both and  count the steps that are left to go to reach the wanted position and calculate the length of a step according to the number of steps. For now we go with the default number of 10 steps.

Each round on the while loop increases/decreases the current value and updates the slider values which triggers in the background (see Slider paragraph). After a pause to let the computer provide another updated 3D view, counting down the steps left to go finishes the loop.

With no steps left the slider is set to the first/last slider position, just in case if a rounding error had occurred.

The dialog window with buttons should look like this and can now move the assembly by 10 steps towards the wanted start/end position:



And the macro so far...

Number of steps
The default setting is to get a quick impression if the assembly is moving as expected without wasting too much computing time.

If the parts jump rather than move smoothly, or if drivers based on angles tend to cause trouble when the difference between two angles is too large, then both can be fixed by increasing the number of steps.

And so another line edit widget is used to alter the number steps (placed after the existing line edit widgets):

The related method just fills the parameter  with the entered value. It is inserted after the method.

The dialog window able to change the number of steps should look like this:



Image sequence
When the motion of our assembly meets our expectations, we can take a picture of each step. The resulting sequence of images can be used to create a short gif animation.

To implement this functionality we need a widget, and a directory to store the images.

One more import and widget:

Back in the method we insert the check box after the slider section:

The method synchronises the parameter  and the display of the check mark.

To define the output parameters we use the method :

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:



And finally the whole macro

Don't forget to set the path in the output method!

Some imperfections

 * The order of the image sequence is reversed as we use the variable steps_left which is counted down.
 * The image directory and the image name are hard-coded.
 * Multiple Controllers are not synchronised.