接入ai
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -51,7 +51,7 @@ def scale_from_motor(
|
||||
reducer_axial_allowance_mm: float = 42.0,
|
||||
min_radial_scale: float = 0.45,
|
||||
max_radial_scale: float = 1.50,
|
||||
min_axial_scale: float = 0.55,
|
||||
min_axial_scale: float = 0.42,
|
||||
max_axial_scale: float = 1.80,
|
||||
) -> HousingScale:
|
||||
target_inner_radius = motor_radial_diameter_mm / 2.0 + radial_clearance_mm
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
from pathlib import Path
|
||||
import math
|
||||
|
||||
import cadquery as cq
|
||||
|
||||
|
||||
AXIS = cq.Vector(0.0, 1.0, 0.0)
|
||||
|
||||
|
||||
def _point_on_xz(radius: float, angle_degrees: float, y: float) -> cq.Vector:
|
||||
angle = math.radians(angle_degrees)
|
||||
return cq.Vector(radius * math.cos(angle), y, radius * math.sin(angle))
|
||||
|
||||
|
||||
def _cylinder(radius: float, y0: float, length: float, x: float = 0.0, z: float = 0.0):
|
||||
return cq.Solid.makeCylinder(radius, length, cq.Vector(x, y0, z), AXIS)
|
||||
|
||||
|
||||
def _ring(outer_radius: float, inner_radius: float, y0: float, length: float):
|
||||
return _cylinder(outer_radius, y0, length).cut(_cylinder(inner_radius, y0, length))
|
||||
|
||||
|
||||
def _conical_ring(
|
||||
outer_start: float,
|
||||
outer_end: float,
|
||||
inner_start: float,
|
||||
inner_end: float,
|
||||
y0: float,
|
||||
length: float,
|
||||
):
|
||||
outer = cq.Solid.makeCone(outer_start, outer_end, length, cq.Vector(0.0, y0, 0.0), AXIS)
|
||||
inner = cq.Solid.makeCone(inner_start, inner_end, length, cq.Vector(0.0, y0, 0.0), AXIS)
|
||||
return outer.cut(inner)
|
||||
|
||||
|
||||
def _sector_cut(angle_center: float, angle_width: float, y0: float, length: float, radius: float = 100.0):
|
||||
start = math.radians(angle_center - angle_width / 2.0)
|
||||
end = math.radians(angle_center + angle_width / 2.0)
|
||||
points = [
|
||||
(0.0, 0.0),
|
||||
(radius * math.cos(start), radius * math.sin(start)),
|
||||
(radius * math.cos(end), radius * math.sin(end)),
|
||||
]
|
||||
plane = cq.Plane(origin=(0.0, y0, 0.0), xDir=(1.0, 0.0, 0.0), normal=(0.0, 1.0, 0.0))
|
||||
return cq.Workplane(plane).polyline(points).close().extrude(length).val()
|
||||
|
||||
|
||||
def _annular_sector_cut(
|
||||
angle_center: float,
|
||||
angle_width: float,
|
||||
inner_radius: float,
|
||||
outer_radius: float,
|
||||
y0: float,
|
||||
length: float,
|
||||
profile_fillet_radius: float = 0.0,
|
||||
axial_fillet_radius: float = 0.0,
|
||||
):
|
||||
start = math.radians(angle_center - angle_width / 2.0)
|
||||
middle = math.radians(angle_center)
|
||||
end = math.radians(angle_center + angle_width / 2.0)
|
||||
inner_start = (inner_radius * math.cos(start), inner_radius * math.sin(start))
|
||||
inner_middle = (inner_radius * math.cos(middle), inner_radius * math.sin(middle))
|
||||
inner_end = (inner_radius * math.cos(end), inner_radius * math.sin(end))
|
||||
outer_start = (outer_radius * math.cos(start), outer_radius * math.sin(start))
|
||||
outer_middle = (outer_radius * math.cos(middle), outer_radius * math.sin(middle))
|
||||
outer_end = (outer_radius * math.cos(end), outer_radius * math.sin(end))
|
||||
plane = cq.Plane(origin=(0.0, y0, 0.0), xDir=(1.0, 0.0, 0.0), normal=(0.0, 1.0, 0.0))
|
||||
cutter = (
|
||||
cq.Workplane(plane)
|
||||
.moveTo(*inner_start)
|
||||
.lineTo(*outer_start)
|
||||
.threePointArc(outer_middle, outer_end)
|
||||
.lineTo(*inner_end)
|
||||
.threePointArc(inner_middle, inner_start)
|
||||
.close()
|
||||
.extrude(length)
|
||||
)
|
||||
if profile_fillet_radius > 0.0:
|
||||
# Round the corners of the annular profile (fillet axes parallel to Y).
|
||||
cutter = cutter.edges("|Y").fillet(profile_fillet_radius)
|
||||
if axial_fillet_radius > 0.0:
|
||||
# Round only the straight radial edges at the two axial ends. This
|
||||
# produces the R10/R5/R2 window run-outs present in the source STEP.
|
||||
end_edges = [
|
||||
edge
|
||||
for edge in cutter.edges("%LINE").vals()
|
||||
if abs(edge.Center().y - y0) < 1.0e-6
|
||||
or abs(edge.Center().y - (y0 + length)) < 1.0e-6
|
||||
]
|
||||
cutter = cutter.newObject(end_edges).fillet(axial_fillet_radius)
|
||||
return cutter.val()
|
||||
|
||||
|
||||
def _radial_bar(angle_degrees: float, y0: float, length: float, inner_radius: float, outer_radius: float, width: float):
|
||||
radial_length = outer_radius - inner_radius
|
||||
bar = (
|
||||
cq.Workplane("XY")
|
||||
.box(radial_length, length, width)
|
||||
.translate(((inner_radius + outer_radius) / 2.0, y0 + length / 2.0, 0.0))
|
||||
)
|
||||
return bar.rotate((0.0, 0.0, 0.0), (0.0, 1.0, 0.0), -angle_degrees).val()
|
||||
|
||||
|
||||
def _rounded_radial_slot(angle_degrees: float, y0: float, length: float):
|
||||
"""A 40 mm wide radial window with R2 corners in its axial section."""
|
||||
plane = cq.Plane(
|
||||
origin=(40.0, y0 + length / 2.0, 0.0),
|
||||
xDir=(0.0, 1.0, 0.0),
|
||||
normal=(1.0, 0.0, 0.0),
|
||||
)
|
||||
slot = (
|
||||
cq.Workplane(plane)
|
||||
.rect(length - 4.0, 36.0)
|
||||
.offset2D(2.0)
|
||||
.extrude(42.0)
|
||||
.rotate((0.0, 0.0, 0.0), (0.0, 1.0, 0.0), -angle_degrees)
|
||||
)
|
||||
return slot.val()
|
||||
|
||||
|
||||
def _support_blend(angle_degrees: float, mirrored: bool):
|
||||
"""One of the six R2 blends between the R64 and R29.2 support arcs."""
|
||||
sharp = (-62.80715975198, 12.298808230444)
|
||||
inner_tangent = (-62.1855700706093, 15.131254904777)
|
||||
lobe_tangent = (-63.6707499640005, 16.8512614004542)
|
||||
inner_center = (0.0, 0.0)
|
||||
blend_center = (-61.6824120316291, 17.0669284278203)
|
||||
lobe_center = (-34.6410161514, 20.0)
|
||||
|
||||
def transform(point):
|
||||
x, z = point
|
||||
if mirrored:
|
||||
axis = math.radians(150.0)
|
||||
ux, uz = math.cos(axis), math.sin(axis)
|
||||
projection = x * ux + z * uz
|
||||
x, z = 2.0 * projection * ux - x, 2.0 * projection * uz - z
|
||||
angle = math.radians(angle_degrees)
|
||||
return (
|
||||
x * math.cos(angle) - z * math.sin(angle),
|
||||
x * math.sin(angle) + z * math.cos(angle),
|
||||
)
|
||||
|
||||
def arc_middle(center, start, end, radius):
|
||||
ux = (start[0] - center[0]) / radius + (end[0] - center[0]) / radius
|
||||
uz = (start[1] - center[1]) / radius + (end[1] - center[1]) / radius
|
||||
scale = radius / math.hypot(ux, uz)
|
||||
return center[0] + ux * scale, center[1] + uz * scale
|
||||
|
||||
points = [transform(point) for point in (sharp, inner_tangent, lobe_tangent)]
|
||||
centers = [transform(point) for point in (inner_center, blend_center, lobe_center)]
|
||||
plane = cq.Plane(origin=(0.0, 90.2, 0.0), xDir=(1.0, 0.0, 0.0), normal=(0.0, -1.0, 0.0))
|
||||
return (
|
||||
cq.Workplane(plane)
|
||||
.moveTo(*points[0])
|
||||
.threePointArc(arc_middle(centers[0], points[0], points[1], 64.0), points[1])
|
||||
.threePointArc(arc_middle(centers[1], points[1], points[2], 2.0), points[2])
|
||||
.threePointArc(arc_middle(centers[2], points[2], points[0], 29.2), points[0])
|
||||
.close()
|
||||
.extrude(10.0)
|
||||
.val()
|
||||
)
|
||||
|
||||
|
||||
def build():
|
||||
# Front cylindrical shell and its smaller continuation.
|
||||
part = cq.Workplane(obj=_ring(79.4, 74.4, -10.0, 22.0))
|
||||
part = part.union(_ring(78.4, 74.4, 12.0, 43.2))
|
||||
|
||||
# Nine radial R2 holes through the front lip, spaced every 40 degrees.
|
||||
for angle in (90.0, 50.0, 10.0, -30.0, -70.0, -110.0, -150.0, -190.0, -230.0):
|
||||
start = _point_on_xz(72.0, angle, -5.0)
|
||||
direction = _point_on_xz(1.0, angle, 0.0)
|
||||
direction = cq.Vector(direction.x, 0.0, direction.z)
|
||||
part = part.cut(cq.Solid.makeCylinder(2.0, 10.0, start, direction))
|
||||
|
||||
# Six long ventilation windows, 40-degree openings with 20-degree ribs.
|
||||
for center in (-110.0, -50.0, 10.0, 70.0, 130.0, 190.0):
|
||||
part = part.cut(
|
||||
_annular_sector_cut(center, 40.0, 70.0, 82.0, 12.0, 40.0, axial_fillet_radius=10.0)
|
||||
)
|
||||
|
||||
# Taper from the large front shell to the narrower middle shell.
|
||||
part = part.union(_conical_ring(78.4, 73.2, 74.4, 69.2, 55.2, 20.0))
|
||||
part = part.union(_ring(73.2, 60.0, 75.2, 5.0))
|
||||
|
||||
# Three small axial holes in the first shoulder ring.
|
||||
for angle in (30.0, 150.0, 270.0):
|
||||
p = _point_on_xz(64.0, angle, 75.2)
|
||||
part = part.cut(cq.Solid.makeCylinder(2.0, 5.0, p, AXIS))
|
||||
|
||||
# Three-lobed support plate: a disk with three large circular openings.
|
||||
support = cq.Workplane(obj=_ring(73.2, 64.0, 80.2, 10.0))
|
||||
for x, z in ((34.6410161514, 20.0), (-34.6410161514, 20.0), (0.0, -40.0)):
|
||||
support = support.cut(_cylinder(29.2, 80.2, 10.0, x, z))
|
||||
part = part.union(support)
|
||||
|
||||
# Thin middle shell and its second, angularly shifted six-window pattern.
|
||||
part = part.union(_ring(73.2, 69.2, 90.2, 30.0))
|
||||
for center in (-150.0, -90.0, -30.0, 30.0, 90.0, 150.0):
|
||||
part = part.cut(
|
||||
_annular_sector_cut(center, 40.0, 65.0, 76.0, 90.2, 20.0, axial_fillet_radius=5.0)
|
||||
)
|
||||
|
||||
# Rear shell is one continuous 2:7 taper. Its inner cavity changes from
|
||||
# a steep R69.2 -> R63.6 cone to the matching shallow taper at Y=125.8.
|
||||
taper_outer = cq.Solid.makeCone(
|
||||
73.2, 64.91428571428571, 29.0, cq.Vector(0.0, 120.2, 0.0), AXIS
|
||||
)
|
||||
taper_inner_a = cq.Solid.makeCone(69.2, 63.6, 5.6, cq.Vector(0.0, 120.2, 0.0), AXIS)
|
||||
taper_inner_b = cq.Solid.makeCone(63.6, 59.2, 15.4, cq.Vector(0.0, 125.8, 0.0), AXIS)
|
||||
part = part.union(taper_outer.cut(taper_inner_a).cut(taper_inner_b))
|
||||
hub = cq.Workplane(obj=_ring(38.0, 26.0, 129.2, 4.0)).union(
|
||||
_ring(38.0, 30.0, 133.2, 16.0)
|
||||
)
|
||||
part = part.union(hub)
|
||||
|
||||
# Stop 0.0001 mm before the coincident rear-plate face so OpenCascade
|
||||
# keeps the six ribs in one valid solid.
|
||||
for center in (30.0, 90.0, 150.0, 210.0, 270.0, 330.0):
|
||||
part = part.cut(_rounded_radial_slot(center, 131.2, 9.9999))
|
||||
|
||||
# Central bore through the solid rear plate, then its six fan windows.
|
||||
part = part.cut(_cylinder(30.0, 141.2, 8.0))
|
||||
for center in (45.0, 105.0, 165.0, 225.0, 285.0, 345.0):
|
||||
cutter = _annular_sector_cut(
|
||||
center, 30.0, 38.0, 59.2, 141.2, 8.0, profile_fillet_radius=2.0
|
||||
)
|
||||
part = part.cut(cutter)
|
||||
|
||||
# These holes pass through both the end plate and the previously added hub.
|
||||
for angle in (-90.0, -30.0, 30.0, 90.0, 150.0, 210.0):
|
||||
p = _point_on_xz(34.0, angle, 141.2)
|
||||
part = part.cut(cq.Solid.makeCylinder(1.81198, 8.0, p, AXIS))
|
||||
|
||||
# Add the small support blends last so they cannot interfere with fusing
|
||||
# the face-connected rear shell and end plate.
|
||||
for mirrored in (False, True):
|
||||
for angle in (0.0, 120.0, 240.0):
|
||||
part = part.union(_support_blend(angle, mirrored))
|
||||
|
||||
# Remove only the six 0.0001 mm run-out residuals after the complete part
|
||||
# is connected. This reaches the exact Y=141.2 boundary without causing
|
||||
# the earlier coincident-face split into six solids.
|
||||
for center in (30.0, 90.0, 150.0, 210.0, 270.0, 330.0):
|
||||
full_slot = _rounded_radial_slot(center, 131.2, 10.0)
|
||||
stable_slot = _rounded_radial_slot(center, 131.2, 9.9999)
|
||||
part = part.cut(full_slot.cut(stable_slot))
|
||||
|
||||
return part
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
output = Path(__file__).resolve().with_name("外壳框架.step")
|
||||
cq.exporters.export(build(), str(output))
|
||||
print(output)
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"platform_id": "actuator_v2_fixed_platform",
|
||||
"motor_step": "../motors/3500_motor_part2_standard.step",
|
||||
"housing_step": "../housings/actuator_v2_knee_abd_main_case_2.step",
|
||||
"reference_assembly_step": "../references/actuator_v2_knee_abd_reference.step"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"module_type": "planetary_joint_module",
|
||||
"motor_step": "../../assets/motors/3500_motor_part2.step",
|
||||
"housing_step": "../../assets/housings/generated_housing_baseline.step",
|
||||
"reducer_requirement": "../reducers/simple_2k_h/simple_2kh_industrial_ratio_7p5_spur.json",
|
||||
"platform_profile": "../../assets/platforms/actuator_v2_fixed_platform.json",
|
||||
"reducer_requirement": "../reducers/simple_2k_h/simple_2kh_industrial_ratio_7p5_spur_compact.json",
|
||||
"placement_policy": "infer_then_write_editable_json",
|
||||
"motor_to_reducer_relation": "motor_output_to_sun_keyed_input",
|
||||
"housing_relation": "ring_fixed_to_housing",
|
||||
"joint_output": "carrier_output_shaft",
|
||||
"output_extension_mm": 8.0,
|
||||
"coupling_clearance_mm": 1.0,
|
||||
"motor_placement_policy": "external_flush_input_end",
|
||||
"output_extension_mm": 2.0,
|
||||
"coupling_clearance_mm": 0.5,
|
||||
"input_shaft_insertion_depth_mm": 4.0,
|
||||
"motor_output_side": "axis_max",
|
||||
"axis_angle_tolerance_deg": 0.5,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"module_type": "planetary_joint_module",
|
||||
"motor_step": "../../assets/motors/3500_motor_part2.step",
|
||||
"housing_step": "../../assets/housings/generated_housing_baseline.step",
|
||||
"reducer_requirement": "../reducers/simple_2k_h_cascade/simple_2kh_cascade_ratio_9_spur.json",
|
||||
"platform_profile": "../../assets/platforms/actuator_v2_fixed_platform.json",
|
||||
"reducer_requirement": "../reducers/simple_2k_h_cascade/simple_2kh_cascade_ratio_9_spur_compact.json",
|
||||
"placement_policy": "infer_then_write_editable_json",
|
||||
"motor_to_reducer_relation": "motor_output_to_s1_sun_input",
|
||||
"housing_relation": "stage_rings_fixed_to_housing",
|
||||
"joint_output": "s2_carrier_output",
|
||||
"motor_placement_policy": "external_flush_input_end",
|
||||
"output_extension_mm": 2.0,
|
||||
"coupling_clearance_mm": 0.5,
|
||||
"input_shaft_insertion_depth_mm": 1.0,
|
||||
"input_shaft_insertion_depth_mm": 4.0,
|
||||
"motor_output_side": "axis_max",
|
||||
"axis_angle_tolerance_deg": 0.5,
|
||||
"axis_distance_tolerance_mm": 0.25,
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"target_ratio": 7.5,
|
||||
"ratio_tolerance": 0.01,
|
||||
"topology_family": "simple_2k_h",
|
||||
"detail_level": "industrial_core",
|
||||
"input": "sun",
|
||||
"fixed": "ring",
|
||||
"output": "carrier",
|
||||
"tooth_form": "spur",
|
||||
"planet_count_candidates": [3],
|
||||
"module_candidates_mm": [0.3],
|
||||
"pressure_angle_deg": 20.0,
|
||||
"face_width_mm": 6.0,
|
||||
"backlash_mm": 0.03,
|
||||
"addendum_coeff": 1.0,
|
||||
"clearance_coeff": 0.25,
|
||||
"ring_rim_thickness_mm": 1.5,
|
||||
"constraints": {
|
||||
"max_outer_diameter_mm": 60.0,
|
||||
"min_planet_neighbor_clearance_mm": 0.3,
|
||||
"min_sun_teeth": 20,
|
||||
"max_sun_teeth": 20,
|
||||
"min_planet_teeth": 55,
|
||||
"max_planet_teeth": 55
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"target_ratio": 9.0,
|
||||
"ratio_tolerance": 0.000001,
|
||||
"topology_family": "simple_2k_h_cascade",
|
||||
"tooth_form": "spur",
|
||||
"planet_count_candidates": [3],
|
||||
"module_candidates_mm": [0.5],
|
||||
"pressure_angle_deg": 20.0,
|
||||
"face_width_mm": 6.0,
|
||||
"backlash_mm": 0.03,
|
||||
"addendum_coeff": 1.0,
|
||||
"clearance_coeff": 0.25,
|
||||
"ring_rim_thickness_mm": 2.5,
|
||||
"constraints": {
|
||||
"max_outer_diameter_mm": 100.0,
|
||||
"min_planet_neighbor_clearance_mm": 0.3,
|
||||
"min_sun_teeth": 36,
|
||||
"max_sun_teeth": 36,
|
||||
"min_planet_teeth": 18,
|
||||
"max_planet_teeth": 18
|
||||
},
|
||||
"stages": [
|
||||
{
|
||||
"stage_id": "s1",
|
||||
"input": "sun",
|
||||
"fixed": "ring",
|
||||
"output": "carrier",
|
||||
"planet_count_candidates": [3],
|
||||
"module_candidates_mm": [0.5]
|
||||
},
|
||||
{
|
||||
"stage_id": "s2",
|
||||
"input": "sun",
|
||||
"fixed": "ring",
|
||||
"output": "carrier",
|
||||
"planet_count_candidates": [3],
|
||||
"module_candidates_mm": [0.5]
|
||||
}
|
||||
],
|
||||
"cascade": {
|
||||
"coupling_policy": "stage_output_to_next_stage_input",
|
||||
"stage_gap_mm": 2.0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user