====== Prototype Enclosures with FreeCAD & OpenSCAD ====== Introduction to 3D Modelling in FreeCAD and OpenSCAD for designing 3D printed mountings for prototype electronics. * [[https://odysee.com/@OpenTechLab:f/otl-008-enclosures:7|odysee]] * [[https://www.youtube.com/watch?v=38Z7E8OcVd8|YouTube]] * [[https://peertube.social/videos/watch/08201efd-5f9b-4b0b-b5cc-80cb3b783023|peertube.social]] * [[http://archive.is/qBhHs|Aluminium Enclosure]] @ $5.88 ===== FreeCAD ===== * [[https://www.freecadweb.org/|FreeCAD Site]] * [[https://www.openhub.net/p/freecad|FreeCAD on Open Hub]] ===== OpenSCAD ===== * [[http://www.openscad.org/|OpenSCAD Website]] * [[https://www.openhub.net/p/openscad|OpenSCAD on Open Hub]] * [[http://www.openscad.org/cheatsheet/|OpenSCAD Cheat Sheet]] * [[https://github.com/sirtaj/vim-openscad|vim OpenSCAD Syntax Highlighting Plugin]] ==== Examples ==== === 5-sided Widget === ''example.scad'' width = 120; height = 60; thickness = 40; hole_dia = 24; difference() { linear_extrude(thickness) difference() { polygon([ [-width/2, -height/2], [-width/2, height/2], [width/2 - height/2, height/2], [width/2, 0], [width/2, -height/2] ]); translate([-width/4, 0]) circle(d=hole_dia); translate([width/4, 0]) circle(d=hole_dia); } translate([0, -height/2, thickness/2]) rotate([90, 0, -45]) cylinder(h=1000, d=hole_dia, center=true); } === PCB Frame === ''frame.scad'' holeSpacingH = 90.40; holeSpacingV = 95; dioHoleOffsetH = 35; frameEdgePaddingV = 15.0; frameEdgePaddingR = 16.0; frameSize = [holeSpacingH + dioHoleOffsetH + frameEdgePaddingR, holeSpacingV + frameEdgePaddingV*2]; frameWidth = 8; frameThickness = 2; frameReinforcementHeight = 4; frameReinforcementThickness = 1.5; mountLength = 18; mountDia = 7; mountHoleDia = 3.5; mountColumns = [0, holeSpacingH, holeSpacingH + dioHoleOffsetH]; pcbThickness = 1.6; footHeight = mountLength * 2 + pcbThickness; footThickness = frameReinforcementThickness; footBaseWidth = 10; footEndWidth = 5; hddMountSpacingH = 3 * 25.4; hddMountSpacingV = (2 + 7/16) * 25.4; hddMountHoleDia = 3; hddCountersinkDia = 5.5; hddMountColumns = [holeSpacingH - hddMountSpacingH, holeSpacingH]; union() { mounts(); frame(); feet(); } module mountOutline(d) { circle(d/2, $fn=32); } module mountOutlines(d) { translate([-frameSize[0] / 2, 0]) union() { for (a=mountColumns) { translate([a, -holeSpacingV/2]) mountOutline(d); translate([a, holeSpacingV/2]) mountOutline(d); } } } module hddMountOutlines(d) { translate([-frameSize[0] / 2, 0]) union() { for (a=hddMountColumns) { translate([a, -hddMountSpacingV/2]) mountOutline(d); translate([a, hddMountSpacingV/2]) mountOutline(d); } } } module mountFlange() { translate([-footThickness/2, 0]) rotate([90, 0, 90]) linear_extrude(footThickness) polygon(points=[ [mountHoleDia/2, 0], [frameEdgePaddingV, 0], [frameEdgePaddingV, frameReinforcementHeight], [mountHoleDia/2, mountLength]]); } module mountFlangeRow() { for (a=mountColumns) translate([a - frameSize[0] / 2, holeSpacingV/2]) mountFlange(); } module mounts() { union() { linear_extrude(mountLength) difference() { mountOutlines(mountDia); mountOutlines(mountHoleDia); } mountFlangeRow(); mirror([0, 1, 0]) mountFlangeRow(); } } module frameFlangeRow(length, columns) { for (a=columns) translate([a - frameSize[0]/2 - frameWidth/2, frameSize[1]/2 - length]) square(size=[frameWidth, length]); } module frameFlanges(length, columns) { frameFlangeRow(length, columns); mirror([0, 1, 0]) frameFlangeRow(length, columns); } module frameRim(width) { difference() { offset(r=width/2) square(size=frameSize, center=true); offset(r=-width/2) square(size=frameSize, center=true); } } module frameHddEndFlange() { translate([-frameSize[0] / 2, (hddMountSpacingV - frameWidth) / 2]) square(size=[hddMountColumns[0], frameWidth]); } module frameOutline() { difference() { union() { frameRim(frameWidth); mountOutlines(frameWidth); hddMountOutlines(frameWidth); frameFlanges(frameEdgePaddingV, mountColumns); frameFlanges((frameSize[1] - hddMountSpacingV) / 2, [hddMountColumns[1]]); frameHddEndFlange(); mirror([0, 1, 0]) frameHddEndFlange(); } mountOutlines(mountHoleDia); hddMountOutlines(hddMountHoleDia); } } module frameReinforcementOutline() { difference() { frameRim(frameReinforcementThickness); mountOutlines(mountHoleDia); } } module hddCountersink() { translate([0, 0, frameThickness]) mirror([0, 0, 1]) cylinder(hddCountersinkDia/2, hddCountersinkDia/2, 0, $fn=32); } module hddCountersinks() { translate([-frameSize[0] / 2, 0]) union() { for (a=hddMountColumns) { translate([a, -hddMountSpacingV/2]) hddCountersink(); translate([a, hddMountSpacingV/2]) hddCountersink(); } } } module frame() { difference() { union() { linear_extrude(frameThickness) frameOutline(); linear_extrude(frameReinforcementHeight) frameReinforcementOutline(); } hddCountersinks(); } } module halfFoot() { linear_extrude(footThickness) polygon(points=[ [-footThickness/2, 0], [-footThickness/2, footHeight], [footEndWidth, footHeight], [footBaseWidth, 0]]); } module foot() { union() { translate([0, footThickness/2]) rotate(a=[90, 0, 0]) halfFoot(); translate([-footThickness/2, 0]) rotate(a=[90, 0, 90]) halfFoot(); } } module feet() { union() { translate([-frameSize[0] / 2, -frameSize[1] / 2]) rotate(a=[0,0,0]) foot(); translate([frameSize[0] / 2, -frameSize[1] / 2]) rotate(a=[0,0,90]) foot(); translate([frameSize[0] / 2, frameSize[1] / 2]) rotate(a=[0,0,180]) foot(); translate([-frameSize[0] / 2, frameSize[1] / 2]) rotate(a=[0,0,270]) foot(); } }