Pneumatik-Zylinder selbst gemacht (I)
Verfasst: 19 Jul 2025, 21:30
3D-Druck: Pneumatikzylinder selbst gemacht
Das Thema Zylinder-Eigenbau beschäftigt mich ja nun mit Unterbrechungen seit einem Viertel Jahrhundert. Es gab Erfolge, die aber mit hohem Aufwand verbunden sind. So kostet ein Zylinder über eine Stunde Handarbeit, wenn ich
- Messing- und Plexiglasrohre vorbereite (ablängen, plandrehen, quer durchbohren)
- die Dichtungen mit Silikon in selbstgefertigten Gussformen anfertige
- Kolbenböden und Zylinderdeckel/boden aus Plexiglasscheiben drehen/fräsen, einschließlich Sicke für den Klebstoff
- Anschlussröhrchen und Achslagerungen für Kolben und Zylinderboden fräsen
Einige Werke in der ftc-Bildersammlung:
Radarmast: https://ftcommunity.de/bilderpool/model ... arald/959/
Dreipunktheber (Fendt-Geräteträger): https://ftcommunity.de/bilderpool/model ... gta/41458/
Kompressor: https://ftcommunity.de/bilderpool/baste ... ssor/1798/
Bagger: https://ftcommunity.de/bilderpool/model ... ery-index/
Etliche Diskussionen sind mit den alten ft-Foren der fischerwerke im digitalen Vergessen versunken. Michal (sannchen90) hat seinerzeit auch Feuer gefangen und eigene Zylinder hergestellt.
Mittlerweile gibt es
1. 3D-Drucker und
2. mit TPU (thermoplastisches Polyurethan) ein druckbares elastisches Material für die Dichtungen.
Ein einfach wirkender Zylinder braucht nur eine Dichtung, auf der Unterseite des Kolbens. Ein doppelwirkender braucht derer drei: zwei am Kolben und eine in der Stirnwand des Zylinders. Hier geht es erst einmal nur um den Kolben; selbiger ist aber auch gleich für doppelwirkenden Betrieb vorgesehen. Dazu braucht er zwei Dichtungen, die sich beidseitig, Rücken an Rücken, am Kolbenboden befinden. Eine davon wird also unten sein. Das "riecht" schon mal gleich nach überbautem Hohlraum und Stützmaterial. Und Stützmaterial an einer Stelle, wo eine Dichtung hin soll -- daraus wird ohne CNC-Fräse nichts werden. Deshalb baue ich den Kolbenboden dreiteilig: zwei in Bezug auf die Dichtung baugleiche Teile Rücken an Rücken (wie auch die Dichtungen) und ein drittes, was die beiden anderen verbindet. Die Dichtungen sind damit auch baugleich. Außerdem sind meine Dichtungen als Ringe ausgeführt: sie liegen an der Außenwand (mit zwei Dichtlippen) und einem inneren Stützring an und haben in der Mitte ein Loch. fischertechnik/Festo machen das anders: der Kolbenboden ist (soweit ich das sehen kann) einteilig, und es gibt zwei Dichtungen: die untere als Topf mit geschlossenem Boden, die obere auch als Topf, aber mit Platz in der Mitte für die Kolbenstange.
Der Trick bei allen genannten Dichtungen ist, dass sie von der Druckluft an die Zylinderwand angepresst werden. Etwas Übermaß und damit ständig vorhandener Anpressdruck ist aber durchaus nötig. Übermaß ist außerdem nötig, um die Unzulänglichkeiten des 3D-Drucks auszubügeln:
1. Die üblichen 3D-Drucker arbeiten in kartesischen Koordinaten. Kreise werden angenähert. Auch wenn man in OpenSCAD aberhunderte von Facetten ($fn, "fragments") definiert oder zwei solche Vielecke um 1/2 Stufe verdreht übereinander legt, kommt keine Kreisbahn dabei heraus.
2. Der Drucker lässt immer wieder einmal einen extra-Tropfen fallen oder zieht einen Faden über das bisher gedruckte.
3. Die Druckplatte ist uneben -- mit Absicht oder ohne. Ideal wäre eine Glasplatte.
Die Dichtflächen kriegt man glatt durch anschleifen, in der Bohrmaschine oder Drehbank. Genauere Untersuchungen habe ich nicht angestellt, aber ich denke, dass die Bearbeitung irgendwo zwischen mechanischem Schliff und Anschmelzen durch Reibungshitze angesiedelt ist.
Zur Software:
Ich verwende OpenSCAD. Dank einer Bibliothek mit mächtigen Funktionen für Basisteile (hier: Rohre mit Fasen einwärts und auswärts, Formschrägen, maximal/minimal-Radius) kommt das eigentliche Programm mit weniger als 100 Zeilen aus. Die Bibliothek bringt noch mal gute 300 Zeilen mit sich. Jedoch, wie der Name "Bibliothek" andeutet, sind diese Funktionen universell verfügbar.
- die verwendete Nomenklatur für Parameternamen (Hausmarke: "Stotter-Notation") mag sich nicht unmittelbar erschließen, erscheint mir aber effizient und praxistauglich. Siehe auch die Einleitung in "Tools-basic15.scad".
- children() und die Basisfunktionen für Spiegelung / Wiederholung mögen für OpenSCAD-Anfänger starker Tobak sein, sind aber auch kein Hexenwerk
- Zylinder-Innenradius und somit Kolbenradius können als Parameter eingestellt werden
- für den Radius der Kolbenstange gilt das gleiche
- für das Übermaß der Dichtlippe sind meine empirischen Werte eingetragen, hier ist sicher Nacharbeit nötig
Zum Aufbau:
Die Kolbenstange kann vorläufig im oberen Bodenteil eingeklemmt werden. Das Einkleben und oder Verstiften kann später immer noch erfolgen.
Dichtungen in TPU drucken: Die Einstellungen sind diejenigen, die man für transparente Optik verwenden würde, d.h. das Bauteil soll frei von Hohlräumen aller Art sein. Also:
- - Schichtdicke auf 0,1 mm reduzieren
- - maximale Vorschubgeschwindigkeit 50 mm/s
- - Temperatur ca ~10°C niedriger setzen
- - Infill: 100%
- - Füllmuster: concentric
- - Wandstärke: im horizontalen Schnitt immer ganzzahlige Vielfache des Düsendurchmessers (bei mir 0,25 mm), ggf Aufmaß (Prusa sagt: 0,53 mm für zwei Bahnen)
- - Nachbearbeitung: mit eingebauter Kolbenstange einspannen und die beiden Dichtflächen am Schleifstein glätten
Kolbenteile: ebenfalls massiv und langsam drucken. Die Böden nach dem Drucken mit Sandpapier glätten, mit Gummikleber einstreichen und Rücken an Rücken, mit dem Verbinderteil durch beide hindurch, aneinander kleben.
Zum Finale:
Natürlich fehlen noch Deckel und Boden des Zylinders. Die kommen später.
# # # # # # # # # # # # # # # die Basis-Bibliothek # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # der Kolbenboden # # # # # # # # # # # # # # # # # # # #
Das Thema Zylinder-Eigenbau beschäftigt mich ja nun mit Unterbrechungen seit einem Viertel Jahrhundert. Es gab Erfolge, die aber mit hohem Aufwand verbunden sind. So kostet ein Zylinder über eine Stunde Handarbeit, wenn ich
- Messing- und Plexiglasrohre vorbereite (ablängen, plandrehen, quer durchbohren)
- die Dichtungen mit Silikon in selbstgefertigten Gussformen anfertige
- Kolbenböden und Zylinderdeckel/boden aus Plexiglasscheiben drehen/fräsen, einschließlich Sicke für den Klebstoff
- Anschlussröhrchen und Achslagerungen für Kolben und Zylinderboden fräsen
Einige Werke in der ftc-Bildersammlung:
Radarmast: https://ftcommunity.de/bilderpool/model ... arald/959/
Dreipunktheber (Fendt-Geräteträger): https://ftcommunity.de/bilderpool/model ... gta/41458/
Kompressor: https://ftcommunity.de/bilderpool/baste ... ssor/1798/
Bagger: https://ftcommunity.de/bilderpool/model ... ery-index/
Etliche Diskussionen sind mit den alten ft-Foren der fischerwerke im digitalen Vergessen versunken. Michal (sannchen90) hat seinerzeit auch Feuer gefangen und eigene Zylinder hergestellt.
Mittlerweile gibt es
1. 3D-Drucker und
2. mit TPU (thermoplastisches Polyurethan) ein druckbares elastisches Material für die Dichtungen.
Ein einfach wirkender Zylinder braucht nur eine Dichtung, auf der Unterseite des Kolbens. Ein doppelwirkender braucht derer drei: zwei am Kolben und eine in der Stirnwand des Zylinders. Hier geht es erst einmal nur um den Kolben; selbiger ist aber auch gleich für doppelwirkenden Betrieb vorgesehen. Dazu braucht er zwei Dichtungen, die sich beidseitig, Rücken an Rücken, am Kolbenboden befinden. Eine davon wird also unten sein. Das "riecht" schon mal gleich nach überbautem Hohlraum und Stützmaterial. Und Stützmaterial an einer Stelle, wo eine Dichtung hin soll -- daraus wird ohne CNC-Fräse nichts werden. Deshalb baue ich den Kolbenboden dreiteilig: zwei in Bezug auf die Dichtung baugleiche Teile Rücken an Rücken (wie auch die Dichtungen) und ein drittes, was die beiden anderen verbindet. Die Dichtungen sind damit auch baugleich. Außerdem sind meine Dichtungen als Ringe ausgeführt: sie liegen an der Außenwand (mit zwei Dichtlippen) und einem inneren Stützring an und haben in der Mitte ein Loch. fischertechnik/Festo machen das anders: der Kolbenboden ist (soweit ich das sehen kann) einteilig, und es gibt zwei Dichtungen: die untere als Topf mit geschlossenem Boden, die obere auch als Topf, aber mit Platz in der Mitte für die Kolbenstange.
Der Trick bei allen genannten Dichtungen ist, dass sie von der Druckluft an die Zylinderwand angepresst werden. Etwas Übermaß und damit ständig vorhandener Anpressdruck ist aber durchaus nötig. Übermaß ist außerdem nötig, um die Unzulänglichkeiten des 3D-Drucks auszubügeln:
1. Die üblichen 3D-Drucker arbeiten in kartesischen Koordinaten. Kreise werden angenähert. Auch wenn man in OpenSCAD aberhunderte von Facetten ($fn, "fragments") definiert oder zwei solche Vielecke um 1/2 Stufe verdreht übereinander legt, kommt keine Kreisbahn dabei heraus.
2. Der Drucker lässt immer wieder einmal einen extra-Tropfen fallen oder zieht einen Faden über das bisher gedruckte.
3. Die Druckplatte ist uneben -- mit Absicht oder ohne. Ideal wäre eine Glasplatte.
Die Dichtflächen kriegt man glatt durch anschleifen, in der Bohrmaschine oder Drehbank. Genauere Untersuchungen habe ich nicht angestellt, aber ich denke, dass die Bearbeitung irgendwo zwischen mechanischem Schliff und Anschmelzen durch Reibungshitze angesiedelt ist.
Zur Software:
Ich verwende OpenSCAD. Dank einer Bibliothek mit mächtigen Funktionen für Basisteile (hier: Rohre mit Fasen einwärts und auswärts, Formschrägen, maximal/minimal-Radius) kommt das eigentliche Programm mit weniger als 100 Zeilen aus. Die Bibliothek bringt noch mal gute 300 Zeilen mit sich. Jedoch, wie der Name "Bibliothek" andeutet, sind diese Funktionen universell verfügbar.
- die verwendete Nomenklatur für Parameternamen (Hausmarke: "Stotter-Notation") mag sich nicht unmittelbar erschließen, erscheint mir aber effizient und praxistauglich. Siehe auch die Einleitung in "Tools-basic15.scad".
- children() und die Basisfunktionen für Spiegelung / Wiederholung mögen für OpenSCAD-Anfänger starker Tobak sein, sind aber auch kein Hexenwerk
- Zylinder-Innenradius und somit Kolbenradius können als Parameter eingestellt werden
- für den Radius der Kolbenstange gilt das gleiche
- für das Übermaß der Dichtlippe sind meine empirischen Werte eingetragen, hier ist sicher Nacharbeit nötig
Zum Aufbau:
Die Kolbenstange kann vorläufig im oberen Bodenteil eingeklemmt werden. Das Einkleben und oder Verstiften kann später immer noch erfolgen.
Dichtungen in TPU drucken: Die Einstellungen sind diejenigen, die man für transparente Optik verwenden würde, d.h. das Bauteil soll frei von Hohlräumen aller Art sein. Also:
- - Schichtdicke auf 0,1 mm reduzieren
- - maximale Vorschubgeschwindigkeit 50 mm/s
- - Temperatur ca ~10°C niedriger setzen
- - Infill: 100%
- - Füllmuster: concentric
- - Wandstärke: im horizontalen Schnitt immer ganzzahlige Vielfache des Düsendurchmessers (bei mir 0,25 mm), ggf Aufmaß (Prusa sagt: 0,53 mm für zwei Bahnen)
- - Nachbearbeitung: mit eingebauter Kolbenstange einspannen und die beiden Dichtflächen am Schleifstein glätten
Kolbenteile: ebenfalls massiv und langsam drucken. Die Böden nach dem Drucken mit Sandpapier glätten, mit Gummikleber einstreichen und Rücken an Rücken, mit dem Verbinderteil durch beide hindurch, aneinander kleben.
Zum Finale:
Natürlich fehlen noch Deckel und Boden des Zylinders. Die kommen später.
# # # # # # # # # # # # # # # die Basis-Bibliothek # # # # # # # # # # # # # # # # # # # #
Code: Alles auswählen
/*
Tools-basic, Basismodule für die Arbeit mit OpenSCAD
Autor : Harald Steinhaus
Stand : 19. Juli 2025
Version : 15
Lizenz : Creative Commons - Attribution, Non Commercial, Share Alike
*/
print = 0; // Bauteile in Druckposition ausgeben: in Druckposition (Abstand, Ausrichtung) und mit Haftrand (Brim)
/*
MY MISSION STATEMENT
I shall:
Avoid oodles of letters in long_names_with_so_much_noise_in_the_line_of_code
Avoid unneccessary curly brackets. If the object of an action is one thing then no brackets are needed: rotate(50) object();
Avoid line breaks which cause more confusion than readibility
- a function call with arguments can be placed in a single line, even together with some translate and rotate
Avoid 2/3 of all those 0s in the code
- very often, translation happens in just one axis. Here are shortcuts for those
- xMov(), yMov() zMov() are each translations on a single axis. No noise from vector brackets and zeros
- zRot() is a rotation of 180° about the z-axis. Why? It has its wwRot parameter with a default of 180° and rotates only about z
Not type all corner coordinates of a symmetric body
- rather program one corner and then mirror() the rest. Or use a RepeatSomething() function. Here: ReiheLin()/ReiheRund()
Use modules with parameters, and the latter with defaults wherever appropriate
- omit the name of a parameter if its value and the values of all others to left are there, and in their right position
- skip name and value of a parameter if you are fine with its default
- still required: when skipping one parameter name, include names for all others to the right (unless they are also omitted)
- sprinkling in a character-type parameter here and there helps to 'synchronize' the eye
Introduce powerful lower-layer functions / modules
- here's the Rohr (tube) that has it all: chamfer, taper, shear, segments, limits.
- here's the Stern (star) that arranges your objects in a circle. With spokes inside, if needed
- here's the Box (box) that has similar intentions but is not yet there
Combine the two points above
- Stern(15, nn=3) object(); // is all that is needed to have object() arranged in 3 locations at 15 mm distance, without spokes
- yRot() object(); // flips object() upside down, as zRot has a default: wwRot=180
Use children()
- both Rohr() and Stern() will subtract a children() part from whatever they produce
- check planetary gears in Tools-gearsPlanets15.scad for applications
- check out the Adventskranz() (advent wreath) example below
Add translations
- yes, once I get around to it
// - - - - - - - - - - - - - - - - - - - -
Odd stuff: here's a rudimentary 'name space' functionality. Or call it a purpose-prefix. Variable names are prefixed with double letters to indicate their function:
rrSomething is a radius
wwSomething is an angle (Winkel)
ssSomething is a thickness (Stärke)
nnSomething is a number of items
zzSomething is a number of teeth (Zähne)
and so on
// - - - - - - - - - - - - - - - - - - - -
More odd stuff:
The focus of this file and its higher-level companions is to generate new parts for the fischertechnik (tm) construction kit. Hence, the prefix
ft indicates something that fits into the fischertechnik system: shapes in 15 mm raster, shafts in 4mm diameter
Hohlwelle(), Bajonettriegel() are generic, but also with fischertechnik in mind
// - - - - - - - - - - - - - - - - - - - -
Still more odd stuff:
OpenSCAD doesn't allow to modify a variable. What if you need to align things between different modules?
--> create one function each to calculate all values that is needed in both places
--> call these functions from there
// - - - - - - - - - - - - - - - - - - - -
Organizational stuff:
using integers 0 and 1 for boolean stuff. These pseudo-booleans make it easier to do calculations with them.
print and inPos are pseudo-boolean variables for maintaining TWO positions / orientations of an item.
* 'inPos' = true: for operation (teeth engaged, stacked on an axis, you name it)
* 'print' = true: for printing (side-by-side, upside down, lined up, centered around a brim patch, and the like)
* print = 1 - inPos
* Rohr(rrAussen, rrInnen, hhBrim) // is a brim patch that appears only if print=1
The general form of a translation is
translate(print * [xp, yp, zp] + inPos * [xi, yi, zi]); // two vectors, one is zero at any time
Of course this also has shortcuts:
xMov(10 + print*20); // Object is at x=10 and moves further 20 when on the printer table
Well, here's a catch:
- print and inPos are defined here, in the lowest-level include file. To change them, you need to open, edit, save the file each time again.
// - - - - - - - - - - - - - - - - - - - -
More organizational stuff:
Generate a cutout view: OpenSCAD doesn't prescribe it, but it is useful: make it the C way and have a pseudo main() routine at the end of each file.
inside this virtual main(),
- have a union() with everything that you want to display
- and subtract from it a deliberate shape, which here is a box by the name of cut()
- and comment / uncomment this shape as you need it
- note that cut() assumes zero size if print = 1
// - - - - - - - - - - - - - - - - - - - -
Yet more odd stuff:
Almost all names and comments in the following are in German. Sorry, I didn't get around to translating at least the comments. But hey -- there ARE comments!
*/
// - - - - Something about CHILDREN - - - -
// Beispiel 1: Children über Modulhierarchie durchreichen:
/*
module innen() {
echo("innen: children:", $children);
if($children > 0) children(0);
} // innen
module aussen() {
echo("außen: children:", $children);
innen() if($children > 1) children(1);
if($children > 0) children(0);
}; // aussen
aussen() { cube(1); xMov(2) sphere(1); };
*/
// Beispiel 2: Konstrukte mit children()
/*
module Der(a) { echo("Der ", $children); xMov(0) cube([2, 2, 2], center=true); zMov(-2) children(); };
module Die(b) { echo("Die ", $children); xMov(5) sphere(1); zMov(2) children(); };
module Das(c) { echo("Das ", $children); xMov(10) cylinder(2, 1, 1, center=true); zMov(4) children(); };
echo("1----"); yMov(0) { Der(1); Die(2); Das(3) cube(0.5); };
echo("2----"); yMov(5) { Der(1) Die(2) Das(3) cube(0.5); };
echo("3----"); yMov(10) { Der(1) { Die(2) Das(3) cube(0.5); }; };
echo("4----"); yMov(15) { Der(1) { Die(2); Das(3) cube(0.5);}; };
echo("5----"); yMov(20) { Der(1) union() { Die(2); Das(3) cube(0.5); }; };
echo("6----"); yMov(25) { Der(1) { union() { Die(2); Das(3) cube(0.5); }; }; Die(2); };
*/
// Beispiel 3: mächtigere Funktionen mit children(): Ein Adventskranz
/*
Adventskranz1(4, 8, 2, 10, 0.5);
xMov(25) Adventskranz2(4, 8, 2, 10);
// so steht's im Buch (mehrzeilig, viele Nullen = "Rauschen") // that's what you see on thingiverse etc.:
module Adventskranz1(nnKerze, radius, rrKerze, hhKerze, ddDocht) {
for (ii = [1 : 1 : nnKerze])
rotate(ii*360/nnnnKerze, [0, 0, 1])
translate([radius, 0, 0])
difference() {
cylinder(h=hhKerze, r=rrKerze, center=false); // Korpus
translate([0, 0, -1]) cylinder(h=hhKerze+2, r=ddDocht/2, center=false); // Loch für den Docht
};
}; // Adventskranz1
// und jetzt die kompakte Version: 1 Aufruf, und mit Sockel und Konus
module Adventskranz2(nnKerze, radius, rrKerze, hhKerze, ddDocht=0.5) {
Stern(radius, 0, 2, 1, nn=nnKerze)
Rohr(rrKerze, ddDocht/2, hhKerze, aoFase=rrKerze-ddDocht/2, auFase=-rrKerze/3, rrMax=rrKerze*1.15);
}; // Adventskranz2
*/
// Zum Thema "Children durch verschachtelte Module hindurch reichen: es muss in jeder Ebene eine Liste weitergereicht werden. Eine Aufzählung würde zu 1 child werden.
// a1() { sphere(0.2); xMov(2) sphere(0.4); xMov(4) sphere(0.6); }
/*
module a1() {
module a3a() { echo("a3a: ", $children); children(0); };
module a3b() { echo("a3b: ", $children); children(0); };
module a3c() { echo("a3c: ", $children); children(0); };
module a2() {
echo("a2: ", $children);
a3a() children(0);
a3b() children(1);
a3c() children(2);
}; // a2
// begin a1:
echo("a1: ", $children);
a2() { children(0); children(1); children(2); }; // <-- children() ergibt ein child mit 3 Objekten drin
} // a1
*/
inPos = 1-print;
$fn = 80;
hhFlachnut = 4.5; // ft-Flachnut, lichte Höhe
achseX = [1, 0, 0]; achseY = [0, 1, 0]; achseZ = [0, 0, 1]; // shortcuts
rrftAchse = 2.15; // Loch für ft-Achse (frei laufend, Düse 0,25 mm)
rrWatte = 1.37; // Bohrung für das gemeine Wattestäbchen (1.25 mm und mehr, je nach Charge)
rrHWelle = 5; // Hohlwelle (HW) für Planetengetriebe, passt in Lager10x15x4
rrRast = rrftAchse+1.2; // Außendurchmesser (ft-)Rastachsaufnahme
spalt = 0.2; // für Passungen, Dovetails, Schwalbenschwanzverbinder
hhBrim = (print==1) ? 0.2 : 0; // Haftrand für 3D-Druck
Draftmodus = 0; // 1 : Zahnräder als Scheiben; Radius = Wälzradius; Zahndefinition: shift/cut/ddOffset raus
nur1Planet = 0; // Planetensätze: nur 1 Exemplar, für Screenshots / Doku; nicht zusammen mit 'Draftmodus'
ddNozzle = 0.25; // Drucker: Düse 0.25; 0.4
hhLayer = 0.15; // Drucker: Schichtdicke
ssWand = (ddNozzle == 0.4) ? 0.8 : 0.75; // Wandstärken div. Teile, Standard (2x0.4 oder <~ mit 0.25)
ssWand1 = (ddNozzle == 0.4) ? 0.4 : 0.5; // Wandstärken div. Teile, für leichte Fälle (1x0.4 oder <~ mit 0.25)
ssWand4 = (ddNozzle == 0.4) ? 1.2 : 1; // Wandstärken div. Teile, für schwerere Fälle (3x0.4 oder <~ mit 0.25)
epsi = 1/128; epsi2 = epsi/2; // gegen z-Fight (Flimmern an gemeinsamen Flächen)
ddKernloch=[1.6, 2.05, 2.5, 3.3]; // Durchmesser für DIN-Gewinde m2, m2.5, m3, m4
polyfaktor3 = 0.5; // Verhältnis Inkreis/Umkreis -> regelmäßiges Polygon dem Kreis umschreiben
polyfaktor4 = 1/(0.5*sqrt(2)); // Rohr(radius * polyfaktor) umschlingt den Kreis
polyfaktor6 = 1/(0.5*sqrt(3));
polyfaktor8 = 1/(0.5*sqrt(2 + sqrt(2)));
module Spiegel(achse, vektor=[0,0,0]) { // Objekt plus Spiegelbild. vektor --> Spiegelbild verschieben z.B. auf unterschiedliche Druckposition
children();
translate(vektor) mirror(achse) children();
} // Spiegel
module zSpiegel(zzOfs) {
children();
zMov(zzOfs) mirror(achseZ) children();
} // zSpiegel
// elementare Abkürzungen (engl: "primitives")
module xRot(ww=180) { rotate(ww, achseX) children(); };
module yRot(ww=180) { rotate(ww, achseY) children(); };
module zRot(ww=180) { rotate(ww, achseZ) children(); };
module xMov(xxOfs) { translate([xxOfs, 0, 0]) children(); };
module yMov(yyOfs) { translate([0, yyOfs, 0]) children(); };
module zMov(zzOfs) { translate([0, 0, zzOfs]) children(); };
module xMirr(vektor=[0,0,0]) { Spiegel(achseX, vektor) children(); };
module yMirr(vektor=[0,0,0]) { Spiegel(achseY, vektor) children(); };
module zMirr(vektor=[0,0,0]) { Spiegel(achseZ, vektor) children(); };
module zFlip(zzOfs, cond=1) { zMov(cond*zzOfs) mirror(cond*achseZ) children(); };
module xCopy(xxOfs) { children(); translate([xxOfs, 0, 0]) children(); };
module yCopy(yyOfs) { children(); translate([0, yyOfs, 0]) children(); };
module zCopy(zzOfs) { children(); translate([0, 0, zzOfs]) children(); };
module zweifach(xxPrintOfs=0) { // Objekte --> zweimal mit 180°
children();
zRot() xMov(print*xxPrintOfs) children();
}; // zweifach
module dmn() { // druckMichNicht, für Hilfskonstruktionen etc.
if (inPos) color("Cyan", 0.4) children();
} // dmn
module zmn() { // zeig mich nicht (nur drucken)
if (print) color("Cyan", 0.4) children();
} // zmn
module nichts() { ; }; // Ommmm. Das muss es auch geben, um "kein children an dieser Position der Liste" zu übergeben
module cut() { // Ecke ausschneiden für Schnittbild
translate([1, 1, 6]) cube(inPos*[32, 32, 12], center=true); // nicht zu groß machen. Wenn der Viewpoint innerhalb von cut() liegt, gibt es seltsame Effekte
} // cut
function stack(idx = $parent_modules - 1) = // Aufrufstack wird bei Fehlern ausgegeben, https : //forum.openscad.org/Pretty-print-module-stack-trace-td7158.html
idx == undef ? "<top-level>" : idx > 0 ? str(parent_module(idx), "() : ", stack(idx - 1)) : str(parent_module(idx), "()");
module zRohr(zzOfs, rrAussen, rrInnen, hoch, zentr=false, facets=60, wwRot=0, wwX = 0) { // facets --> Mehreck
zMov(zzOfs) rotate(wwX, achseX) zRot(wwRot + ((facets == 4) ? 45 : 0)) difference() {
cylinder(h = hoch, r = rrAussen, center = zentr, $fn=facets);
cylinder(h = hoch*4, r = rrInnen, center = true, $fn=facets);
}
} // zRohr
// Beispiele:
// Rohr(25, 16, 10, facets=6, wwSeg=360, wwAnf=90, wwKipp=20, iuFase=-4, ioFase=3, aoFase=-4, auFase=1, hhMax=12, rrMax=23.5, rrMin=14);
// Stern(50, nn=3) Rohr(25, 16, 40, false, facets=80, wwSeg=300, wwAnf=0, wwKipp=-40, iuFase=-3, ioFase=-6, aoFase=-4, auFase=-3, rrMin=0, hhMax=40, rrMax=42, hhMin=-1);
// Rohr(25, 16, 40, wwScher=30, auFase=2, aoFase=-2, ioFase=-2, iuFase=2, rrMax=49, rrMin=16.5);
// Rohr(20, 15, 15, wwScher=-30, wwKipp=30, aoFase=-2, rrMax=25, hhMax=20);
module Rohr(rrAussen, rrInnen, hoch, zentr=false, facets=60, wwSeg=360, wwAnf=0, wwKipp=0, wwScher=0, iuFase=0, ioFase=0, aoFase=0, auFase=0, rrMin, rrMax, hhMin, hhMax, xxScher) {
// > > > children() werden alle abgezogen. Nützlich für: absoluten max-Radius, weitere Bohrungen, Statikloch, Einschnürungen, Fasen für Vielecke etc.
// wwSeg = 360 --> Vollrund. Sonst: Ringsegment über wwSeg
// facets: kleine Werte liefern Vielecke (eine Ecke liegt in x-Richtung. Ausnahme: facets=4 --> Vierkant, wird immer achsparallel gemacht
// die Ecke innen/unten liegt bei z=0, auch bei wwKipp<>0 oder wenn Fasen dran sind
// rrInnen > rrAussen --> "interessante" Formen
// wwAnf: drehen um Längsachse (für Vielecke und Segmente)
// wwKipp: Segmente kippen: positiv einwärts, negativ auswärts. Min/Max-Werte werden *nicht* gekippt.
// --> auswärts kippen hebt die Innenkante und senkt die äußere. Entsprechendes für einwärts kippen.
// wwScher: Segmente werden geschert (positiv=einwärts). Mischen mit wwKipp --> "interessante" Formen
// ! Fasen immer =< Wandstärke und =< Höhe, sonst "interessante" Formen
// Ausnahme 1: Kippung einwärts + auFase < 0 (beliebiger Wert): Außenwand nach unten projizieren
// Ausnahme 2: Kippung einwärts + iuFase <> 0: "interessante" Formen
// ! facets <~40 und wwSeg<360 --> "interessante" Formen (5 / 360 = Fünfeck; 5 / 359 = Viereck mit Schlitz)
// Fasen sind immer 45° (sonst --> Ringsegment() oder wwKipp/wwScher verwenden)
// rrMin, rrMax wirken auf das Gesamtwerk: kein Material innerhalb von rrMin und außerhalb von rrMax
dx = rrAussen-rrInnen;
fill = ((auFase < 0) && (wwKipp > 0)) ? 1 : 0; // wenn einwärts, wwKipp > 0:
dx2 = dx * cos(wwKipp); // dann: Projektion des Bodens auf x-Achse
q = dx2 * cos(wwKipp);
h = dx2 * sin(wwKipp);
xxSch = (xxScher == undef) ? hoch * tan(-wwScher) : -xxScher;
auF = max(auFase, 0);
poly = [ [0, abs(iuFase)], [0+xxSch, hoch-abs(ioFase)], // innen
[0+ioFase+xxSch, hoch], [dx-aoFase+xxSch, hoch], // oben
[dx+xxSch, hoch-abs(aoFase)], [dx, (fill*auF) + (1-fill)*abs(auFase)], // außen
[(1-fill) * (dx-auFase) + fill*q, -fill*h], [0+iuFase, 0] ]; // unten
hhMx = (hhMax == undef) ? hoch*2 + abs(aoFase) + abs(auFase) : hhMax; // wenn hhMax/rrMax = undef: willkürliche maxBox
hhMn = (hhMin == undef) ? -hoch*2 - abs(aoFase) - abs(auFase) : hhMin; // wenn hhMin = undef: willkürliche maxBox
rrMx = (rrMax == undef) ? rrAussen*2 + abs(aoFase) + abs(auFase) : rrMax;
rrMn = (rrMin == undef) ? 0 : rrMin;
maxBox = [ [0, hhMn], [0, hhMx], [rrMx, hhMx], [rrMx, hhMn] ];
minBox = [ [rrMn, hhMn], [rrMn, hhMx], [rrMx, hhMx], [rrMx, hhMn] ];
// Debug: die Rotationskörper färben und übereinander legen:
// zMov(-1) linear_extrude(center=false, height=0.5) xMov(rrInnen) zRot(wwKipp) polygon(poly);
// color("Cyan", 0.2) zMov(-2) linear_extrude(center=false, height=0.5) polygon(minBox);
// color("Blue", 0.2) zMov(-3) linear_extrude(center=false, height=0.5) polygon(maxBox);
difference() {
zMov(-hoch/2 * ((zentr == true) ? 1 : 0) )
zRot(wwAnf + ((facets == 4) ? 45 : 0))
rotate_extrude(angle=wwSeg, convexity = 10, $fn=facets) intersection() {
polygon(maxBox);
polygon(minBox);
xMov(rrInnen) zRot(wwKipp) polygon(poly);
};
if ($children>0) children(); // Children werden vom Ergebnis abgezogen (z.B. Querbohrung)
};
} // Rohr
module Brimstern(rrI, nn=6, wwRot=0, mitRing = 0, rrA) { // Haftrand für runde Druckteile
rrAussen = (rrA==undef) ? rrI+6 : rrA;
color("Yellow", 0.2) {
Stern(rrAussen-2, rrI, hhBrim, 2.2, nn=nn, wwRot=wwRot);
if(mitRing) Rohr(rrAussen, rrAussen-2, hhBrim);
}
} // Brimstern
// Box(5, 11, 10, 6, allFase=1);
module Box(xxLang, yyLang, hoch, ddWand, zentr=0, lvFase=0, lhFase=0, rhFase=0, rvFase=0, scaleCh=1, allFase) { // 4 Wände mit senkrechten Fasen, kein Boden
// > > > children werden in den äußeren Ecken (mit scaleCh) platziert
// ddWand zählt von den Außenwänden einwärts
// Fasen immer positiv, sonst "interessante" Formen
// l, r: x-Achse
lvF = (allFase == undef) ? lvFase : allFase;
lhF = (allFase == undef) ? lhFase : allFase;
rvF = (allFase == undef) ? rvFase : allFase;
rhF = (allFase == undef) ? rhFase : allFase;
polyA = [ [0, lvF], [0, yyLang-lhF], // links
[0+lhF, yyLang], [xxLang-rhF, yyLang], // oben
[xxLang, yyLang-rhF], [xxLang, rvF], // außen abwärts
[xxLang-rvF, 0], [0+lvF, 0] ]; // unten
vector= [xxLang/2, yyLang/2, 0];
translate(-1*zentr*vector) {
linear_extrude(height=hoch) {
difference() {
polygon(polyA);
offset(delta=-ddWand) polygon(polyA);
}
}
if ($children > 0) translate(vector) xMirr() yMirr() translate(scaleCh*vector) children(0);
};
// if(print) if(ddWand<=0.8) translate(-1*zentr*vector) yMirr([0, yyLang, 0]) yMov(0.8) cube([xxLang, 1.2, hhBrim]); // innen hinein, kann aber gegenüber herausstehen
} // Box
module ReiheLin(nn, xxStep=0, yyStep=0, zzStep=0) { // Perlenkette, gerade
// *Step > 0 --> erstes Element bei 0
// *Step < 0 --> die Reihe wird entlang dieser Achse zentriert
ff = (nn-1)/2;
translate([(xxStep < 0) ? ff * xxStep : 0, (yyStep < 0) ? ff * yyStep : 0, (zzStep < 0) ? ff * zzStep : 0])
for(ii = [0 : 1 : nn-1])
translate(ii*[abs(xxStep), abs(yyStep), abs(zzStep)]) children();
} // ReiheLin
// ReiheRund(8, rr=15, wwAnf=90, wwStep=-20, rrStep=0, zzStep=0) sphere(2);
module ReiheRund(nn, rr, wwAnf=0, wwStep=0, rrStep=0, zzStep=0) { // Perlenkette um ein Zentrum.
// *Step < 0 --> wird entlang dieser Achse zentriert
ff = (nn-1)/2;
zRot((wwStep<0) ? ff * wwStep : 0) translate([(rrStep < 0) ? ff * rrStep : 0, 0, (zzStep < 0) ? ff * zzStep : 0])
for(ii = [0 : 1 : nn-1])
zRot(wwAnf + ii*abs(wwStep))
translate([rr + ii*abs(rrStep), 0, ii*abs(zzStep)]) children();
} // ReiheRund
module Stern(rrAussen=0, rrInnen=0, hoch=0, breit=0, nn, wwRot=0) {
// > > > children(1): subtrahiert je 1x children(1) bei rrInnen von den Strahlen
// > > > children(0): platziert DANN je 1x children(0) bei rrAussen ans Ende der Strahlen
assert(nn > 0);
wwStep = 360/nn;
for(ii = [0: 1: nn-1]) {
wwDreh = wwStep*ii + wwRot;
zRot(wwDreh) translate([rrInnen, -breit/2, 0]) difference() {
cube([rrAussen-rrInnen, breit, hoch], center = false);
if ($children>1) yMov(breit/2) children(1);
};
if ($children>0) zRot(wwDreh) xMov(rrAussen) children(0);
}
} // Stern
// - - - - - - - main() - - - - - - - - - - - - - - - - - - - - -
difference() {
union() {
// hier ist die Spielwiese
// Rohr(15, 6, 20, aoFase=4, wwScher=10, rrMin=4, auFase=-2, rrMax=15.5);
}; // union
*xMov(20) zMov(-epsi) zRot(45) cut();
}
Code: Alles auswählen
/*
Kolben für Pneumatikzylinder, Modellbau, light duty
Autor : Harald Steinhaus
Stand : 19. Juli 2025
Version : 08
Lizenz : Creative Commons - Attribution, Non Commercial, Share Alike
Erzeugt CAD-Daten für:
- Kolbenboden, dreiteilig, für beidseitige Abdichtung
- Dichtung für den Kolben
Benötigt:
Zylinder: Fremdteil aus Plexiglas, Messing, etc. (Haushaltswaren)
Kolbenstange: Fremdteil, gedacht ist Messingrohr 4 mm (Baumarkt)
Bohrmaschine oder Drehbank zum Glätten der Dichtlippe, nebst Schutzbrille
optional: Bohrmaschine + Draht zum Verstiften der Kolbenstange
Filament: TPU für die Dichtung. Shore-Härte: nicht zu viel (A 80 probieren)
FIlament: PETG, PLA, (ABS?) für die Kolbenteile
Gummikleber ("flüssige Naht", "Zeltkleber"). KEIN Acryl nehmen!
Sandpapier (150, 200, was gerade da ist)
Schleifstein, feine Körnung (3000 - 6000)
Fehlt:
Bauteile für Zylinderdeckel und -boden (in Arbeit)
*/
include <Tools-basic15.scad>
$fn = 80;
ssKolben = 0.75; // Stärke des Kolbenbodens
rrKolben = 20.08/2; // Innenradius
rrMuffe = 2.03; // Messingrohr 4 mm, strammer Sitz
rrKnopf = 1.3;
ooKnopf = 5.2;
module Bodenscheibe(offen=0) { // Trägerscheibe mit Löchern, 2 Stück Rücken an Rücken kommen auf den Kolbenboden
Rohr(rrKolben, offen*(rrMuffe+0.5), ssKolben) // die Scheibe
Stern(ooKnopf, nn=5) zRohr(-1, rrKnopf, 0, ssKolben+2, facets=10); // minus fünf Löcher
zMov(ssKolben-epsi) {
zMov(1.5) Rohr(rrKolben-1.8, rrKolben-2.8, 1.3, xxScher = -1.1, aoFase=0.2, rrMax=rrKolben-1, rrMin=rrKolben-2.8) // Dichtung festhalten
translate([14, 0, 3.2]) yRot(-55) Rohr(6, 0, 10); // Nut = Einlegehilfe
Rohr(rrKolben-1.8, rrKolben-2.8, 1.5);
Rohr(rrKolben, rrKolben-0.5, 0.6, ioFase=0.2);
};
} // Bodenscheibe
module Kolbenboden() {
hhMuffe = 6;
hhKnopf = ssKolben*2+2.5;
color("Wheat") yMov(print*20) { // erste Bodenscheibe (zum Kopf hin)
Rohr(rrMuffe+1.2, rrMuffe, hhMuffe, auFase=-1.8, iuFase=0.4, rrMax=ooKnopf-rrKnopf) // Muffe für Kolbenstange
zMov(4.5) yRot(90) Rohr(0.5, 0, 10, true); // abzüglich Querbohrung
Bodenscheibe(offen=1);
};
color("Tan") yMov(-print*20)
zMov(-4*inPos) mirror(inPos*achseZ) Bodenscheibe(offen=0); // zweite Bodenscheibe (zum Zylinderboden)
zMov(-12*inPos) color("LightGreen") { // Scheibchen mit Stempeln durch beide hindurch
Stern(ooKnopf, nn=5) Rohr(rrKnopf-0.1, rrKnopf-ddNozzle*3, hhKnopf, facets=10, aoFase=0.4);
Rohr(rrKolben-3.4, 0, 0.75, aoFase=0.25);
};
Box(12, 24, hhBrim, 2, 1);
} // Kolbenboden
module Dichtung(zzOfs) {
rrLippe = rrKolben+0.15;
zMov(zzOfs) color("SpringGreen", 0.8) {
zMov(3-epsi) Rohr(rrKolben+0.4, rrKolben-0.25, 1, xxScher = -0.3, facets=200, rrMax=rrLippe+0.47); // Dichtlippe 1
zMov(1.5-epsi) Rohr(rrKolben-0.8, rrKolben-1.55, 1.51, xxScher=-1.21, rrMax=rrLippe+0.35);
Rohr(rrKolben-0.8, rrKolben-1.55, 1.5, auFase=-0.5, iuFase=-0.3, ioFase=0, rrMax=rrKolben-0.5, rrMin=rrKolben-1.75); // Dichtlippe 2
};
} // Dichtung
// - - - - - - - - - - - - - - main() - - - - - - - - - - - - - - -
difference() {
union() {
xMov(-print*20) Kolbenboden(); // Drucken in PLA, PETG, ...
zMov(0.1) Dichtung(ssKolben); // Drucken in TPU
* if(inPos) color("Cyan", 0.2) zRohr(-10, rrKolben+1, rrKolben+0.2, 20); // transparent, wenn als letztes Teil aufgeführt
}
* translate([15, -1, -7-epsi]) rotate(10, achseZ) cut(); // auskommentieren für Schnittbild
} ;