from cadquery import exporters from cq_warehouse.extensions import Workplane from cq_warehouse.fastener import * from cq_warehouse.thread import * from cqmore.curve import archimedeanSpiral, circle from cqmore.polygon import regularPolygon, star from cqmore.polyhedron import polarZonohedra, Polyhedron, superellipsoid from svg_path import addSvgPath from svgpathtools import svg2paths import cadquery as cq import cqmore from math import ceil, floor Workplane = cqmore.extend(Workplane) Workplane.addSvgPath = addSvgPath screw_simple = False # Controls whether to not actually make the screw threads, saves time running it for testing screw_length = 10 # FIXME need different ones for different holes top_screw = ButtonHeadScrew( size="M3-0.5", fastener_type="iso7380_1", length=screw_length * MM, simple=screw_simple, ) gland_diameter = 13.2 gland_radius = gland_diameter / 2.0 barrel_diameter = 11 barrel_radius = barrel_diameter / 2.0 # digikey perfboard # It's the distance to the *middle* of the hole breadboard_height = 68.68 breadboard_width = 50.8 bb_hole_dist_from_top = 5.37 bb_hole_dist_from_side = 25.23 bb_hole_diameter = 2.76 # buck converter bc_height = 29.83 # from center of hole to other hole bc_width = 15.5 # from center of hole to other hole, but horizontally # large buck converter lbc_height = 63.18 lbc_width = 57.8 lbc_hole_dist_from_top = 4.5 lbc_hole_dist_from_side = 25.8 lbc_hole_diameter = 5.8 lbc_hole_radius = lbc_hole_diameter / 2.0 pwm_width = 13.45 pwm_height = 32 wall_thickness = 3 box_radius = 87 + wall_thickness box_thickness = 42 pole_height = box_thickness - 3 inner_pole_height = 13 pole_dist = 3 lid = Workplane() lower_box = Workplane() lid = ( lid.workplane() .makePolygon( regularPolygon( nSides=8, radius=box_radius - (wall_thickness / 2.0), thetaStart=0, thetaEnd=360, ) ) .extrude(5) .faces(">Z[1]") .makePolygon( regularPolygon( nSides=8, radius=box_radius - wall_thickness - pole_dist, thetaStart=0, thetaEnd=360, ) ) .vertices() .cskHole(3, 5, pole_height) ) def make_component_holder_octogon( result, pole_height, pole_dist, box_radius, x_offset=0, y_offset=0, ): pole_height_pct = 0.2 return ( result.workplane(offset=(pole_height / 3) - wall_thickness) .move(x_offset, y_offset) .makePolygon( regularPolygon( nSides=8, radius=box_radius - wall_thickness - pole_dist, # FIXME subtract wall_thickness on the input instead thetaStart=0, thetaEnd=360, ) ) .vertices() .cylinder(pole_height, 3) .workplane(offset=(pole_height * (1 - pole_height_pct) - wall_thickness + 2.2)) .move(x_offset, y_offset) .makePolygon( regularPolygon( nSides=8, radius=box_radius - wall_thickness - pole_dist, thetaStart=0, thetaEnd=360, ) ) .vertices() .threadedHole( top_screw, pole_height * pole_height_pct, simple=screw_simple, fit="Close" ) ) def make_component_holder_line( result, pole_height=0, pole_radius=3, line_x_dist=0, line_y_dist=0, x_offset=0, y_offset=0, screw=top_screw, ): return ( result.workplane(offset=-wall_thickness) .move(x_offset, y_offset) .line( line_x_dist, line_y_dist, ) .vertices() .cylinder(inner_pole_height, pole_radius) .workplane(offset=(wall_thickness * 1.7)) .move(x_offset, y_offset) .line( line_x_dist, line_y_dist, ) .vertices() .threadedHole(screw, inner_pole_height, simple=screw_simple, fit="Close") ) def make_component_holder( result, pole_dist, pole_height=inner_pole_height, pole_radius=3, box_width=None, box_height=None, x_offset=0, y_offset=0, screw=top_screw, ): return ( result.workplane(offset=-wall_thickness) .move(x_offset, y_offset) .rect( box_height, box_width, ) .vertices() .cylinder(pole_height, pole_radius) .workplane(offset=wall_thickness * 1.7) .move(x_offset, y_offset) .rect( box_height, box_width, ) .vertices() .threadedHole(screw, pole_height, simple=screw_simple, fit="Close") ) def make_component_holder_self_tapping( result, pole_dist, pole_height=inner_pole_height, pole_radius=3, box_width=None, box_height=None, x_offset=0, y_offset=0, thread_diameter=1.2, ): thread_radius = thread_diameter / 2.0 return ( result.workplane(offset=-wall_thickness) .move(x_offset, y_offset) .rect( box_height, box_width, ) .vertices() .cylinder(pole_height, pole_radius) .workplane(offset=(wall_thickness)) .move(x_offset, y_offset) .rect( box_height, box_width, ) .vertices() .cylinder(pole_height * 0.7, thread_radius, combine="cut") ) def add_gland_holes(result, side_index, gland_holes): num_sides = 8 # Calculate the angle of the side's normal angle_step = 360 / (num_sides * 2) angle = angle_step * side_index + angle_step holes = Workplane("YZ").workplane(offset=82) for i, (x_offset, y_offset, cylinder_height, cylinder_radius) in enumerate( gland_holes ): if i < len(gland_holes) - 1: holes = ( holes.move(x_offset, y_offset) .cylinder(cylinder_height, cylinder_radius) .workplane(offset=0) ) else: holes = holes.move(x_offset, y_offset).cylinder( cylinder_height, cylinder_radius ) holes = holes.rotate((0, 0, 0), (0, 0, 1), angle) return result.cut(holes) lower_box = ( lower_box.makePolygon( regularPolygon( nSides=8, radius=box_radius, thetaStart=0, thetaEnd=360, ) ) .extrude(box_thickness) .workplane(offset=-((box_thickness / 2.0) - wall_thickness)) .makePolygon( regularPolygon( nSides=8, radius=box_radius - wall_thickness, thetaStart=0, thetaEnd=360, ) ) .extrude(box_thickness * 2, combine="cut") .workplane(offset=(box_thickness / 2.0) + 8) .makePolygon( regularPolygon( nSides=8, radius=box_radius - wall_thickness + 2, thetaStart=0, thetaEnd=360, ) ) .extrude(box_thickness * 2, combine="cut") ) lower_box = make_component_holder_octogon( lower_box, pole_height, pole_dist, box_radius, x_offset=0, y_offset=0 ) lower_box = make_component_holder( lower_box, pole_dist, pole_height=inner_pole_height, box_width=breadboard_width, box_height=breadboard_height, x_offset=0, y_offset=40, ) lower_box = make_component_holder_line( lower_box, pole_height=inner_pole_height, line_x_dist=breadboard_height + 2.2, line_y_dist=0, x_offset=-(breadboard_height / 2.0) - 1.7, y_offset=40, ) bc_pole_radius = 4 lower_box = lower_box.workplane(offset=-4).move(0, -50).box(lbc_width - 5, 5, 13) lower_box = ( lower_box.workplane(offset=-4).move(0, bc_pole_radius).box(lbc_width - 5, 5, 13) ) lower_box = make_component_holder_line( lower_box, pole_height=6, pole_radius=bc_pole_radius, line_x_dist=0, line_y_dist=lbc_height - lbc_hole_diameter - lbc_hole_radius, x_offset=0, y_offset=-(lbc_width - lbc_hole_diameter - lbc_hole_radius + 1.1), ) # small buck converter lower_box = make_component_holder( lower_box, pole_dist, pole_height=inner_pole_height, box_width=bc_height, box_height=bc_width, # yes they're reversed on purpose x_offset=50, y_offset=-30, ) # mosfets lower_box = make_component_holder_self_tapping( lower_box, pole_dist, pole_height=inner_pole_height, box_width=pwm_height, box_height=pwm_width, # yes they're reversed on purpose x_offset=-55, y_offset=15, ) # cable gland holes lower_box = add_gland_holes( lower_box, 10, [ (-15, gland_radius * 3.0, 5, gland_radius), (15, gland_radius * 3.0, 5, gland_radius), ], ) lower_box = add_gland_holes( lower_box, 8, [ (-15, barrel_radius * 3.6, 5, barrel_radius), (15, gland_radius * 3.0, 5, gland_radius), ], ) cq.exporters.export(lower_box, "/home/deck/model_files/fan_control_box_lower.stl") cq.exporters.export(lid, "/home/deck/model_files/fan_control_box_lid.stl") try: show_object(lid) except NameError: pass