1
0
mirror of https://github.com/nophead/NopSCADlib.git synced 2025-01-17 05:28:14 +01:00
NopSCADlib/vitamins/pcb.scad
Chris Palmer 3299aad5c8 Parametric potentiometers added, changes PCB "potentiometer" parameters.
The first one is now the type that defaults to the previous BigTreeTech version.
The second parameter is the shaft length overrride.

Added ESP32_DOIT_V1, ArduinoNano and KY_040 breakout PCBs.
2021-09-11 12:01:04 +01:00

1275 lines
44 KiB
OpenSCAD

//
// NopSCADlib Copyright Chris Palmer 2018
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
//
//! PCBs and perfboard with optional components. The shape can be a rectangle with optionally rounded corners or a polygon for odd shapes like Arduino.
//
panel_clearance = 0.2;
include <../core.scad>
include <buttons.scad>
include <green_terminals.scad>
include <pin_headers.scad>
use <microswitch.scad>
use <7_segment.scad>
use <../utils/rounded_cylinder.scad>
use <../utils/dogbones.scad>
use <../utils/thread.scad>
use <../utils/tube.scad>
use <d_connector.scad>
use <led.scad>
use <dip.scad>
use <axial.scad>
use <smd.scad>
include <potentiometers.scad>
function pcb_name(type) = type[1]; //! Description
function pcb_length(type) = type[2]; //! Length
function pcb_width(type) = type[3]; //! Width
function pcb_thickness(type) = type[4]; //! Thickness
function pcb_radius(type) = type[5]; //! Corner radius
function pcb_hole_d(type) = type[6]; //! Mounting hole diameter
function pcb_land_d(type) = type[7]; //! Pad around mounting hole
function pcb_colour(type) = type[8]; //! Colour of the substrate
function pcb_parts_on_bom(type) = type[9]; //! True if the parts should be separate BOM items
function pcb_holes(type) = type[10]; //! List of hole positions
function pcb_components(type) = type[11]; //! List of components
function pcb_accessories(type) = type[12]; //! List of accessories to go on the BOM, SD cards, USB cables, etc.
function pcb_grid(type) = type[13]; //! Grid origin if a perfboard
function pcb_polygon(type) = type[14]; //! Optional outline polygon for odd shaped boards
function pcb_screw(type, cap = hs_cap) = Len(type[15]) ? type[15] : find_screw(cap, screw_smaller_than(pcb_hole_d(type))); //! Mounting screw type
function pcb_size(type) = [pcb_length(type), pcb_width(type), pcb_thickness(type)]; //! Length, width and thickness in a vector
function pcb_component(type, name, index = 0) = //! Return the component specified by name and index
[for(component = pcb_components(type)) if(component[3] == name) component][index];
function pcb_grid_pos(type, x, y, z = 0) = //! Returns a pcb grid position
let(grid = pcb_grid(type))
[-pcb_size(type).x / 2 + grid.x + x * (is_undef(grid[5]) ? 2.54 : grid[5]),
-pcb_size(type).y / 2 + grid.y + y * (is_undef(grid[6]) ? 2.54 : grid[6]),
pcb_size(type).z + z];
module pcb_grid(type, x, y, z = 0) //! Positions children at specified grid position
translate(pcb_grid_pos(type, x, y, z))
children();
// allows negative ordinates to represent offsets from the far edge
function pcb_coord(type, p) = let(l = pcb_length(type), w = pcb_width(type)) //! Convert offsets from the edge to coordinates relative to the centre
[(p.x >= 0 ? p.x : l + p.x) - l / 2,
(p.y >= 0 ? p.y : w + p.y) - w / 2];
module pcb_hole_positions(type, all = true) { // Position children at the hole positions, including holes not used for screws
holes = pcb_holes(type);
for($i = [0 : 1 : len(holes) - 1]) {
hole = holes[$i];
if(len(hole) == 2 || all)
translate(pcb_coord(type, hole))
children();
}
}
module pcb_screw_positions(type) //! Positions children at the mounting hole positions
pcb_hole_positions(type, false) children();
module chip(length, width, thickness, colour, cutout = false) //! Draw a coloured cube to represent a chip, or other rectangular component, or cylinder if width is zero
if(!cutout)
color(colour)
if(width)
translate_z(thickness / 2) cube([length, width, thickness], center = true);
else
cylinder(d = length, h = thickness);
module usb_A_tongue() {
l = 9;
w = 12;
h = 2;
color("white")
translate([-1, 0 , h / 2])
rotate([90, 0, 90])
hull() {
linear_extrude(l - 2)
square([w, h], center = true);
linear_extrude(l)
square([w - 1, h - 1], center = true);
}
}
module usb_Ax1(cutout = false) { //! Draw USB type A single socket
usb_A(h = 6.5, v_flange_l = 4.5, bar = 0, cutout = cutout);
}
module usb_Ax2(cutout = false) { //! Draw USB type A dual socket
usb_A(h = 15.6, v_flange_l = 12.15, bar = 3.4, cutout = cutout);
}
module usb_A(h, v_flange_l, bar, cutout) {
l = 17;
w = 13.25;
flange_t = 0.4;
h_flange_h = 0.8;
h_flange_l = 11;
v_flange_h = 1;
socket_h = (h - 2 * flange_t - bar) / 2;
translate_z(h / 2)
if(cutout)
rotate([90, 0, 90])
rounded_rectangle([w + 2 * v_flange_h + 2 * panel_clearance,
h + 2 * h_flange_h + 2 * panel_clearance, 100], r = cnc_bit_r);
else {
color("silver") rotate([0, 90, 0]) {
linear_extrude(l, center = true)
difference() {
square([h, w], center = true);
for(s = [-1, 1])
translate([s * (bar / 2 + socket_h / 2), 0])
square([socket_h, w - 2 * flange_t], center = true);
}
translate_z(-l / 2 + 0.5)
cube([h, w, 1], center = true);
translate_z(l / 2 - flange_t)
linear_extrude(flange_t) difference() {
union() {
square([h + 2 * h_flange_h, h_flange_l], center = true);
square([v_flange_l, w + 2 * v_flange_h], center = true);
}
square([h - eps, w - eps], center = true);
}
}
for(z = bar ? [-1, 1] : [0])
translate_z(z * (bar / 2 + socket_h / 2))
usb_A_tongue();
}
}
module molex_usb_Ax2(cutout) { //! Draw Molex dual USB A connector suitable for perf board
w = 15.9;
h = 16.6;
l = 17;
pin_l = 2.8;
clearance = 0.2;
tag_l = 4.4;
tag_r = 0.5;
tag_w = 1.5;
tag_t = 0.3;
tag_p = 5.65;
if(cutout)
translate([0, -w / 2 - clearance, -clearance])
cube([100, w + 2 * clearance, h + 2 * clearance]);
else {
color(silver)
translate([-l / 2, 0])
rotate([90, 0, 90])
translate([-w / 2, 0]) {
cube([w, h, l - 9]);
linear_extrude(l)
difference() {
square([w, h]);
for(z = [-1, 1])
translate([w / 2, h / 2 + z * 8.5 / 2])
square([12.6, 5.08], center = true);
}
}
for(z = [-1, 1])
translate_z(h / 2 + z * 8.5 / 2)
usb_A_tongue();
color(silver)
rotate(-90) {
for(x = [-1.5 : 1 : 1.5], y = [0.5 : 1 : 1.5])
translate([inch(x / 10), -l / 2 + inch(y / 10)])
hull() {
cube([0.6, 0.3, 2 * pin_l - 2], center = true);
cube([0.4, 0.3, 2 * pin_l], center = true);
}
for(side = [-1, 1], end = [0, 1])
translate([side * w / 2, -l / 2 + tag_w / 2 + end * tag_p])
rotate(-side * 90)
hull() {
translate([0, tag_l - tag_r])
cylinder(r = tag_r, h = tag_t);
translate([-tag_w / 2, 0])
cube([tag_w, eps, tag_t]);
}
}
}
}
module molex_usb_Ax1(cutout) { //! Draw Molex USB A connector suitable for perf board
w = 15.3;
h = 7.7;
l = 14.5;
pin_l = 2.8;
clearance = 0.2;
tag_l = 4.4;
tag_r = 0.5;
tag_w = 1.5;
tag_t = 0.3;
if(cutout)
translate([0, -w / 2 - clearance, -clearance])
cube([100, w + 2 * clearance, h + 2 * clearance]);
else {
color(silver)
translate([-l / 2, 0])
rotate([90, 0, 90])
translate([-w / 2, 0]) {
cube([w, h, l - 9]);
linear_extrude(l)
difference() {
square([w, h]);
translate([w / 2, h / 2])
square([12.6, 5.08], center = true);
}
}
translate([-1.5, 0, h / 2])
usb_A_tongue();
color(silver)
rotate(-90) {
for(x = [-1.5 : 1 : 1.5])
translate([inch(x / 10), - l / 2 + inch(0.05)])
hull() {
cube([0.6, 0.3, 2 * pin_l - 2], center = true);
cube([0.4, 0.3, 2 * pin_l], center = true);
}
for(side = [-1, 1])
translate([side * w / 2, -l / 2 + 4.2])
rotate(-side * 90)
hull() {
translate([0, tag_l - tag_r])
cylinder(r = tag_r, h = tag_t);
translate([-tag_w / 2, 0])
cube([tag_w, eps, tag_t]);
}
}
}
}
module rj45(cutout = false) { //! Draw RJ45 Ethernet connector
l = 21;
w = 16;
h = 13.5;
plug_h = 6.8;
plug_w = 12;
plug_z = 4;
tab_z = 0.8;
tab_w = 4;
translate_z(h / 2)
if(cutout)
rotate([90, 0, 90])
dogbone_rectangle([w + 2 * panel_clearance, h + 2 * panel_clearance, 100], center = false);
else {
rotate([0, 90, 0]) {
mouth = plug_z + plug_h - tab_z;
color("silver") {
linear_extrude(l, center = true)
difference() {
square([h, w], center = true);
translate([h / 2 - tab_z - mouth / 2, 0])
square([mouth + 0.1, plug_w + 0.1], center = true);
}
translate_z(-l / 2)
cube([h, w, eps], center = true);
}
color(grey(30)) {
linear_extrude(l - 0.2, center = true)
difference() {
square([h - 0.1, w - 0.1], center = true);
translate([h / 2 - plug_z - plug_h / 2, 0])
square([plug_h, plug_w - 0.1], center = true);
translate([h / 2 - tab_z - plug_h / 2, 0])
square([plug_h, tab_w], center = true);
}
translate_z(-l / 2 + 1)
cube([h - 0.1, w - 0.1, 0.1], center = true);
}
}
}
}
module jack(cutout = false) { //! Draw 3.5mm jack
l = 12;
w = 7;
h = 6;
d = 6;
ch = 2.5;
translate_z(h / 2)
if(cutout)
rotate([0, 90, 0])
cylinder(d = d + 2 * panel_clearance, h = 100);
else
color(grey(20))
rotate([0, 90, 0]) {
linear_extrude(l / 2)
difference() {
square([h, w], center = true);
circle(d = 3.5);
}
tube(or = d / 2, ir = 3.5 / 2, h = l / 2 + ch, center = false);
translate_z(-l / 4)
cube([h, w, l / 2], center = true);
}
}
module buzzer(height, diameter, colour) { //! Draw PCB buzzer with specified height, diameter and colour
color (colour)
tube(or = diameter / 2, ir = height > 5 ? 1 : 0.75, h = height, center = false);
color("white")
cylinder(d = 2, h = max(height - 3 , 0.5));
}
function hdmi_depth(type) = type[2]; //! Front to back depth
function hdmi_width1(type) = type[3]; //! Inside width at the top
function hdmi_width2(type) = type[4]; //! Inside width at the bottom
function hdmi_height1(type) = type[5]; //! Inside height at the sides
function hdmi_height2(type) = type[6]; //! Inside height in the middle
function hdmi_height(type) = type[7]; //! Outside height above the PCB
function hdmi_thickness(type) = type[8]; //! Wall thickness of the metal
hdmi_full = [ "hdmi_full", "HDMI socket", 12, 14, 10, 3, 4.5, 6.5, 0.5 ];
hdmi_mini = [ "hdmi_mini", "Mini HDMI socket", 7.5, 10.5, 8.3, 1.28, 2.5, 3.2, 0.35 ];
hdmi_micro = [ "hdmi_micro", "Micro HDMI socket", 8.5, 5.9, 4.43, 1.4, 2.3, 3, 0.3 ];
module hdmi(type, cutout = false) { //! Draw HDMI socket
vitamin(str("hdmi(", type[0], "): ", type[1]));
l = hdmi_depth(type);
iw1 = hdmi_width1(type);
iw2 = hdmi_width2(type);
ih1 = hdmi_height1(type);
ih2 = hdmi_height2(type);
h = hdmi_height(type);
t = hdmi_thickness(type);
module D() {
hull() {
translate([-iw1 / 2, h - t - ih1])
square([iw1, ih1]);
translate([-iw2 / 2, h - t - ih2])
square([iw2, ih2]);
}
}
if(cutout)
rotate([90, 0, 90])
linear_extrude(100)
offset(t + panel_clearance)
D();
else
color("silver")
rotate([90, 0, 90]) {
linear_extrude(l, center = true)
difference() {
offset(t)
D();
D();
}
translate_z(-l / 2)
linear_extrude(1)
offset(t)
D();
}
}
module usb_uA(cutout = false) { //! Draw USB micro A connector
l = 6;
iw1 = 7;
iw2 = 5.7;
ih1 = 1;
ih2 = 1.85;
h = 2.65;
t = 0.4;
flange_h = 3;
flange_w = 8;
module D() {
hull() {
translate([-iw1 / 2, h - t - ih1])
square([iw1, ih1]);
translate([-iw2 / 2, h - t - ih2])
square([iw2, ih2]);
}
}
if(cutout)
rotate([90, 0, 90])
linear_extrude(100)
offset((flange_h - ih2) / 2 + 2 * panel_clearance)
D();
else
color("silver") rotate([90, 0, 90]) {
linear_extrude(l, center = true)
difference() {
offset(t)
D();
D();
}
translate_z(-l / 2)
linear_extrude(1)
offset(t)
D();
translate_z(l / 2 - t)
linear_extrude(t) difference() {
union() {
translate([0, h - t - ih1 / 2])
square([flange_w, ih1], center = true);
translate([0, h / 2 + flange_h / 4])
square([iw1, flange_h / 2], center = true);
translate([0, h / 2 - flange_h / 4])
square([iw2, flange_h / 2], center = true);
}
D();
}
}
}
module usb_C(cutout = false) { //! Draw USB C connector
l = 7.35;
w = 8.94;
h = 3.26;
t = 0.4;
flange_h = 3;
flange_w = 8;
module O()
translate([0, h / 2])
rounded_square([w, h], h / 2 - 0.5, center = true);
if(cutout)
rotate([90, 0, 90])
linear_extrude(100)
offset(2 * panel_clearance)
O();
else
color("silver") rotate([90, 0, 90]) {
linear_extrude(l, center = true)
difference() {
O();
offset(-t)
O();
}
translate_z(-l / 2)
linear_extrude(2.51)
O();
}
}
module usb_B(cutout = false) { //! Draw USB B connector
l = 16.4;
w = 12.2;
h = 11;
tab_w = 5.6;
tab_h = 3.2;
d_h = 7.78;
d_w = 8.45;
d_w2 = 5;
d_h2 = d_h - (d_w - d_w2) / 2;
module D()
hull() {
translate([-d_w / 2, 0])
square([d_w, d_h2]);
translate([-d_w2 /2, 0])
square([d_w2, d_h]);
}
if(cutout)
translate([50, 0, h / 2 - panel_clearance])
cube([100, w + 2 * panel_clearance, h + 2 * panel_clearance], center = true);
else
translate_z(h / 2) rotate([90, 0, 90]) {
color("silver") {
linear_extrude(l, center = true)
difference() {
square([w, h], center = true);
translate([0, -d_h / 2])
offset(delta = 0.2)
D();
}
translate_z(-l / 2 + 0.1)
cube([w, h, 0.2], center = true);
}
color("white") {
linear_extrude(l - 0.4, center = true)
difference() {
square([w - 0.2, h - 0.2], center = true);
translate([0, -d_h / 2])
difference() {
D();
translate([0, d_h / 2])
square([tab_w, tab_h], center = true);
}
}
translate_z( -(l - 0.4) / 2 + 1)
cube([w - 0.2, h - 0.2, 2], center = true);
}
}
}
module barrel_jack(cutout = false) { //! Draw barrel power jack
l = 13.2;
w = 8.89;
h = 11;
bore_d = 6.3;
bore_h = 6.5;
bore_l = 11.8;
pin_d = 2;
front = 3.3;
r = 0.5;
contact_d = 2;
contact_w = 4;
inset = 1;
if(cutout)
;
else {
color(grey(20)) rotate([0, 90, 0]) {
linear_extrude(l, center = true) {
difference() {
translate([-h / 2, 0])
rounded_square([h, w], r);
translate([-bore_h, 0])
circle(d = bore_d);
translate([-h / 2 - bore_h, 0])
square([h, w], center = true);
}
}
translate_z(l / 2 - front)
linear_extrude(front) {
difference() {
translate([-h / 2, 0])
rounded_square([h, w], r);
translate([-bore_h, 0])
circle(d = bore_d);
}
}
translate([-bore_h, 0])
tube(or = w / 2 - 0.5, ir = bore_d / 2, h = l);
translate([-bore_h, 0, -l / 2])
cylinder(d = w -1, h = l - bore_l);
}
color("silver") {
translate([l / 2 - inset - pin_d / 2, 0, bore_h])
hull() {
sphere(pin_d / 2);
rotate([0, -90, 0])
cylinder(d = pin_d, h = bore_l - inset);
}
hull() {
translate([l / 2 - inset - contact_d / 2, 0, bore_h - bore_d / 2])
rotate([90, 0, 0])
cylinder(d = contact_d, h = contact_w, center = true);
translate([l / 2 - bore_l, 0, bore_h - bore_d / 2 + contact_d / 4])
cube([eps, contact_w, eps], center = true);
}
}
}
}
module uSD(size, cutout = false) { //! Draw uSD socket
min_w = 12;
w = size.x - min_w;
t = 0.15;
if(cutout)
;
else
translate_z(size.z / 2) {
color("silver")
rotate([90, 0, 90]) {
linear_extrude(size.y, center = true)
difference() {
square([size.x, size.z], center = true);
square([size.x - 2 * t, size.z - 2 * t], center = true);
}
translate_z(-size.y / 2 + t / 2)
cube([size.x, size.z, t], center = true);
}
if(w > 0)
color(grey(20))
rotate([90, 0, 90])
translate_z(t)
linear_extrude(size.y - t, center = true)
difference() {
square([size.x - 2 * t, size.z - 2 * t], center = true);
translate([-size.x / 2 + min_w / 2 + 0.7, size.z / 2 - t])
square([min_w, 2.2], center = true);
}
}
}
module flex(cutout = false) { //! Draw flexistrip connector
l = 20.6;
w = 3;
h = 5.6;
top_l = 22.4;
top_t = 1.1;
tab_l = 13;
tab_w = 1;
slot_l = 16.4;
slot_w = 0.7;
slot_offset = 0.6;
if(cutout)
;
else {
color(grey(30)) {
translate_z(0.5)
cube([l, w, 1], center = true);
linear_extrude(h)
difference() {
square([l, w], center = true);
translate([0, -w / 2 + slot_offset + slot_w / 2])
square([slot_l, slot_w], center = true);
}
translate_z(h - top_t)
linear_extrude(top_t)
difference() {
union() {
square([top_l, w], center = true);
hull() {
translate([0, -w / 2 + (w + tab_w) / 2])
square([tab_l - 1, w + tab_w], center = true);
square([tab_l, w], center = true);
}
}
translate([0, -w / 2 + slot_offset + slot_w / 2])
square([slot_l, slot_w], center = true);
}
}
}
}
small_ff = [[11.8, 0.9], [17, 1.4, 1.2], [12, 1.6, 1.2], [16, 1.1, 1.2]];
large_ff = [[16, 1.25], [22, 1.5, 2.5], [16, 4.0, 2.5], [21, 0, 2.5]];
function ff_slot(type) = type[0]; //! Flat flex slot size
function ff_latch(type) = type[1]; //! Flat flex latch size
function ff_mid(type) = type[2]; //! Flat flex middle section size
function ff_back(type) = type[3]; //! Flat flex back section size
module flat_flex(type, cutout = false) { //! Draw flat flexistrip connector as used on RPI0
slot = ff_slot(type);
latch = ff_latch(type);
mid = ff_mid(type);
back = ff_back(type);
w = latch.y + mid.y + back.y;
if(cutout)
;
else {
color(grey(30))
translate([0, w / 2 - latch.y])
rotate([90, 0, 180])
linear_extrude(latch.y)
difference() {
translate([-latch.x / 2, 0])
square([latch.x, latch.z]);
square([slot.x, slot.y * 2], center = true);
}
color("ivory") {
translate([-back.x / 2, -w / 2])
if(back.y)
cube(back);
translate([-mid.x / 2, -w / 2 + back.y])
cube(mid);
}
color(grey(80))
translate([-back.x / 2, -w / 2 + back.y + eps])
cube([back.x, mid.y - 2 * eps, mid.z - eps]);
}
}
module terminal_35(ways, colour = "blue") { //! Draw 3.5mm terminal block
vitamin(str("terminal_35(", ways, "): Terminal block ", ways, " way 3.5mm"));
pitch = 3.5;
width = ways * pitch;
depth = 7;
height = 8.3;
chamfer_h = 3;
chamfer_d = 1;
box_z = 0.5;
box_w = 2.88;
box_h = 4.1;
wire_z = 2;
wire_d = 2;
pin_l = 4.2;
pin_d = 0.9;
module single() {
screw_r = 1;
color(colour) {
rotate([90, 0, 0])
linear_extrude(pitch, center = true)
polygon(points = [
[ depth / 2, 0],
[ depth / 2, box_z],
[-depth / 2 + 1, box_z],
[-depth / 2 + 1, box_z + box_h],
[ depth / 2, box_z + box_h],
[ depth / 2, height - chamfer_h],
[ depth / 2 - chamfer_d, height],
[ -screw_r - eps, height],
[ -screw_r - eps, box_z + box_h],
[ screw_r + eps, box_z + box_h],
[ screw_r + eps, height],
[-depth / 2, height],
[-depth / 2, 0],
]);
linear_extrude(box_z + box_h)
difference() {
square([depth, pitch], center = true);
translate([1, 0])
square([depth, box_w], center = true);
}
translate_z(box_z + box_h)
linear_extrude(height - box_z - box_h)
difference() {
square([2 * screw_r + 0.1, pitch], center = true);
circle(screw_r);
}
}
color("silver") {
screw_z = box_z + box_h;
translate_z(screw_z) {
cylinder(r = screw_r, h = height - screw_z - 1); // screw
linear_extrude(height - screw_z - 0.5)
difference() {
circle(1);
square([4, 0.5], center = true); // screw slot
square([0.5, 1.7], center = true); // second screw slot
}
}
translate_z(box_z - pin_l)
cylinder(d = pin_d, h = pin_l + box_z, $fn = 16); // pin
translate_z(box_z + box_h / 2) // terminal
rotate([0, -90, 0]) {
linear_extrude(depth - 2, center = true)
difference() {
square([box_h, box_w], center = true);
translate([wire_z - box_z - box_h / 2, 0])
circle(d = wire_d);
}
translate_z(depth / 2 - 1.5)
cube([box_h, box_w, 1], center = true);
}
}
}
for(i = [0: ways -1])
translate([0, i * pitch - width / 2 + pitch / 2])
single();
}
module molex_254(ways, right_angle = 0, skip = undef) { //! Draw molex header, set `right_angle` to 1 for normal right angle version or -1 for inverted right angle version.
vitamin(str("molex_254(", ways, "): Molex KK header ", ways, " way"));
pitch = 2.54;
width = ways * pitch - 0.1;
depth = 6.35;
height = 8.15;
base = 3.18;
back = 1;
below = 2.3;
above = 9;
pin_w = 0.64;
r = 1;
a = right_angle ? width / 2 - r - pin_w / 2 : above;
ra_offset = 2.72;
color("white")
translate(right_angle ? [-ra_offset, 0, depth / 2] : [ 0, 0, 0])
rotate(right_angle ? right_angle > 0 ? [180, 90, 0] : [0, -90, 0] : [ 0, 0, 0])
union() {
translate([ -depth / 2, -width / 2,])
cube([depth, width, base]);
w = width - pitch;
translate([- depth / 2, -w / 2])
cube([back, w, height]);
}
color("silver")
for(i = [0 : ways -1])
if(is_undef(skip) || !in(skip, i))
translate([0, i * pitch - width / 2 + pitch / 2]) {
translate_z((a + below) / 2 - below)
cube([pin_w, pin_w, a + below], center = true);
l = above + ra_offset - r - pin_w / 2;
if(right_angle) {
translate([-l / 2 - r - pin_w / 2, 0, width / 2])
cube([l, pin_w, pin_w], center = true);
translate([-r - pin_w / 2, 0, a])
rotate([90, 0, 0])
rotate_extrude(angle = 90)
translate([r + pin_w / 2, 0])
square(pin_w, true);
}
}
}
module vero_pin(cropped = false) { //! Draw a vero pin
vitamin("vero_pin(): Vero board pin");
l = cropped ? 7.5 : 10;
d = 1.03;
spline_d = 1.23;
spline_h = 1.3;
collar_d = 1.72;
collar_h = 0.65;
above = 3.6;
splines = 6;
spline_w = 0.3;
color(silver) {
translate_z(-l + above + collar_h)
cylinder(d = d, h = l, $fn = 32);
cylinder(d = collar_d, h = collar_h);
for(i = [0 : splines - 1])
rotate(360 * i / splines)
translate([d / 2, 0, -spline_h])
rounded_rectangle([spline_d - d, spline_w, spline_h], spline_w / 4, center = false);
}
}
module standoff(h, d, h2, d2) { //! Draw a standoff
color("white") {
cylinder(d = d, h = h);
hull() {
translate_z(-(h2 - h) / 2 + d2 / 2)
sphere(d = d2);
translate_z(h +(h2 - h) / 2 - d2 / 2)
sphere(d = d2);
}
}
}
module trimpot10(vertical, cutout = false) { //! Draw a ten turn trimpot
l = 10;
w = 9.5;
h = 4.8;
foot_w = 1;
foot_h = 0.5;
screw_h = 1.5;
screw_d = 2.25;
slot_w = 0.6;
slot_h = 0.8;
module screw_pos()
translate([-w / 2 + screw_d / 2, -l / 2, h - screw_d / 2])
rotate([90, 0, 0])
children();
translate(vertical ? [0, -h / 2, l / 2] : [0, 0])
rotate([vertical ? -90 : 0, 0, 0]) {
if(cutout)
screw_pos()
poly_drill(r = (screw_d + 1) / 2, h = 100, center = false);
else
color("#2CA1FD") {
translate([0, -foot_h / 2, foot_h / 2 + h / 2])
cube([w, l - foot_h, h - foot_h], center = true);
for(x = [-1, 1], y = [-1, 1])
translate([x * (w - foot_w) / 2, y * (l - foot_w) / 2, h / 2])
cube([foot_w, foot_w, h], center = true);
}
color(brass)
screw_pos() {
cylinder(d = screw_d, h = screw_h - slot_h);
linear_extrude(screw_h)
difference() {
circle(d = screw_d);
square([slot_w, screw_d + 1], center = true);
}
}
}
}
module block(size, colour, makes_cutout, cutouts) //! Draw a coloured cube to represent a random PCB component
if(cutouts) {
if(makes_cutout)
translate([-50, 0, size.z / 2 - panel_clearance])
cube([100, size.y + 2 * panel_clearance, size.z + 2 * panel_clearance], center = true);
}
else
color(colour)
translate_z(size.z / 2)
cube(size, center = true);
module pcb_component(comp, cutouts = false, angle = undef) { //! Draw pcb component from description
function show(comp, part) = (comp[3] == part || comp[3] == str("-",part)) && (!cutouts || angle == undef || angle == comp.z);
function param(n, default = 0) = len(comp) > n ? comp[n] : default;
rotate(comp.z) {
// Components that have a cutout parameter go in this section
if(show(comp, "2p54header")) pin_header(2p54header, comp[4], comp[5], param(6, false), param(8, false), cutouts, colour = param(7, undef));
if(show(comp, "2p54joiner")) pin_header(2p54joiner, comp[4], comp[5], param(6, false), param(8, false), cutouts, colour = param(7, undef));
if(show(comp, "2p54boxhdr")) box_header(2p54header, comp[4], comp[5], param(6, false), cutouts);
if(show(comp, "2p54socket")) pin_socket(2p54header, comp[4], comp[5], param(6, false), param(7, 0), param(8, false), cutouts, param(9, undef));
if(show(comp, "chip")) chip(comp[4], comp[5], comp[6], param(7, grey(30)), cutouts);
if(show(comp, "rj45")) rj45(cutouts);
if(show(comp, "usb_A")) usb_Ax1(cutouts);
if(show(comp, "usb_Ax2")) usb_Ax2(cutouts);
if(show(comp, "usb_uA")) usb_uA(cutouts);
if(show(comp, "usb_B")) usb_B(cutouts);
if(show(comp, "usb_C")) usb_C(cutouts);
if(show(comp, "jack")) jack(cutouts);
if(show(comp, "barrel_jack")) barrel_jack(cutouts);
if(show(comp, "hdmi")) hdmi(hdmi_full, cutouts);
if(show(comp, "mini_hdmi")) hdmi(hdmi_mini, cutouts);
if(show(comp, "micro_hdmi")) hdmi(hdmi_micro, cutouts);
if(show(comp, "flex")) flex(cutouts);
if(show(comp, "flat_flex")) flat_flex(param(4, false) ? large_ff : small_ff, cutouts);
if(show(comp, "uSD")) uSD(comp[4], cutouts);
if(show(comp, "trimpot10")) trimpot10(param(4, false), cutouts);
if(show(comp, "molex_usb_Ax2")) molex_usb_Ax2(cutouts);
if(show(comp, "molex_usb_Ax1")) molex_usb_Ax1(cutouts);
if(show(comp, "smd_led")) smd_led(comp[4], comp[5], cutouts);
if(show(comp, "7seg")) let(z = param(6, 0)) translate_z(z) 7_segment_digits(comp[4], comp[5], pin_length = z + 3, cutout = cutouts);
if(show(comp, "block")) block(size = [comp[4], comp[5], comp[6]], colour = comp[7], makes_cutout = param(8));
if(!cutouts) {
// Components that don't have a cutout parameter go in this section
if(show(comp, "button_6mm")) square_button(button_6mm);
if(show(comp, "button_4p5mm")) square_button(button_4p5mm);
if(show(comp, "microswitch")) translate_z(microswitch_thickness(comp[4])/2) microswitch(comp[4]);
if(show(comp, "pcb")) translate_z(comp[4]) pcb(comp[5]);
if(show(comp, "standoff")) standoff(comp[4], comp[5], comp[6], comp[7]);
if(show(comp, "term254")) green_terminal(gt_2p54,comp[4], comp[5], param(6,"lime"));
if(show(comp, "gterm")) green_terminal(comp[4], comp[5], comp[6], param(7,"lime"));
if(show(comp, "gterm35")) green_terminal(gt_3p5, comp[4], comp[5], param(6,"lime"));
if(show(comp, "gterm508")) green_terminal(gt_5p08, comp[4], comp[5], param(6,"lime"));
if(show(comp, "gterm635")) green_terminal(gt_6p35, comp[4], comp[5], param(6,"lime"));
if(show(comp, "term35")) terminal_35(comp[4], param(5,"blue"));
if(show(comp, "transition")) idc_transition(2p54header, comp[4], comp[5]);
if(show(comp, "led")) translate_z(eps) led(comp[4], comp[5], 2.6);
if(show(comp, "pdip")) pdip(comp[4], comp[5], param(6, false), param(7, inch(0.3)));
if(show(comp, "ax_res")) ax_res(comp[4], comp[5], param(6, 5), param(7, 0));
if(show(comp, "link")) wire_link(l = comp[4], h = param(5, 1), d = param(6, 0.8), tail = param(7, 3));
if(show(comp, "D_plug")) translate_z(d_pcb_offset(comp[4])) d_plug(comp[4], pcb = true);
if(show(comp, "molex_hdr")) molex_254(comp[4], param(5, 0), param(6, undef));
if(show(comp, "jst_xh")) jst_xh_header(jst_xh_header, comp[4], param(5, false), param(6, "white"), param(7, undef));
if(show(comp, "jst_ph")) jst_xh_header(jst_ph_header, comp[4], param(5, false), param(6, "white"), param(7, undef));
if(show(comp, "potentiometer")) let(pot = param(4, BTT_encoder)) translate_z(pot_size(pot).z) vflip() potentiometer(pot, shaft_length = param(5, undef));
if(show(comp, "buzzer")) buzzer(param(4, 9), param(5, 12), param(6, grey(20)));
if(show(comp, "smd_res")) smd_resistor(comp[4], comp[5]);
if(show(comp, "smd_cap")) smd_capacitor(comp[4], comp[5]);
if(show(comp, "vero_pin")) vero_pin(param(4, false));
}
}
}
function pcb_component_position(type, name, index = 0) = //! Return x y position of specified component
[for(comp = pcb_components(type), p = [pcb_coord(type, [comp.x, comp.y])]) if(comp[3] == name) [p.x, p.y]][index];
module pcb_component_position(type, name) { //! Position child at the specified component position
for(comp = pcb_components(type)) {
p = pcb_coord(type, [comp.x, comp.y]);
if(comp[3][0] == "-") {
if(comp[3] == str("-", name))
translate([p.x, p.y])
vflip()
children();
}
else
if(comp[3] == name)
translate([p.x, p.y, pcb_thickness(type)])
children();
}
}
module pcb_components(type, cutouts = false, angle = undef) { //! Draw list of PCB components on the PCB
not_on_bom(pcb_parts_on_bom(type))
for(comp = pcb_components(type)) {
p = pcb_coord(type, [comp.x, comp.y]);
if(comp[3][0] == "-")
translate([p.x, p.y])
vflip()
pcb_component(comp, cutouts, angle);
else
translate([p.x, p.y, pcb_thickness(type)])
pcb_component(comp, cutouts, angle);
}
}
module pcb_grid_components(type, components, cutouts = false, angle = undef) //! Draw list of components on the PCB grid for perf board
for(comp = components) {
p = pcb_grid_pos(type, comp.x, comp.y);
if(comp[3][0] == "-")
translate([p.x, p.y])
vflip()
pcb_component(comp, cutouts, angle);
else
translate([p.x, p.y, pcb_thickness(type)])
pcb_component(comp, cutouts, angle);
}
module pcb_cutouts(type, angle = undef) pcb_components(type, true, angle); //! Make cut outs to clear components on a PCB
module pcb_grid_positions(type) {
grid = pcb_grid(type);
x0 = grid.x;
y0 = grid.y;
cols = is_undef(grid[2]) ? round((pcb_length(type) - 2 * x0) / inch(0.1)) : grid[2] - 1;
rows = is_undef(grid[3]) ? round((pcb_width(type) - 2 * y0) / inch(0.1)) : grid[3] - 1;
for(x = [0 : cols], y = [0 : rows])
pcb_grid(type, x, y)
children();
}
module pcb(type) { //! Draw specified PCB
grid = pcb_grid(type);
t = pcb_thickness(type);
w = pcb_width(type);
l = pcb_length(type);
module pcb_shape()
if(Len(pcb_polygon(type)))
polygon(pcb_polygon(type));
else
rounded_square([l, w], r = pcb_radius(type));
if(pcb_name(type))
vitamin(str("pcb(", type[0], "): ", pcb_name(type)));
for(part = pcb_accessories(type))
vitamin(part);
color(pcb_colour(type))
linear_extrude(t)
difference() {
pcb_shape();
pcb_hole_positions(type)
offset(eps)
circle4n(d = pcb_hole_d(type));
if(Len(grid))
pcb_grid_positions(type)
circle(d = 1 + eps);
}
land = pcb_land_d(type);
land_r = Len(land) > 2 ? land[2] : 0;
hole = pcb_hole_d(type);
plating = 0.1;
color(Len(land) > 3 ? land[3] : silver)
translate_z(t / 2)
linear_extrude(t + 2 * plating, center = true)
difference() {
intersection() {
pcb_hole_positions(type)
if(is_list(land)) {
p = pcb_holes(type)[$i]; // If edge SMT pad then make it rectangular to overlap without gaps
edge = abs(p.x) < eps || abs(p.x - l) < eps || abs(p.y) < eps || abs(p.y - w) < eps;
rounded_square([land.x, land.y], edge ? 0 : land_r);
}
else
circle(d = max(land, 1));
offset(eps)
pcb_shape(); // Handle half holes on the edge of PCBs such as ESP8266
}
pcb_hole_positions(type)
circle4n(d = hole);
}
fr4 = pcb_colour(type) != "sienna";
pcb_colour = pcb_colour(type);
plating_colour = is_undef(grid[4]) ? ((pcb_colour == "green" || pcb_colour == "#2140BE") ? silver : pcb_colour == "sienna" ? copper : gold) : grid[4];
color(plating_colour)
translate_z(-plating)
linear_extrude(fr4 ? t + 2 * plating : plating)
if(Len(grid)) {
pcb_grid_positions(type)
difference() {
circle(d = 2);
circle(d = 1);
}
if(fr4 && len(grid) < 3 && pcb_holes(type)) { // oval lands at the ends
screw_x = pcb_coord(type, pcb_holes(type)[0]).x;
y0 = pcb_grid(type).y;
rows = round((pcb_width(type) - 2 * y0) / inch(0.1));
for(end = [-1, 1], y = [1 : rows - 1])
translate([end * screw_x, y0 + y * inch(0.1) - pcb_width(type) / 2])
hull()
for(x = [-1, 1])
translate([x * 1.6 / 2, 0])
circle(d = 2);
}
}
pcb_components(type);
}
module pcb_spacer(screw, height, wall = 1.8, taper = 0) { //! Generate STL for PCB spacer
stl(str("pcb_spacer", round(screw_radius(screw) * 20), round(height * 10), taper ? str("_", taper) : ""));
ir = screw_clearance_radius(screw);
or = corrected_radius(ir) + wall;
if(height > taper)
linear_extrude(height - taper)
poly_ring(or, ir);
if(taper)
linear_extrude(height)
poly_ring(ir + 2 * extrusion_width, ir);
}
module pcb_base(type, height, thickness, wall = 2) { //! Generate STL for a base with PCB spacers
screw = pcb_screw(type);
ir = screw_clearance_radius(screw);
or = corrected_radius(ir) + wall;
union() {
linear_extrude(thickness)
difference() {
hull()
pcb_screw_positions(type)
poly_ring(or, ir);
pcb_screw_positions(type)
poly_circle(ir);
}
linear_extrude(height)
pcb_screw_positions(type)
poly_ring(or, ir);
}
}
module pcb_assembly(type, height, thickness) { //! Draw PCB assembly with spaces and fasteners in place
translate_z(height)
pcb(type);
screw = pcb_screw(type);
if(!is_undef(screw)) {
screw_length = screw_length(screw, height + thickness + pcb_thickness(type), 1, nyloc = true);
taper = screw_smaller_than(pcb_hole_d(type)) > 2 * screw_radius(screw); // Arduino?
pcb_screw_positions(type) {
translate_z(height + pcb_thickness(type))
screw(screw, screw_length);
stl_colour(pp1_colour)
if(taper)
pcb_spacer(screw, height, taper = 2);
else
pcb_spacer(screw, height);
translate_z(-thickness)
vflip()
nut_and_washer(screw_nut(screw), true);
}
}
}