Pracovní plocha Assembly
Úvod
Pracovní prostředí Assembly je vestavěné pracovní prostředí pro sestavy v programu FreeCAD. Využívá open-source řešič Ondsel.
Nástroje
Assembly
Nová sestava: vytvoří kořenovou sestavu v aktuálním dokumentu nebo podsestavu v již existující aktivní sestavě.
Vložit součást: vloží součást do aktivní sestavy.
Nová součást: vloží novou součást.
Vyřešit sestavu: vyřeší aktuálně aktivní sestavu.
Rozložený pohled: vytvoří v aktivní sestavě kontejner rozložených pohledů, který obsahuje jeden nebo více rozložených pohledů.
Snapshot: captures the current assembly state (placement and visibility). Double-clicking the Snapshot object restores the assembly to that state. introduced in 26.3
Vytvořit simulaci: vytvoří simulaci aktuální sestavy. introduced in 1.1
Kusovník: vytvoří kusovník (BOM) na základě vybrané sestavy nebo na základě dokumentu.
- Tento nástroj je určen pro vývojáře a nebude součástí budoucích verzí. (viz diskusní vlákno)
Spoje
Přepnout ukotvení: zafixuje polohu a orientaci tvaru vzhledem k souřadnicovému systému sestavy, ke které patří.
Rigid Group: creates a rigid group that permanently locks the selected components together. introduced in 26.3
Pevný spoj: vytvoří spoj, který spojí dvě součásti sestavy a zabrání jakémukoli pohybu či otáčení; lze ho však použít i k definování jiných typů spojů.
Rotační spoj: vytváří kloubové spojení, které umožňuje otáčení dvou vybraných dílů kolem jedné osy.
Válcový spoj: vytvoří válcový spoj mezi dvěma vybranými díly, který umožňuje otáčení kolem jedné osy a posun podél téže osy.
Posuvný spoj: vytvoří posuvný (prizmatický) kloub mezi dvěma vybranými díly, který umožňuje lineární pohyb podél jedné osy a zároveň omezuje otáčení.
Kulový spoj: vytvoří kulový kloub mezi dvěma vybranými díly v jednom bodě, což umožňuje volnou rotaci kolem tohoto bodu, přičemž oba díly zůstávají v tomto bodě spojeny.
Vzdálenostní spoj: vytvoří vzdálenostní spoj mezi dvěma vybranými díly, čímž se stanoví vzdálenost mezi oběma díly.
Paralelní spoj: vytvoří paralelní spoj mezi dvěma vybranými díly tak, že osy Z vybraných souřadnicových systémů nastaví do rovnoběžné polohy.
Pravoúhlý spoj: vytvoří pravoúhlý spoj mezi dvěma vybranými díly tak, že osy Z vybraných souřadnicových soustav nastaví do pravoúhlého postavení.
Úhlový spoj: vytvoří úhlový spoj mezi dvěma vybranými díly a zafixuje úhel mezi osami Z vybraných souřadnicových systémů.
Ozubený hřebenový spoj: vytvoří ozubený hřebenový spoj, který spojuje posuv součásti kluzného kloubu s otáčením součásti otočného kloubu.
Šroubový spoj: vytvoří šroubový (špirálový) spoj, který spojuje posun součásti posuvného spoje s otáčením součásti otočného spoje.
Ozubený spoj: vytvoří ozubený spoj, který spojuje otáčení dvou součástí dvou různých otočných spojů.
Pásový spoj: vytvoří pásový spoj, který spojuje otáčení dvou součástí dvou různých otočných kloubů.
Předvolby
Předvolby: nastavení pro pracovní prostředí Assembly.
Příklad kliky a šoupátka
Tento příklad je dočasný a může být odstraněn, jakmile budou k dispozici odpovídající popisy či návody.
Sestava kliky a šoupátka
Vytvářená sestava se skládá ze čtyř částí: základny, posuvné tyče, kliky a ojnice. Tyto části jsou spojeny čtyřmi klouby.
Sestavené díly: Základna (oranžová), posuvná tyč (světle modrá), kliková hřídel (červená), ojnice (zelená)
Příprava dílů
V tomto příkladu jsou všechny součásti i sestava vytvořeny v jednom dokumentu.
Válcové tvary objektů jsou buď rovnoběžné, nebo kolmé; ostatní tvary nejsou pro tento příklad relevantní, pokud nedochází ke kolizím. S ohledem na to můžete modelovat vlastní objekty nebo je vytvořit pomocí níže uvedeného kódu v jazyce Python. Tento kód vytvoří nový dokument se čtyřmi objekty (jednoduššími než na obrázcích). Stačí zkopírovat a vložit následující řádky do konzole Pythonu:
import FreeCAD as App
import FreeCADGui as Gui
import Part
doc = App.newDocument()
box1 = Part.makeBox(140, 40, 7, App.Vector(0, -20, 0))
cyl1 = Part.makeCylinder(4, 8, App.Vector(120, 0, 7))
box2 = Part.makeBox(20, 12, 10, App.Vector(5, -6, 7))
cyl2 = Part.makeCylinder(6, 20, App.Vector(25, 0, 17), App.Vector(-1, 0, 0))
cyl3 = Part.makeCylinder(4, 20, App.Vector(25, 0, 17), App.Vector(-1, 0, 0))
shape = box1.fuse([cyl1, box2, cyl2]).removeSplitter().cut(cyl3)
base = doc.addObject("Part::Feature", "Base")
base.Shape = shape
box1 = Part.makeBox(4, 12, 12, App.Vector(-12, -6, 0))
box2 = Part.makeBox(14, 12, 4, App.Vector(-8, -6, 0))
cyl1 = Part.makeCylinder(4, 8, App.Vector(0, 0, 4))
cyl2 = Part.makeCylinder(4, 88, App.Vector(-12, 0, 6),App.Vector(-1, 0, 0))
shape = box1.fuse([box2, cyl1, cyl2]).removeSplitter()
slider_rod = doc.addObject("Part::Feature", "SliderRod")
slider_rod.Shape = shape
slider_rod.Placement.Base = App.Vector(100, -40, 0)
cyl1 = Part.makeCylinder(7.5, 4)
box1 = Part.makeBox(15, 30, 4, App.Vector(-7.5, 0, 0))
cyl2 = Part.makeCylinder(7.5, 4, App.Vector(0, 30, 0))
cyl3 = Part.makeCylinder(4, 6, App.Vector(0, 30, 4))
cyl4 = Part.makeCylinder(4, 4)
shape = cyl1.fuse([box1, cyl2]).removeSplitter().fuse(cyl3).cut(cyl4)
crank = doc.addObject("Part::Feature", "Crank")
crank.Shape = shape
crank.Placement.Base = App.Vector(125, -70, 0)
cyl1 = Part.makeCylinder(6, 4)
box1 = Part.makeBox(50, 12, 4, App.Vector(0, -6, 0))
cyl2 = Part.makeCylinder(6, 4, App.Vector(50, 0, 0))
cyl3 = Part.makeCylinder(4, 4)
cyl4 = Part.makeCylinder(4, 4, App.Vector(50, 0, 0))
shape = cyl1.fuse([box1, cyl2]).removeSplitter().cut(cyl3.fuse(cyl4))
connecting_rod = doc.addObject("Part::Feature", "ConnectingRod")
connecting_rod.Shape = shape
connecting_rod.Placement.Base = App.Vector(25, -70, 0)
mat = base.ViewObject.ShapeAppearance[0]
mat.DiffuseColor = (0.80, 0.60, 0.15, 0.0)
base.ViewObject.ShapeAppearance = (mat,)
mat = slider_rod.ViewObject.ShapeAppearance[0]
mat.DiffuseColor = (0.55, 0.70, 0.70, 0.0)
slider_rod.ViewObject.ShapeAppearance = (mat,)
mat = crank.ViewObject.ShapeAppearance[0]
mat.DiffuseColor = (0.70, 0.30, 0.20, 0.0)
crank.ViewObject.ShapeAppearance = (mat,)
mat = connecting_rod.ViewObject.ShapeAppearance[0]
mat.DiffuseColor = (0.55, 0.70, 0.0, 0.0)
connecting_rod.ViewObject.ShapeAppearance = (mat,)
doc.recompute()
view = Gui.ActiveDocument.ActiveView
view.viewIsometric()
view.fitAll()
Přidání sestavy
Pomocí nástroje Nová sestava přidejte do dokumentu sestavu.
Stromová struktura dílů a sestavy
Umístění dílů do sestavy
Ve stromovém zobrazení přetáhněte součásti na objekt Assembly. Nyní je může zpracovat řešič sestavy.
Všechny díly jsou nyní v kontejneru Sestavy
Uzemnění součásti
Aby sestava zůstala v požadované poloze, je třeba základní díl uzamknout, čili uzemnit, jak se tomu zde říká. Vyberte základní díl ve stromovém zobrazení nebo v 3D pohledu a použijte nástroj Přepnout ukotvení. Tím se zafixuje poloha základny vzhledem k lokálnímu souřadnicovému systému (LCS) kontejneru sestavy. Do kontejneru spojů se přidá objekt GroundedJoint.
Rozbalte kontejner Joints, abyste našli objekt GroundedJoint
Alternativa: Vložení odkazu
Místo výše zmíněných dvou kroků je také možné použít nástroj Component k umístění objektů do sestavy. První objekt se automaticky stane ukotvenou součástí. Je tedy nutné začít s objektem Base. Nástroj vytvoří propojení a původní objekty zůstanou mimo sestavu. Aby nedocházelo k záměně, doporučuje se je skrýt.
Vytvoření spojů
Spoj spojuje přesně dva prvky z různých částí. Tyto prvky lze volitelně vybrat před spuštěním požadovaného nástroje pro vytvoření spoje (výběr libovolného počtu prvků jiného než dva vede k prázdnému výběru). Tyto prvky určují polohu a orientaci LCS, která je znázorněna vyplněným kruhem v lokální rovině XY a třemi přímkami podél lokální osy X (červená), Y (zelená) a Z (modrá).
- Otočný kloub mezi základnou a klikou
Vybrané prvky + Otočný spoj → přestavěný klikový hřídel
Přesuňte Crank pomocí levého tlačítka myši. Měla by být možná pouze rotace kolem otočného bodu.
- Kloubový spoj mezi základnou a posuvnou tyčí
Vybrané prvky + Posuvný spoj → přesunutá tyč šoupátka
Přesuňte Slider Rod pomocí levého tlačítka myši. Měl by být možný pouze posun podél její osy.
- Otočný spoj mezi klikou a ojnicí
Vybrané prvky + Otočný spoj → přesunutá ojnice
Přesuňte ConnectingRod pomocí levého tlačítka myši. Měla by být možná pouze rotace kolem otočného bodu.
Pokud se v jedné přímce nachází více spojů, musíme řešiči pomoci najít rozumné řešení.
V případě potřeby klikněte na jednotlivé části a přetáhněte je do pozice, která usnadní výpočet.
- Válcové spojení mezi ojnicí a posuvnou tyčí
Vybrané prvky + Válcový spoj → dokončená Sestava
V hotové sestavě přetáhněte díly pomocí ukazatele myši podle použitých spojů.
Poznámka
Čep tyče šoupátka je orientován nadbytečně. Jeho osová čára je rovnoběžná s čepem základny v rámci kinematického řetězce vedoucího od základny přes kliku a ojnici, tj. jeho lokální osa Z se nemůže otáčet kolem žádné osy X ani Y. Kloub šoupátka rovněž brání otáčení své osy Z kolem dvou lokálních os, čímž vznikají dva nadbytečně omezené stupně volnosti. Válcový kloub namísto kloubu typu Slider by zablokoval pouze jednu rotaci, což by vedlo pouze k jedinému nadbytečně omezenému stupni volnosti.
Otáčení kliky
Abychom mohli řídit uspořádání sestavy pomocí úhlu mezi základnou a klikou, musíme změnit kloub typu Revolute mezi nimi na kloub typu Fixed. K tomu dvakrát klikněte na objekt typu Revolute ve stromovém zobrazení. V dialogovém okně změňte typ kloubu z Revolute na Fixed a upravte hodnotu otáčení podle potřeby (pohyb by měl sledovat pohyb kolečka myši).
Upozorňujeme, že změna typu kloubu změní jeho označení (Label), nikoli však jeho název (Name). V tomto případě se označení změní na "Fixed".
Chceme-li oživit sestavu, můžeme pomocí kódu v jazyce Python změnit rotaci (Offset1.Angle) kloubu typu Fixed. Stačí zkopírovat a vložit následující řádky do konzoly jazyka Python:
import math
import FreeCAD as App
import FreeCADGui as Gui
actuator = App.ActiveDocument.getObjectsByLabel("Fixed")[0]
for angle in range(0, 361, 10):
# A full rotation of the Crank in steps of 10°
actuator.Offset1.Rotation.Angle = math.radians(angle)
App.ActiveDocument.recompute()
Gui.updateGui()
Horní mez rozsahu musí být větší než 360, aby byl tento úhel zahrnut jako platný výsledek.
Příklad kardanového kloubu
Universal joint assembly
In this example a universal joint is created.
The assembly consists of three solid parts: two identical Forks and a Cross. Two additional non solid elements, Axle1 and Axle2, representing the angled axles, are also needed. The axles and the solid parts are connected with several joints.
Prepare parts
In this example all parts and the assembly are created in one document.
The Python code below will create a new document with four objects (only 1 Fork). Just copy-paste the following lines in the Python Console:
import math
import FreeCAD as App
import FreeCADGui as Gui
import Part
doc = App.newDocument()
axle1 = doc.addObject("Part::Line", "Axle1")
axle1.X2 = -80
axle1.Y2 = 0
axle1.Z2 = 0
axle2 = doc.addObject("Part::Line", "Axle2")
axle2.X2 = 80
axle2.Y2 = 0
axle2.Z2 = 0
axle2.Placement.Rotation.Angle = math.radians(20)
sph1 = Part.makeSphere(50, App.Vector(0, 0, 0), App.Vector(-1, 0, 0), 0, 90, 360)
box1 = Part.makeBox(50, 40, 80, App.Vector(-50, -20, -40))
cyl1 = Part.makeCylinder(20, 80, App.Vector(0, 0, -40))
cyl2 = Part.makeCylinder(20, 80, App.Vector(0, 0, 0), App.Vector(-1, 0, 0))
cyl3 = Part.makeCylinder(30, 60, App.Vector(0, -30, 0), App.Vector(0, 1, 0))
box2 = Part.makeBox(30, 60, 60, App.Vector(0, -30, -30))
cyl4 = Part.makeCylinder(15, 80, App.Vector(0, 0, -40))
cyl5 = Part.makeCylinder(15, 80, App.Vector(0, 0, 0), App.Vector(-1, 0, 0))
shape = sph1.common(box1).fuse([cyl1, cyl2]).cut(cyl3.fuse([box2, cyl4, cyl5]))
fork = doc.addObject("Part::Feature", "Fork")
fork.Shape = shape.removeSplitter()
fork.Placement.Base = App.Vector(0, 100, 0)
cyl1 = Part.makeCylinder(15, 80, App.Vector(0, 0, -40))
cyl2 = Part.makeCylinder(15, 80, App.Vector(0, -40, 0), App.Vector(0, 1, 0))
shape = cyl1.fuse([cyl2])
cross = doc.addObject("Part::Feature", "Cross")
cross.Shape = shape.removeSplitter()
cross.Placement.Base = App.Vector(70, 100, 0)
mat = fork.ViewObject.ShapeAppearance[0]
mat.DiffuseColor = (0.80, 0.60, 0.15, 0.0)
fork.ViewObject.ShapeAppearance = (mat,)
mat = cross.ViewObject.ShapeAppearance[0]
mat.DiffuseColor = (0.55, 0.70, 0.70, 0.0)
cross.ViewObject.ShapeAppearance = (mat,)
doc.recompute()
view = Gui.ActiveDocument.ActiveView
view.viewIsometric()
view.fitAll()
Change angle of axles
The angle between the axles is set to 20 degrees. If you want to change this value select Axle2 and change the Placement.Angle property. This property must be changed before moving Axle2 into the assembly.
Warning: parts may collide if the angle is too large.
Add an assembly
With the New Assembly tool add an assembly to the document.
Move the axles into the assembly
In the Tree View drag and drop the axles on the Assembly object.
Ground the axles
Select the two axles in the Tree View and use the Toggle Grounded tool.
Move the solids into the assembly
For the other objects we will use the Component tool:
- Invoke the tool.
- In the dialog that opens click the Cross object once, and the Fork object twice.
- Press the OK button.
- Make the objects outside the assembly invisible.
- If the objects inside the assembly overlap too much you can drag them to a new position.
Apply joints
- A Revolute joint between Axle1 and Fork001
Selected elements + Revolute Joint + Offset of +40mm or -40mm → rearranged Fork001
If you invoke the tool first and then select the elements, you can click near the correct endpoint of Axle1 to avoid having to enter an offset.
- A Cylindrical joint between Fork001 and Cross001
Selected elements + Cylindrical Joint → rearranged Cross001
- A Cylindrical joint between Axle2 and Fork002
Selected elements + Cylindrical Joint → rearranged Fork002
- A Cylindrical joint between Cross001 and Fork002
Selected elements + Cylindrical Joint → rearranged Cross001 and Fork002
Drive the universal joint
The universal joint can be driven by moving Fork001 with the left mouse.
If you want to check the situation at distinct rotation angles do the following:
- Change the Cylindrical joint between Axle1 and Fork001 to a Fixed joint.
- Select the Offset1.Angle property of the Fixed joint and roll the mouse wheel.
- The universal joint may be positioned to any angle.
Example vise
Assembly of a vise
In this example a vise is created.
The assembly consists of three solid parts: a fixed and a movable jaw and a screw with a lever. One additional non solid element, a crank, is also needed. The crank and the solid parts are connected with several joints.
A Screw Joint couples the translation of a part with a Slider Joint to the rotation of a part with a Revolute Joint. The screw part shall make both a translation and a rotation movement hence it must be a part with a Cylindrical Joint. In this assembly, the screw part will be coupled to the movable jaw with a Distance Joint, to the non solid crank with a Parallel Joint, and to the fixed jaw with a Cylindrical Joint.
Prepare parts
In this example all parts and the assembly are created in one document.
The Python code below will create a new document with four objects. Just copy-paste the following lines in the Python Console:
import math
import FreeCAD as App
import FreeCADGui as Gui
import Part
doc = App.newDocument()
box1 = Part.makeBox(95, 40, 75, App.Vector(0, -20, -22))
cyl1 = Part.makeCylinder(35, 80, App.Vector(0, -40, 53), App.Vector(0, 1, 0), 90)
box2 = Part.makeBox(20, 80, 30, App.Vector(-20, -40, 58))
cyl2 = Part.makeCylinder(15, 80, App.Vector(-15, -40, 58), App.Vector(0, 1, 0), 90)
box3 = Part.makeBox(5, 80, 15, App.Vector(-20, -40, 58))
box4 = Part.makeBox(35, 24, 24, App.Vector(0, -12, -12))
box5 = Part.makeBox(60, 34, 69, App.Vector(35, -17, -19))
cyl3 = Part.makeCylinder(20, 55, App.Vector(-20, -40, 53), App.Vector(1, 0, 0))
cyl4 = Part.makeCylinder(20, 55, App.Vector(-20, 40, 53), App.Vector(1, 0, 0))
cyl5 = Part.makeCylinder(5, 35, App.Vector(0, 0, 38), App.Vector(1, 0, 0))
box6 = Part.makeBox(7, 88, 15, App.Vector(-22, -44, 75))
box7 = Part.makeBox(95, 90, 10, App.Vector(0, -45, -32))
shape = box1.fuse([cyl1, box2, box6, box7]).cut(cyl2.fuse([box3, cyl3, cyl4, cyl5, box4, box5]))
fixedJaw = doc.addObject("Part::Feature", "FixedJaw")
fixedJaw.Shape = shape.removeSplitter()
fixedJaw.Placement.Rotation.Axis = App.Vector(0, 0, 1)
fixedJaw.Placement.Rotation.Angle = math.radians(180)
box1 = Part.makeBox(35, 40, 75, App.Vector(0, -20, -22))
cyl1 = Part.makeCylinder(35, 80, App.Vector(0, -40, 53), App.Vector(0, 1, 0), 90)
box2 = Part.makeBox(20, 80, 30, App.Vector(-20, -40, 58))
cyl2 = Part.makeCylinder(15, 80, App.Vector(-15, -40, 58), App.Vector(0, 1, 0), 90)
box3 = Part.makeBox(160, 24, 24, App.Vector(-160, -12, -12))
box4 = Part.makeBox(5, 80, 15, App.Vector(-20, -40, 58))
box5 = Part.makeBox(160, 18, 18, App.Vector(-160, -9, -9))
cyl3 = Part.makeCylinder(20, 55, App.Vector(-20, -40, 53), App.Vector(1, 0, 0))
cyl4 = Part.makeCylinder(20, 55, App.Vector(-20, 40, 53), App.Vector(1, 0, 0))
cyl5 = Part.makeCylinder(5, 35, App.Vector(0, 0, 38), App.Vector(1, 0, 0))
box6 = Part.makeBox(7, 88, 15, App.Vector(-22, -44, 75))
shape = box1.fuse([cyl1, box2, box3, box6]).cut(cyl2.fuse([box4, cyl3, cyl4, box5, cyl5]))
movableJaw = doc.addObject("Part::Feature", "MovableJaw")
movableJaw.Shape = shape.removeSplitter()
movableJaw.Placement.Base = App.Vector(150, 100, 0)
cyl1 = Part.makeCylinder(5, 190, App.Vector(0, 0, 0), App.Vector(1, 0, 0))
cyl2 = Part.makeCylinder(10, 20, App.Vector(190, 0, 0), App.Vector(1, 0, 0))
cyl3 = Part.makeCylinder(4, 100, App.Vector(200, 0, -50), App.Vector(0, 0, 1))
shape = cyl1.fuse([cyl2, cyl3])
leverScrew = doc.addObject("Part::Feature", "LeverScrew")
leverScrew.Shape = shape.removeSplitter()
leverScrew.Placement.Base = App.Vector(150, -100, 0)
wire1 = Part.makePolygon([App.Vector(0, 0, 100), App.Vector(0, 0, 0), App.Vector(100, 0, 0)])
crank = doc.addObject("Part::Feature", "Crank")
crank.Shape = wire1
crank.Placement.Base = App.Vector(0, -100, 0)
mat = fixedJaw.ViewObject.ShapeAppearance[0]
mat.DiffuseColor = (0.80, 0.60, 0.15, 0.0)
fixedJaw.ViewObject.ShapeAppearance = (mat,)
mat = movableJaw.ViewObject.ShapeAppearance[0]
mat.DiffuseColor = (0.55, 0.70, 0.70, 0.0)
movableJaw.ViewObject.ShapeAppearance = (mat,)
mat = leverScrew.ViewObject.ShapeAppearance[0]
mat.DiffuseColor = (0.70, 0.30, 0.20, 0.0)
leverScrew.ViewObject.ShapeAppearance = (mat,)
doc.recompute()
view = Gui.ActiveDocument.ActiveView
view.viewIsometric()
view.fitAll()
Add an assembly
With the New Assembly tool add an assembly to the document.
Move the parts into the assembly container
In the Tree View drag and drop the parts on the Assembly object. They can now be handled by the Assembly's solver.
Ground a part
To keep the assembly at the desired position, the FixedJaw part should be locked, or grounded as it is called here. Select the FixedJaw in the Tree View or in the 3D View and use the Toggle Grounded tool. A GroundedJoint object is added to the Joints container.
Apply joints
- A Revolute joint between FixedJaw and Crank
Selected elements + Revolute Joint → rearranged Crank
- A Slider joint between FixedJaw and MovableJaw
Selected elements + Slider Joint → rearranged MovableJaw
Set the Min length to -77 mm and the Max length to -7 mm. This limits the opening of the vise to 70 mm.
The next three joints are necessary to force the LeverScrew to: translate like the MovableJaw, rotate like the Crank, and rotate around the main axis.
- A Distance joint between LeverScrew and MovableJaw
Selected elements + Distance Joint → rearranged LeverScrew
Select two faces. Set the distance value to 20 mm.
- A Parallel joint between LeverScrew and Crank
Selected elements + Parallel Joint → rearranged LeverScrew
- A Cylindrical joint between LeverScrew and FixedJaw
Selected elements + Cylindrical Joint → rearranged LeverScrew
- A Screw joint between MovableJaw and Crank
Selected elements (LeverScrew invisible) + Screw Joint → complete vise mechanism (LeverScrew visible)
If necessary make the LeverScrew invisible during selection.
Set the Pitch radius to 5 mm
Drive the vise
The vise can be driven by moving Crank or MovableJaw with the left mouse.
Example shock absorber
Assembly of a shock absorber
In this example a shock absorber is created.
The assembly consists of three solid parts: a piston, a cylinder and a spring. Three additional non solid elements, two axles and a rod are also needed. All parts are connected with several joints.
The hinge of the piston rotates around Axle2, while the hinge of the cylinder moves on an arc of circle centered on Axle1. The non solid Rod is used for this movement. The length of the Rod is the radius of the arc.
Prepare parts
The Python code below will create a new document with 6 objects. Create a new macro and copy-paste the code below in the Python editor (not in the Python Console). Then run the macro.
The code below cannot be run from the Python Console because the spring must be a Part::FeaturePython object defined by of a class with the callback functions execute() and onChanged(). Only then can its height be changed via a property.
import math
import FreeCAD as App
import FreeCADGui as Gui
import Part
doc = App.newDocument()
class Spring():
def __init__(self, spring):
spring.addProperty("App::PropertyLength", "Height", "Spring", "Height of the helix").Height = 200.0
spring.Proxy = self
spring.ViewObject.Proxy = 0
def execute(self, spring):
helix = Part.makeHelix(spring.Height/8.5, spring.Height, 35)
startPnt = helix.Edges[0].Curve.value(0)
section = Part.Wire([Part.Circle(startPnt, App.Vector(0, 1, 0), 5).toShape()])
hel1 = helix.makePipeShell([section], True, True)
box1 = Part.makeBox(80, 80, 10, App.Vector(-40, -40, -10))
box2 = Part.makeBox(80, 80, 10, App.Vector(-40, -40, spring.Height))
shape = hel1.cut(box1).cut(box2)
spring.Shape = shape
def onChanged(self, spring, prop):
if prop == "Height":
self.execute(spring)
spring = doc.addObject("Part::FeaturePython", "Spring")
Spring(spring)
spring.Placement.Base = App.Vector(0, 100, 0)
axle1 = doc.addObject("Part::Line", "Axle1")
axle1.X2 = 0
axle1.Y2 = 80
axle1.Z2 = 0
axle2 = doc.addObject("Part::Line", "Axle2")
axle2.X2 = 0
axle2.Y2 = 80
axle2.Z2 = 0
axle2.Placement.Base = App.Vector(120, 0, -250)
rod = doc.addObject("Part::Line", "Rod")
rod.X2 = 100
rod.Y2 = 0
rod.Z2 = 0
rod.Placement.Base = App.Vector(0, -50, 0)
cyl1 = Part.makeCylinder(40, 10,App.Vector(0, 0, -5))
tor1 = Part.makeTorus(40, 5)
cyl2 = Part.makeCylinder(45, 5)
box1 = Part.makeBox(30, 10, 30,App.Vector(-15, -5, -35))
cyl3 = Part.makeCylinder(15, 10, App.Vector(0, -5, -35), App.Vector(0, 1, 0))
cyl4 = Part.makeCylinder(40, 5)
cyl5 = Part.makeCylinder(5, 10,App.Vector(0, -5, -35), App.Vector(0, 1, 0))
cyl6 = Part.makeCylinder(5, 130)
cyl7 = Part.makeCylinder(20, 5,App.Vector(0, 0, 130))
shape = cyl1.fuse([tor1,cyl2, box1, cyl3]).cut(cyl4.fuse([cyl5])).fuse([cyl6, cyl7])
piston = doc.addObject("Part::Feature", "Piston")
piston.Shape = shape.removeSplitter()
piston.Placement.Base = App.Vector(200, 100, -200)
cyl1 = Part.makeCylinder(40, 10,App.Vector(0, 0, -5))
tor1 = Part.makeTorus(40, 5)
cyl2 = Part.makeCylinder(45, 5)
box1 = Part.makeBox(30, 10, 30,App.Vector(-15, -5, -35))
cyl3 = Part.makeCylinder(15, 10,App.Vector(0, -5, -35), App.Vector(0, 1, 0))
cyl4 = Part.makeCylinder(40, 5)
cyl5 = Part.makeCylinder(5, 10,App.Vector(0, -5, -35), App.Vector(0, 1, 0))
cyl6 = Part.makeCylinder(25, 130)
tor2 = Part.makeTorus(20, 5,App.Vector(0, 0, 130))
cyl7 = Part.makeCylinder(20, 135)
cyl8 = Part.makeCylinder(20, 130)
cyl9 = Part.makeCylinder(5, 135)
shape = cyl1.fuse([tor1, cyl2, box1, cyl3]).cut(cyl4.fuse([cyl5])).fuse([cyl6, tor2, cyl7]).cut(cyl8.fuse([cyl9]))
cylinder = doc.addObject("Part::Feature", "Cylinder")
cylinder.Shape = shape.removeSplitter()
cylinder.Placement.Rotation.Axis = App.Vector(0, 1, 0)
cylinder.Placement.Rotation.Angle = math.pi
cylinder.Placement.Base = App.Vector(100, 100, 0)
mat = piston.ViewObject.ShapeAppearance[0]
mat.DiffuseColor = (0.80, 0.60, 0.15, 0.0)
piston.ViewObject.ShapeAppearance = (mat,)
mat = cylinder.ViewObject.ShapeAppearance[0]
mat.DiffuseColor = (0.55, 0.70, 0.70, 0.0)
cylinder.ViewObject.ShapeAppearance = (mat,)
doc.recompute()
view = Gui.ActiveDocument.ActiveView
view.viewIsometric()
view.fitAll()
Add an assembly
With the New Assembly tool add an assembly to the document.
Move the parts into the assembly container
In the Tree View drag and drop the parts on the Assembly object. They can now be handled by the Assembly's solver.
Ground the two axles
To keep the assembly at the desired position, the two axles should be locked, or grounded as it is called here. Select the two axles in the Tree View or in the 3D View and use the Toggle Grounded tool. Two GroundedJoint objects are added to the Joints container.
Apply joints
- A Revolute joint between Axle2 and Piston
Revolute Joint + Selected elements → rearranged Piston
- A Slider joint between Piston and Cylinder
Slider Joint + Selected elements → rearranged and moved Cylinder
Please pay attention to the location of the coordinate system before selecting a face. It should be in the center of each face.
Drag the Cylinder to create some distinct between it and the Piston. The supporting faces for the Spring should be visible.
- A Distance joint between Piston and Cylinder
Distance Joint + Selected faces → rearranged Cylinder Distance set to 200 mm
Set the distance value to 200 mm.
The next two joints are necessary to force the hinge of the Cylinder to move on an arc of circle.
- A Cylindrical joint between Axle1 and Rod
Cylindrical Joint + Selected elements → rearranged Rod
Make sure the Z-Axis of the coordinate system (blue) is perpendicular to the Rod by selecting an endpoint.
- A Revolute joint between Rod and Cylinder
Revolute Joint + Selected elements → rearranged Cylinder
Again make sure the Z-Axis of the coordinate system (blue) is perpendicular to the Rod.
You may encounter problems with this joint. If that is the case try the following:
- Delete the joint.
- Switch to the front view.
- Rotate the assembly (by dragging the Piston) and rotate the Rod so that center of the hinge hole of the Cylinder lies on the Rod.
- Create the joint again.
The next two joints are necessary to fix the Spring to the support face.
- A Parallel joint between Spring and Piston
Parallel Joint + Selected faces → rearranged Spring
Select the center of the support face on the Piston and the center of the bottom face of the spring. Keep the distance value 0.
- A Fixed joint between Spring and Piston
Fixed Joint + Selected elements → rearranged Spring
Select the bottom vertex of the cylinder's seam in the Piston and the corner vertex in the Spring.
- Connect the distance property of the Distance joint to the Spring's Height property using an expression:
- Select the Spring in the Tree View.
- Select the blue icon
in the Height property field.
- Enter in the expression editor:
<<Distance>>.Distance
Drive the shock absorber
To do so double-click the Distance object in the Tree View and change its Distance property. Recompute the document. The spring changes its length.
- Assembly: New Assembly, Component, New Part, Solve Assembly, Exploded View, Simulation, Bill of Materials
- Joints: Toggle Grounded, Fixed Joint, Revolute Joint, Cylindrical Joint, Slider Joint, Ball Joint, Distance Joint, Parallel Joint, Perpendicular Joint, Angle Joint, Rack and Pinion Joint, Screw Joint, Gears Joint, Belt Joint
- Preferences: Preferences
- Getting started
- Installation: Download, Windows, Linux, Mac, Additional components, Docker, AppImage, Ubuntu Snap
- Basics: About FreeCAD, Interface, Mouse navigation, Selection methods, Object name, Preferences, Workbenches, Document structure, Properties, Help FreeCAD, Donate
- Help: Tutorials, Video tutorials
- Workbenches: Std Base, Assembly, BIM, CAM, Draft, FEM, Inspection, Material, Mesh, OpenSCAD, Part, PartDesign, Points, Reverse Engineering, Robot, Sketcher, Spreadsheet, Surface, TechDraw, Test Framework
- Hubs: User hub, Power users hub, Developer hub
