From 7f78ee2745614bdf5db67f6d9bbccbe460b8186b Mon Sep 17 00:00:00 2001 From: Scott Worley Date: Sat, 7 Oct 2023 01:18:21 -0700 Subject: [PATCH] housing: Start --- housing/cherryVoid.scad | 51 +++++++++++++++ housing/roundedCube.scad | 114 ++++++++++++++++++++++++++++++++++ housing/tattlekey.scad | 130 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 295 insertions(+) create mode 100644 housing/cherryVoid.scad create mode 100644 housing/roundedCube.scad create mode 100644 housing/tattlekey.scad diff --git a/housing/cherryVoid.scad b/housing/cherryVoid.scad new file mode 100644 index 0000000..419af34 --- /dev/null +++ b/housing/cherryVoid.scad @@ -0,0 +1,51 @@ +// Retrieved from https://www.thingiverse.com/thing:4120804 + +// Riskable's Cherry MX void/cutout module for making keyboard (top) plates and key switch testers + +$fn = 32; + +use // Because it's nice to have rounded corners on these sorts of things + +// AUTHOR: Riskable +// VERSION: 1.1 (Changelog is at the bottom) +// LICENSE: Creative Commons - Attribution - Non-Commercial (if you want to use it in a commercial setting/product just ask!) + +// NOTES +/* + * Feel free to use this .scad in your own projects to add proper Cherry MX-styled switch cutouts to keyboards, perhipherals, testers, or whatever you like. + * You can just copy cherry_switch_void() into your own code if you like--it's entirely self-contained and reasonably small. Just make sure to credit, "This module was written by Riskable:" or something like that =) +*/ + +/* Creates the shape of a (proper) Cherry MX switch hole. + height: The thickness, really. Doesn't impact PLATE_THICKNESS + x_extra: Extra (void) space on the X axis (e.g. to save some plastic). Doesn't change the top plate. + y_extra: Extra (void) space on the Y axis. Same thing as X. + tolerance: Extra room on all sides (0.1 default should be good for most printers) + plate_thickness: How thick the top plate will be. Typical Cherry MX plates are about 1.5mm thick. +*/ +module cherry_switch_void(height=12, x_extra=0, y_extra=0, tolerance=0.1, plate_thickness=1.5, corner_radius=0.5) { // Cherry MX body is supposed to be 11.6mm + switch_width = 15.6; + switch_length = 14; // Slightly shorter because we're making an acurate profile (see below) + center_space = 3.5; // Space between the cutouts on the sides of the switch + sides_width = (5+center_space); // Taken from the Cherry MX developer PDF + // Make the basic switch shape: + cube( + [switch_length+tolerance, switch_length+tolerance, height], + center=true); + // Profile for the sides: + translate([0,sides_width/2,0]) + cube([switch_width-tolerance, center_space+tolerance, height], center=true); + translate([0,-sides_width/2,0]) + cube([switch_width-tolerance,center_space+tolerance, height], center=true); + // Fill out the rest with a solid cube so that there's a top plate + empty space beneath + translate([0,0,plate_thickness]) + roundedCube( + [switch_width+x_extra, switch_width+y_extra, height], + r=corner_radius, center=true); +} + +/* +CHANGELOG: + 1.1: Now using roundedCube so the interior edges aren't so sharp. + 1.0: Initial release +*/ diff --git a/housing/roundedCube.scad b/housing/roundedCube.scad new file mode 100644 index 0000000..262665d --- /dev/null +++ b/housing/roundedCube.scad @@ -0,0 +1,114 @@ +// Retrieved from https://www.thingiverse.com/thing:4120804 + +/* + roundedCube() v1.0.3 by robert@cosmicrealms.com from https://github.com/Sembiance/openscad-modules + Allows you to round any edge of a cube + + Usage + ===== + Prototype: roundedCube(dim, r, x, y, z, xcorners, ycorners, zcorners, $fn) + Arguments: + - dim = Array of x,y,z numbers representing cube size + - r = Radius of corners. Default: 1 + - x = Round the corners along the X axis of the cube. Default: false + - y = Round the corners along the Y axis of the cube. Default: false + - z = Round the corners along the Z axis of the cube. Default: true + - xcorners = Array of 4 booleans, one for each X side of the cube, if true then round that side. Default: [true, true, true, true] + - ycorners = Array of 4 booleans, one for each Y side of the cube, if true then round that side. Default: [true, true, true, true] + - zcorners = Array of 4 booleans, one for each Z side of the cube, if true then round that side. Default: [true, true, true, true] + - rx = Radius of the x corners. Default: [r, r, r, r] + - ry = Radius of the y corners. Default: [r, r, r, r] + - rz = Radius of the z corners. Default: [r, r, r, r] + - center = Whether to render the cube centered or not. Default: false + - $fn = How smooth you want the rounding to be. Default: 128 + + Change Log + ========== + 2018-08-21: v1.0.3 - Added ability to set the radius of each corner individually with vectors: rx, ry, rz + 2017-05-15: v1.0.2 - Fixed bugs relating to rounding corners on the X axis + 2017-04-22: v1.0.1 - Added center option + 2017-01-04: v1.0.0 - Initial Release + + Thanks to Sergio Vilches for the initial code inspiration +*/ + +// Example code: + +/*cube([5, 10, 4]); + +translate([8, 0, 0]) { roundedCube([5, 10, 4], r=1); } +translate([16, 0, 0]) { roundedCube([5, 10, 4], r=1, zcorners=[true, false, true, false]); } + +translate([24, 0, 0]) { roundedCube([5, 10, 4], r=1, y=true, z=false); } +translate([32, 0, 0]) { roundedCube([5, 10, 4], r=1, x=true, z=false); } +translate([40, 0, 0]) { roundedCube([5, 10, 4], r=1, x=true, y=true, z=true); } +*/ + +module roundedCube(dim, r=1, x=false, y=false, z=true, xcorners=[true,true,true,true], ycorners=[true,true,true,true], zcorners=[true,true,true,true], center=false, rx=[undef, undef, undef, undef], ry=[undef, undef, undef, undef], rz=[undef, undef, undef, undef], $fn=128) +{ + translate([(center==true ? (-(dim[0]/2)) : 0), (center==true ? (-(dim[1]/2)) : 0), (center==true ? (-(dim[2]/2)) : 0)]) + { + difference() + { + cube(dim); + + if(z) + { + translate([0, 0, -0.1]) + { + if(zcorners[0]) + translate([0, dim[1]-(rz[0]==undef ? r : rz[0])]) { rotateAround([0, 0, 90], [(rz[0]==undef ? r : rz[0])/2, (rz[0]==undef ? r : rz[0])/2, 0]) { meniscus(h=dim[2], r=(rz[0]==undef ? r : rz[0]), fn=$fn); } } + if(zcorners[1]) + translate([dim[0]-(rz[1]==undef ? r : rz[1]), dim[1]-(rz[1]==undef ? r : rz[1])]) { meniscus(h=dim[2], r=(rz[1]==undef ? r : rz[1]), fn=$fn); } + if(zcorners[2]) + translate([dim[0]-(rz[2]==undef ? r : rz[2]), 0]) { rotateAround([0, 0, -90], [(rz[2]==undef ? r : rz[2])/2, (rz[2]==undef ? r : rz[2])/2, 0]) { meniscus(h=dim[2], r=(rz[2]==undef ? r : rz[2]), fn=$fn); } } + if(zcorners[3]) + rotateAround([0, 0, -180], [(rz[3]==undef ? r : rz[3])/2, (rz[3]==undef ? r : rz[3])/2, 0]) { meniscus(h=dim[2], r=(rz[3]==undef ? r : rz[3]), fn=$fn); } + } + } + + if(y) + { + translate([0, -0.1, 0]) + { + if(ycorners[0]) + translate([0, 0, dim[2]-(ry[0]==undef ? r : ry[0])]) { rotateAround([0, 180, 0], [(ry[0]==undef ? r : ry[0])/2, 0, (ry[0]==undef ? r : ry[0])/2]) { rotateAround([-90, 0, 0], [0, (ry[0]==undef ? r : ry[0])/2, (ry[0]==undef ? r : ry[0])/2]) { meniscus(h=dim[1], r=(ry[0]==undef ? r : ry[0])); } } } + if(ycorners[1]) + translate([dim[0]-(ry[1]==undef ? r : ry[1]), 0, dim[2]-(ry[1]==undef ? r : ry[1])]) { rotateAround([0, -90, 0], [(ry[1]==undef ? r : ry[1])/2, 0, (ry[1]==undef ? r : ry[1])/2]) { rotateAround([-90, 0, 0], [0, (ry[1]==undef ? r : ry[1])/2, (ry[1]==undef ? r : ry[1])/2]) { meniscus(h=dim[1], r=(ry[1]==undef ? r : ry[1])); } } } + if(ycorners[2]) + translate([dim[0]-(ry[2]==undef ? r : ry[2]), 0]) { rotateAround([-90, 0, 0], [0, (ry[2]==undef ? r : ry[2])/2, (ry[2]==undef ? r : ry[2])/2]) { meniscus(h=dim[1], r=(ry[2]==undef ? r : ry[2])); } } + if(ycorners[3]) + rotateAround([0, 90, 0], [(ry[3]==undef ? r : ry[3])/2, 0, (ry[3]==undef ? r : ry[3])/2]) { rotateAround([-90, 0, 0], [0, (ry[3]==undef ? r : ry[3])/2, (ry[3]==undef ? r : ry[3])/2]) { meniscus(h=dim[1], r=(ry[3]==undef ? r : ry[3])); } } + } + } + + if(x) + { + translate([-0.1, 0, 0]) + { + if(xcorners[0]) + translate([0, dim[1]-(rx[0]==undef ? r : rx[0])]) { rotateAround([0, 90, 0], [(rx[0]==undef ? r : rx[0])/2, 0, (rx[0]==undef ? r : rx[0])/2]) { meniscus(h=dim[0], r=(rx[0]==undef ? r : rx[0])); } } + if(xcorners[1]) + translate([0, dim[1]-(rx[1]==undef ? r : rx[1]), dim[2]-(rx[1]==undef ? r : rx[1])]) { rotateAround([90, 0, 0], [0, (rx[1]==undef ? r : rx[1])/2, (rx[1]==undef ? r : rx[1])/2]) { rotateAround([0, 90, 0], [(rx[1]==undef ? r : rx[1])/2, 0, (rx[1]==undef ? r : rx[1])/2]) { meniscus(h=dim[0], r=(rx[1]==undef ? r : rx[1])); } } } + if(xcorners[2]) + translate([0, 0, dim[2]-(rx[2]==undef ? r : rx[2])]) { rotateAround([180, 0, 0], [0, (rx[2]==undef ? r : rx[2])/2, (rx[2]==undef ? r : rx[2])/2]) { rotateAround([0, 90, 0], [(rx[2]==undef ? r : rx[2])/2, 0, (rx[2]==undef ? r : rx[2])/2]) { meniscus(h=dim[0], r=(rx[2]==undef ? r : rx[2])); } } } + if(xcorners[3]) + rotateAround([-90, 0, 0], [0, (rx[3]==undef ? r : rx[3])/2, (rx[3]==undef ? r : rx[3])/2]) { rotateAround([0, 90, 0], [(rx[3]==undef ? r : rx[3])/2, 0, (rx[3]==undef ? r : rx[3])/2]) { meniscus(h=dim[0], r=(rx[3]==undef ? r : rx[3])); } } + } + } + } + } +} + +module meniscus(h, r, fn=128) +{ + $fn=fn; + + difference() + { + cube([r+0.2, r+0.2, h+0.2]); + translate([0, 0, -0.1]) { cylinder(h=h+0.4, r=r); } + } +} + +module rotateAround(a, v) { translate(v) { rotate(a) { translate(-v) { children(); } } } } diff --git a/housing/tattlekey.scad b/housing/tattlekey.scad new file mode 100644 index 0000000..f117e27 --- /dev/null +++ b/housing/tattlekey.scad @@ -0,0 +1,130 @@ +use + +key_interface_size = 19; +key_interface_corner_r = 5; + +housing_inner_h = 10; // Chosen to let board fit inside +housing_inner_w = 21; + +thickness = 1.7; + +wiring_l = 12; + +pico_board_l = 51.0; +pico_board_w = 21.0; +pico_total_h = 3.7; + +$fs = .1; +$fa = 6; + +slop = 128; +epsilon = 1/64; + +module pico_hole(d, x, y) { + translate([x, y, -slop/2]) + cylinder(h=slop, d = d); +} + +module pico_w(hole_d = 2.1) { + board_l = pico_board_l; + board_w = pico_board_w; + board_h = 1.0; + + hole_x1 = 2.0; + hole_x2 = board_l - 2.0; + hole_y_spacing = 11.4; + hole_y = (board_w - hole_y_spacing)/2; + + difference() { + color("green") + cube([board_l, board_w, board_h]); + + pico_hole(hole_d, hole_x1, hole_y); + pico_hole(hole_d, hole_x2, hole_y); + pico_hole(hole_d, hole_x1, hole_y + hole_y_spacing); + pico_hole(hole_d, hole_x2, hole_y + hole_y_spacing); + + } + + total_l = 52.3; + total_h = pico_total_h; + usb_w = 8.0; + usb_l = 5.6; + usb_h = 3.0; + color("lightgray") + translate([board_l - total_l, (board_w-usb_w)/2, total_h-usb_h]) + cube([usb_l, usb_w, usb_h]); + + button_l = 4.2; + button_w = 3.4; + button_h = 3.5; + button_x = 9.9; + button_y = 5.2; + color("white") + translate([button_x, button_y, epsilon]) + cube([button_l, button_w, button_h]); + + wifi_l = 10.0; + wifi_w = 12.0; + wifi_h = 2.8; + wifi_x = 33.0; + color("lightgray") + translate([wifi_x, (board_w-wifi_w)/2, epsilon]) + cube([wifi_l, wifi_w, wifi_h]); +} + +module at_key() { + translate([pico_board_l + wiring_l, 0, 0]) + rotate([45, 0, 0]) + rotate([0, 90, 0]) + children(); +} + +module key_interface_shape(thick = thickness) { + inner = key_interface_size - 2*key_interface_corner_r; + linear_extrude(thick) + minkowski() { + square([inner, inner], center=true); + circle(r=key_interface_corner_r); + } +} + +module key_interface() { + at_key() + difference() { + key_interface_shape(); + + #translate([0, 0, 6 - epsilon]) + cherry_switch_void(); + } +} + +module housing(length = pico_board_l) { + inner_squish = housing_inner_h / housing_inner_w; + housing_outer_w = housing_inner_w + 2 * thickness; + housing_outer_h = housing_inner_h + 2 * thickness; + outer_squish = housing_outer_h / housing_outer_w; + rotate([90, 0, 0]) + rotate([0, 90, 0]) + linear_extrude(length) + difference() { + scale([1, outer_squish]) + circle(d = housing_outer_w); + scale([1, inner_squish]) + circle(d = housing_inner_w); + } +} + +/* +!union() {housing(); hull() { + at_key() key_interface_shape(epsilon); + translate([pico_board_l-wiring_l, 0, 0]) + housing(wiring_l); +}} +*/ + +translate([0, -pico_board_w/2, -1]) +pico_w(hole_d = 2); + +key_interface(); +housing(); -- 2.44.1