614 lines
23 KiB
Python
614 lines
23 KiB
Python
from math import atan2, cos, degrees, radians, sin, tau
|
|
|
|
from build123d import (
|
|
Align,
|
|
Box,
|
|
BuildPart,
|
|
BuildSketch,
|
|
Circle,
|
|
Color,
|
|
Compound,
|
|
Cone,
|
|
Cylinder,
|
|
Edge,
|
|
Location,
|
|
Locations,
|
|
Mode,
|
|
Plane,
|
|
Polygon,
|
|
RectangleRounded,
|
|
add,
|
|
extrude,
|
|
fillet,
|
|
sweep,
|
|
)
|
|
|
|
|
|
# Units: millimeters.
|
|
# Origin: axis 1/base yaw center at X=0, Y=0. XY is the floor/display plane, +Z is up.
|
|
# Static display pose: raised shoulder, bent elbow, compact 3-axis wrist reaching mostly +X.
|
|
|
|
DISPLAY_BASE_LENGTH = 180.0
|
|
DISPLAY_BASE_WIDTH = 140.0
|
|
DISPLAY_BASE_THICKNESS = 12.0
|
|
DISPLAY_BASE_CENTER = (60.0, 0.0, 0.0)
|
|
|
|
FIXED_BASE_DIAMETER = 82.0
|
|
FIXED_BASE_BOTTOM_Z = 12.0
|
|
FIXED_BASE_TOP_Z = 42.0
|
|
|
|
TURNTABLE_DIAMETER = 72.0
|
|
TURNTABLE_BOTTOM_Z = 42.0
|
|
TURNTABLE_TOP_Z = 58.0
|
|
|
|
SHOULDER_CENTER = (0.0, 0.0, 90.0)
|
|
ELBOW_CENTER = (74.0, 0.0, 142.0)
|
|
WRIST_ROLL_CENTER = (154.0, 0.0, 128.0)
|
|
WRIST_PITCH_CENTER = (174.0, 0.0, 128.0)
|
|
TOOL_ROLL_CENTER = (196.0, 0.0, 128.0)
|
|
TOOL_FLANGE_CENTER = (216.0, 0.0, 128.0)
|
|
|
|
MATTE_WHITE = Color(0.91, 0.92, 0.90, 1.0)
|
|
LIGHT_GRAY = Color(0.73, 0.76, 0.76, 1.0)
|
|
DARK_GRAPHITE = Color(0.10, 0.11, 0.12, 1.0)
|
|
DEEP_GRAPHITE = Color(0.045, 0.048, 0.052, 1.0)
|
|
BRUSHED_STEEL = Color(0.74, 0.76, 0.76, 1.0)
|
|
DARK_STEEL = Color(0.24, 0.25, 0.26, 1.0)
|
|
BLUE_ACCENT = Color(0.02, 0.30, 0.82, 1.0)
|
|
ORANGE_ACCENT = Color(1.0, 0.46, 0.10, 1.0)
|
|
MATTE_BLACK = Color(0.005, 0.006, 0.007, 1.0)
|
|
|
|
|
|
def _set_metadata(part, label: str, color: Color):
|
|
part.label = label
|
|
part.color = color
|
|
return part
|
|
|
|
|
|
def _safe_fillet(edges, radius: float) -> None:
|
|
selected = list(edges)
|
|
if not selected:
|
|
return
|
|
try:
|
|
fillet(selected, radius=radius)
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def _axis_rotation(axis: str) -> tuple[float, float, float]:
|
|
if axis == "x":
|
|
return (0.0, 90.0, 0.0)
|
|
if axis == "y":
|
|
return (90.0, 0.0, 0.0)
|
|
return (0.0, 0.0, 0.0)
|
|
|
|
|
|
def _make_axis_cylinder(
|
|
label: str,
|
|
axis: str,
|
|
center: tuple[float, float, float],
|
|
radius: float,
|
|
length: float,
|
|
color: Color,
|
|
fillet_radius: float = 0.0,
|
|
):
|
|
with BuildPart() as cyl:
|
|
Cylinder(
|
|
radius=radius,
|
|
height=length,
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
)
|
|
if fillet_radius > 0.0:
|
|
_safe_fillet(cyl.edges(), fillet_radius)
|
|
part = cyl.part.moved(Location(center, _axis_rotation(axis)))
|
|
return _set_metadata(part, label, color)
|
|
|
|
|
|
def _make_axis_ring(
|
|
label: str,
|
|
axis: str,
|
|
center: tuple[float, float, float],
|
|
outer_radius: float,
|
|
inner_radius: float,
|
|
thickness: float,
|
|
color: Color,
|
|
):
|
|
with BuildPart() as ring:
|
|
Cylinder(
|
|
radius=outer_radius,
|
|
height=thickness,
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
)
|
|
Cylinder(
|
|
radius=inner_radius,
|
|
height=thickness + 0.4,
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
mode=Mode.SUBTRACT,
|
|
)
|
|
_safe_fillet(ring.edges(), 0.25)
|
|
part = ring.part.moved(Location(center, _axis_rotation(axis)))
|
|
return _set_metadata(part, label, color)
|
|
|
|
|
|
def _make_screw_head(
|
|
label: str,
|
|
axis: str,
|
|
center: tuple[float, float, float],
|
|
radius: float,
|
|
height: float,
|
|
color: Color = BRUSHED_STEEL,
|
|
):
|
|
with BuildPart() as screw:
|
|
Cylinder(
|
|
radius=radius,
|
|
height=height,
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
)
|
|
with Locations(Location((0.0, 0.0, height / 2.0 - 0.18))):
|
|
Cylinder(
|
|
radius=radius * 0.43,
|
|
height=0.45,
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
mode=Mode.SUBTRACT,
|
|
)
|
|
_safe_fillet(screw.edges(), min(0.5, radius * 0.22))
|
|
part = screw.part.moved(Location(center, _axis_rotation(axis)))
|
|
return _set_metadata(part, label, color)
|
|
|
|
|
|
def _make_rounded_box(
|
|
label: str,
|
|
size: tuple[float, float, float],
|
|
center: tuple[float, float, float],
|
|
radius: float,
|
|
color: Color,
|
|
rotation: tuple[float, float, float] = (0.0, 0.0, 0.0),
|
|
):
|
|
with BuildPart() as box:
|
|
Box(*size, align=(Align.CENTER, Align.CENTER, Align.CENTER))
|
|
if radius > 0.0:
|
|
_safe_fillet(box.edges(), radius)
|
|
part = box.part.moved(Location(center, rotation))
|
|
return _set_metadata(part, label, color)
|
|
|
|
|
|
def _rounded_plate_profile_points(
|
|
x_min: float,
|
|
x_max: float,
|
|
z_min: float,
|
|
z_max: float,
|
|
radius: float,
|
|
steps: int = 8,
|
|
) -> list[tuple[float, float]]:
|
|
points: list[tuple[float, float]] = []
|
|
centers = (
|
|
(x_max - radius, z_min + radius, -90.0, 0.0),
|
|
(x_max - radius, z_max - radius, 0.0, 90.0),
|
|
(x_min + radius, z_max - radius, 90.0, 180.0),
|
|
(x_min + radius, z_min + radius, 180.0, 270.0),
|
|
)
|
|
for cx, cz, start, end in centers:
|
|
for step in range(steps + 1):
|
|
angle = radians(start + (end - start) * step / steps)
|
|
points.append((cx + radius * cos(angle), cz + radius * sin(angle)))
|
|
return points
|
|
|
|
|
|
def _outer_rect_edges(part, length: float, width: float, z_min: float, z_max: float, tol: float = 0.08):
|
|
edges = []
|
|
for edge in part.edges():
|
|
bbox = edge.bounding_box()
|
|
center = bbox.center()
|
|
on_outer_x = abs(abs(center.X) - length / 2.0) <= tol
|
|
on_outer_y = abs(abs(center.Y) - width / 2.0) <= tol
|
|
on_top_or_bottom = abs(center.Z - z_min) <= tol or abs(center.Z - z_max) <= tol
|
|
if (on_outer_x or on_outer_y) and on_top_or_bottom:
|
|
edges.append(edge)
|
|
return edges
|
|
|
|
|
|
def _make_display_base():
|
|
with BuildPart() as base:
|
|
with BuildSketch(Plane.XY):
|
|
RectangleRounded(
|
|
DISPLAY_BASE_LENGTH,
|
|
DISPLAY_BASE_WIDTH,
|
|
8.0,
|
|
align=(Align.CENTER, Align.CENTER),
|
|
)
|
|
extrude(amount=DISPLAY_BASE_THICKNESS)
|
|
|
|
for x_abs in (-20.0, 120.0):
|
|
for y_pos in (-50.0, 50.0):
|
|
x_pos = x_abs - DISPLAY_BASE_CENTER[0]
|
|
with Locations(Location((x_pos, y_pos, -0.6))):
|
|
Cylinder(
|
|
radius=3.0,
|
|
height=DISPLAY_BASE_THICKNESS + 1.2,
|
|
align=(Align.CENTER, Align.CENTER, Align.MIN),
|
|
mode=Mode.SUBTRACT,
|
|
)
|
|
with Locations(Location((x_pos, y_pos, DISPLAY_BASE_THICKNESS - 3.2))):
|
|
Cone(
|
|
bottom_radius=3.0,
|
|
top_radius=6.0,
|
|
height=3.4,
|
|
align=(Align.CENTER, Align.CENTER, Align.MIN),
|
|
mode=Mode.SUBTRACT,
|
|
)
|
|
|
|
_safe_fillet(
|
|
_outer_rect_edges(base.part, DISPLAY_BASE_LENGTH, DISPLAY_BASE_WIDTH, 0.0, DISPLAY_BASE_THICKNESS),
|
|
3.0,
|
|
)
|
|
|
|
part = base.part.moved(Location(DISPLAY_BASE_CENTER))
|
|
return _set_metadata(part, "rounded_rectangular_display_base_180x140x12_with_four_countersunk_holes", DARK_GRAPHITE)
|
|
|
|
|
|
def _make_fixed_base():
|
|
return _make_axis_cylinder(
|
|
"fixed_cylindrical_base_axis1_od82_z12_to_z42",
|
|
"z",
|
|
(0.0, 0.0, (FIXED_BASE_BOTTOM_Z + FIXED_BASE_TOP_Z) / 2.0),
|
|
FIXED_BASE_DIAMETER / 2.0,
|
|
FIXED_BASE_TOP_Z - FIXED_BASE_BOTTOM_Z,
|
|
LIGHT_GRAY,
|
|
fillet_radius=2.0,
|
|
)
|
|
|
|
|
|
def _make_turntable():
|
|
return _make_axis_cylinder(
|
|
"rotating_base_turntable_axis1_od72_z42_to_z58",
|
|
"z",
|
|
(0.0, 0.0, (TURNTABLE_BOTTOM_Z + TURNTABLE_TOP_Z) / 2.0),
|
|
TURNTABLE_DIAMETER / 2.0,
|
|
TURNTABLE_TOP_Z - TURNTABLE_BOTTOM_Z,
|
|
DARK_GRAPHITE,
|
|
fillet_radius=1.5,
|
|
)
|
|
|
|
|
|
def _make_pedestal():
|
|
with BuildPart() as pedestal:
|
|
with BuildSketch(Plane.XY):
|
|
RectangleRounded(46.0, 58.0, 7.0, align=(Align.CENTER, Align.CENTER))
|
|
extrude(amount=43.0)
|
|
_safe_fillet(pedestal.edges(), 2.5)
|
|
part = pedestal.part.moved(Location((0.0, 0.0, 47.0)))
|
|
return _set_metadata(part, "rounded_shoulder_pedestal_46x58x43_to_axis2_center", MATTE_WHITE)
|
|
|
|
|
|
def _make_shoulder_lug(label: str, y_center: float):
|
|
with BuildPart() as lug:
|
|
with Locations(Location((3.0, y_center, 73.5))):
|
|
Box(34.0, 12.0, 37.0, align=(Align.CENTER, Align.CENTER, Align.CENTER))
|
|
with Locations(Location((0.0, y_center, 90.0))):
|
|
Cylinder(
|
|
radius=22.0,
|
|
height=12.0,
|
|
rotation=(90.0, 0.0, 0.0),
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
)
|
|
Cylinder(
|
|
radius=13.0,
|
|
height=14.0,
|
|
rotation=(90.0, 0.0, 0.0),
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
mode=Mode.SUBTRACT,
|
|
)
|
|
_safe_fillet(lug.edges(), 1.6)
|
|
return _set_metadata(lug.part, label, MATTE_WHITE)
|
|
|
|
|
|
def _make_upper_arm_link(label: str, y_center: float):
|
|
shoulder = SHOULDER_CENTER
|
|
elbow = ELBOW_CENTER
|
|
dx = elbow[0] - shoulder[0]
|
|
dz = elbow[2] - shoulder[2]
|
|
link_length = (dx * dx + dz * dz) ** 0.5 + 8.0
|
|
link_angle = -degrees(atan2(dz, dx))
|
|
mid = ((shoulder[0] + elbow[0]) / 2.0, y_center, (shoulder[2] + elbow[2]) / 2.0)
|
|
|
|
with BuildPart() as link:
|
|
with BuildSketch(Plane.XZ.offset(-5.0)):
|
|
RectangleRounded(link_length, 18.0, 8.0, align=(Align.CENTER, Align.CENTER))
|
|
extrude(amount=10.0)
|
|
|
|
with BuildSketch(Plane.XZ.offset(-6.2)):
|
|
RectangleRounded(56.0, 7.4, 3.5, align=(Align.CENTER, Align.CENTER))
|
|
extrude(amount=12.4, mode=Mode.SUBTRACT)
|
|
_safe_fillet(link.edges(), 1.5)
|
|
|
|
part = link.part.moved(Location(mid, (0.0, link_angle, 0.0)))
|
|
return _set_metadata(part, label, MATTE_WHITE)
|
|
|
|
|
|
def _make_forearm_housing():
|
|
elbow = ELBOW_CENTER
|
|
wrist = WRIST_ROLL_CENTER
|
|
dx = wrist[0] - elbow[0]
|
|
dz = wrist[2] - elbow[2]
|
|
length = (dx * dx + dz * dz) ** 0.5
|
|
angle = -degrees(atan2(dz, dx))
|
|
center = ((elbow[0] + wrist[0]) / 2.0, 0.0, (elbow[2] + wrist[2]) / 2.0)
|
|
|
|
with BuildPart() as forearm:
|
|
Cone(
|
|
bottom_radius=16.0,
|
|
top_radius=12.0,
|
|
height=length,
|
|
rotation=(0.0, 90.0, 0.0),
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
)
|
|
_safe_fillet(forearm.edges(), 1.6)
|
|
|
|
part = forearm.part.moved(Location(center, (0.0, angle, 0.0)))
|
|
return _set_metadata(part, "tapered_rounded_forearm_housing_elbow_to_wrist_axis4", MATTE_WHITE)
|
|
|
|
|
|
def _make_forearm_panel(label: str, side: float):
|
|
elbow = ELBOW_CENTER
|
|
wrist = WRIST_ROLL_CENTER
|
|
dx = wrist[0] - elbow[0]
|
|
dz = wrist[2] - elbow[2]
|
|
angle = -degrees(atan2(dz, dx))
|
|
center = ((elbow[0] + wrist[0]) / 2.0, 0.0, (elbow[2] + wrist[2]) / 2.0)
|
|
|
|
with BuildPart() as panel:
|
|
with Locations(Location((6.0, side * 15.3, 0.0))):
|
|
Box(50.0, 1.2, 10.0, align=(Align.CENTER, Align.CENTER, Align.CENTER))
|
|
_safe_fillet(panel.edges(), 0.7)
|
|
|
|
part = panel.part.moved(Location(center, (0.0, angle, 0.0)))
|
|
return _set_metadata(part, label, DEEP_GRAPHITE)
|
|
|
|
|
|
def _rotated_y_point(
|
|
local: tuple[float, float, float],
|
|
center: tuple[float, float, float],
|
|
angle_deg: float,
|
|
) -> tuple[float, float, float]:
|
|
angle = radians(angle_deg)
|
|
x_pos = center[0] + local[0] * cos(angle) + local[2] * sin(angle)
|
|
y_pos = center[1] + local[1]
|
|
z_pos = center[2] - local[0] * sin(angle) + local[2] * cos(angle)
|
|
return (x_pos, y_pos, z_pos)
|
|
|
|
|
|
def _forearm_panel_screws(parts: list):
|
|
elbow = ELBOW_CENTER
|
|
wrist = WRIST_ROLL_CENTER
|
|
dx = wrist[0] - elbow[0]
|
|
dz = wrist[2] - elbow[2]
|
|
angle = -degrees(atan2(dz, dx))
|
|
center = ((elbow[0] + wrist[0]) / 2.0, 0.0, (elbow[2] + wrist[2]) / 2.0)
|
|
for side_name, side in (("positive_y", 1.0), ("negative_y", -1.0)):
|
|
for index, local_x in enumerate((-16.0, 25.0), start=1):
|
|
screw_center = _rotated_y_point((local_x, side * 16.1, 0.0), center, angle)
|
|
parts.append(
|
|
_make_screw_head(
|
|
f"forearm_recessed_panel_{side_name}_socket_screw_{index}",
|
|
"y",
|
|
screw_center,
|
|
1.55,
|
|
1.0,
|
|
)
|
|
)
|
|
|
|
|
|
def _add_circular_screws(
|
|
parts: list,
|
|
prefix: str,
|
|
axis: str,
|
|
axis_center: tuple[float, float, float],
|
|
face_coordinates: tuple[float, ...],
|
|
bolt_circle_radius: float,
|
|
count: int,
|
|
screw_radius: float,
|
|
screw_height: float,
|
|
start_angle: float = 0.0,
|
|
):
|
|
for face_index, face_coord in enumerate(face_coordinates, start=1):
|
|
for index in range(count):
|
|
angle = start_angle + tau * index / count
|
|
if axis == "z":
|
|
center = (
|
|
axis_center[0] + bolt_circle_radius * cos(angle),
|
|
axis_center[1] + bolt_circle_radius * sin(angle),
|
|
face_coord,
|
|
)
|
|
elif axis == "y":
|
|
center = (
|
|
axis_center[0] + bolt_circle_radius * cos(angle),
|
|
face_coord,
|
|
axis_center[2] + bolt_circle_radius * sin(angle),
|
|
)
|
|
else:
|
|
center = (
|
|
face_coord,
|
|
axis_center[1] + bolt_circle_radius * cos(angle),
|
|
axis_center[2] + bolt_circle_radius * sin(angle),
|
|
)
|
|
parts.append(
|
|
_make_screw_head(
|
|
f"{prefix}_face_{face_index}_socket_head_screw_{index + 1:02d}",
|
|
axis,
|
|
center,
|
|
screw_radius,
|
|
screw_height,
|
|
)
|
|
)
|
|
|
|
|
|
def _make_wrist_yoke_lug(label: str, y_center: float):
|
|
with BuildPart() as lug:
|
|
with Locations(Location((164.5, y_center, 128.0))):
|
|
Box(25.0, 7.0, 17.0, align=(Align.CENTER, Align.CENTER, Align.CENTER))
|
|
with Locations(Location((174.0, y_center, 128.0))):
|
|
Cylinder(
|
|
radius=14.5,
|
|
height=7.0,
|
|
rotation=(90.0, 0.0, 0.0),
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
)
|
|
Cylinder(
|
|
radius=8.0,
|
|
height=8.0,
|
|
rotation=(90.0, 0.0, 0.0),
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
mode=Mode.SUBTRACT,
|
|
)
|
|
_safe_fillet(lug.edges(), 1.0)
|
|
return _set_metadata(lug.part, label, MATTE_WHITE)
|
|
|
|
|
|
def _make_tool_flange():
|
|
with BuildPart() as flange:
|
|
Cylinder(
|
|
radius=19.0,
|
|
height=7.0,
|
|
rotation=(0.0, 90.0, 0.0),
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
)
|
|
Cylinder(
|
|
radius=5.0,
|
|
height=9.0,
|
|
rotation=(0.0, 90.0, 0.0),
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
mode=Mode.SUBTRACT,
|
|
)
|
|
for index in range(6):
|
|
angle = tau * index / 6.0
|
|
y_pos = 14.0 * cos(angle)
|
|
z_pos = 14.0 * sin(angle)
|
|
with Locations(Location((0.0, y_pos, z_pos))):
|
|
Cylinder(
|
|
radius=2.0,
|
|
height=9.0,
|
|
rotation=(0.0, 90.0, 0.0),
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
mode=Mode.SUBTRACT,
|
|
)
|
|
_safe_fillet(flange.edges(), 0.6)
|
|
part = flange.part.moved(Location(TOOL_FLANGE_CENTER))
|
|
return _set_metadata(part, "standard_tool_flange_axis6_od38_thick7_with_10mm_bore_and_6x4mm_holes", BRUSHED_STEEL)
|
|
|
|
|
|
def _make_cable_guide():
|
|
points = [
|
|
(-15.0, -31.0, 94.0),
|
|
(8.0, -31.0, 101.0),
|
|
(36.0, -30.0, 119.0),
|
|
(66.0, -28.0, 139.0),
|
|
(78.0, -27.0, 148.0),
|
|
(104.0, -28.0, 142.0),
|
|
(134.0, -27.0, 135.0),
|
|
(155.0, -22.0, 132.0),
|
|
(174.0, -18.0, 130.0),
|
|
]
|
|
path = Edge.make_spline(points)
|
|
tangent = (
|
|
points[1][0] - points[0][0],
|
|
points[1][1] - points[0][1],
|
|
points[1][2] - points[0][2],
|
|
)
|
|
profile_plane = Plane(origin=points[0], x_dir=(0.0, 1.0, 0.0), z_dir=tangent)
|
|
|
|
with BuildPart() as cable:
|
|
with BuildSketch(profile_plane):
|
|
Circle(2.0)
|
|
sweep(path=path, is_frenet=True)
|
|
_safe_fillet(cable.edges(), 0.2)
|
|
return _set_metadata(cable.part, "matte_black_external_cable_guide_4mm_swept_tube_shoulder_to_wrist", MATTE_BLACK)
|
|
|
|
|
|
def _make_cable_clamp(label: str, center: tuple[float, float, float], angle_y: float):
|
|
with BuildPart() as clamp:
|
|
Box(12.0, 6.0, 5.0, align=(Align.CENTER, Align.CENTER, Align.CENTER))
|
|
Cylinder(
|
|
radius=2.2,
|
|
height=14.0,
|
|
rotation=(90.0, 0.0, 0.0),
|
|
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
|
mode=Mode.SUBTRACT,
|
|
)
|
|
_safe_fillet(clamp.edges(), 0.6)
|
|
part = clamp.part.moved(Location(center, (0.0, angle_y, 0.0)))
|
|
return _set_metadata(part, label, DARK_STEEL)
|
|
|
|
|
|
def _make_axis_label_ring_set(parts: list):
|
|
parts.append(_make_axis_ring("blue_accent_ring_axis1_base_yaw_vertical_z", "z", (0.0, 0.0, 58.9), 38.0, 35.4, 1.6, BLUE_ACCENT))
|
|
parts.append(_make_axis_ring("orange_accent_ring_axis2_shoulder_pitch_y_left", "y", (0.0, -37.1, 90.0), 25.0, 22.0, 1.8, ORANGE_ACCENT))
|
|
parts.append(_make_axis_ring("orange_accent_ring_axis2_shoulder_pitch_y_right", "y", (0.0, 37.1, 90.0), 25.0, 22.0, 1.8, ORANGE_ACCENT))
|
|
parts.append(_make_axis_ring("blue_accent_ring_axis3_elbow_pitch_y_left", "y", (74.0, -34.6, 142.0), 24.0, 21.0, 1.8, BLUE_ACCENT))
|
|
parts.append(_make_axis_ring("blue_accent_ring_axis3_elbow_pitch_y_right", "y", (74.0, 34.6, 142.0), 24.0, 21.0, 1.8, BLUE_ACCENT))
|
|
parts.append(_make_axis_ring("orange_accent_ring_axis4_wrist_roll_x", "x", (154.0, 0.0, 128.0), 17.0, 15.0, 2.0, ORANGE_ACCENT))
|
|
parts.append(_make_axis_ring("blue_accent_ring_axis5_wrist_pitch_y", "y", (174.0, 0.0, 128.0), 16.0, 14.0, 2.0, BLUE_ACCENT))
|
|
parts.append(_make_axis_ring("orange_accent_ring_axis6_tool_roll_x", "x", (196.0, 0.0, 128.0), 14.0, 12.0, 2.0, ORANGE_ACCENT))
|
|
|
|
|
|
def gen_step():
|
|
"""Return a labeled six-axis industrial robot arm display assembly in millimeters."""
|
|
parts = [
|
|
_make_display_base(),
|
|
_make_fixed_base(),
|
|
_make_turntable(),
|
|
_make_axis_ring("dark_circular_seam_between_fixed_base_and_turntable_axis1", "z", (0.0, 0.0, 42.2), 41.4, 36.0, 0.8, DEEP_GRAPHITE),
|
|
_make_pedestal(),
|
|
_make_shoulder_lug("shoulder_yoke_negative_y_lug_with_axis2_bore", -24.0),
|
|
_make_shoulder_lug("shoulder_yoke_positive_y_lug_with_axis2_bore", 24.0),
|
|
_make_axis_cylinder("dark_graphite_shoulder_motor_housing_axis2_od44_length72", "y", SHOULDER_CENTER, 22.0, 72.0, DARK_GRAPHITE, 1.6),
|
|
_make_axis_cylinder("left_shoulder_raised_joint_cap_od48_thick3", "y", (0.0, -37.5, 90.0), 24.0, 3.0, LIGHT_GRAY, 0.6),
|
|
_make_axis_cylinder("right_shoulder_raised_joint_cap_od48_thick3", "y", (0.0, 37.5, 90.0), 24.0, 3.0, LIGHT_GRAY, 0.6),
|
|
_make_upper_arm_link("upper_arm_negative_y_rounded_side_link_with_oval_lightening_cutout", -18.0),
|
|
_make_upper_arm_link("upper_arm_positive_y_rounded_side_link_with_oval_lightening_cutout", 18.0),
|
|
_make_axis_cylinder("dark_graphite_elbow_joint_housing_axis3_od42_length66", "y", ELBOW_CENTER, 21.0, 66.0, DARK_GRAPHITE, 1.8),
|
|
_make_axis_cylinder("negative_y_elbow_raised_joint_cap_od46_thick3", "y", (74.0, -34.5, 142.0), 23.0, 3.0, LIGHT_GRAY, 0.6),
|
|
_make_axis_cylinder("positive_y_elbow_raised_joint_cap_od46_thick3", "y", (74.0, 34.5, 142.0), 23.0, 3.0, LIGHT_GRAY, 0.6),
|
|
_make_forearm_housing(),
|
|
_make_forearm_panel("negative_y_dark_recessed_side_panel_on_tapered_forearm", -1.0),
|
|
_make_forearm_panel("positive_y_dark_recessed_side_panel_on_tapered_forearm", 1.0),
|
|
_make_axis_cylinder("dark_graphite_wrist_roll_housing_axis4_od30_length28", "x", WRIST_ROLL_CENTER, 15.0, 28.0, DARK_GRAPHITE, 1.1),
|
|
_make_wrist_yoke_lug("wrist_pitch_fork_negative_y_lug_axis5", -20.0),
|
|
_make_wrist_yoke_lug("wrist_pitch_fork_positive_y_lug_axis5", 20.0),
|
|
_make_axis_cylinder("dark_graphite_wrist_pitch_joint_axis5_od28_length46", "y", WRIST_PITCH_CENTER, 14.0, 46.0, DARK_GRAPHITE, 1.0),
|
|
_make_axis_cylinder("negative_y_wrist_pitch_cap_od31_thick2", "y", (174.0, -24.0, 128.0), 15.5, 2.0, LIGHT_GRAY, 0.4),
|
|
_make_axis_cylinder("positive_y_wrist_pitch_cap_od31_thick2", "y", (174.0, 24.0, 128.0), 15.5, 2.0, LIGHT_GRAY, 0.4),
|
|
_make_axis_cylinder("dark_graphite_final_wrist_tool_roll_cylinder_axis6_od24_length30", "x", TOOL_ROLL_CENTER, 12.0, 30.0, DARK_GRAPHITE, 0.9),
|
|
_make_axis_cylinder("short_steel_tool_flange_pilot_hub_axis6_od18_length5", "x", (211.0, 0.0, 128.0), 9.0, 5.0, BRUSHED_STEEL, 0.4),
|
|
_make_tool_flange(),
|
|
_make_cable_guide(),
|
|
]
|
|
|
|
_make_axis_label_ring_set(parts)
|
|
|
|
_add_circular_screws(parts, "turntable_top_bolt_circle_58mm", "z", (0.0, 0.0, 0.0), (59.0,), 29.0, 8, 2.1, 1.7, start_angle=tau / 16.0)
|
|
_add_circular_screws(parts, "shoulder_axis2_joint_cap", "y", SHOULDER_CENTER, (-39.0, 39.0), 17.0, 6, 1.6, 1.1, start_angle=tau / 12.0)
|
|
_add_circular_screws(parts, "elbow_axis3_joint_cap", "y", ELBOW_CENTER, (-36.0, 36.0), 16.0, 6, 1.55, 1.1, start_angle=tau / 12.0)
|
|
_add_circular_screws(parts, "wrist_pitch_axis5_cap", "y", WRIST_PITCH_CENTER, (-25.2, 25.2), 10.5, 4, 1.25, 0.9, start_angle=tau / 8.0)
|
|
_add_circular_screws(parts, "wrist_roll_axis4_cap", "x", WRIST_ROLL_CENTER, (139.2, 168.8), 10.5, 4, 1.25, 0.9, start_angle=tau / 8.0)
|
|
_add_circular_screws(parts, "tool_flange_visible_fastener_circle", "x", TOOL_FLANGE_CENTER, (220.0,), 14.0, 6, 1.35, 0.8, start_angle=tau / 12.0)
|
|
_forearm_panel_screws(parts)
|
|
|
|
upper_angle = -degrees(atan2(ELBOW_CENTER[2] - SHOULDER_CENTER[2], ELBOW_CENTER[0] - SHOULDER_CENTER[0]))
|
|
forearm_angle = -degrees(atan2(WRIST_ROLL_CENTER[2] - ELBOW_CENTER[2], WRIST_ROLL_CENTER[0] - ELBOW_CENTER[0]))
|
|
parts.extend(
|
|
[
|
|
_make_cable_clamp("shoulder_cable_saddle_clamp_attached_to_rear_yoke", (-8.0, -29.5, 97.0), 0.0),
|
|
_make_cable_clamp("upper_arm_cable_saddle_clamp_following_raised_link", (39.0, -29.5, 121.0), upper_angle),
|
|
_make_cable_clamp("elbow_cable_saddle_clamp_at_cross_over", (78.0, -27.5, 148.0), 0.0),
|
|
_make_cable_clamp("forearm_cable_saddle_clamp_on_tapered_cover", (131.0, -27.5, 136.0), forearm_angle),
|
|
_make_cable_clamp("wrist_cable_saddle_clamp_near_axis4", (158.0, -21.5, 132.0), 0.0),
|
|
]
|
|
)
|
|
|
|
assembly = Compound(
|
|
obj=parts,
|
|
children=parts,
|
|
label="six_axis_industrial_robot_arm_static_display_pose",
|
|
)
|
|
return assembly
|