195 lines
6.4 KiB
Python
195 lines
6.4 KiB
Python
"""Split-clamp actuator mounts for the leg-wheel example."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import simplecadapi as scad
|
|
|
|
from leg_common import make_part_with_connectors_rpart
|
|
from leg_dimensions import (
|
|
BODY_STANDOFF_THICKNESS,
|
|
BODY_STANDOFF_Z,
|
|
CASE_CLAMP_INNER_RADIUS,
|
|
CASE_CLAMP_OUTER_RADIUS,
|
|
CASE_CLAMP_PINCH_AXIS_RADIUS,
|
|
CASE_CLAMP_PINCH_HALF_SPAN,
|
|
CASE_CLAMP_PINCH_HOLE_RADIUS,
|
|
CASE_CLAMP_SLIT_WIDTH,
|
|
CASE_CLAMP_WIDTH,
|
|
KNEE_CASE_CLAMP_Z,
|
|
ROOT_AXIS,
|
|
THIGH_CASE_CLAMP_Z,
|
|
)
|
|
|
|
|
|
def make_split_case_clamp_rsolid(
|
|
*, center: tuple[float, float, float], z_center: float, tag: str
|
|
) -> scad.Solid:
|
|
"""Create one machinable C-clamp with coaxial pinch-bolt ears."""
|
|
|
|
z_min = z_center - CASE_CLAMP_WIDTH / 2.0
|
|
outer = scad.make_cylinder_rsolid(
|
|
radius=CASE_CLAMP_OUTER_RADIUS,
|
|
height=CASE_CLAMP_WIDTH,
|
|
bottom_face_center=(center[0], center[1], z_min),
|
|
axis=(0.0, 0.0, 1.0),
|
|
)
|
|
bore = scad.make_cylinder_rsolid(
|
|
radius=CASE_CLAMP_INNER_RADIUS,
|
|
height=CASE_CLAMP_WIDTH + 2.0,
|
|
bottom_face_center=(center[0], center[1], z_min - 1.0),
|
|
axis=(0.0, 0.0, 1.0),
|
|
)
|
|
clamp = scad.cut_rsolid(outer, bore, skip_non_intersecting=False)
|
|
|
|
ear_center_x = center[0] + CASE_CLAMP_PINCH_AXIS_RADIUS - 2.5
|
|
ear_center_y = CASE_CLAMP_SLIT_WIDTH / 2.0 + 2.5
|
|
ears = [
|
|
scad.make_box_rsolid(
|
|
width=8.0,
|
|
height=5.0,
|
|
depth=CASE_CLAMP_WIDTH,
|
|
bottom_face_center=(ear_center_x, center[1] + sign * ear_center_y, z_min),
|
|
)
|
|
for sign in (-1.0, 1.0)
|
|
]
|
|
clamp = scad.union_rsolid(clamp, ears, glue=False)
|
|
slit = scad.make_box_rsolid(
|
|
width=15.0,
|
|
height=CASE_CLAMP_SLIT_WIDTH,
|
|
depth=CASE_CLAMP_WIDTH + 2.0,
|
|
bottom_face_center=(center[0] + 31.0, center[1], z_min - 1.0),
|
|
)
|
|
pinch_hole = scad.make_cylinder_rsolid(
|
|
radius=CASE_CLAMP_PINCH_HOLE_RADIUS,
|
|
height=CASE_CLAMP_PINCH_HALF_SPAN * 2.0,
|
|
bottom_face_center=(
|
|
center[0] + CASE_CLAMP_PINCH_AXIS_RADIUS,
|
|
center[1] - CASE_CLAMP_PINCH_HALF_SPAN,
|
|
z_center,
|
|
),
|
|
axis=(0.0, 1.0, 0.0),
|
|
)
|
|
clamp = scad.cut_rsolid(
|
|
clamp,
|
|
slit,
|
|
pinch_hole,
|
|
skip_non_intersecting=False,
|
|
)
|
|
clamp = scad.apply_tag(shape=clamp, tag=tag)
|
|
print(
|
|
f"{tag}: bore_d={CASE_CLAMP_INNER_RADIUS * 2.0:.2f} "
|
|
f"pinch_hole_d={CASE_CLAMP_PINCH_HOLE_RADIUS * 2.0:.2f} "
|
|
f"faces={len(clamp.get_faces())} volume={clamp.get_volume():.3f}"
|
|
)
|
|
return clamp
|
|
|
|
|
|
def make_body_mount_plate_rpart(*, material: scad.Material) -> scad.Part:
|
|
"""Build the two-collar body mount for coaxial tandem root actuators."""
|
|
|
|
lower = make_split_case_clamp_rsolid(
|
|
center=ROOT_AXIS,
|
|
z_center=THIGH_CASE_CLAMP_Z,
|
|
tag="role.thigh_actuator_split_clamp",
|
|
)
|
|
upper = make_split_case_clamp_rsolid(
|
|
center=ROOT_AXIS,
|
|
z_center=KNEE_CASE_CLAMP_Z,
|
|
tag="role.knee_drive_split_clamp",
|
|
)
|
|
lower_z = THIGH_CASE_CLAMP_Z - CASE_CLAMP_WIDTH / 2.0
|
|
upper_z = KNEE_CASE_CLAMP_Z + CASE_CLAMP_WIDTH / 2.0
|
|
post_height = upper_z - lower_z
|
|
post_offset_x = 35.0
|
|
posts = [
|
|
scad.make_cylinder_rsolid(
|
|
radius=3.8,
|
|
height=post_height,
|
|
bottom_face_center=(ROOT_AXIS[0] + sign * post_offset_x, ROOT_AXIS[1], lower_z),
|
|
axis=(0.0, 0.0, 1.0),
|
|
)
|
|
for sign in (-1.0, 1.0)
|
|
]
|
|
collar_bridges = [
|
|
scad.make_box_rsolid(
|
|
width=8.0,
|
|
height=7.6,
|
|
depth=CASE_CLAMP_WIDTH,
|
|
bottom_face_center=(
|
|
ROOT_AXIS[0] + sign * 33.0,
|
|
ROOT_AXIS[1],
|
|
clamp_z - CASE_CLAMP_WIDTH / 2.0,
|
|
),
|
|
)
|
|
for sign in (-1.0, 1.0)
|
|
for clamp_z in (THIGH_CASE_CLAMP_Z, KNEE_CASE_CLAMP_Z)
|
|
]
|
|
lug_z_min = BODY_STANDOFF_Z - BODY_STANDOFF_THICKNESS / 2.0
|
|
lugs = [
|
|
scad.make_box_rsolid(
|
|
width=24.0,
|
|
height=18.0,
|
|
depth=BODY_STANDOFF_THICKNESS,
|
|
bottom_face_center=(ROOT_AXIS[0] + sign * 41.0, ROOT_AXIS[1], lug_z_min),
|
|
)
|
|
for sign in (-1.0, 1.0)
|
|
]
|
|
mount = scad.union_rsolid(lower, upper, posts, collar_bridges, lugs, glue=False)
|
|
torso_holes = [
|
|
scad.make_cylinder_rsolid(
|
|
radius=2.3,
|
|
height=BODY_STANDOFF_THICKNESS + 2.0,
|
|
bottom_face_center=(ROOT_AXIS[0] + sign * 45.0, ROOT_AXIS[1], lug_z_min - 1.0),
|
|
axis=(0.0, 0.0, 1.0),
|
|
)
|
|
for sign in (-1.0, 1.0)
|
|
]
|
|
mount = scad.cut_rsolid(mount, torso_holes, skip_non_intersecting=False)
|
|
mount = scad.apply_tag(shape=mount, tag="role.body_mount_plate")
|
|
print(
|
|
"body_mount_plate: root_actuators=2 tandem=true "
|
|
f"clamp_z=({THIGH_CASE_CLAMP_Z:.1f},{KNEE_CASE_CLAMP_Z:.1f}) "
|
|
f"torso_holes=2 faces={len(mount.get_faces())} volume={mount.get_volume():.3f}"
|
|
)
|
|
return make_part_with_connectors_rpart(
|
|
part_id="body_mount_plate",
|
|
body=mount,
|
|
name="Coaxial tandem root actuator split-clamp and body lug bracket",
|
|
material=material,
|
|
connectors=(
|
|
("case_axis", (ROOT_AXIS[0], ROOT_AXIS[1], THIGH_CASE_CLAMP_Z), "z", "Thigh actuator clamp datum"),
|
|
(
|
|
"knee_drive_case_axis",
|
|
(ROOT_AXIS[0], ROOT_AXIS[1], KNEE_CASE_CLAMP_Z),
|
|
"z",
|
|
"Knee-drive actuator clamp datum opposite the crank",
|
|
),
|
|
(
|
|
"thigh_clamp_bolt_seat",
|
|
(
|
|
ROOT_AXIS[0] + CASE_CLAMP_PINCH_AXIS_RADIUS,
|
|
ROOT_AXIS[1] + CASE_CLAMP_PINCH_HALF_SPAN - 0.9,
|
|
THIGH_CASE_CLAMP_Z,
|
|
),
|
|
"y",
|
|
"Thigh collar M4 bolt head seat",
|
|
),
|
|
(
|
|
"knee_clamp_bolt_seat",
|
|
(
|
|
ROOT_AXIS[0] + CASE_CLAMP_PINCH_AXIS_RADIUS,
|
|
ROOT_AXIS[1] + CASE_CLAMP_PINCH_HALF_SPAN - 0.9,
|
|
KNEE_CASE_CLAMP_Z,
|
|
),
|
|
"y",
|
|
"Knee-drive collar M4 bolt head seat",
|
|
),
|
|
(
|
|
"body_frame_axis",
|
|
(ROOT_AXIS[0], ROOT_AXIS[1], BODY_STANDOFF_Z),
|
|
"z",
|
|
"Body frame datum",
|
|
),
|
|
),
|
|
)
|