Modulares Schwergewicht-Feldbett aus Alu-Rohren (25×1.5) mit Stahl-Konnektoren (33.7×2.5). Design-Docs, Materialrecherche, Gewichtsberechnung, Korrosionsschutz-Analyse, und zwei getestete FreeCAD-Makros (Struktur + Konnektoren-Detail). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
360 lines
12 KiB
Python
360 lines
12 KiB
Python
"""
|
||
Feldbett Struktur v2 — FreeCAD Python Script
|
||
=============================================
|
||
Zeigt das komplette Feldbett mit allen Rohren in Realgröße.
|
||
A-Stangen sind segmentiert (je 350mm), Stift-Verbinder angedeutet.
|
||
|
||
Ausführen: FreeCAD → Makro → Makro ausführen → diese Datei wählen
|
||
|
||
Koordinatensystem:
|
||
X = Längsrichtung (Liegeachse)
|
||
Y = Höhe (oben = Liegefläche)
|
||
Z = Querrichtung (Breite)
|
||
|
||
Rohrtriplet "Komfortabel":
|
||
Standard : Alu 25×1.5 mm (Strukturrohre)
|
||
Stift : Alu 18×1.0 mm (Inline-Verbinder A-Stangen)
|
||
Hülse : Stahl 33.7×2.5 mm (Konnektoren C1/C2)
|
||
"""
|
||
|
||
import FreeCAD as App
|
||
import FreeCADGui as Gui
|
||
import Part
|
||
import math
|
||
|
||
# ============================================================
|
||
# PARAMETER
|
||
# ============================================================
|
||
|
||
# Geometrie
|
||
L = 350.0 # Stangenlänge [mm] — ALLE Stangen gleich
|
||
BREITE_AA = 700.0 # Abstand zwischen Längsstangen (A–A) [mm]
|
||
MODULE = 3 # Anzahl Module
|
||
|
||
# Rohre — Triplet "Komfortabel"
|
||
# Standard (Alu 25×1.5)
|
||
STD_DA = 25.0 # Außendurchmesser [mm]
|
||
STD_WAND = 1.5 # Wandstärke [mm]
|
||
STD_DI = STD_DA - 2.0 * STD_WAND # 22.0 mm
|
||
|
||
# Stift-Verbinder (Alu 18×1.0)
|
||
STIFT_DA = 18.0
|
||
STIFT_WAND = 1.0
|
||
STIFT_DI = STIFT_DA - 2.0 * STIFT_WAND
|
||
STIFT_LAENGE = 100.0 # 50mm Einstecktiefe pro Seite
|
||
|
||
# Hülse / Konnektor (Stahl 33.7×2.5)
|
||
HUEL_DA = 33.7
|
||
HUEL_WAND = 2.5
|
||
HUEL_DI = HUEL_DA - 2.0 * HUEL_WAND # 28.7 mm
|
||
HUEL_LAENGE = 40.0 # Länge pro Hülsenstück
|
||
|
||
# Farben (R, G, B) je 0.0–1.0
|
||
FARBE_A = (0.20, 0.45, 0.75) # blau — Längsstangen
|
||
FARBE_D = (0.06, 0.43, 0.34) # grün — Diagonalen
|
||
FARBE_Q = (0.73, 0.46, 0.09) # amber — Querstreben
|
||
FARBE_B = (0.42, 0.25, 0.63) # lila — Beine
|
||
FARBE_STIFT = (0.85, 0.55, 0.15) # orange — Stift-Verbinder
|
||
FARBE_C1 = (0.85, 0.35, 0.15) # rot-orange — Connector 1
|
||
FARBE_C2 = (0.15, 0.55, 0.75) # blau-grün — Connector 2
|
||
|
||
# ============================================================
|
||
# BERECHNETE GEOMETRIE
|
||
# ============================================================
|
||
|
||
hwA = BREITE_AA / 2.0 # halbe Breite A–A
|
||
hwQ = L / 2.0 # halbe Q-Länge (Q = L)
|
||
dZ = hwA - hwQ # Z-Einzug von A nach Q
|
||
|
||
legH2 = 0.75 * L**2 - dZ**2
|
||
if legH2 <= 0:
|
||
raise ValueError(
|
||
f"Geometrie unmöglich: L={L} zu kurz für Breite={BREITE_AA}. "
|
||
f"Erhöhe L oder reduziere BREITE_AA."
|
||
)
|
||
|
||
legH = math.sqrt(legH2) # Höhe pro Ebene (A→Q oder Q→Boden)
|
||
totalH = 2.0 * legH # Gesamthöhe
|
||
step = 2.0 * L # Modul-Abstand in X
|
||
aEnd = (MODULE - 1) * step + L # X-Ende der Längsstangen
|
||
|
||
# Kontrollrechnung D/B-Länge
|
||
dLen = math.sqrt((L / 2)**2 + legH**2 + dZ**2)
|
||
|
||
# A-Stangen Segmente
|
||
a_per_side = int(aEnd / L)
|
||
|
||
print("=" * 55)
|
||
print("FELDBETT STRUKTUR v2")
|
||
print("=" * 55)
|
||
print(f" Stangenlänge L = {L:.0f} mm")
|
||
print(f" Breite A–A = {BREITE_AA:.0f} mm")
|
||
print(f" Liegelänge = {aEnd:.0f} mm = {aEnd/10:.0f} cm")
|
||
print(f" Höhe gesamt = {totalH:.0f} mm = {totalH/10:.1f} cm")
|
||
print(f" legH (pro Ebene) = {legH:.1f} mm")
|
||
print(f" D/B-Länge = {dLen:.1f} mm (soll = {L:.0f})")
|
||
print(f" Module = {MODULE}")
|
||
print(f" A-Segmente pro Seite = {a_per_side}")
|
||
print(f"\n Standard : {STD_DA}×{STD_WAND} mm (Alu)")
|
||
print(f" Stift : {STIFT_DA}×{STIFT_WAND} mm (Alu)")
|
||
print(f" Hülse : {HUEL_DA}×{HUEL_WAND} mm (Stahl)")
|
||
print(f" Spiel Hülse↔Std = {HUEL_DI - STD_DA:.1f} mm")
|
||
print(f" Spiel Std↔Stift = {STD_DI - STIFT_DA:.1f} mm")
|
||
print()
|
||
|
||
# ============================================================
|
||
# HILFSFUNKTIONEN
|
||
# ============================================================
|
||
|
||
def make_tube(p1, p2, da, wand, label, color, group=None):
|
||
"""Hohlrohr von p1 nach p2."""
|
||
direction = p2 - p1
|
||
length = direction.Length
|
||
if length < 0.01:
|
||
return None
|
||
|
||
di = da - 2.0 * wand
|
||
outer = Part.makeCylinder(da / 2.0, length)
|
||
inner = Part.makeCylinder(di / 2.0, length)
|
||
tube = outer.cut(inner)
|
||
|
||
z_axis = App.Vector(0, 0, 1)
|
||
norm_dir = direction.normalize()
|
||
cross = z_axis.cross(norm_dir)
|
||
dot = z_axis.dot(norm_dir)
|
||
|
||
if cross.Length > 1e-6:
|
||
angle = math.degrees(math.acos(max(-1.0, min(1.0, dot))))
|
||
rot = App.Rotation(cross, angle)
|
||
elif dot < 0:
|
||
rot = App.Rotation(App.Vector(1, 0, 0), 180)
|
||
else:
|
||
rot = App.Rotation()
|
||
|
||
tube.Placement = App.Placement(p1, rot)
|
||
|
||
obj = doc.addObject("Part::Feature", label)
|
||
obj.Shape = tube
|
||
if hasattr(obj, "ViewObject") and obj.ViewObject:
|
||
obj.ViewObject.ShapeColor = color
|
||
|
||
if group:
|
||
group.addObject(obj)
|
||
|
||
return obj
|
||
|
||
|
||
def vec(x, y, z):
|
||
return App.Vector(x, y, z)
|
||
|
||
|
||
def make_group(name):
|
||
return doc.addObject("App::DocumentObjectGroup", name)
|
||
|
||
# ============================================================
|
||
# DOKUMENT ANLEGEN
|
||
# ============================================================
|
||
|
||
doc_name = "Feldbett_v2"
|
||
if doc_name in App.listDocuments():
|
||
App.closeDocument(doc_name)
|
||
|
||
doc = App.newDocument(doc_name)
|
||
|
||
grp_A = make_group("A_Laengsstangen")
|
||
grp_Q = make_group("Q_Querstreben")
|
||
grp_D = make_group("D_Diagonalen")
|
||
grp_B = make_group("B_Beine")
|
||
grp_stift = make_group("Stift_Verbinder")
|
||
grp_c1 = make_group("Connector_1_Huelsen")
|
||
grp_c2 = make_group("Connector_2_Huelsen")
|
||
|
||
# ============================================================
|
||
# A — LÄNGSSTANGEN (segmentiert, 2× je a_per_side Stücke)
|
||
# ============================================================
|
||
|
||
for side, zS in [("L", -1), ("R", +1)]:
|
||
zA = zS * hwA
|
||
for seg in range(a_per_side):
|
||
x0 = seg * L
|
||
x1 = x0 + L
|
||
make_tube(
|
||
vec(x0, totalH, zA),
|
||
vec(x1, totalH, zA),
|
||
STD_DA, STD_WAND,
|
||
f"A_{side}_seg{seg+1}", FARBE_A, grp_A
|
||
)
|
||
|
||
# ============================================================
|
||
# STIFT-VERBINDER (A-Stangen inline, zwischen Segmenten)
|
||
# ============================================================
|
||
|
||
for side, zS in [("L", -1), ("R", +1)]:
|
||
zA = zS * hwA
|
||
for joint in range(a_per_side - 1):
|
||
xJ = (joint + 1) * L # Stoßstelle
|
||
x0 = xJ - STIFT_LAENGE / 2.0
|
||
x1 = xJ + STIFT_LAENGE / 2.0
|
||
make_tube(
|
||
vec(x0, totalH, zA),
|
||
vec(x1, totalH, zA),
|
||
STIFT_DA, STIFT_WAND,
|
||
f"Stift_{side}_{joint+1}", FARBE_STIFT, grp_stift
|
||
)
|
||
|
||
# ============================================================
|
||
# MODULE — Q, D, B + Konnektor-Hülsen
|
||
# ============================================================
|
||
|
||
for m in range(MODULE):
|
||
xStart = m * step
|
||
xAL = xStart # X linker A-Knoten
|
||
xAR = xStart + L # X rechter A-Knoten
|
||
xQ = xStart + L / 2 # X Mitte → Q-Position
|
||
|
||
suf = f"_M{m+1}"
|
||
|
||
# --- Q Querstrebe ---
|
||
make_tube(
|
||
vec(xQ, legH, -hwQ),
|
||
vec(xQ, legH, +hwQ),
|
||
STD_DA, STD_WAND,
|
||
"Q" + suf, FARBE_Q, grp_Q
|
||
)
|
||
|
||
# --- D Diagonalen (4 pro Modul) ---
|
||
for side, zS in [("L", -1), ("R", +1)]:
|
||
zA = zS * hwA
|
||
zQe = zS * hwQ
|
||
|
||
# linker A-Knoten → Q-Ende
|
||
make_tube(
|
||
vec(xAL, totalH, zA),
|
||
vec(xQ, legH, zQe),
|
||
STD_DA, STD_WAND,
|
||
f"D_AL_{side}{suf}", FARBE_D, grp_D
|
||
)
|
||
# rechter A-Knoten → Q-Ende
|
||
make_tube(
|
||
vec(xAR, totalH, zA),
|
||
vec(xQ, legH, zQe),
|
||
STD_DA, STD_WAND,
|
||
f"D_AR_{side}{suf}", FARBE_D, grp_D
|
||
)
|
||
|
||
# --- B Beine (4 pro Modul, gespiegelt) ---
|
||
for side, zS in [("L", -1), ("R", +1)]:
|
||
zA = zS * hwA
|
||
zQe = zS * hwQ
|
||
|
||
make_tube(
|
||
vec(xQ, legH, zQe),
|
||
vec(xAL, 0, zA),
|
||
STD_DA, STD_WAND,
|
||
f"B_AL_{side}{suf}", FARBE_B, grp_B
|
||
)
|
||
make_tube(
|
||
vec(xQ, legH, zQe),
|
||
vec(xAR, 0, zA),
|
||
STD_DA, STD_WAND,
|
||
f"B_AR_{side}{suf}", FARBE_B, grp_B
|
||
)
|
||
|
||
# --- Connector 2 Hülsen (an Q-Enden) ---
|
||
# Jedes Q-Ende bekommt 4 Hülsen: Q-links, Q-rechts, D(aufwärts), B(abwärts)
|
||
for zS in [-1, +1]:
|
||
zA = zS * hwA
|
||
zQe = zS * hwQ
|
||
qEnd = vec(xQ, legH, zQe)
|
||
side_label = "L" if zS < 0 else "R"
|
||
|
||
# Richtungsvektoren vom Q-Ende aus
|
||
# Q verläuft in ±Z → Hülsen zeigen in +Z und -Z
|
||
for qdir, qlabel in [((0,0,-1), "Ql"), ((0,0,+1), "Qr")]:
|
||
d = App.Vector(*qdir).normalize()
|
||
p1 = qEnd
|
||
p2 = vec(qEnd.x + d.x*HUEL_LAENGE, qEnd.y + d.y*HUEL_LAENGE, qEnd.z + d.z*HUEL_LAENGE)
|
||
make_tube(p1, p2, HUEL_DA, HUEL_WAND,
|
||
f"C2_{qlabel}_{side_label}{suf}", FARBE_C2, grp_c2)
|
||
|
||
# D-Richtung (vom Q-Ende zum A-Knoten oben = umgekehrte D-Richtung)
|
||
# Wir nehmen die Richtung zum linken A-Knoten als Referenz
|
||
vDr = vec(xAL - xQ, totalH - legH, zA - zQe).normalize()
|
||
p2 = vec(qEnd.x + vDr.x*HUEL_LAENGE, qEnd.y + vDr.y*HUEL_LAENGE, qEnd.z + vDr.z*HUEL_LAENGE)
|
||
make_tube(qEnd, p2, HUEL_DA, HUEL_WAND,
|
||
f"C2_D_{side_label}{suf}", FARBE_C2, grp_c2)
|
||
|
||
# B-Richtung (vom Q-Ende zum Bodenknoten)
|
||
vB = vec(xAL - xQ, 0 - legH, zA - zQe).normalize()
|
||
p2 = vec(qEnd.x + vB.x*HUEL_LAENGE, qEnd.y + vB.y*HUEL_LAENGE, qEnd.z + vB.z*HUEL_LAENGE)
|
||
make_tube(qEnd, p2, HUEL_DA, HUEL_WAND,
|
||
f"C2_B_{side_label}{suf}", FARBE_C2, grp_c2)
|
||
|
||
# --- Connector 1 Hülsen (an A-Knoten oben und Fußpunkten unten) ---
|
||
for xF in [xAL, xAR]:
|
||
for side, zS in [("L", -1), ("R", +1)]:
|
||
zA = zS * hwA
|
||
zQe = zS * hwQ
|
||
xi = int(xF)
|
||
|
||
# === C1 oben: am A-Knoten, verbindet A-Stange mit D-Diagonale ===
|
||
aNode = vec(xF, totalH, zA)
|
||
|
||
# Hülse entlang A (±X)
|
||
make_tube(
|
||
vec(xF - HUEL_LAENGE/2, totalH, zA),
|
||
vec(xF + HUEL_LAENGE/2, totalH, zA),
|
||
HUEL_DA, HUEL_WAND,
|
||
f"C1o_A_x{xi}_{side}{suf}", FARBE_C1, grp_c1
|
||
)
|
||
# Hülse entlang D (nach unten zum Q-Ende)
|
||
vD = vec(xQ - xF, legH - totalH, zQe - zA).normalize()
|
||
p2 = vec(aNode.x + vD.x*HUEL_LAENGE, aNode.y + vD.y*HUEL_LAENGE, aNode.z + vD.z*HUEL_LAENGE)
|
||
make_tube(aNode, p2, HUEL_DA, HUEL_WAND,
|
||
f"C1o_D_x{xi}_{side}{suf}", FARBE_C1, grp_c1)
|
||
|
||
# === C1 unten (Fuß): am Bodenknoten, verbindet B-Bein mit Bodenkontakt ===
|
||
fNode = vec(xF, 0, zA)
|
||
|
||
# Hülse für B (nach oben zum Q-Ende)
|
||
vBup = vec(xQ - xF, legH, zQe - zA).normalize()
|
||
p2 = vec(fNode.x + vBup.x*HUEL_LAENGE, fNode.y + vBup.y*HUEL_LAENGE, fNode.z + vBup.z*HUEL_LAENGE)
|
||
make_tube(fNode, p2, HUEL_DA, HUEL_WAND,
|
||
f"C1u_B_x{xi}_{side}{suf}", FARBE_C1, grp_c1)
|
||
|
||
# Hülse als Fuß (nach unten, senkrecht)
|
||
make_tube(
|
||
vec(xF, 0, zA),
|
||
vec(xF, -HUEL_LAENGE, zA),
|
||
HUEL_DA, HUEL_WAND,
|
||
f"C1u_F_x{xi}_{side}{suf}", FARBE_C1, grp_c1
|
||
)
|
||
|
||
# ============================================================
|
||
# ABSCHLUSS
|
||
# ============================================================
|
||
|
||
doc.recompute()
|
||
|
||
try:
|
||
Gui.activeDocument().activeView().fitAll()
|
||
Gui.SendMsgToActiveView("ViewFit")
|
||
except Exception:
|
||
pass
|
||
|
||
# Stückliste
|
||
print("STÜCKLISTE:")
|
||
print(f" {a_per_side * 2:>3}× A Längsstangen (Alu {STD_DA}×{STD_WAND} × {L:.0f}mm)")
|
||
print(f" {MODULE:>3}× Q Querstreben (Alu {STD_DA}×{STD_WAND} × {L:.0f}mm)")
|
||
print(f" {MODULE*4:>3}× D Diagonalen (Alu {STD_DA}×{STD_WAND} × {L:.0f}mm)")
|
||
print(f" {MODULE*4:>3}× B Beine (Alu {STD_DA}×{STD_WAND} × {L:.0f}mm)")
|
||
print(f" {'-'*50}")
|
||
print(f" {a_per_side*2 + MODULE + MODULE*8:>3}× Standardrohre gesamt")
|
||
print()
|
||
print(f" {(a_per_side-1)*2:>3}× Stift-Verbinder (Alu {STIFT_DA}×{STIFT_WAND} × {STIFT_LAENGE:.0f}mm)")
|
||
print(f" {24:>3}× Connector 1 (je 2 Hülsen Stahl {HUEL_DA}×{HUEL_WAND} × {HUEL_LAENGE:.0f}mm)")
|
||
print(f" { 6:>3}× Connector 2 (je 4 Hülsen Stahl {HUEL_DA}×{HUEL_WAND} × {HUEL_LAENGE:.0f}mm)")
|
||
print()
|
||
print(f" Objekte im Dokument: {len(doc.Objects)}")
|
||
print("\nFeldbett v2 erfolgreich erstellt!")
|