Created
June 28, 2020 11:55
-
-
Save nophead/d148f2ec63454c9e8e36a14b3e4ccb69 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
//! Arduino thermostat to control a beer fridge to use it as an environmental chamber. | |
// | |
// GNU GPL v2 | |
// nop.head@gmail.com | |
// hydraraptor.blogspot.com | |
// | |
// Top level model | |
// | |
$pp1_colour = "grey"; | |
$pp2_colour = "white"; | |
$extrusion_width = 0.5; | |
include <NopSCADlib/lib.scad> | |
use <NopSCADlib/printed/foot.scad> | |
use <NopSCADlib/printed/printed_box.scad> | |
iec = IEC_inlet_atx; | |
iec2 = IEC_outlet; | |
lcd = LCD1602A; | |
switch_pcb = PERF80x20; | |
tx = SMALLTX; | |
arduino = ArduinoUno3; | |
expansion = Keyes5p1; | |
lcd_pcb = display_pcb(lcd); | |
foot = Foot(d = 13, h = 5, t = 2, r = 1, screw = M3_dome_screw); | |
module foot_stl() foot(foot); | |
base_overlap = 2; | |
height_overlap = 1; | |
base_outset = 1; | |
base_thickness = 2; | |
base_screw = foot_screw(foot); | |
base_insert = screw_insert(base_screw); | |
base_boss_r = insert_hole_radius(base_insert) + 2; | |
base_washer = screw_washer(base_screw); | |
base_screw_used = base_thickness + washer_thickness(base_washer) + insert_length(base_insert) + foot_thickness(foot); | |
base_screw_length = screw_shorter_than(base_screw_used); | |
base_screw_overlap = max(0, base_screw_length - base_screw_used) + 0.5; | |
base_boss_h = insert_length(base_insert) + base_screw_overlap; | |
top_thickness = 2; | |
partition_t = 2; | |
tx_screw = tx_screw(tx); | |
tx_insert = screw_insert(tx_screw); | |
tx_washer = screw_washer(tx_screw); | |
tx_screw_length = screw_shorter_than(tx_foot_thickness(tx) + 2 * washer_thickness(tx_washer) + insert_length(tx_insert) + 1); | |
tx_z = insert_length(tx_insert) + 1.5; | |
thermo_width = 15.5; | |
thermo_length = 54; | |
thermo_height = 15.5; | |
case_inner_rad = 6; | |
case_width = 1 + tx_foot_width(tx) / 2 + tx_bobbin_width(tx) / 2 + iec_width(iec) + case_inner_rad; | |
case_depth = thermo_width + 2 + pcb_width(switch_pcb) + 2 + pcb_width(lcd_pcb) + 2 + partition_t + 3 + tx_depth(tx) + 3; | |
case_height = 50; | |
case_wall = 2; | |
echo(case_width = case_width, case_depth = case_depth, case_height = case_height); | |
tx_x = -case_width / 2 + tx_foot_width(tx) / 2 + 1; | |
tx_y = case_depth / 2 - 3 - tx_depth(tx) / 2; | |
wire_hole_x = -case_width / 2 + 7.5; | |
wire_hole_z = top_thickness + 15; | |
wire_hole_d = 5; | |
thermo_y = -case_depth / 2 + thermo_width / 2; | |
thermo_z = top_thickness + thermo_height / 2; | |
switch_screw = pcb_screw(switch_pcb); | |
switch_washer = screw_washer(switch_screw); | |
switch_insert = screw_insert(switch_screw); | |
switch_screw_length = 6; | |
switch_positions = [[2.5, 3, "yellow"], [9.5, 3, "yellow"], [17.5, 3, "red"], [24.5, 3, "red"]]; | |
switch_x = -case_width / 2 + 2 + pcb_length(switch_pcb) / 2; | |
switch_y = thermo_y + thermo_width / 2 + pcb_width(switch_pcb) / 2 + 2; | |
switch_z = 12.5 - pcb_thickness(switch_pcb); | |
switch = button_12mm; | |
thermo_x = switch_x; | |
lcd_x = switch_x; | |
lcd_y = switch_y + pcb_width(switch_pcb) / 2 + 2 + pcb_width(lcd_pcb) / 2; | |
lcd_z = 1; | |
lcd_screw = pcb_screw(lcd_pcb, hs_pan); | |
lcd_insert = screw_insert(lcd_screw); | |
lcd_screw_length = screw_shorter_than(pcb_thickness(lcd_pcb) + insert_length(lcd_insert)); | |
partition_y = lcd_y + pcb_width(lcd_pcb) / 2 + 2 + partition_t / 2; | |
iec_x = tx_x + tx_bobbin_width(tx) / 2 + iec_width(iec) / 2; | |
iec_y = case_depth / 2 + case_wall; | |
iec_z = top_thickness + iec_body_h(iec) / 2 + 1; | |
iec2_z = iec_z + iec_flange_h(iec) / 2 + 1 + iec_flange_h(iec2) / 2; | |
iec_insert = screw_insert(iec_screw(iec)); | |
ssr_length = 44; | |
ssr_depth = 11; | |
ssr_height = 26; | |
ssr_pin_l = 7; | |
ssr_pin_d = 1; | |
ssr_pin_y = ssr_depth / 2 - 1.5; | |
ssr_pins = [2, 4, 9, 13]; | |
ssr_x = case_width / 2 - ssr_depth / 2 - base_outset; | |
ssr_y = partition_y -inch(0.1) * ((ssr_pins[1] + ssr_pins[2]) / 2 - 8); | |
ssr_z = top_thickness + ssr_height / 2; | |
ssr_wall = 1.6; | |
ssr_clearance = 0.2; | |
fence_t = 1; | |
fence_h = case_height - ssr_height; | |
arduino_screw = pcb_screw(arduino); | |
arduino_insert = screw_insert(arduino_screw); | |
arduino_screw_length = screw_shorter_than(pcb_thickness(arduino) + insert_length(arduino_insert)); | |
arduino_x = -case_width / 2 - case_wall + 7 + pcb_length(arduino) / 2 ; | |
arduino_y = thermo_y + thermo_width / 2 + pcb_width(arduino) / 2 + 2; | |
arduino_z = case_height + top_thickness - insert_length(arduino_insert); | |
expansion_z = arduino_z + 12.65; | |
thermo_socket_width = 16; | |
thermo_socket_width2 = 18; | |
thermo_socket_depth = 8; | |
thermo_socket_height = 26; | |
thermo_socket_screw_z = 23; | |
thermo_socket_screw_pitch = 12; | |
thermo_socket_screw = M2_cap_screw; // actually 8BA. | |
thermo_socket_x = case_width / 2 - thermo_socket_width2 / 2; | |
thermo_socket_y = -case_depth / 2 + case_inner_rad + thermo_socket_depth / 2; | |
thermo_socket_z = thermo_socket_height / 2; | |
thermo_socket_wall = 2.5; | |
power_jack_depth = 9; | |
power_jack_width = 22.8; | |
power_jack_width2 = 11; | |
power_jack_height = 11.38; | |
power_jack_t = 2; | |
power_jack_hole_pitch = 17.925; | |
power_jack_hole_d = 2.3; | |
power_jack_r = 1.5; | |
power_jack_bore = 6.2; | |
power_jack_pin_d = 2; | |
power_jack_screw = M2_cap_screw; | |
power_jack_insert = screw_insert(power_jack_screw); | |
power_jack_washer = screw_washer(power_jack_screw); | |
power_jack_screw_length = screw_shorter_than(washer_thickness(power_jack_washer) + power_jack_t + insert_length(power_jack_insert)); | |
power_jack_x = thermo_socket_x; | |
power_jack_y = switch_y + inch(0.05); // line up with the buttons for aesthetics but a bit close for inserting the insert. | |
power_jack_z = round_to_layer(top_thickness + insert_length(power_jack_insert)); | |
power_plug_d = 8.3; | |
power_plug_h = 2; | |
module power_jack_holes() | |
for(side = [-1, 1]) | |
translate([side * power_jack_hole_pitch / 2, 0]) | |
children(); | |
module power_jack() { | |
vitamin("PWRSOCK: 6mm panel mount barrel jack socket"); | |
d = power_jack_depth; | |
h = power_jack_height; | |
b = power_jack_bore; | |
pin_d = power_jack_pin_d; | |
contact_d = 3; | |
contact_w = 4; | |
contact_t = 0.2; | |
inset = 0.5; | |
color(grey(20)) render() difference() { | |
union() { | |
rounded_rectangle([power_jack_width, d, power_jack_t], r = power_jack_r, center = false); | |
hull() { | |
cylinder(d = d, h = h); | |
translate([0, -d / 2]) | |
cube([power_jack_width2 - d / 2, d, h]); | |
} | |
} | |
hull() { | |
cylinder(d = b, h = h - 1); | |
translate([0, -b / 2]) | |
cube([power_jack_width2 - (d - b) - b / 2, b, h - 1]); | |
} | |
power_jack_holes() | |
cylinder(d = power_jack_hole_d, h = 100, center = true); | |
} | |
color("silver") render() { | |
hull() { | |
translate_z(pin_d / 2 + inset) | |
sphere(pin_d / 2); | |
translate_z(h - 1) | |
cylinder(d = pin_d, h = eps); | |
} | |
difference() { | |
hull() | |
translate([b / 2 + contact_d / 2 - 1, 0, contact_d / 2 + inset]) { | |
rotate([90, 0, 0]) | |
cylinder(d = contact_d, h = contact_w, center = true); | |
translate_z(h - 1 - inset - contact_d / 2) | |
cube([contact_d + 1, contact_w, eps], center = true); | |
} | |
hull() | |
translate([b / 2 + contact_d / 2 - 1, 0, contact_d / 2 + inset]) { | |
rotate([90, 0, 0]) | |
cylinder(d = contact_d - 2 * contact_t, h = contact_w, center = true); | |
translate_z(h - 1 - inset - contact_d / 2) | |
cube([contact_d + 1 - 2 * contact_t, contact_w + 1, 2 * eps], center = true); | |
} | |
} | |
} | |
} | |
module ssr() { | |
vitamin("SMT20004: SMT 2000/4 Solid state relay"); | |
color(grey(20)) render() | |
cube([ssr_length, ssr_depth, ssr_height], center = true); | |
color("silver") render() | |
for(i = [0 : 16]) | |
if(in(ssr_pins, i)) | |
translate([i * inch(0.1) - inch(0.8), ssr_pin_y, -ssr_height / 2 - ssr_pin_l]) | |
cylinder(d = ssr_pin_d, h = ssr_pin_l); | |
} | |
module thermo_socket_holes() { | |
for(side = [-1, 1]) | |
translate([side * thermo_socket_screw_pitch / 2, 0, thermo_socket_screw_z -thermo_socket_height / 2]) | |
rotate([90, 0, 180]) | |
children(); | |
} | |
module thermo_socket() { | |
vitamin("THRMSKT: Thermocouple socket"); | |
pin_pitch = 7.9; | |
pin_t = 0.8; | |
pin_w1 = 3.1; | |
pin_w2 = 2.3; | |
pin_l = 12.7; | |
insert = screw_insert(thermo_socket_screw); | |
color("yellow") render() difference() { | |
union() { | |
cube([thermo_socket_width, thermo_socket_depth, thermo_socket_height], center = true); | |
translate_z(-thermo_socket_height / 2 + 2.5) | |
cube([thermo_socket_width2, thermo_socket_depth, 1], center = true); | |
translate_z(thermo_socket_screw_z -thermo_socket_height / 2) | |
rotate([90, 0, 0]) | |
rounded_rectangle([thermo_socket_width2, 6, thermo_socket_depth], 1, center = true); | |
} | |
thermo_socket_holes() | |
cylinder(r = screw_clearance_radius(thermo_socket_screw), h = 100, center = true); | |
for(side = [-1, 1]) | |
translate([side * pin_pitch / 2, 0, - thermo_socket_height / 2]) | |
cube([side > 0 ? pin_w1 : pin_w2 + 0.2, pin_t + 0.2, pin_l * 2], center = true); | |
} | |
thermo_socket_holes() | |
translate_z(-thermo_socket_depth / 2 - eps) | |
not_on_bom() no_explode() vflip() insert(insert); | |
} | |
module switch_assembly() | |
assembly("switch") { | |
pcb(switch_pcb); | |
for(p = switch_positions) | |
pcb_grid(switch_pcb, p.x, p.y, - pcb_thickness(switch_pcb)) | |
vflip() | |
square_button(switch, p.z); | |
pcb_screw_positions(switch_pcb) | |
translate_z(pcb_thickness(switch_pcb)) | |
screw(switch_screw, switch_screw_length); | |
} | |
module case_additions() { | |
translate([switch_x, switch_y]) | |
pcb_screw_positions(switch_pcb) | |
insert_boss(switch_insert, switch_z, 1.7); | |
translate([lcd_x, lcd_y]) | |
pcb_screw_positions(lcd_pcb) | |
insert_boss(lcd_insert, display_thickness(lcd) + lcd_z, 1.5); | |
translate([0, partition_y]) | |
cube([case_width, partition_t, (case_height + top_thickness) * 2], center = true); | |
translate([tx_x, tx_y]) | |
rounded_rectangle([tx_foot_width(tx), tx_foot_depth(tx), tx_z ], 2, center = false); | |
translate([iec_x, iec_y]) | |
for(side = [-1, 1]) | |
translate([side * iec_pitch(iec) / 2, 0]) | |
cube([2 * (insert_hole_radius(iec_insert) + 2), | |
2 * (insert_hole_length(iec_insert) + 2), | |
2 * (iec2_z + insert_hole_radius(iec_insert) + 2)], center = true); | |
translate([ssr_x - ssr_depth / 2 - ssr_wall - ssr_clearance / 2, ssr_y - ssr_length / 2 - ssr_wall - ssr_clearance / 2, 0]) | |
cube([100, ssr_length + 2 * ssr_wall + ssr_clearance, ssr_z]); | |
translate([thermo_socket_x - thermo_socket_width2 / 2 + 50, thermo_socket_y + thermo_socket_depth / 2 + thermo_socket_wall / 2, thermo_socket_z]) | |
cube([100, thermo_socket_wall, thermo_socket_height], center = true); | |
translate([power_jack_x, power_jack_y]) { | |
cylinder(d = power_plug_d + 2 * case_wall, h = power_jack_z); | |
rotate(90) | |
power_jack_holes() | |
insert_boss(power_jack_insert, power_jack_z, 1.8); | |
} | |
} | |
module case_holes() { | |
translate([switch_x, switch_y, switch_z]) { | |
pcb_screw_positions(switch_pcb) | |
insert_hole(switch_insert, switch_z - insert_hole_length(switch_insert) - 0.5); | |
for(p = switch_positions) | |
pcb_grid(switch_pcb, p.x, p.y, - pcb_thickness(switch_pcb)) { | |
poly_cylinder(r = square_button_cap_d(switch) / 2 + 0.25, h = 100, center = true); | |
h = square_button_h(switch) + square_button_cap_stem(switch) + square_button_cap_flange_h(switch) + 0.25; | |
poly_cylinder(r = square_button_cap_flange_d(switch) / 2 + 0.25, h = 2 * h, center = true); | |
} | |
} | |
translate([lcd_x, lcd_y, lcd_z]) { | |
display_aperture(lcd, 0.1); | |
translate([0, 0, display_thickness(lcd)] + display_pcb_offset(lcd)) | |
pcb_screw_positions(lcd_pcb) | |
insert_hole(lcd_insert, lcd_z + display_thickness(lcd) - insert_hole_length(lcd_insert) - 0.5); | |
} | |
translate([tx_x, tx_y, tx_z]) | |
transformer_hole_positions(tx) | |
insert_hole(tx_insert, tx_z - insert_hole_length(tx_insert) - 0.5); | |
translate([wire_hole_x, partition_y, wire_hole_z]) | |
rotate([90, 0, 0]) | |
teardrop_plus(r = wire_hole_d / 2, h = partition_t + 1); | |
translate([iec_x, iec_y, iec_z]) | |
rotate([-90, 180, 0]) | |
iec_holes(iec, h = 20, horizontal = true, insert = true); | |
translate([iec_x, iec_y, iec2_z]) | |
rotate([-90, 180, 0]) | |
iec_holes(iec2, h = 20, horizontal = true, insert = true); | |
translate([arduino_x, arduino_y, arduino_z]) | |
vflip() | |
clip(zmax = 20) pcb_cutouts(arduino); | |
translate([thermo_socket_x - 0.1, thermo_socket_y - 0.05 ]) | |
cube([thermo_socket_width + 0.2, thermo_socket_depth + 0.1, 80], center = true); | |
translate([thermo_socket_x, thermo_socket_y, thermo_socket_z]) | |
thermo_socket_holes() | |
teardrop_plus(r = screw_clearance_radius(thermo_socket_screw), h = thermo_socket_depth + 2 * thermo_socket_wall + 1); | |
translate([ssr_x, ssr_y, ssr_z - ssr_height / 2 + 50]) | |
cube([ssr_depth + ssr_clearance, ssr_length + ssr_clearance, 100], center = true); | |
for(side = [-1, 1]) | |
translate([case_width / 2 - 5, partition_y + side * (partition_t / 2 + (fence_t + 1) / 2), case_height + top_thickness]) | |
cube([10, fence_t + 1, 20], center = true); | |
translate([power_jack_x, power_jack_y]) | |
hanging_hole(power_jack_z - power_plug_h, power_jack_bore / 2) | |
poly_circle(power_plug_d / 2 + 0.2); | |
} | |
module fence_stl() { | |
stl("fence"); | |
w1 = ssr_depth; | |
t1 = partition_t; | |
w2 = w1 + 2 - 0.2; | |
t = partition_t + 2 * fence_t + 0.2; | |
linear_extrude(height = fence_h - layer_height) | |
difference() { | |
square([w2, t], center = true); | |
for(side = [-1, 1]) | |
translate([side * w2 / 2, 0]) | |
square([w2 - w1, partition_t + 0.2], center = true); | |
} | |
} | |
module base_additions() { | |
translate([arduino_x, -arduino_y]) | |
pcb_screw_positions(arduino) { | |
insert_boss(arduino_insert, case_height + top_thickness + base_thickness - arduino_z); | |
insert_boss(arduino_insert, case_height + top_thickness + base_thickness - arduino_z - 2, 2); | |
} | |
} | |
module base_holes() { | |
} | |
box = pbox(name = "case", wall = case_wall, top_t = top_thickness, base_t = base_thickness, foot = foot, radius = case_inner_rad, size = [case_width, case_depth, case_height]); | |
module case_stl() pbox(box) { case_additions(); case_holes(); } | |
module case_base_stl() pbox_base(box) { base_additions(); base_holes(); } | |
module arduino_assembly() { | |
pcb(arduino); | |
pcb_screw_positions(arduino) | |
translate_z(pcb_thickness(arduino)) | |
screw(arduino_screw, arduino_screw_length); | |
explode(50) | |
translate_z(expansion_z - arduino_z) | |
pcb(expansion); | |
} | |
module base_inserts_assembly(alpha = 1) | |
assembly("base_inserts") { | |
translate([arduino_x, -arduino_y, case_height + top_thickness + base_thickness - arduino_z + eps]) | |
pcb_screw_positions(arduino) | |
insert(arduino_insert); | |
stl_colour(pp2_colour, alpha) render() case_base_stl(); | |
} | |
module base_assembly(alpha = 1) | |
assembly("base") { | |
translate([arduino_x, -arduino_y, case_height + top_thickness + base_thickness - arduino_z + eps]) | |
arduino_assembly(); | |
base_inserts_assembly(alpha = alpha); | |
} | |
module case_assembly() pose([26, 0, 164], [0, 0, 36]) | |
assembly("case") { | |
stl_colour(pp1_colour) render() case_stl(); | |
pbox_inserts(box); | |
translate([iec_x, iec_y, iec_z]) | |
rotate([-90, 0, 0]) | |
iec_inserts(iec); | |
translate([iec_x, iec_y, iec2_z]) | |
rotate([-90, 0, 0]) | |
iec_inserts(iec2); | |
translate([lcd_x, lcd_y, lcd_z]) | |
translate([0, 0, display_thickness(lcd)] + display_pcb_offset(lcd)) | |
pcb_screw_positions(lcd_pcb) | |
insert(lcd_insert); | |
translate([tx_x, tx_y, tx_z]) | |
transformer_hole_positions(tx) | |
insert(tx_insert); | |
translate([power_jack_x, power_jack_y, power_jack_z]) | |
rotate(90) | |
power_jack_holes() | |
insert(power_jack_insert); | |
translate([switch_x, switch_y, switch_z]) | |
pcb_screw_positions(switch_pcb) | |
insert(switch_insert); | |
} | |
module main_assembly() pose([230, 0, 315], exploded = false) | |
assembly("main") { | |
case_assembly(); | |
pbox_base_screws(box, base_thickness); | |
translate([switch_x, switch_y, switch_z]) | |
switch_assembly(); | |
translate([lcd_x, lcd_y, lcd_z]) { | |
display(lcd); | |
translate([0, 0, display_thickness(lcd)] + display_pcb_offset(lcd)) | |
pcb_screw_positions(lcd_pcb) | |
translate_z(pcb_thickness(lcd_pcb)) | |
screw(lcd_screw, lcd_screw_length); | |
} | |
translate([tx_x, tx_y, tx_z]) { | |
transformer(tx); | |
transformer_hole_positions(tx) | |
translate_z(tx_foot_thickness(tx)) | |
screw_and_washer(tx_screw, tx_screw_length, true); | |
} | |
translate([iec_x, iec_y, iec_z]) | |
rotate([-90, 0, 0]) | |
iec_assembly(iec, 0); | |
translate([iec_x, iec_y, iec2_z]) | |
rotate([-90, 0, 0]) | |
iec_assembly(iec2, 0); | |
translate([ssr_x, ssr_y, ssr_z]) | |
rotate([180, 0, 90]) | |
ssr(); | |
translate([ssr_x, partition_y, ssr_z + ssr_height / 2]) | |
fence_stl(); | |
translate([thermo_x, thermo_y, thermo_z]) | |
color("Ivory") cube([thermo_length, thermo_width, thermo_height], center = true); | |
translate([thermo_socket_x, thermo_socket_y, thermo_socket_z]) { | |
thermo_socket(); | |
thermo_socket_holes() | |
translate_z(thermo_socket_depth / 2 + thermo_socket_wall) | |
screw_and_washer(thermo_socket_screw, 12); | |
} | |
translate([power_jack_x, power_jack_y, power_jack_z]) | |
rotate(90) { | |
power_jack(); | |
power_jack_holes() | |
translate_z(power_jack_t) | |
screw_and_washer(power_jack_screw, power_jack_screw_length); | |
} | |
translate_z(case_height + top_thickness + base_thickness + eps) vflip() base_assembly(0.5); | |
} | |
if($preview) | |
main_assembly(); | |
else rotate(90) | |
if(1) { | |
case_stl(); | |
translate([lcd_x, lcd_y]) | |
fence_stl(); | |
} | |
else base_stl(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment