diff --git a/README.md b/README.md index f03a677..333776c 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Both standard motherboard adapters and cases can be generated with SBC Case Buil ### Rack Mount Case Adjustments Tab -Both 1U and 2U, 10" and 19", rack cases are configured in this tab. The first entry *rack width* selects if 10" or 19" rack cases are being created. The *rack size* sets wether 1U or 2U. The remaining tab is divided into six groups of settings each representing a virtual bay. Each bay group specifies the SBC thru the pickbox *Rack Bay1* respectively. With *rack bay1 xyz loc* and *rack bay1 rotation determining the position and z-axis rotation. The type of bay is set in the *rack bay1 face* pickbox followed by two checkboxes for the internal dividing wall, rear fan and a bay conduit selection pickbox. +Both 1U and 2U, 10" and 19", rack cases are configured in this tab. The first entry *rack width* selects if 10" or 19" rack cases are being created. The *rack size* sets wether 1U or 2U. There is a 2mm wall in front of every removable bay. *removable bay height* allows the tray height to be reduced to form an opening which allows for tray removal and venting when installed with other rack cases above. The remaining tab is divided into six groups of settings each representing a virtual bay. Each bay group specifies the SBC thru the pickbox *Rack Bay1* respectively. With *rack bay1 xyz loc* and *rack bay1 rotation determining the position and z-axis rotation. The type of bay is set in the *rack bay1 face* pickbox followed by two checkboxes for the internal dividing wall, rear fan and a bay conduit selection pickbox. ### 3D Case Adjustments Tab @@ -796,7 +796,7 @@ DESCRIPTION: creates nut holder of various styles. size[0] = top diameter or x size in mm size[1] = bottom diameter or y size in mm size[2] = holder height in mm - data[0] = "m2", "m2.5", "m3", "m4" + data[0] = "m2", "m2.5", "m3", "m4", "m3-insert" data[1] = "default", "sloped", "trap" mask[0] = true mask[1] = length diff --git a/lib/holder.scad b/lib/holder.scad index 01dd762..321f59a 100644 --- a/lib/holder.scad +++ b/lib/holder.scad @@ -29,7 +29,7 @@ USAGE: nut_holder(nut, style, dia_x, dia_y, height, mask) - nut = "m2", "m2.5", "m3", "m4" + nut = "m2", "m2.5", "m3", "m4", "m3-insert" style = "default", "sloped", "trap" dia_x = top diameter or x size in mm dia_y = bottom diameter or y size in mm @@ -87,6 +87,10 @@ module nut_holder(nut, style, dia_x, dia_y, height, mask) { translate([0, 0, -1]) cylinder(d=nuts[2][0]+.5, h=height+2); translate([0, 0, 2]) cylinder(d=nuts[2][1]*2/sqrt(3), h=height, $fn=6); } + if(nut == "m3-insert") { + translate([0, 0, -1]) cylinder(d=nuts[2][0]+.5, h=height+2); + translate([0, 0, 0]) cylinder(d=4.2, h=5.1); + } if(nut == "m4") { translate([0, 0, -1]) cylinder(d=nuts[3][0]+.5, h=height+2); translate([0, 0, 2]) cylinder(d=nuts[3][1]*2/sqrt(3), h=height, $fn=6); @@ -106,7 +110,11 @@ module nut_holder(nut, style, dia_x, dia_y, height, mask) { } if(nut == "m3") { translate([0, 0, -1]) cylinder(d=nuts[2][0]+.5, h=height+2); - translate([0, 0, 2]) cylinder(d=nuts[2][1]*2/sqrt(3), h=height, $fn=6); + translate([0, 0, 0]) cylinder(d=nuts[2][1]*2/sqrt(3), h=height+5, $fn=6); + } + if(nut == "m3-insert") { + translate([0, 0, -1]) cylinder(d=nuts[2][0]+.5, h=height+2); + translate([0, 0, 0]) cylinder(d=4.2, h=5.1); } if(nut == "m4") { translate([0, 0, -1]) cylinder(d=nuts[3][0]+.5, h=height+2); diff --git a/lib/rack.scad b/lib/rack.scad index 1e78736..6b5a890 100644 --- a/lib/rack.scad +++ b/lib/rack.scad @@ -16,6 +16,8 @@ Code released under GPLv3: http://www.gnu.org/licenses/gpl.html rack_end_bracket(side, size, thick) + rack_rail(style, rack_1u, hole_dia, thick) + rack_stand(rack_1u) */ @@ -36,7 +38,9 @@ module rack_end_bracket(side, size, thick) { + u1 = 44.45; depth = size == "1u" ? 44.45 : size == "1u+" ? 59.26 : size == "1u++" ? 74.07 : size == "2u" ? 2*44.45 : size == "3u" ? 3*44.45 : 4*44.45; + mask = size == "1u" ? 44.45 : size == "1u+" ? 88.9 : size == "1u++" ? 88.9 : size == "2u" ? 2*44.45 : size == "3u" ? 3*44.45 : 4*44.45; c_fillet = 2; hole = 3.2; rack_hole = 6; @@ -50,7 +54,7 @@ module rack_end_bracket(side, size, thick) { $fn=90; if(side == "left") { - translate([thick,-thick,depth]) rotate([270,0,0]) + translate([thick,0,0]) rotate([90,0,0]) difference() { union() { translate([(-tab_width/2),(depth/2),thick/2]) @@ -60,8 +64,11 @@ module rack_end_bracket(side, size, thick) { cube_fillet_inside([b_width,b_depth,b_height], vertical=[0,0,0,0],top=[c_fillet,0,c_fillet,0],bottom=[0,0,0,0], $fn=90); } - for (c=[7.5:15:depth]) { - translate([(3-thick)-9-(15.875-9)/2,c,-adjust]) slot(rack_hole,3,thick+(adjust*2)); + for(i=[0:u1:mask-u1]) { + for(c=[6.35:15.875:44.45]) { + translate([(3-thick)-9-(15.875-9)/2,c+i,-adjust]) + slot(rack_hole,3,thick+(adjust*2)); + } } } } @@ -76,9 +83,123 @@ module rack_end_bracket(side, size, thick) { cube_fillet_inside([b_width,b_depth,b_height], vertical=[0,0,0,0],top=[c_fillet,0,c_fillet,0],bottom=[0,0,0,0], $fn=90); } - for (c=[7.5:15:depth]) { - translate([(3-thick)-9-(15.875-9)/2,c,-adjust]) slot(rack_hole,3,thick+(adjust*2)); + for(i=[0:u1:mask-u1]) { + for(c=[6.35:15.875:44.45]) { + translate([(3-thick)-9-(15.875-9)/2,c+i,-adjust]) slot(rack_hole,3,thick+(adjust*2)); + } } } } } + + +/* + NAME: rack_rail + DESCRIPTION: creates rack rail lengths + TODO: none + + USAGE: rack_rail(style, rack_1u, hole_dia, thick) + + style = "none", "nut", "insert" + rack_1u = number of 1u + hole_dia = hole size to create + thick = thickness of bracket + +*/ + +module rack_rail(style, rack_1u, hole_dia, thick) { + + 1u = 44.45; + mount_rail = 15.875; + 1u_hole_offset = 6.35; + 1u_hole_spacing = 15.875; + height = rack_1u * 1u; + + difference() { + union() { + cube([mount_rail, thick, height]); + if(style == "nut" || style == "insert") { + fastner = style == "insert" ? "m3-insert" : "m3"; + for(i=[0:rack_1u-1]) { + translate([mount_rail/2, adj, i*1u]) { + translate([0,0,1u_hole_offset]) rotate([90,0,0]) + nut_holder(fastner, "sloped", 7, mount_rail-1, 3, [false,10,2,"default"]); + translate([0,0,1u_hole_offset+1u_hole_spacing]) + rotate([90,0,0]) nut_holder(fastner, "sloped", 7, mount_rail-1, 3, [false,10,2,"default"]); + translate([0,0,1u_hole_offset+2*1u_hole_spacing]) + rotate([90,0,0]) nut_holder(fastner, "sloped", 7, mount_rail-1, 3, [false,10,2,"default"]); + } + } + } + } + for(i=[0:rack_1u-1]) { + translate([mount_rail/2, -1, i*1u]) { + translate([0,thick+2,1u_hole_offset]) rotate([90,0,0]) cylinder(d = hole_dia, h=thick+2); + translate([0,thick+2,1u_hole_offset+1u_hole_spacing]) rotate([90,0,0]) cylinder(d = hole_dia, h=thick+2); + translate([0,thick+2,1u_hole_offset+2*1u_hole_spacing]) rotate([90,0,0]) cylinder(d = hole_dia, h=thick+2); + } + } + translate([-1,-1,height]) cube([mount_rail+2,thick+2,10]); + } +} + + +/* + NAME: rack_stand + DESCRIPTION: creates rack stand of 1u hieght + TODO: none + + USAGE: rack_stand(rack_1u) + + rack_1u = number of 1u + +*/ + +module rack_stand(rack_1u) { + + 1u = 44.45; + mount_rail = 15.875; + thick = 5; + height = rack_1u * 1u; + height_offset = 25.4/2; + hole_dia = 3.2; + c_fillet = 9; + rail_offset = 87.5; + foot_length = 175; + foot_thick = thick; + $fn=180; + + // vertical rack rails + translate([0, 0, height_offset-adj]) rack_rail(rack_fasteners, rack_1u, hole_dia, thick); + + // bottom feet + translate([mount_rail/2, -rail_offset/2, foot_thick-2]) cube_fillet_inside([mount_rail, foot_length, foot_thick], + vertical=[0,0,0,0], top=[c_fillet,0,c_fillet,0], bottom=[0,0,0,0], $fn=90); + + // bottom connection piece + translate([0, 0, 0]) cube([mount_rail, thick, height_offset]); + + // top extension piece + ext_len = rack_1u == 4 ? thick : rack_1u == 3 ? thick : thick; + translate([0, 0, height+height_offset-adj]) cube([mount_rail, thick, ext_len]); + + // support arc + if(rack_1u > 0) { + ext_adj = rack_1u == 4 ? 4.5*thick : rack_1u == 3 ? 3.5*thick : 2.5*thick; + difference() { + translate([0,(height/2)-5*thick,ext_adj]) rotate([0,90,0]) { + difference() { + translate([0,0,0]) cylinder(d=(2*height)+(3*thick), h=mount_rail); + translate([0,0,-adj]) cylinder(d=(2*height)+thick, h=mount_rail+(2*adj)); + } + } + // top trim + translate([-1, thick, height+height_offset-5]) cube([mount_rail+2, 300, 40]); + // front trim + translate([-1, 42.75, -175]) cube([mount_rail+2, 300, 400]); + translate([-1, thick, foot_thick]) cube([mount_rail+2, 300, 400]); + // bottom trim + translate([-1, -150, -174.5]) cube([mount_rail+2, 300, 175]); + } + } +} \ No newline at end of file diff --git a/mod/case_rack.scad b/mod/case_rack.scad index b9563ce..38fbb22 100644 --- a/mod/case_rack.scad +++ b/mod/case_rack.scad @@ -1004,7 +1004,7 @@ module bay_tray(depth, bay) { union() { slab([reminsert-wallthick-gap-2,depth-.5,1],.5); translate([0, 1.5, 0]) rotate([90,0,0]) - slab([reminsert-wallthick-gap-2,bay_height-3,1.5],.5); + slab([reminsert-wallthick-gap-2,bay_height-3+removable_bay_height,1.5],.5); } // case floor panel clamp holes translate([baysize-2.5,(depth/2)-gap-wallthick+3,-adj]) diff --git a/sbc_case_builder.json b/sbc_case_builder.json index ca009e9..6f7307f 100644 --- a/sbc_case_builder.json +++ b/sbc_case_builder.json @@ -7479,7 +7479,7 @@ "bottom_standoff_insert_height": "5.1", "bottom_standoff_pillar": "hex", "bottom_standoff_reverse": "false", - "bottom_standoff_size": "m3", + "bottom_standoff_size": "m3_tap", "bottom_standoff_support_height": "4", "bottom_standoff_support_size": "10", "bottom_standoff_type": "countersunk", @@ -12760,7 +12760,7 @@ "ext_top_standoffs": "false", "fan_size": "0", "flat_blank_section": "false", - "floorthick": "2", + "floorthick": "3", "front_cover_pattern": "solid", "gap": "1", "gpio_opening": "none", diff --git a/sbc_case_builder.scad b/sbc_case_builder.scad index d371d50..e5307ff 100644 --- a/sbc_case_builder.scad +++ b/sbc_case_builder.scad @@ -78,14 +78,15 @@ rear_io_shield = false; rack_width = 19; //[10,19] // size of rack mount cases 1U or 2U // rack_size = "1u"; //["1u","1u+","1u++","2u"] -// enable rack io plate opening for sbc +removable_bay_height = 0; // [-4 : .5 : 0] +// bay sbc device Rack_Bay1 = "none"; // ["none", "c1+", "c2", "c4", "hc4", "c5", "xu4", "xu4q", "mc1", "hc1", "n1", "n2", "n2+", "n2l", "n2lq", "m1", "m1s", "m2", "h2", "h2+", "h3", "h3+", "h4", "h4+", "h4_ultra", "show2", "rpipico", "rpipicow", "rpicm4+ioboard", "rpicm1", "rpicm3", "rpicm3l", "rpicm3+", "rpicm4s", "rpicm4", "rpicm4l", "rpizero", "rpizerow", "rpizero2w", "rpi1a+", "rpi1b+", "rpi2b", "rpi3a+", "rpi3b", "rpi3b+", "rpi4b", "rpi5", "a64", "a64lts", "rock64", "rockpro64", "quartz64a", "quartz64b", "h64b", "star64", "soedge_a-baseboard", "soedge_rk1808", "rock4a", "rock4b", "rock4a+", "rock4b+", "rock4c", "rock4c+", "rock5b-v1.3", "rock5b", "rock5bq", "rock5b+", "nio12l", "vim1", "vim2", "vim3", "vim3l", "vim4", "tinkerboard", "tinkerboard-s", "tinkerboard-2", "tinkerboard-2s", "tinkerboard-r2", "tinkerboard-r2s", "opizero", "opizero2", "opir1plus_lts", "opir1", "opi5", "opi5max", "jetsonnano", "lepotato", "sweetpotato", "tritium-h2+", "tritium-h3", "tritium-h5", "solitude", "alta", "atomicpi", "visionfive2", "visionfive2q", "bpif3", "milk-v_duos", "licheerv+dock", "rak19007", "cnano-avr128da48", "nodemcu-32s", "cs-solarmeter", "feather-m0_express", "feather-m0_wifi", "feather-m4_express"] rack_bay1_xyz_loc = [0,0,0]; // [0:.5:450] rack_bay1_rotation = 0; // [0:90:270] -rack_bay1_face = "fixed"; //["open","fixed","removable","vent"] +rack_bay1_face = "fixed"; // ["open","fixed","removable","vent"] rack_bay1_wall = false; // [true,false] -rack_bay1_rear_fan = false; //[true,false] -rack_bay1_rear_conduit = "none"; //["none","conduit","grommet","grommets-vertical"] +rack_bay1_rear_fan = false; // [true,false] +rack_bay1_rear_conduit = "none"; // ["none","conduit","grommet","grommets-vertical"] Rack_Bay2 = "none"; // ["none", "c1+", "c2", "c4", "hc4", "c5", "xu4", "xu4q", "mc1", "hc1", "n1", "n2", "n2+", "n2l", "n2lq", "m1", "m1s", "m2", "h2", "h2+", "h3", "h3+", "h4", "h4+", "h4_ultra", "show2", "rpipico", "rpipicow", "rpicm4+ioboard", "rpicm1", "rpicm3", "rpicm3l", "rpicm3+", "rpicm4s", "rpicm4", "rpicm4l", "rpizero", "rpizerow", "rpizero2w", "rpi1a+", "rpi1b+", "rpi2b", "rpi3a+", "rpi3b", "rpi3b+", "rpi4b", "rpi5", "a64", "a64lts", "rock64", "rockpro64", "quartz64a", "quartz64b", "h64b", "star64", "soedge_a-baseboard", "soedge_rk1808", "rock4a", "rock4b", "rock4a+", "rock4b+", "rock4c", "rock4c+", "rock5b-v1.3", "rock5b", "rock5bq", "rock5b+", "nio12l", "vim1", "vim2", "vim3", "vim3l", "vim4", "tinkerboard", "tinkerboard-s", "tinkerboard-2", "tinkerboard-2s", "tinkerboard-r2", "tinkerboard-r2s", "opizero", "opizero2", "opir1plus_lts", "opir1", "opi5", "opi5max", "jetsonnano", "lepotato", "sweetpotato", "tritium-h2+", "tritium-h3", "tritium-h5", "solitude", "alta", "atomicpi", "visionfive2", "visionfive2q", "bpif3", "milk-v_duos", "licheerv+dock", "rak19007", "cnano-avr128da48", "nodemcu-32s", "cs-solarmeter", "feather-m0_express", "feather-m0_wifi", "feather-m4_express"] rack_bay2_xyz_loc = [0,0,0]; // [0:.5:450] diff --git a/sbccb_accessory_tool.scad b/sbccb_accessory_tool.scad new file mode 100644 index 0000000..8c8ac7f --- /dev/null +++ b/sbccb_accessory_tool.scad @@ -0,0 +1,99 @@ +/* + SBC Case Builder Accessory Tool Copyright 2025 Edward A. Kisiel hominoid@cablemi.com + This file is part of SBC Case Builder https://github.com/hominoids/SBC_Case_Builder + + This program 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. + + 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 this program. If not, see . + Code released under GPLv3: http://www.gnu.org/licenses/gpl.html + + see https://github.com/hominoids/SBC_Case_Builder +*/ + + include <./sbc_case_builder_library.scad>; + + /* [View] */ + // viewing mode "model", "platter" + view = "model"; // [model, platter] + individual_part = "bottom"; // [top, bottom, right, left, front, rear, io_shield, accessories] + // section individual parts for panel cases + section_part = false; // [true,false] + accessory = "grommet"; // ["fan cover", "grommet", "hd25 holder", "1u rack stand"] + + /* [Fan Cover] */ + fan_style = "fan_hex"; // ["fan_open", "fan_1", "fan_2", "fan_hex"] + fan_size = 40; // [25, 30, 40, 50, 60, 80, 92, 120] + fan_cover_thickness = 2; // [2 : .25 : 5] + + /* [Grommet] */ + grommet_style = "sleeve"; // ["sleeve"] + grommet_od = 10; // [6 : .25 : 20] + grommet_id = 6; // [2 : .25 : 20] + installation_wall_thickness = 2; // [2 : .25 : 5] + + /* [2.5" HD Holder] */ + holder_length = 110; // [110, 145] + holder_width = 101.6; // [101.6 : .1 : 150] + + /* [1U Rack Stand] */ + rack_width = 19; // [10, 19] + rack_1u = 4; // [1 : 4] + rack_depth = 150; // [25 : 200] + rack_fasteners = "nut"; // ["none", "nut", "insert"] + + /* [Hidden] */ + mask = [true, 10, 2, "default"]; + nmask = [false, 10, 2, "default"]; + + adj = .01; + $fn = 90; + + // model view + if (view == "model") { + if(accessory == "fan cover") { + fan_cover(fan_size, fan_cover_thickness, fan_style); + } + if(accessory == "grommet") { + grommet("front", grommet_style, grommet_od, grommet_id, installation_wall_thickness, true, nmask); + } + if(accessory == "hd25 holder") { + hd35_25holder(holder_length, holder_width); + } + if(accessory == "1u rack stand") { + rack_stand(rack_1u); + } + } + + + // platter view + if (view == "platter") { + if(accessory == "fan cover") { + fan_cover(fan_size, fan_cover_thickness, fan_style); + } + if(accessory == "grommet" && grommet_style == "sleeve") { + translate([0,0,0]) rotate([270,0,0]) difference() { + grommet("bottom", grommet_style, grommet_od, grommet_id, installation_wall_thickness, false, nmask); + translate([-grommet_od,-.125,-3]) cube([20,10,20]); + } + translate([0,20,0]) rotate([270,0,0]) difference() { + grommet("bottom", grommet_style, grommet_od, grommet_id, installation_wall_thickness, false, nmask); + translate([-grommet_od,-.125,-3]) cube([20,10,20]); + } + translate([0,-20,0]) + grommet_clip(grommet_style, grommet_od, grommet_id, installation_wall_thickness); + } + if(accessory == "hd25 holder") { + hd35_25holder(holder_length, holder_width); + } + if(accessory == "1u rack stand") { + rotate([0,270,0]) rack_stand(rack_1u); + } + }