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

207 lines
6.8 KiB
Python

"""Gear and carrier parts for the four-planet planetary reducer."""
from __future__ import annotations
import simplecadapi as scad
from common import ground_solid, make_axis_part_rpart, make_z_rotation_rplacement
from dimensions import (
ADDENDUM_FACTOR,
BACKLASH,
CARRIER_ARM_WIDTH,
CARRIER_BOTTOM_Z,
CARRIER_HUB_RADIUS,
CARRIER_PIN_BOSS_RADIUS,
CARRIER_PIN_HEIGHT,
CARRIER_THICKNESS,
CLEARANCE_FACTOR,
GEAR_AXIS_Z,
GEAR_HEIGHT,
MODULE,
PLANET_CENTER_RADIUS,
PLANET_COUNT,
PLANET_PIN_CLEARANCE_RADIUS,
PLANET_PIN_RADIUS,
PLANET_TEETH,
PRESSURE_ANGLE,
RING_RIM_THICKNESS,
RING_TEETH,
SUN_BORE_RADIUS,
SUN_TEETH,
planet_angle_degrees,
planet_center_xy,
)
def make_sun_gear_rpart(*, material: scad.Material) -> scad.Part:
"""Create the input sun gear with a service bore and axis connector."""
sun = scad.std.gear.make_spur_gear_rsolid(
n_teeth=SUN_TEETH,
module=MODULE,
pressure_angle=PRESSURE_ANGLE,
gear_height=GEAR_HEIGHT,
addendum_factor=ADDENDUM_FACTOR,
clearance_factor=CLEARANCE_FACTOR,
backlash=BACKLASH,
)
bore = scad.make_cylinder_rsolid(
radius=SUN_BORE_RADIUS,
height=GEAR_HEIGHT + 2.0,
bottom_face_center=(0.0, 0.0, -1.0),
axis=(0.0, 0.0, 1.0),
)
sun = scad.cut_rsolid(sun, bore, skip_non_intersecting=False)
sun = scad.apply_tag(shape=sun, tag="role.sun_input_gear")
ground_solid(label="sun_gear", solid=sun)
return make_axis_part_rpart(
part_id="sun_input_gear",
body=sun,
name="Input sun gear, 24 teeth",
material=material,
connector_specs=(("axis", (0.0, 0.0, GEAR_AXIS_Z), "Sun input axis"),),
)
def make_ring_gear_rpart(*, material: scad.Material) -> scad.Part:
"""Create the fixed internal ring gear without an enclosing housing."""
ring = scad.std.gear.make_spur_ring_gear_rsolid(
n_teeth=RING_TEETH,
module=MODULE,
pressure_angle=PRESSURE_ANGLE,
gear_height=GEAR_HEIGHT,
rim_thickness=RING_RIM_THICKNESS,
backlash=BACKLASH,
addendum_factor=ADDENDUM_FACTOR,
clearance_factor=CLEARANCE_FACTOR,
)
ring = scad.apply_tag(shape=ring, tag="role.fixed_internal_ring_gear")
ground_solid(label="ring_gear", solid=ring)
return make_axis_part_rpart(
part_id="fixed_ring_gear",
body=ring,
name="Fixed internal ring gear, 60 teeth",
material=material,
connector_specs=(("axis", (0.0, 0.0, GEAR_AXIS_Z), "Fixed ring axis"),),
)
def make_planet_gear_rpart(*, material: scad.Material) -> scad.Part:
"""Create one reusable planet gear with a carrier-pin bore."""
planet = scad.std.gear.make_spur_gear_rsolid(
n_teeth=PLANET_TEETH,
module=MODULE,
pressure_angle=PRESSURE_ANGLE,
gear_height=GEAR_HEIGHT,
addendum_factor=ADDENDUM_FACTOR,
clearance_factor=CLEARANCE_FACTOR,
backlash=BACKLASH,
)
bore = scad.make_cylinder_rsolid(
radius=PLANET_PIN_CLEARANCE_RADIUS,
height=GEAR_HEIGHT + 2.0,
bottom_face_center=(0.0, 0.0, -1.0),
axis=(0.0, 0.0, 1.0),
)
planet = scad.cut_rsolid(planet, bore, skip_non_intersecting=False)
planet = scad.apply_tag(shape=planet, tag="role.reusable_planet_gear")
ground_solid(label="planet_gear", solid=planet)
return make_axis_part_rpart(
part_id="planet_gear",
body=planet,
name="Reusable planet gear, 18 teeth",
material=material,
connector_specs=(("axis", (0.0, 0.0, GEAR_AXIS_Z), "Planet spin axis"),),
)
def make_carrier_rpart(*, material: scad.Material) -> scad.Part:
"""Create the four-pin carrier output spider."""
hub = scad.make_cylinder_rsolid(
radius=CARRIER_HUB_RADIUS,
height=CARRIER_THICKNESS,
bottom_face_center=(0.0, 0.0, CARRIER_BOTTOM_Z),
axis=(0.0, 0.0, 1.0),
)
arms: list[scad.Solid] = []
pin_bosses: list[scad.Solid] = []
pins: list[scad.Solid] = []
for index in range(PLANET_COUNT):
angle = planet_angle_degrees(index=index)
x, y = planet_center_xy(index=index)
arm = scad.make_box_rsolid(
width=PLANET_CENTER_RADIUS + CARRIER_PIN_BOSS_RADIUS,
height=CARRIER_ARM_WIDTH,
depth=CARRIER_THICKNESS,
bottom_face_center=(PLANET_CENTER_RADIUS / 2.0, 0.0, CARRIER_BOTTOM_Z),
)
arms.append(
scad.rotate_shape(
shape=arm,
angle=angle,
axis=(0.0, 0.0, 1.0),
origin=(0.0, 0.0, 0.0),
)
)
pin_bosses.append(
scad.make_cylinder_rsolid(
radius=CARRIER_PIN_BOSS_RADIUS,
height=CARRIER_THICKNESS,
bottom_face_center=(x, y, CARRIER_BOTTOM_Z),
axis=(0.0, 0.0, 1.0),
)
)
pins.append(
scad.make_cylinder_rsolid(
radius=PLANET_PIN_RADIUS,
height=CARRIER_PIN_HEIGHT,
bottom_face_center=(x, y, CARRIER_BOTTOM_Z),
axis=(0.0, 0.0, 1.0),
)
)
carrier = scad.union_rsolid([hub, arms, pin_bosses, pins], glue=False)
center_bore = scad.make_cylinder_rsolid(
radius=SUN_BORE_RADIUS + 0.8,
height=CARRIER_THICKNESS + 2.0,
bottom_face_center=(0.0, 0.0, CARRIER_BOTTOM_Z - 1.0),
axis=(0.0, 0.0, 1.0),
)
carrier = scad.cut_rsolid(carrier, center_bore, skip_non_intersecting=False)
carrier = scad.apply_tag(shape=carrier, tag="role.four_pin_output_carrier")
ground_solid(label="carrier", solid=carrier)
connector_specs = [
("axis", (0.0, 0.0, GEAR_AXIS_Z), "Carrier output axis"),
("output_axis", (0.0, 0.0, GEAR_AXIS_Z), "Public output axis"),
]
connector_specs.extend(
(
f"planet_{index + 1}_axis",
(*planet_center_xy(index=index), GEAR_AXIS_Z),
f"Planet {index + 1} carrier pin axis",
)
for index in range(PLANET_COUNT)
)
return make_axis_part_rpart(
part_id="four_pin_output_carrier",
body=carrier,
name="Four-pin output carrier spider",
material=material,
connector_specs=tuple(connector_specs),
)
def make_planet_component_rplacement(*, index: int) -> scad.Placement:
"""Return the placement for one of the four equally spaced planets."""
angle = planet_angle_degrees(index=index)
x, y = planet_center_xy(index=index)
tooth_phase = angle + 180.0 - (180.0 / PLANET_TEETH)
print(
f"planet_{index + 1}: center=({x:.3f},{y:.3f},0.000) "
f"carrier_angle={angle:.1f} spin_phase={tooth_phase:.1f}"
)
return make_z_rotation_rplacement(origin=(x, y, 0.0), angle_degrees=tooth_phase)