Skip to content

Instantly share code, notes, and snippets.

@nophead
Created June 28, 2020 11:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nophead/d148f2ec63454c9e8e36a14b3e4ccb69 to your computer and use it in GitHub Desktop.
Save nophead/d148f2ec63454c9e8e36a14b3e4ccb69 to your computer and use it in GitHub Desktop.
//
//! 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