Section bracing
This commit is contained in:
parent
97675a2fc8
commit
4dcd97613b
|
@ -12,21 +12,26 @@ class Onbashira(Model):
|
|||
n_side: int = 6
|
||||
# Dimensions of each side panel
|
||||
side_width: float = 200.0
|
||||
side_length: float = 600.0
|
||||
|
||||
# Side panels have different lengths
|
||||
side_length1: float = 200.0
|
||||
side_length2: float = 350.0
|
||||
side_length3: float = 400.0
|
||||
|
||||
side_thickness: float = 25.4 / 8
|
||||
|
||||
# Joints between two sets of side panels
|
||||
angle_joint_thickness: float = 25.4 / 4
|
||||
angle_joint_thickness: float = 10.0
|
||||
# Z-axis size of each angle joint
|
||||
angle_joint_depth: float = 50.0
|
||||
angle_joint_depth: float = 60.0
|
||||
# Gap of each angle joint to connect the outside to the inside
|
||||
angle_joint_gap: float = 10.0
|
||||
angle_joint_bolt_length: float = 50.0
|
||||
angle_joint_bolt_diam: float = 10.0
|
||||
# Position of the holes, with (0, 0) being the centre of each side
|
||||
angle_joint_hole_position: list[float] = field(default_factory=lambda: [
|
||||
(20, 20),
|
||||
(70, 20),
|
||||
angle_joint_bolt_position: list[float] = field(default_factory=lambda: [
|
||||
(20, 15),
|
||||
(70, 15),
|
||||
])
|
||||
|
||||
# Dimensions of gun barrels
|
||||
|
@ -54,7 +59,7 @@ class Onbashira(Model):
|
|||
material_side: Material = Material.WOOD_BIRCH
|
||||
material_bearing: Material = Material.PLASTIC_PLA
|
||||
material_bearing_ball: Material = Material.ACRYLIC_TRANSPARENT
|
||||
material_brace: Material = Material.METAL_AL
|
||||
material_brace: Material = Material.PLASTIC_PLA
|
||||
|
||||
def __post_init__(self):
|
||||
assert self.n_side >= 3
|
||||
|
@ -65,6 +70,9 @@ class Onbashira(Model):
|
|||
assert self.rotor_inner_radius < self.bearing_track_radius < self.stator_bind_radius
|
||||
assert self.angle_joint_thickness > self.side_thickness
|
||||
|
||||
for (x, y) in self.angle_joint_bolt_position:
|
||||
assert y < self.angle_joint_depth / 2
|
||||
|
||||
@property
|
||||
def angle_side(self) -> float:
|
||||
return 360 / self.n_side
|
||||
|
@ -183,19 +191,35 @@ class Onbashira(Model):
|
|||
"""
|
||||
pass
|
||||
|
||||
@target(name="side-panel", kind=TargetKind.DXF)
|
||||
def profile_side_panel(self) -> Cq.Sketch:
|
||||
def profile_side_panel(
|
||||
self,
|
||||
length: float,
|
||||
hasFrontHole: bool = False,
|
||||
hasBackHole: bool = True) -> Cq.Sketch:
|
||||
assert hasFrontHole or hasBackHole
|
||||
signs = ([1] if hasFrontHole else []) + ([-1] if hasBackHole else [])
|
||||
return (
|
||||
Cq.Sketch()
|
||||
.rect(self.side_width, self.side_length)
|
||||
.rect(self.side_width, length)
|
||||
.push([
|
||||
(sx * x, sy * (length/2 - y))
|
||||
for (x, y) in self.angle_joint_bolt_position
|
||||
for sx in [1, -1]
|
||||
for sy in signs
|
||||
])
|
||||
.circle(self.angle_joint_bolt_diam/2, mode="s")
|
||||
)
|
||||
|
||||
def side_panel(self) -> Cq.Workplane:
|
||||
def side_panel(self, length: float, hasFrontHole: bool = True, hasBackHole: bool = True) -> Cq.Workplane:
|
||||
w = self.side_width
|
||||
l = self.side_length
|
||||
sketch = self.profile_side_panel(
|
||||
length=length,
|
||||
hasFrontHole=hasFrontHole,
|
||||
hasBackHole=hasBackHole,
|
||||
)
|
||||
result = (
|
||||
Cq.Workplane()
|
||||
.placeSketch(self.profile_side_panel())
|
||||
.placeSketch(sketch)
|
||||
.extrude(self.side_thickness)
|
||||
)
|
||||
# Bevel the edges
|
||||
|
@ -207,11 +231,27 @@ class Onbashira(Model):
|
|||
(0, self.bulk_radius),
|
||||
])
|
||||
.close()
|
||||
.extrude(l)
|
||||
.translate(Cq.Vector(0, l/2,0))
|
||||
.extrude(length)
|
||||
.translate(Cq.Vector(0, length/2, 0))
|
||||
)
|
||||
# Intersect the side panel
|
||||
return result * intersector
|
||||
result = result * intersector
|
||||
|
||||
# Mark all attachment points
|
||||
t = self.side_thickness
|
||||
for i, (x, y) in enumerate(self.angle_joint_bolt_position):
|
||||
px = x
|
||||
py = length / 2 - y
|
||||
result.tagAbsolute(f"holeFPI{i}", (+px, py, t), direction="+Z")
|
||||
result.tagAbsolute(f"holeFSI{i}", (-px, py, t), direction="+Z")
|
||||
result.tagAbsolute(f"holeFPO{i}", (+px, py, 0), direction="-Z")
|
||||
result.tagAbsolute(f"holeFSO{i}", (-px, py, 0), direction="-Z")
|
||||
result.tagAbsolute(f"holeBPI{i}", (+px, -py, t), direction="+Z")
|
||||
result.tagAbsolute(f"holeBSI{i}", (-px, -py, t), direction="+Z")
|
||||
result.tagAbsolute(f"holeBPO{i}", (+px, -py, 0), direction="-Z")
|
||||
result.tagAbsolute(f"holeBSO{i}", (-px, -py, 0), direction="-Z")
|
||||
|
||||
return result
|
||||
|
||||
def angle_joint(self) -> Cq.Workplane:
|
||||
"""
|
||||
|
@ -220,6 +260,10 @@ class Onbashira(Model):
|
|||
|
||||
To provide tensile strength along the Z-axis, the panels must be bolted
|
||||
onto the angle joint.
|
||||
|
||||
The holes are marked hole(L/R)(P/S)(O/I)(i), where L/R corresponds to the two
|
||||
sections being joined, and P/S corresponds to the two facets
|
||||
(primary/secondary) being joined. O/I corresponds to the outside/inside
|
||||
"""
|
||||
|
||||
# Create the slot carving
|
||||
|
@ -276,10 +320,45 @@ class Onbashira(Model):
|
|||
.cut(slot.translate((0, 0, -self.angle_joint_depth-self.angle_joint_gap/2)))
|
||||
.intersect(intersector)
|
||||
)
|
||||
hole_negative = Cq.Solid.makeCylinder(
|
||||
radius=self.angle_joint_bolt_diam/2,
|
||||
height=h,
|
||||
pnt=(0,0,0),
|
||||
dir=(1,0,0),
|
||||
)
|
||||
dy = self.angle_joint_gap / 2
|
||||
locrot = Cq.Location(0, 0, 0, 0, 0, 360/self.n_side)
|
||||
for (x, y) in self.angle_joint_bolt_position:
|
||||
p1 = Cq.Location((0, x, dy+y))
|
||||
p2 = Cq.Location((0, x, -dy-y))
|
||||
p1r = locrot * Cq.Location((0, -x, dy+y))
|
||||
p2r = locrot * Cq.Location((0, -x, -dy-y))
|
||||
result = result \
|
||||
- hole_negative.moved(p1) \
|
||||
- hole_negative.moved(p2) \
|
||||
- hole_negative.moved(p1r) \
|
||||
- hole_negative.moved(p2r)
|
||||
# Mark the absolute locations of the mount points
|
||||
dr = self.bulk_radius + self.angle_joint_thickness
|
||||
dr0 = self.bulk_radius
|
||||
dri = self.bulk_radius - self.angle_joint_thickness
|
||||
for i, (x, y) in enumerate(self.angle_joint_bolt_position):
|
||||
py = dy + y
|
||||
result.tagAbsolute(f"holeLPO{i}", (dr, x, py), direction="+X")
|
||||
result.tagAbsolute(f"holeRPO{i}", (dr, x, -py), direction="+X")
|
||||
result.tagAbsolute(f"holeLPM{i}", (dr0, x, py), direction="-X")
|
||||
result.tagAbsolute(f"holeRPM{i}", (dr0, x, -py), direction="-X")
|
||||
result.tagAbsolute(f"holeLPI{i}", (dri, x, py), direction="-X")
|
||||
result.tagAbsolute(f"holeRPI{i}", (dri, x, -py), direction="-X")
|
||||
result.tagAbsolute(f"holeLSO{i}", locrot * Cq.Location(dr, -x, py), direction="+X")
|
||||
result.tagAbsolute(f"holeRSO{i}", locrot * Cq.Location(dr, -x, -py), direction="+X")
|
||||
result.tagAbsolute(f"holeLSM{i}", locrot * Cq.Location(dr0, -x, py), direction="-X")
|
||||
result.tagAbsolute(f"holeRSM{i}", locrot * Cq.Location(dr0, -x, -py), direction="-X")
|
||||
result.tagAbsolute(f"holeLSI{i}", locrot * Cq.Location(dri, -x, py), direction="-X")
|
||||
result.tagAbsolute(f"holeRSI{i}", locrot * Cq.Location(dri, -x, -py), direction="-X")
|
||||
return result
|
||||
|
||||
|
||||
|
||||
def bearing_ball(self) -> Cq.Solid:
|
||||
return Cq.Solid.makeSphere(radius=self.bearing_ball_diam/2, angleDegrees1=-90)
|
||||
|
||||
|
@ -335,11 +414,10 @@ class Onbashira(Model):
|
|||
)
|
||||
return a
|
||||
|
||||
def assembly(self) -> Cq.Assembly:
|
||||
def assembly_section(self, **kwargs) -> Cq.Assembly:
|
||||
a = Cq.Assembly()
|
||||
side = self.side_panel()
|
||||
side = self.side_panel(**kwargs)
|
||||
r = self.bulk_radius
|
||||
a = a.add(self.assembly_rotor(), name="rotor")
|
||||
for i in range(self.n_side):
|
||||
a = a.addS(
|
||||
side,
|
||||
|
@ -349,3 +427,62 @@ class Onbashira(Model):
|
|||
loc=Cq.Location.rot2d(i*360/self.n_side) * Cq.Location(-r,0,0,90,0,90),
|
||||
)
|
||||
return a
|
||||
def assembly_ring(self) -> Cq.Assembly:
|
||||
a = Cq.Assembly()
|
||||
side = self.angle_joint()
|
||||
r = self.bulk_radius
|
||||
for i in range(self.n_side):
|
||||
a = a.addS(
|
||||
side,
|
||||
name=f"side{i}",
|
||||
material=self.material_brace,
|
||||
role=Role.CASING | Role.DECORATION,
|
||||
loc=Cq.Location.rot2d(i*360/self.n_side),
|
||||
)
|
||||
return a
|
||||
|
||||
def assembly(self) -> Cq.Assembly:
|
||||
a = Cq.Assembly()
|
||||
a = (
|
||||
a
|
||||
.add(
|
||||
self.assembly_section(length=self.side_length1, hasFrontHole=False, hasBackHole=True),
|
||||
name="section1",
|
||||
)
|
||||
.add(
|
||||
self.assembly_ring(),
|
||||
name="ring1",
|
||||
)
|
||||
.add(
|
||||
self.assembly_section(length=self.side_length2, hasFrontHole=True, hasBackHole=True),
|
||||
name="section2",
|
||||
)
|
||||
.add(
|
||||
self.assembly_ring(),
|
||||
name="ring2",
|
||||
)
|
||||
.add(
|
||||
self.assembly_section(length=self.side_length3, hasFrontHole=True, hasBackHole=True),
|
||||
name="section3",
|
||||
)
|
||||
)
|
||||
for (nl, nc, nr) in [
|
||||
("section1", "ring1", "section2"),
|
||||
("section2", "ring2", "section3"),
|
||||
]:
|
||||
for i in range(self.n_side):
|
||||
j = (i + 1) % self.n_side
|
||||
for ih in range(len(self.angle_joint_bolt_position)):
|
||||
a = a.constrain(
|
||||
f"{nl}/side{i}?holeBSO{ih}",
|
||||
f"{nc}/side{i}?holeLPM{ih}",
|
||||
"Plane",
|
||||
)
|
||||
a = a.constrain(
|
||||
f"{nr}/side{i}?holeFPO{ih}",
|
||||
f"{nc}/side{i}?holeRSM{ih}",
|
||||
"Plane",
|
||||
)
|
||||
|
||||
a = a.add(self.assembly_rotor(), name="rotor")
|
||||
return a.solve()
|
||||
|
|
|
@ -162,6 +162,15 @@ def tagPlane(self, tag: str,
|
|||
|
||||
Cq.Workplane.tagPlane = tagPlane
|
||||
|
||||
def tag_absolute(
|
||||
self,
|
||||
tag: str,
|
||||
loc: Union[Cq.Location, Tuple[float, float, float]],
|
||||
direction: Union[str, Cq.Vector, Tuple[float, float, float]] = '+Z'):
|
||||
return self.pushPoints([loc]).tagPlane(tag, direction=direction)
|
||||
|
||||
Cq.Workplane.tagAbsolute = tag_absolute
|
||||
|
||||
def make_sphere(r: float = 2) -> Cq.Solid:
|
||||
"""
|
||||
Makes a full sphere. The default function makes a hemisphere
|
||||
|
|
Loading…
Reference in New Issue