Onbashira rotor-stator mechanism

This commit is contained in:
Leni Aniva 2025-02-25 21:04:25 -08:00
parent f4704b9ad6
commit a74f919a5b
Signed by: aniva
GPG Key ID: 4D9B1C8D10EA4C50
2 changed files with 122 additions and 4 deletions

View File

@ -25,6 +25,9 @@ class Role(Flag):
PARENT = auto()
CHILD = auto()
CASING = auto()
STATOR = auto()
ROTOR = auto()
BEARING = auto()
# Springs, cushions
DAMPING = auto()
# Main structural support
@ -59,6 +62,9 @@ ROLE_COLOR_MAP = {
Role.PARENT: _color('blue4', 0.6),
Role.CASING: _color('dodgerblue3', 0.6),
Role.CHILD: _color('darkorange2', 0.6),
Role.STATOR: _color('gray', 0.5),
Role.ROTOR: _color('blue3', 0.5),
Role.BEARING: _color('green3', 0.8),
Role.DAMPING: _color('springgreen', 1.0),
Role.STRUCTURE: _color('gray', 0.4),
Role.DECORATION: _color('lightseagreen', 0.4),

View File

@ -16,11 +16,27 @@ class Onbashira(Model):
side_thickness: float = 25.4 / 8
# Dimensions of gun barrels
barrel_diam: float = 45.0
barrel_length: float = 300.0
# Radius from barrel centre to axis
rotation_radius: float = 75.0
# Radius of ball bearings
bearing_ball_diam: float = 30.0
bearing_ball_gap: float = 1.0
bearing_height: float = 40.0
bearing_thickness: float = 20.0
material_side: Material = Material.WOOD_BIRCH
material_bearing: Material = Material.PLASTIC_PLA
material_bearing_ball: Material = Material.ACRYLIC_TRANSPARENT
material_brace: Material = Material.ALUMINUM
def __post_init__(self):
assert self.n_side >= 3
# Bulk must be large enough for the barrel + bearing to rotate
assert self.bulk_radius - self.side_thickness - self.bearing_thickness - self.bearing_diam > self.rotation_radius + self.barrel_diam / 2
assert self.bearing_height > self.bearing_diam
@property
def angle_side(self) -> float:
@ -29,11 +45,17 @@ class Onbashira(Model):
def angle_dihedral(self) -> float:
return 180 - self.angle_side
@property
def barrel_radius(self) -> float:
def bulk_radius(self) -> float:
"""
Calculate radius of the barrel to the centre
Calculate radius of the bulk to the centre
"""
return self.side_width / 2 / math.tan(math.radians(self.angle_side / 2))
@property
def bearing_diam(self) -> float:
return self.bearing_ball_diam + self.bearing_ball_gap
@property
def bearing_radius(self) -> float:
return self.bulk_radius - self.side_thickness - self.bearing_thickness - self.bearing_diam / 2
@target(name="side-panel", kind=TargetKind.DXF)
def profile_side_panel(self) -> Cq.Sketch:
@ -55,7 +77,7 @@ class Onbashira(Model):
.polyline([
(-w/2, 0),
(w/2, 0),
(0, self.barrel_radius),
(0, self.bulk_radius),
])
.close()
.extrude(l)
@ -64,10 +86,100 @@ class Onbashira(Model):
# Intersect the side panel
return result * intersector
def bearing_channel(self) -> Cq.Solid:
"""
Generates a toroidal channel for the ball bearings
"""
return Cq.Solid.makeTorus(
radius1=self.bearing_radius,
radius2=self.bearing_diam/2,
)
@target(name="inner-rotor")
def inner_rotor(self) -> Cq.Workplane:
r_outer = self.bearing_radius
base = Cq.Solid.makeCylinder(
radius=r_outer,
height=self.bearing_height
).translate(Cq.Vector(0,0,-self.bearing_height/2))
r_rot = self.rotation_radius
channel = self.bearing_channel()
return (
Cq.Workplane()
.add(base - channel)
.faces(">Z")
.workplane()
.polygon(
nSides=self.n_side,
diameter=2 * r_rot,
forConstruction=True
)
.vertices()
.hole(self.barrel_diam)
)
return base - channel
@target(name="outer-rotor")
def outer_rotor(self) -> Cq.Workplane:
polygon_radius = (self.bulk_radius - self.side_thickness) / math.cos(math.radians(self.angle_side / 2))
profile = (
Cq.Sketch()
.regularPolygon(
r=polygon_radius,
n=self.n_side,
)
)
inner = Cq.Solid.makeCylinder(
radius=self.bearing_radius,
height=self.bearing_height,
)
base = (
Cq.Workplane()
.placeSketch(profile)
.extrude(self.bearing_height)
.cut(inner)
.translate(Cq.Vector(0,0,-self.bearing_height/2))
.cut(self.bearing_channel())
)
r = self.bearing_radius * 2
subtractor = Cq.Solid.makeBox(
length=r * 2,
width=r * 2,
height=self.bearing_height,
).translate(Cq.Vector(-r, -r, -self.bearing_height))
return base - subtractor
def bearing_ball(self) -> Cq.Solid:
return Cq.Solid.makeSphere(radius=self.bearing_ball_diam/2, angleDegrees1=-90)
def assembly_bearing(self) -> Cq.Assembly:
a = (
Cq.Assembly()
.addS(
self.inner_rotor(),
name="inner",
material=self.material_bearing,
role=Role.ROTOR,
)
.addS(
self.outer_rotor(),
name="outer",
material=self.material_bearing,
role=Role.STATOR,
)
)
for i in range(self.n_side):
ball = self.bearing_ball()
a = a.addS(
ball,
name=f"bearing_ball{i}",
material=self.material_bearing_ball,
role=Role.BEARING,
loc=Cq.Location.rot2d(i * 360/self.n_side) * Cq.Location(self.bearing_radius, 0, 0),
)
return a
def assembly(self) -> Cq.Assembly:
a = Cq.Assembly()
side = self.side_panel()
r = self.barrel_radius
r = self.bulk_radius
for i in range(6):
a = a.addS(
side,