El ambiente de trabajo A2plus es un Ambiente de trabajo externo para ensamble diferentes piezas en FreeCAD.
Esta documentación describe la versión de A2plus 0.4.47 o más reciente.
El ambiente de trabajo A2plus es un complemento de FreeCAD. Se puede instalar fácilmente a través del de FreeCAD Administrador de complementos desde el menú Herramientas → Administrador de complementos.
A2plus está en desarrollo activo y obtendrá nuevas características con frecuencia. Por lo tanto, debería actualizarlo regularmente utilizando también el menú Herramientas → Administrador de complementos.
El código de A2plus está alojado y desarrollado en GitHub y también puede ser instalado manualmente copiándolo en el directorio Mod de FreeCAD.
Primero cambia a la barra de herramientas A2plus en FreeCAD. Para crear un ensamblaje crea un nuevo archivo en FreeCAD. Al principio este archivo necesita ser guardado. Se recomienda (pero no es necesario) guardarlo en la misma carpeta de las piezas que quieres ensamblar.
Ahora se pueden añadir piezas al ensamblaje utilizando el botón de la barra de herramientas o
. El botón
añade todos los cuerpos del archivo seleccionado como una sola pieza. Cuando se utiliza el botón
se puede elegir qué parte de un archivo debe ser importada como parte. De esta forma se puede, por ejemplo, importar sólo un boceto para ensamblar otras piezas utilizando el boceto para determinar las posiciones de las piezas.
La primera parte añadida obtiene una posición fija por defecto. (Puede cambiar esto más tarde a través de la propiedad de la parte DatosPosición fija.)
Parts that are already in the assembly can be cloned with the toolbar button .
To edit a part from the assembly, select it in the model tree and use the toolbar button . This will open the part into a new tab in FreeCAD or switch to its tab if the file is already opened.
To update changed parts in assemblies click on the toolbar button . The toolbar button
imports parts too but recursively over possible subassemblies. If you select one or some parts in FreeCAD's the tree view, A2plus will ask you to only update the selected parts.
Imported parts will keep their external dependencies and can be edited. For well-defined parts like screws it is however useful that their shape cannot be edited. This can be achieved with the toolbar button that converts the selected part to a static copy of the original part.
To save the assembly and close it afterwards, the toolbar button can be used.
Toggling the toolbar button sets the way you can select several several edges, faces etc.: Either with a single click or by Ctrl+click.
Assembling parts is done by adding constraints between parts. After a constraint A2plus will move the parts according to the constraint if possible.
To create a constraint between parts, keep the Ctrl key pressed and select each an edge or face of two parts. Then click the toolbar button of the desired constraint. A dialog will pop up that is descried in section Constraints. The constraint will be added in the model tree attached to the affected parts.
For complex constraints between parts A2plus might fail to solve the constraints. Therefore also have a look at section Troubleshooting for strategies to resolve such cases.
The more parts you add, the more important it is to keep track. A2plus therefore offers these tools to move and view parts:
When creating a constraint such a dialog will be displayed after you pressed a constraint toolbar button:
Above: The A2plus Constraint Properties Dialog
For certain constraints it allows you to modify the constraint direction. With the button Solve you can check beforehand if this new constraint can be solved by A2plus. If not, have a look at section Troubleshooting.
Constraints can be disabled by changing its visibility. This is done by selecting the constraint in the tree view and pressing Space. This toggles the property DatosSuppressed. A suppressed constraint is not taken into account when the assembly is solved.
A2plus provides the following constraints:
Select either a vertex (point), circle or sphere on each part. If a circle or sphere was selected, its center point will be used for the constraint. The toolbar button adds the constraint pointIdentity that make the vertices coincident.
Select a vertex (point), or circular edge (will select its center point), or a spherical face (will also select its center point) on one part and an edge on the other part. The toolbar button adds the constraint pointOnLine. It will put the vertex on the edge.
Select a vertex (point), or circular edge (will select its center point), or a spherical face (will also select its center point) on one part and a plane on the other part. The toolbar button adds the constraint pointOnPlane. The constraint dialog allows you to specify an offset between the point and the plane. This offset can also be flipped between both sides of the plane. If the offset is zero, the constraint will put the vertex on the plane.
Select either a spherical face or a vertex (point) on both parts. The toolbar button adds the constraint sphereCenterIdent. It will either make the center of the spheres, the center of the sphere and the vertex, or the vertices coincident.
Select a circular edge on both parts. The toolbar button adds the constraint circularEdge. The constraint dialog allows you to specify an offset between the edges. This offset can also be flipped. You can furthermore set the constraint direction and lock the rotation of the parts. If the offset is zero, the constraint will put the edges concentric in the same plane.
Select either a cylindrical face or a linear edge on both parts. The toolbar button adds the constraint axisCoincident. The constraint dialog allows you to specify the axis direction. The dialog allows you furthermore to lock the rotation of the parts. The constraint will make the axes or lines coincident.
Select either a cylindrical face or a linear edge on both parts. The toolbar button adds the constraint axisParallel. The constraint dialog allows you to specify the axis direction. The constraint will make the axes or lines parallel.
Select either a cylindrical face or a linear edge on one part and a plane on the other part. The toolbar button adds the constraint axisPlaneParallel. The constraint will make the axis or line parallel to the plane.
Select either a cylindrical face or a linear edge on one part and a plane on the other part. The toolbar button adds the constraint axisPlaneNormal. The constraint will make the axis or line normal to the plane.
Select either a cylindrical face or a linear edge on one part and a plane on the other part. The toolbar button adds the constraint axisPlaneAngle. The constraint will at first make the axis parallel to the plane. Then you can adjust the angle for the axis in the appearing constraint settings dialog.
Select a plane on both parts. The toolbar button adds the constraint planesParallel. The constraint dialog allows you to specify the constraint direction. The constraint will make the planes parallel.
Select a plane on both parts. The toolbar button adds the constraint planeCoincident. The constraint dialog allows you to specify a constraint direction and an offset between the planes. This offset can also be flipped. If the offset is zero, the constraint will make the planes coincident.
Select a plane on both parts. The toolbar button adds the constraint angledPlanes. The constraint dialog allows you to specify an angle between the planes. The constraint will make the planes at first parallel and the set the specified angle.
Select either a closed edge or a plane on both parts. The toolbar button adds the constraint centerOfMass. The constraint dialog allows you to specify an offset between the edges or planes. This offset can also be flipped. You can furthermore set the constraint direction and lock the rotation of the parts. If the offset is zero, the constraint will put the edges or planes into the same plane.
An assembly can contain other assemblies. They are added like parts by pressing the toolbar button and selecting a *.FCStd file containing an assembly. Such subassemblies can also be edited like parts using the toolbar button
. Please make sure for higher assembly stages that you update the assembly recursively via the toolbar button
when there were changes.
Possible constraints for a selection are displayed in the toolbar and the Constraint Tools dialog by enabling the corresponding buttons. The Constraint Tools dialog is opened via the toolbar button . It is intended to stay open to be able to add quickly several constraints to the assembly.
Existing constraints can be edited by selecting them in the model tree and then either double-clicking on it or using the toolbar button . This opens the Constraint Properties dialog.
Constraints can be temporarily suppressed by selecting them in the model tree and changing the tree element property DatosSuppressed.
Constraints can be deleted either by selecting them in the model tree and pressing Del or by selecting a part with constraints in the model tree and using the toolbar button .
All constraints can be resolved at any time with the toolbar button . If the toolbar button
is turned on a resolve is automatically done after every edit of a constraint.
The toolbar button affects the constraint that was added most recently. It flips the constraint direction.
With the tool, it is possible the show and inspect existing constraints. After clicking it a dialog pops up. Then either select a part in the tree and click the button Import from part to get all constraints of this part, or select one or more constraints in the tree and click the button Import from Tree. As result you get all info about the constraints. By clicking in the column Suppress a single constraint can be suppressed. For more features, follow the tooltips of the other dialog buttons.
To create part lists of assemblies, the different parts of the assembly must get part info that can be read by A2plus. This is done by editing the part using the toolbar button . In the opened part press the toolbar button
and a spreadsheet with the name #PARTINFO# is created.
The structure of the spreadsheet is like this:
Fill out the grey fields with info you have and want to have in the final parts list.
In the assembly or subassembly use the toolbar button . It will ask you if you want to iterate recursively over all subassemblies. Click on Yes. This creates a new spreadsheet with the name #PARTSLIST#. It contains the info from the different #PARTSINFO# spreadsheets of the parts in a list like this:
The position (POS) is automatically set according to the appearance of the parts in the model tree. The top level part will get POS 1.
The quantity (QTY) is automatically calculated from the assembly. If a parts is twice in the assembly it will get QTY 2.
If you have updated a part info you can refresh the parts list by pressing the toolbar button again.
For subassemblies you can also create an info spreadsheet using the toolbar button . When you create or update the parts list of the main assembly this info will be used if you click on No for the question if you want to iterate recursively over all subassemblies. Then the different parts are not in the parts list but only the subassemblies.
The toolbar button creates an HTML file with the structure of your assembly. The file will by default be created in the folder of your assembly file. The structure looks like this:
The button labels every part of the assembly with its degrees of freedom. Furthermore it outputs a list with all parts and their dependencies. The list is output into FreeCAD's widget Report view. If this widget is currently not visible, it can either be shown by right-clicking into an empty part of the FreeCAD toolbar area and then choosing it in the appearing context menu or with the menu View → Panels → Report view.
The degrees of freedom labels can be removed by clicking the button again.
The button labels every part of the assembly in the 3D view with its name. The part labels can be removed by clicking the button
again
Sometimes it is necessary to have the whole assembly combined as one shape. This shape can then for example be used for 3D printing in the Mesh workbench or for drawings in the TechDraw workbench. It is created using the toolbar button . The shape is by default not made visible. Use the same toolbar button to update the shape in case of changes in the assembly.
With the menu A2plus → Misc → Convert absolute paths of imported parts to relative ones you can convert absolute paths of imported parts to relative ones.
The a2plus preferences can be accessed via FreeCAD's menu Edit → Preferences and there in the section A2plus. You can set the following options:
Sooner or later you will get the problem that A2plus cannot solve the constraints you set. To overcome this, there are different strategies:
This is the safest method when you have several constraints because this tool attempts to solve one constraint after another until it finds the conflicting constraint. Then you can go on with the other strategies to resolve the identified constraint. The tool is called using the toolbar button .
Sometimes constraints seem to be consistently defined but they can nevertheless not be solved. An example: Assume you have a planesParallel constraint set for two planes. Now you want to set for the same planes the planeCoincident constraint and A2plus cannot solve this. Then the constraint directions of planesParallel and planeCoincident are different. Use the same direction for both constraints to fix this.
A2plus offers to automatically check the right direction for all constraints of the assembly using the toolbar button .
Most cases of unsolvable constraints occur directly when adding a new constraint. The solution is then to delete the constraint you added last. A2plus will propose this, too.
Sometimes the deletion strategy is the only one, for example when you edited a part in FreeCAD so that faces or edges connected to constraints are missing. You should then delete one constraint that is connected to the changed part at a time. Use the toolbar button after every deletion to see if you reached a solvable state.
When you got an assembly that can be solved, add step by step the constraints you need.
In some cases the solver only needs better start values to solve the constraints. Take for example the case that you have an axle part and a wheel part. You add a axisCoincident constraint and get no info that the solver failed but the parts are not moved accordingly and in the Report view widget of FreeCAD you see "REACHED POS-ACCURACY :0.0". A solution for this is to move the parts closer to that position you like to get by the constraint.
Note: Assure that at least one part of the constraint has the property Datosfixed Position set to false.
If you miss some features of your part after the import to an A2plus assembly, check the property DatosTip.
A2plus imports bodies of parts with all their features up to the tip feature. This is sensible because setting the tip to a certain feature means that all features behind the tip should not appear in the final part. So if you miss a part feature in A2plus, open the part via the toolbar button , then select a body and look at its property DatosTip. If the tip is not at the feature where you want it, right-click on the feature where the tip should be and choose
Set tip. Finally save the part and reload the assembly using the toolbar button
.
If you cannot see a clear reason why some constraints cannot be resolved, you can try to use the toolbar button . This will resolve all constraints and re-group then again under the different parts.
Assemblies created with A2plus older than March 2019 do not show the correct icons for imported parts and have obsolete properties. These assemblies can be migrated to A2plus version 0.4.35 and newer using the menu A2plus → Misc → Migrate proxies of imported parts. After doing this, you must save and reopen your assembly file.
This strategy is not necessary for Windows.
On some operating systems you can get problems if the file names or the file paths of parts or the assembly contain accented characters. Therefore avoid such characters and also special characters in general.
This strategy is no longer necessary for assemblies created with A2plus 0.3.11 or newer because A2plus issues now a warning for missing fixed positions.
When you set a constraint between two parts and no part has the property Datosfixed Position set to true or is connected by a constraint to a part with Datosfixed Position set to true, the constraint cannot be solved. The same happens if both parts of the constraint have Datosfixed Position set to true.
Then A2plus outputs the info about the failed solution, but sometimes you only see that the parts are not moved accordingly and in the Report view widget of FreeCAD you see "REACHED POS-ACCURACY :0.0". This means the solver finished without errors but it could actually not solve the constraints.
Therefore check that at least one of your parts in the assembly has Datosfixed Position set to true. Then assure that you only set constraints to a part which is somehow connected to the fixed part. To visualise these dependencies, see section Assembly Structure.
This strategy is no longer necessary for assemblies created with A2plus 0.4.0 or newer because A2plus rotates the parts now automatically a bit in the background to get a sufficient start angle for the solver.
The solver often fails for the constraint angledPlanes if the two selected planes have currently an angle of 0° or 180°. (The parts are not moved accordingly and in the Report view widget of FreeCAD you see "REACHED POS-ACCURACY :0.0".) A solution for this is to rotate one part by a few degrees using FreeCAD's transform feature (right-click on the part in the model tree and select in the context menu Transform).
Note: Assure that at least one part of the constraint has the property Datosfixed Position set to false.
A2plus offers animations via dragging and via Python scripts.
Dragging animations are interactive since you trigger it by dragging a part of the assembly. To get these kind of animations:
Here is an example assembly to try out the dragging animation: A2p_example-for-dragging-animation.FCStd
Above: The dragging animation using the example assembly
Despite the dragging mode offers nice interactive animations, they are sometimes not precise enough for screencasts or videos. Scripted animations have the advantage that they animate movements and rotations in a defined way. You can for example rotate a part by exactly 10° back and forth. The following examples use an assembly where a part should be rotated. If you try to animate this using the dragging mode, you will see how hard it is to get a back and forth rotation that you can e.g. show your boss in a presentation. With the interactive example script, however, this is an easy task.
A scripted animation works usually this way:
It is also possible to change instead of a placement parameter a constraint, for example the distance between 2 planes.
The simplest way to script an animation is a non-interactive animation that follows a defined movement. Here is an example: First download this assembly file: A2p_animated-example.FCStd and also this Python script: A2p_animation-example-script.py.
This is the content of the script and the lines beginning with a '#' describe what the different script lines do:
# import libraries
import time, math, PySide
import A2plus.a2p_solversystem as a2p_solver
# we use steps of 1 degree
step = 1
# wait 1 ms between every step
timeout = 0.001
# initial angle is 0 degree
angle = 0
# we take the currently opened document
document = FreeCAD.activeDocument()
# we want later change the rotation angle of the part "star_wheel_001"
starWheel = document.getObject("star_wheel_001")
# define a progress dialog running from 0 to 360
progressDialog = PySide.QtGui.QProgressDialog(u"Animation progress", u"Stop", 0, 360)
# the while block is the main loop to change the angle and solve
# the assembly constraints subsequently
while angle < 360: # run this loop until we have one full turn (360 degrees)
# increase the rotation angle
angle += step
# set the new angle to the progress dialog
progressDialog.setValue(angle)
# change the rotation angle of the part "star_wheel_001"
starWheel.Placement.Rotation.Angle = math.radians(angle)
# solve the constraints
a2p_solver.solveConstraints(document, useTransaction=True)
# update the view after the solving ('Gui' stands for 'graphical user interface')
FreeCADGui.updateGui()
# bring the progress dialog to front
PySide.QtGui.QWidget.raise_(progressDialog)
# if 'Stop' was pressed in the dialog, exit the loop
if progressDialog.wasCanceled():
angle = 360
# wait some time before performing the next step
time.sleep(timeout)
To use the script to perform the animation, we must
To practice, just change something in the script and execute it afterwards. For example increase step to 5.
This is the result of the example animation:
The first script example demonstrated how to create an animation without any user feedback. For most applications you need to interact with the animation. For example the interesting issue in the example is to see how the driving pins cross the center groove of the wheel. To have a closer look you might present this detail to your colleagues or boss. Therefore you need an interactive solution.
This can be done by using a custom animation dialog with a slider. By moving the slider you can set the rotation angle and therefore rotate back and forth at interesting position.
We use the same assembly file: A2p_animated-example.FCStd and this Python script: A2p_animation-example-script.py.
This is the content of the script to get the interactive animation dialog:
# import libraries
import time, math, PySide, sys
import FreeCAD.A2plus.a2p_solversystem as a2p_solver
from FreeCAD import Units
from PySide import QtCore, QtGui
# wait 1 ms after every calculation
timeout = 0.001
# we take the currently opened document
document = FreeCAD.activeDocument()
# we want later change the rotation angle of the part "star_wheel_001"
starWheel = document.getObject("star_wheel_001")
class AnimationDlg(QtGui.QWidget): # the animation dialog
def __init__(self): # to initialize the dialog
super(AnimationDlg, self).__init__()
self.initUI()
def initUI(self): # the definition of the dialog components
self.setMinimumSize(self.minimumSizeHint()) # set the minimal dialog size to minimum
self.setWindowTitle('Animation Dialog')
# use a grid layout for the whole form
self.mainLayout = QtGui.QGridLayout()
self.lineNo = 0 # first dialog grid line
# add description label
DescriptionLabel = QtGui.QLabel(self)
DescriptionLabel.setText("Change slider to change rotation angle")
self.mainLayout.addWidget(DescriptionLabel,self.lineNo,0,1,4)
# next dialog grid line
self.lineNo += 1
# add a label; there is no need for the "self." prefix because we don't want to change the label later
LabelMin = QtGui.QLabel(self)
LabelMin.setText("Min")
LabelMin.setFixedHeight(32)
self.mainLayout.addWidget(LabelMin,self.lineNo,0)
# add a spin edit to define the slider minimum
self.MinEdit = QtGui.QSpinBox(self)
# get the angle unit as string
self.MinEdit.setSuffix(" " + str(FreeCAD.Units.Quantity(1, FreeCAD.Units.Angle))[2:])
self.MinEdit.setMaximum(999)
self.MinEdit.setMinimum(0)
self.MinEdit.setSingleStep(10)
self.MinEdit.setValue(0)
self.MinEdit.setFixedHeight(32)
self.MinEdit.setToolTip("Minimal angle for the slider")
QtCore.QObject.connect(self.MinEdit, QtCore.SIGNAL("valueChanged(int)"), self.setMinEdit)
self.mainLayout.addWidget(self.MinEdit,self.lineNo,1)
# add the slider
self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
self.slider.setRange(0, 360)
self.slider.setValue(0)
self.slider.setFixedHeight(32)
self.slider.setToolTip("Move the slider to change the rotation angle")
QtCore.QObject.connect(self.slider, QtCore.SIGNAL("sliderMoved(int)"), self.handleSliderValue)
self.mainLayout.addWidget(self.slider,self.lineNo,2)
# add a label
LabelMax = QtGui.QLabel(self)
LabelMax.setText("Max")
LabelMax.setFixedHeight(32)
self.mainLayout.addWidget(LabelMax,self.lineNo,3)
# add a spin edit to define the slider maximum
self.MaxEdit = QtGui.QSpinBox(self)
# get the angle unit as string
self.MaxEdit.setSuffix(" " + str(FreeCAD.Units.Quantity(1, FreeCAD.Units.Angle))[2:])
self.MaxEdit.setMaximum(999)
self.MaxEdit.setMinimum(1)
self.MaxEdit.setSingleStep(10)
self.MaxEdit.setValue(360)
self.MaxEdit.setFixedHeight(32)
self.MaxEdit.setToolTip("Maximal angle for the slider")
QtCore.QObject.connect(self.MaxEdit, QtCore.SIGNAL("valueChanged(int)"), self.setMaxEdit)
self.mainLayout.addWidget(self.MaxEdit,self.lineNo,4)
# next dialog grid line
self.lineNo += 1
# add a spacer
self.mainLayout.addItem(QtGui.QSpacerItem(10,10), 0, 0)
# add a label
LabelCurrent = QtGui.QLabel(self)
LabelCurrent.setText("Current angle:")
LabelCurrent.setFixedHeight(32)
self.mainLayout.addWidget(LabelCurrent,self.lineNo,1)
# output the current angle
self.CurrentAngle = QtGui.QLineEdit(self)
self.CurrentAngle.setText(str(0))
self.CurrentAngle.setFixedHeight(32)
self.CurrentAngle.setToolTip("Current rotation angle")
self.CurrentAngle.isReadOnly()
self.mainLayout.addWidget(self.CurrentAngle,self.lineNo,2)
# add label for the unit
LabelUnit = QtGui.QLabel(self)
LabelUnit.setText("deg")
LabelUnit.setFixedHeight(32)
self.mainLayout.addWidget(LabelUnit,self.lineNo,3)
# button to close the dialog
self.Close = QtGui.QPushButton(self)
self.Close.setText("Close")
self.Close.setFixedHeight(32)
self.Close.setToolTip("Closes the dialog")
QtCore.QObject.connect(self.Close, QtCore.SIGNAL("clicked()"), self.CloseClicked)
self.mainLayout.addWidget(self.Close,self.lineNo,4)
# place the defined grid layout to the dialog
self.setLayout(self.mainLayout)
self.update()
def handleSliderValue(self):
# set slider value as angle
starWheel.Placement.Rotation.Angle = math.radians(self.slider.value())
# output current angle
self.CurrentAngle.setText(str(self.slider.value()))
# solve the constraints
a2p_solver.solveConstraints(document)
# update the view after the solving ('Gui' stands for 'graphical user interface')
FreeCADGui.updateGui()
# wait some time, important to give time to perform calculations
time.sleep(timeout)
def setMinEdit(self):
# assure that the minimum is samller than the maximum
if self.MinEdit.value() >= self.MaxEdit.value():
self.MaxEdit.setValue(self.MinEdit.value() + 1)
self.slider.setRange(self.MinEdit.value(), self.MaxEdit.value())
def setMaxEdit(self):
# assure that the minimum is samller than the maximum
if self.MinEdit.value() >= self.MaxEdit.value():
self.MinEdit.setValue(self.MaxEdit.value() - 1)
self.slider.setRange(self.MinEdit.value(), self.MaxEdit.value())
def CloseClicked(self):
AnimationDialog.close()
# create and show the defined dialog
AnimationDialog = AnimationDlg()
AnimationDialog.show()
# run this loop when the dialog is visible
while AnimationDialog.isVisible():
# update the view; important to give the OS feedback the dialog is alive
FreeCADGui.updateGui()
# bring the dialog to front, so that the dialog is always visible
QtGui.QWidget.raise_(AnimationDialog)
# output slider value here too because during the calculation the slider might have been moved
AnimationDialog.CurrentAngle.setText(str(AnimationDialog.slider.value()))
The dialog defined in the script looks like this:
To understand the script syntax better, here is some command info:
starWheel.Placement.Rotation.Angle = math.radians(angle)
Here we change the placement property Rotation.Angle
of the part get got previously as starWheel
. This property gets the angle as radian. The function radians()
from the library math
converts the angle from degree to radian.
The property Rotation.Angle
uses the current placement axis of the part (in our example the X-axis). To rotate the part e.g. around the Z-axis one can set the rotation axis (before calling the rotation command) using the command:
starWheel.Placement.Rotation.Axis = FreeCAD.Vector(0,0,1)
Instead of rotating, parts can also be moved. To change for example the placement in Y-direction of the wheel, the command would be:
starWheel.Placement.Base.y = PositionShift
In this case we would not define the variable angle
but PositionShift
that we change on every loop run.
There are different ways to set the placement of a part. Some are documented here. Unfortunately there is no list (yet) with all possible placement commands.
a2p_solver.solveConstraints(document, useTransaction=False/True)
This is an A2plus-specific command. It solves the assembly constraints of the assembly we previously got as document
. The option useTransaction
specifies if FreeCAD should store every change in the undo/redo stack. For large animations you might therefore set it to false
.