Prototype Enclosures with FreeCAD & OpenSCAD

Summary

Jul 8, 2017
Introduction to 3D Modelling in FreeCAD and OpenSCAD for designing 3D printed mountings for prototype electronics.

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();
  }
}