Files
2026-07-22 13:48:46 +08:00

175 lines
5.9 KiB
Python

"""Standard bearing factories and coaxial/planet placements."""
from __future__ import annotations
import simplecadapi as scad
if __package__:
from .common import make_annulus_rsolid, make_axis_part_rpart, make_z_rotation_rplacement
from .dimensions import BearingSpec, PLANET_COUNT, StageSpec
from .gears import planet_center_xy
else:
from common import make_annulus_rsolid, make_axis_part_rpart, make_z_rotation_rplacement
from dimensions import BearingSpec, PLANET_COUNT, StageSpec
from gears import planet_center_xy
def make_standard_planet_bearing_rassembly(
*,
bearing_id: str,
spec: BearingSpec,
material: scad.Material,
) -> scad.Assembly:
"""Create the reused catalog-style planet ball bearing assembly."""
bearing = make_main_bearing_rassembly(
bearing_id=bearing_id,
spec=spec,
material=material,
)
print(
f"bearing_{bearing_id}: bore={spec.bore_diameter:.1f} od={spec.outer_diameter:.1f} "
f"width={spec.width:.1f} balls={spec.ball_count} material={material.material_id}"
)
return bearing
def make_main_bearing_rassembly(
*,
bearing_id: str,
spec: BearingSpec,
material: scad.Material,
) -> scad.Assembly:
"""Create a uniquely identified bearing when several catalog sizes share one graph."""
bore_radius = spec.bore_diameter / 2.0
outer_radius = spec.outer_diameter / 2.0
ball_radius = spec.ball_diameter / 2.0
pitch_radius = (bore_radius + outer_radius) / 2.0
inner_outer_radius = pitch_radius - ball_radius * 0.55
outer_inner_radius = pitch_radius + ball_radius * 0.55
inner_ring = make_annulus_rsolid(
outer_radius=inner_outer_radius,
inner_radius=bore_radius,
bottom_z=-spec.width / 2.0,
height=spec.width,
tags=("role.bearing_inner_ring",),
)
outer_ring = make_annulus_rsolid(
outer_radius=outer_radius,
inner_radius=outer_inner_radius,
bottom_z=-spec.width / 2.0,
height=spec.width,
tags=("role.bearing_outer_ring",),
)
ball = scad.make_sphere_rsolid(
radius=ball_radius,
center=(pitch_radius, 0.0, 0.0),
)
inner_part = make_axis_part_rpart(
part_id=f"{bearing_id}_inner_ring",
body=inner_ring,
name=f"{bearing_id} inner race",
material=material,
connectors=(("axis", (0.0, 0.0, 0.0), "Inner-ring axis"),),
)
outer_part = make_axis_part_rpart(
part_id=f"{bearing_id}_outer_ring",
body=outer_ring,
name=f"{bearing_id} outer race",
material=material,
connectors=(("axis", (0.0, 0.0, 0.0), "Outer-ring axis"),),
)
ball_part = make_axis_part_rpart(
part_id=f"{bearing_id}_reusable_ball",
body=ball,
name=f"{bearing_id} reusable rolling element",
material=material,
connectors=(),
)
bearing = scad.make_assembly_rassembly(
assembly_id=bearing_id,
name=f"Ball bearing {spec.bore_diameter:g}x{spec.outer_diameter:g}x{spec.width:g}",
)
bearing = scad.add_component_rassembly(
assembly=bearing,
item=outer_part,
component_id="outer_ring",
placement=scad.identity_placement_rplacement(),
name="Outer ring",
)
bearing = scad.add_component_rassembly(
assembly=bearing,
item=inner_part,
component_id="inner_ring",
placement=scad.identity_placement_rplacement(),
name="Inner ring",
)
for index in range(spec.ball_count):
angle = 360.0 * index / spec.ball_count
bearing = scad.add_component_rassembly(
assembly=bearing,
item=ball_part,
component_id=f"ball_{index + 1:02d}",
placement=make_z_rotation_rplacement(origin=(0.0, 0.0, 0.0), angle_degrees=angle),
name=f"Rolling element {index + 1}",
)
bearing = scad.add_revolute_constraint_rassembly(
assembly=bearing,
constraint_id="inner_outer_revolute",
connector_a=scad.make_connector_ref_rconnectorref(
component_id="outer_ring",
connector_id="axis",
),
connector_b=scad.make_connector_ref_rconnectorref(
component_id="inner_ring",
connector_id="axis",
),
drive_angle_degrees=None,
angle_limit=None,
name="Inner ring rotation in outer ring",
)
for connector_id, component_id in (("outer_axis", "outer_ring"), ("inner_axis", "inner_ring")):
bearing = scad.forward_connector_rassembly(
assembly=bearing,
connector_id=connector_id,
source_component_id=component_id,
source_connector_id="axis",
name=connector_id.replace("_", " "),
offset=None,
)
radial_wall = (spec.outer_diameter - spec.bore_diameter) / 2.0 - spec.ball_diameter
axial_margin = spec.width - spec.ball_diameter
print(
f"bearing_{bearing_id}: bore={spec.bore_diameter:.1f} od={spec.outer_diameter:.1f} "
f"width={spec.width:.1f} balls={spec.ball_count} radial_wall={radial_wall:.2f} "
f"axial_margin={axial_margin:.2f}"
)
return bearing
def make_coaxial_bearing_rplacement(*, center_z: float) -> scad.Placement:
"""Place a standard bearing center plane on the actuator Z axis."""
return make_z_rotation_rplacement(origin=(0.0, 0.0, center_z), angle_degrees=0.0)
def make_planet_bearing_rplacement(
*,
stage: StageSpec,
index: int,
) -> scad.Placement:
"""Place a standard planet bearing at the gear midplane."""
if index < 0 or index >= PLANET_COUNT:
raise ValueError(f"planet bearing index out of range: {index}")
center = planet_center_xy(stage=stage, index=index)
print(
f"{stage.stage_id}_planet_bearing_{index + 1}: "
f"center=({center[0]:.3f},{center[1]:.3f},{stage.mid_z:.3f})"
)
return make_z_rotation_rplacement(
origin=(center[0], center[1], stage.mid_z),
angle_degrees=0.0,
)