SPEC = {
"project": "RUBISCO2",
"assembly": "TEST RIG · sand-separator calibration cradle",
"units": "mm",
"axes": {
"+X": "long rig axis, 1200 mm nominal",
"+Y": "short rig axis, 720 mm base frame / 800 mm top plate nominal",
"+Z": "vertical",
},
"origin": "center of base-frame footprint at floor level",
"output": {
"glb": "RUBISCO2_TEST_RIG_complete_assembly.glb",
"stl": None,
"note": "STL export intentionally skipped.",
},
"materials": {
"PTR / A36 steel": {"color": "medium grey"},
"sheet metal": {"color": "light grey"},
"stainless reference plate": {"color": "silver"},
"motor mount steel": {"color": "dark steel"},
},
"parts": [
{
"part_no": "PRT-90001",
"name": "Test plate (small)",
"qty": 1,
"bbox_mm": [1200, 800, 3],
"placement": "flat on top of base frame, centered on rig",
},
{
"part_no": "PRT-90002",
"name": "Rig leg",
"qty": 4,
"bbox_mm": [40, 40, 677],
"placement": "one vertical leg under each base-frame corner",
},
{
"part_no": "PRT-90003",
"name": "Rig side wall",
"qty": 2,
"bbox_mm": [1200, 2, 200],
"placement": "long enclosure panels at +Y and -Y edges of top plate",
},
{
"part_no": "PRT-90004",
"name": "Rig back wall",
"qty": 2,
"bbox_mm": [2, 800, 200],
"placement": "short enclosure panels at +X and -X edges of top plate",
},
{
"part_no": "PRT-90005",
"name": "Frame long rail",
"qty": 2,
"bbox_mm": [1200, 40, 40],
"placement": "base-frame longitudinal rails at +Y and -Y",
},
{
"part_no": "PRT-90006",
"name": "Frame short rail",
"qty": 2,
"bbox_mm": [40, 720, 40],
"placement": "base-frame cross rails at +X and -X",
},
{
"part_no": "PRT-90007",
"name": "Motor mount",
"qty": 1,
"bbox_mm": [200, 400, 5],
"placement": "vertical accessory plate mounted outboard of +X end wall",
},
{
"part_no": "PRT-90011",
"name": "Sand tray",
"qty": 1,
"bbox_mm": [600, 400, 350],
"placement": "removable catch tray centered below the test plate",
},
{
"part_no": "PRT-90016",
"name": "VFD box",
"qty": 1,
"bbox_mm": [100, 140, 140],
"placement": "small enclosure stub mounted outboard of +Y side wall",
},
{
"part_no": "PRT-90017",
"name": "Jack handle",
"qty": 1,
"bbox_mm": [12, 150, 12],
"placement": "loose T-handle accessory parked near the -X side of the rig",
},
],
"assembly_children": [
"FRAME · PRT-90005 long rail 1/2 · PTR 40×40 weldment",
"FRAME · PRT-90005 long rail 2/2 · PTR 40×40 weldment",
"FRAME · PRT-90006 short rail 1/2 · PTR 40×40 weldment",
"FRAME · PRT-90006 short rail 2/2 · PTR 40×40 weldment",
"LEGS · PRT-90002 rig leg 1/4 · PTR vertical",
"LEGS · PRT-90002 rig leg 2/4 · PTR vertical",
"LEGS · PRT-90002 rig leg 3/4 · PTR vertical",
"LEGS · PRT-90002 rig leg 4/4 · PTR vertical",
"ENCLOSURE · PRT-90003 side wall 1/2 · sheet panel",
"ENCLOSURE · PRT-90003 side wall 2/2 · sheet panel",
"ENCLOSURE · PRT-90004 back wall 1/2 · sheet panel",
"ENCLOSURE · PRT-90004 back wall 2/2 · sheet panel",
"REFERENCE · PRT-90001 test plate · stainless calibration surface",
"DRIVE · PRT-90007 motor mount · drilled steel plate",
"COLLECTION · PRT-90011 sand tray · removable sheet-metal catch tray",
"ELECTRICAL · PRT-90016 VFD box · enclosure stub",
"ADJUSTMENT · PRT-90017 jack handle · screw-jack T-handle",
],
}
import cadquery as cq
OUTFILE = "RUBISCO2_TEST_RIG_complete_assembly.glb"
# ---------------------------------------------------------------------------
# Solid helpers
# CadQuery 2.7.0 idiom: build from cq.Solid.makeXxx().moved(cq.Location(...)).
# No Workplane.add().translate() usage.
# ---------------------------------------------------------------------------
def box_corner(dx, dy, dz, xmin, ymin, zmin):
return cq.Solid.makeBox(dx, dy, dz).moved(
cq.Location(cq.Vector(xmin, ymin, zmin))
)
def centered_box(dx, dy, dz):
return cq.Solid.makeBox(dx, dy, dz).moved(
cq.Location(cq.Vector(-dx / 2.0, -dy / 2.0, -dz / 2.0))
)
def cyl_z(radius, height, x, y, zmin):
return cq.Solid.makeCylinder(
radius,
height,
pnt=cq.Vector(x, y, zmin),
dir=cq.Vector(0, 0, 1),
)
def make_motor_mount_plate():
plate = centered_box(200, 400, 5)
# Simple through-hole representation for the gearmotor bolt pattern.
holes = [
cyl_z(8, 12, -60, -120, -6),
cyl_z(8, 12, 60, -120, -6),
cyl_z(8, 12, -60, 120, -6),
cyl_z(8, 12, 60, 120, -6),
cyl_z(25, 12, 0, 0, -6),
]
for h in holes:
plate = plate.cut(h)
return plate
def make_sand_tray():
# Open-top catch tray. Overall bounding box remains 600 × 400 × 350 mm.
base = box_corner(600, 400, 20, -300, -200, 0)
wall_y_neg = box_corner(600, 20, 350, -300, -200, 0)
wall_y_pos = box_corner(600, 20, 350, -300, 180, 0)
wall_x_neg = box_corner(20, 400, 350, -300, -200, 0)
wall_x_pos = box_corner(20, 400, 350, 280, -200, 0)
tray = base.fuse(wall_y_neg)
tray = tray.fuse(wall_y_pos)
tray = tray.fuse(wall_x_neg)
tray = tray.fuse(wall_x_pos)
return tray
# ---------------------------------------------------------------------------
# Part geometry library, local part coordinates
# ---------------------------------------------------------------------------
PRT_90001_test_plate = centered_box(1200, 800, 3)
PRT_90002_leg = centered_box(40, 40, 677)
PRT_90003_side_wall = centered_box(1200, 2, 200)
PRT_90004_back_wall = centered_box(2, 800, 200)
PRT_90005_long_rail = centered_box(1200, 40, 40)
PRT_90006_short_rail = centered_box(40, 720, 40)
PRT_90007_motor_mount = make_motor_mount_plate()
PRT_90011_sand_tray = make_sand_tray()
PRT_90016_vfd_box = centered_box(100, 140, 140)
PRT_90017_jack_handle = centered_box(12, 150, 12)
# ---------------------------------------------------------------------------
# Colors
# ---------------------------------------------------------------------------
COLOR_PTR_STEEL = cq.Color(0.45, 0.47, 0.48, 1.0)
COLOR_SHEET_METAL = cq.Color(0.72, 0.74, 0.75, 1.0)
COLOR_STAINLESS = cq.Color(0.82, 0.84, 0.82, 1.0)
COLOR_DARK_STEEL = cq.Color(0.25, 0.27, 0.28, 1.0)
COLOR_ELECTRICAL = cq.Color(0.18, 0.22, 0.24, 1.0)
COLOR_HANDLE = cq.Color(0.34, 0.34, 0.32, 1.0)
# ---------------------------------------------------------------------------
# Assembly
# Coordinate convention:
# X = 1200 mm long axis
# Y = short axis
# Z = vertical
# Origin is centered on the frame footprint at floor level.
# ---------------------------------------------------------------------------
def loc(x, y, z):
return cq.Location(cq.Vector(x, y, z))
def build_assembly():
assy = cq.Assembly(
name="RUBISCO2 · TEST RIG · complete calibration cradle assembly"
)
# Base-frame rail elevations:
# legs run from z=0 to z=677;
# 40 mm PTR frame sits above legs, from z=677 to z=717.
rail_z = 697
leg_z = 677 / 2.0
# Long rails: 1200 × 40 × 40, at the long sides of 1200 × 720 footprint.
assy.add(
PRT_90005_long_rail,
name="FRAME · PRT-90005 long rail 1/2 · PTR 40×40 weldment",
loc=loc(0, -340, rail_z),
color=COLOR_PTR_STEEL,
)
assy.add(
PRT_90005_long_rail,
name="FRAME · PRT-90005 long rail 2/2 · PTR 40×40 weldment",
loc=loc(0, 340, rail_z),
color=COLOR_PTR_STEEL,
)
# Short rails: 40 × 720 × 40, closing the rectangular cradle.
assy.add(
PRT_90006_short_rail,
name="FRAME · PRT-90006 short rail 1/2 · PTR 40×40 weldment",
loc=loc(-580, 0, rail_z),
color=COLOR_PTR_STEEL,
)
assy.add(
PRT_90006_short_rail,
name="FRAME · PRT-90006 short rail 2/2 · PTR 40×40 weldment",
loc=loc(580, 0, rail_z),
color=COLOR_PTR_STEEL,
)
# Four vertical legs at the frame corners.
assy.add(
PRT_90002_leg,
name="LEGS · PRT-90002 rig leg 1/4 · PTR vertical",
loc=loc(-580, -340, leg_z),
color=COLOR_PTR_STEEL,
)
assy.add(
PRT_90002_leg,
name="LEGS · PRT-90002 rig leg 2/4 · PTR vertical",
loc=loc(580, -340, leg_z),
color=COLOR_PTR_STEEL,
)
assy.add(
PRT_90002_leg,
name="LEGS · PRT-90002 rig leg 3/4 · PTR vertical",
loc=loc(-580, 340, leg_z),
color=COLOR_PTR_STEEL,
)
assy.add(
PRT_90002_leg,
name="LEGS · PRT-90002 rig leg 4/4 · PTR vertical",
loc=loc(580, 340, leg_z),
color=COLOR_PTR_STEEL,
)
# Reference test plate: 1200 × 800 × 3, sitting on top of the base frame.
assy.add(
PRT_90001_test_plate,
name="REFERENCE · PRT-90001 test plate · stainless calibration surface",
loc=loc(0, 0, 718.5),
color=COLOR_STAINLESS,
)
# Sheet-metal enclosure walls, standing on the reference/top plane.
# Side panels use 2 mm thickness and are placed at the +/-Y edges.
assy.add(
PRT_90003_side_wall,
name="ENCLOSURE · PRT-90003 side wall 1/2 · sheet panel",
loc=loc(0, -399, 820),
color=COLOR_SHEET_METAL,
)
assy.add(
PRT_90003_side_wall,
name="ENCLOSURE · PRT-90003 side wall 2/2 · sheet panel",
loc=loc(0, 399, 820),
color=COLOR_SHEET_METAL,
)
# End/back panels close the 1200 × 800 upper cradle footprint.
assy.add(
PRT_90004_back_wall,
name="ENCLOSURE · PRT-90004 back wall 1/2 · sheet panel",
loc=loc(-599, 0, 820),
color=COLOR_SHEET_METAL,
)
assy.add(
PRT_90004_back_wall,
name="ENCLOSURE · PRT-90004 back wall 2/2 · sheet panel",
loc=loc(599, 0, 820),
color=COLOR_SHEET_METAL,
)
# Motor mount accessory:
# local catalog part is 200 × 400 × 5; rotate it vertical so the 5 mm
# thickness projects outboard along +X.
motor_mount_loc = cq.Location(
cq.Vector(625, 0, 820),
cq.Vector(0, 1, 0),
90,
)
assy.add(
PRT_90007_motor_mount,
name="DRIVE · PRT-90007 motor mount · drilled steel plate",
loc=motor_mount_loc,
color=COLOR_DARK_STEEL,
)
# Sand collection tray below the test area. Geometry is authored in
# floor-referenced local coordinates, so it is added at identity location.
assy.add(
PRT_90011_sand_tray,
name="COLLECTION · PRT-90011 sand tray · removable sheet-metal catch tray",
loc=loc(0, 0, 0),
color=COLOR_SHEET_METAL,
)
# VFD enclosure stub mounted outside the +Y side wall.
assy.add(
PRT_90016_vfd_box,
name="ELECTRICAL · PRT-90016 VFD box · enclosure stub",
loc=loc(-450, 471, 805),
color=COLOR_ELECTRICAL,
)
# Screw-jack handle parked near the -X side as a loose adjustment accessory.
assy.add(
PRT_90017_jack_handle,
name="ADJUSTMENT · PRT-90017 jack handle · screw-jack T-handle",
loc=loc(-660, -285, 735),
color=COLOR_HANDLE,
)
return assy
assembly = build_assembly()
result = assembly
assembly.save(OUTFILE)