diff --git a/README.md b/README.md index fba639d..48e3fd4 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Supported boards | [NanoPi Neo 2](boards/nanopi_neo2.scad) | ![NanoPi Neo 2](boards/gif/nanopi_neo2.gif) | | [Orange Pi Zero](boards/orangepi_zero.scad) | ![Orange Pi Zero](boards/gif/orangepi_zero.gif) | | [Raspberry Pi 3](boards/rpi3.scad) | ![Raspberry Pi 3](boards/gif/rpi3.gif) | +| [Raspberry Pi 4](boards/rpi4.scad) | ![Raspberry Pi 4](boards/gif/rpi4.gif) | Corresponding cases @@ -34,6 +35,8 @@ Corresponding cases | [NanoPi Neo 2](cases/nanopi_neo2.scad) | ![NanoPi Neo 2](cases/gif/nanopi_neo2.gif) | [VERIFIED](pics/nanopi_neo2.jpg):
![NanoPi Neo 2](pics/small/nanopi_neo2.jpg) | | [Orange Pi Zero](cases/orangepi_zero.scad) | ![Orange Pi Zero](cases/gif/orangepi_zero.gif) | [VERIFIED](pics/orangepi_zero.jpg):
![Orange Pi Zero](pics/small/orangepi_zero.jpg) | | [Raspberry Pi 3](cases/rpi3.scad) | ![Raspberry Pi 3](cases/gif/rpi3.gif) | [VERIFIED](pics/rpi3.jpg):
![Raspberry Pi 3](pics/small/rpi3.jpg) | +| [Raspberry Pi 4](cases/rpi4.scad) | ![Raspberry Pi 4](cases/gif/rpi4.gif) | [VERIFIED](pics/rpi4.jpg):
![Raspberry Pi 4](pics/small/rpi4.jpg) | +| [Raspberry Pi 4](cases/rpi4_blower.scad)(blower fan case) | ![Raspberry Pi 4](cases/gif/rpi4_blower.gif) | [VERIFIED](pics/rpi4_blower.jpg):
![Raspberry Pi 4](pics/small/rpi4_blower.jpg) | Usage diff --git a/boards.scad b/boards.scad index a68f8f1..d8691e4 100644 --- a/boards.scad +++ b/boards.scad @@ -22,6 +22,7 @@ use use use use +use use boards = [ @@ -31,6 +32,8 @@ boards = [ ["nanopi_neo2", nanopi_neo2_info()], ["orangepi_zero", orangepi_zero_info()], ["rpi3", raspberry_pi_3_info()], + ["rpi4", raspberry_pi_4_info()], + ["rpi4_blower", raspberry_pi_4_info(blower=true)], ["wemos_esp8266", wemos_esp8266_info()], ]; @@ -42,6 +45,8 @@ module boards_get_plate_2d(id) { nanopi_neo2_plate_2d(); orangepi_zero_plate_2d(); raspberry_pi_3_plate_2d(); + raspberry_pi_4_plate_2d(); + raspberry_pi_4_plate_2d(); // blower case wemos_esp8266_plate_2d(); } } @@ -54,6 +59,8 @@ module boards_get_board(id) { nanopi_neo2(); orangepi_zero(); raspberry_pi_3(); + raspberry_pi_4(); + raspberry_pi_4(blower=true); wemos_esp8266(); } } diff --git a/boards/bbb.scad b/boards/bbb.scad index 2ed4212..084c2d9 100644 --- a/boards/bbb.scad +++ b/boards/bbb.scad @@ -87,7 +87,7 @@ comp_info = [ [ethernet_info(), ethernet_dim, [ 1, 1,-1], [0,0,2], [-1,-1, 1], [-in2mm(100), in2mm(855), 0]], [female_header_info(), gpio_dim, [-1, 1,-1], [0,0,0], [-1, 1, 1], [18, -0.5, 0]], [female_header_info(), gpio_dim, [-1,-1,-1], [0,0,0], [-1,-1, 1], [18, 0.5, 0]], - [microhdmi_info(), microhdmi_dim, [ 1,-1, 1], [0,0,0], [ 1,-1,-1], [ in2mm(25), in2mm(850), 0]], + [microhdmi_info(), microhdmi_dim, [ 1, 1,-1], [2,0,0], [ 1,-1,-1], [ in2mm(25), in2mm(850), 0]], [microsdcard_info(), microsdcard_dim, [ 1,-1, 1], [0,0,0], [ 1,-1,-1], [in2mm(110), in2mm(1205)+.5, 0]], [microsdslot_info(), microsdslot_dim, [ 1,-1, 1], [0,0,0], [ 1,-1,-1], [0, in2mm(1205), 0]], [miniusb_info(), miniusb_dim, [ 1, 1, 1], [0,0,2], [-1,-1,-1], [-in2mm(25), in2mm(1575), 0]], @@ -108,7 +108,7 @@ module beaglebone_black() { ethernet(dim=ethernet_dim); female_header_pitch254(dim=gpio_dim, n=23, m=2); female_header_pitch254(dim=gpio_dim, n=23, m=2); - microhdmi(dim=microhdmi_dim); + microhdmi(dim=microhdmi_dim, l_fold=0); microsdcard(dim=microsdcard_dim); microsdslot(dim=microsdslot_dim); miniusb(dim=miniusb_dim); diff --git a/boards/gif/bbb.gif b/boards/gif/bbb.gif index f571aa0..ec01f4d 100644 Binary files a/boards/gif/bbb.gif and b/boards/gif/bbb.gif differ diff --git a/boards/gif/cubieboard.gif b/boards/gif/cubieboard.gif index a923ae2..967481e 100644 Binary files a/boards/gif/cubieboard.gif and b/boards/gif/cubieboard.gif differ diff --git a/boards/gif/hikey.gif b/boards/gif/hikey.gif index c7af0e0..b6209bc 100644 Binary files a/boards/gif/hikey.gif and b/boards/gif/hikey.gif differ diff --git a/boards/gif/nanopi_neo2.gif b/boards/gif/nanopi_neo2.gif index b7e2689..fd92484 100644 Binary files a/boards/gif/nanopi_neo2.gif and b/boards/gif/nanopi_neo2.gif differ diff --git a/boards/gif/orangepi_zero.gif b/boards/gif/orangepi_zero.gif index 9d55ce6..f8a7de1 100644 Binary files a/boards/gif/orangepi_zero.gif and b/boards/gif/orangepi_zero.gif differ diff --git a/boards/gif/rpi3.gif b/boards/gif/rpi3.gif index 6aa365e..ec3e8fa 100644 Binary files a/boards/gif/rpi3.gif and b/boards/gif/rpi3.gif differ diff --git a/boards/gif/rpi4.gif b/boards/gif/rpi4.gif new file mode 100644 index 0000000..2094b6b Binary files /dev/null and b/boards/gif/rpi4.gif differ diff --git a/boards/gif/wemos_esp8266.gif b/boards/gif/wemos_esp8266.gif new file mode 100644 index 0000000..334a05d Binary files /dev/null and b/boards/gif/wemos_esp8266.gif differ diff --git a/boards/rpi4.scad b/boards/rpi4.scad new file mode 100644 index 0000000..64d8c73 --- /dev/null +++ b/boards/rpi4.scad @@ -0,0 +1,155 @@ +// Copyright (c) 2017 Clément Bœsch +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +include <../globals.scad> + +use <../case.scad> +use <../utils.scad> +use <../electronics/cpu.scad> +use <../electronics/hdmi.scad> +use <../electronics/header.scad> +use <../electronics/jack.scad> +use <../electronics/misc.scad> +use <../electronics/network.scad> +use <../electronics/sd.scad> +use <../electronics/usb.scad> + + +board_dim = [85, 56, 1.25]; + + +/* Plate holes */ +hole_d = 2.75; +hole_orig = [board_dim[0], board_dim[1]] * -.5; +ring_off = 5.6 - hole_d; +hole_pad = 3.5; +holes_pos = [for (y=[0, 49], x=[0, 58]) hole_orig + [x, y] + hole_pad*[1,1]]; + +lusb = 17.5; +wusb = 15; +husb = 16; + +duct_th = 1.2; + +/* Components bounding box dimensions */ +ethernet_dim = [21.25, 16,13.75]; +gpio_dim = [ 51, 5, 8.5]; +microhdmi_dim = [ 7.3, 6.5, 3.25]; +jack_dim = [ 14.5, 7, 6]; +microsdcard_dim = [ 15, 11, 1]; +microsdslot_dim = [ 11.5, 12, 1.25]; +usbc_dim = [ 7.35, 8.94, 3.2]; +serialcon_dim = [ 2.5, 22, 5.5]; +usbx2_dim = [ lusb, wusb, husb]; +cpu_dim = [ 15, 15, 2.4]; // draw cpu to assist fan aligmnent + +ethusb_dim = [ lusb, 3.25, husb]; // cleanup box +usbusb_dim = [ lusb, 3, husb]; // cleanup box +btm_cutout_dim = [ 10,52.5,husb+1]; +duct_dim = [15+2*duct_th,20+2*duct_th,26.2]; + +module raspberry_pi_4_plate_2d() { + plate_2d(board_dim[0], board_dim[1], 3); +} + +function comp_info(blower=false) = [ + /* info function box dimensions comp-corner rotate board-corner position */ + [microhdmi_info(), microhdmi_dim, [ 1, 0,-1], [0,0,3], [-1,-1, 1], [ 26,-1.65, 0]], + [microhdmi_info(), microhdmi_dim, [ 1, 0,-1], [0,0,3], [-1,-1, 1], [39.5,-1.65, 0]], + [jack_info(), jack_dim, [ 1, 0,-1], [0,0,3], [-1,-1, 1], [53.5, -2, 0]], + [microsdcard_info(), microsdcard_dim, [ 1, 0,-1], [2,0,2], [-1, 0,-1], [-2.25, 0, 0]], + [microsdslot_info(), microsdslot_dim, [ 1, 0,-1], [2,0,2], [-1, 0,-1], [ 1.75, 0, 0]], + [usbc_info(), usbc_dim, [ 1, 0,-1], [0,0,3], [-1,-1, 1], [11.2, -1.2, 0]], + [pin_header_info(), gpio_dim, [ 0, 0,-1], [0,0,0], [-1, 1, 1], [32.5, -3.5, 0]], + [serialcon_rpi_info(), serialcon_dim, [ 0,-1,-1], [0,0,0], [-1,-1, 1], [ 46.5, 1, 0]], // camera + [serialcon_rpi_info(), serialcon_dim, [ 0, 0,-1], [0,0,2], [-1,-1, 1], [ 4, 28, 0]], // display + [cpu_info(), cpu_dim, [ 0, 0,-1], [0,0,3], [-1,-1, 1], [29.25,32.5, 0]], + if(blower) each [ + [ethernet_info(), ethernet_dim, [ 1, 0,-1], [0,0,0], [ 1,-1, 1], [ 3,45.75, 0], 0], + [usbx2_info(), usbx2_dim, [ 1, 0,-1], [0,0,0], [ 1,-1, 1], [ 3.2, 9, 0], 0], + [usbx2_info(), usbx2_dim, [ 1, 0,-1], [0,0,0], [ 1,-1, 1], [ 3.2, 27, 0], 0], + // Case top needs to cover usb/eth, for blower to mount to. + // This component ensures bottom has no odd overhangs on top after extending it's height. + [unknown_info(), btm_cutout_dim, [ 1,-1,-1], [0,0,0], [ 1,-1, 1], [ 3.2, 1.56,-1], 0], + // for case top cutout + [duct_info(), duct_dim, [ 0, 0, 0], [0,0,0], [-1,-1, 1], [29.25,32.5,17.2], 0.25] + + ] else each [ + [ethernet_info(), ethernet_dim, [ 1, 0,-1], [0,0,0], [ 1,-1, 1], [ 3,45.75, 0]], + [usbx2_info(), usbx2_dim, [ 1, 0,-1], [0,0,0], [ 1,-1, 1], [ 3.2, 9, 0]], + [usbx2_info(), usbx2_dim, [ 1, 0,-1], [0,0,0], [ 1,-1, 1], [ 3.2, 27, 0]], + [unknown_info(), ethusb_dim, [ 1, 0,-1], [0,0,0], [ 1,-1, 1], [ 3.2, 36, 0]], + [unknown_info(), usbusb_dim, [ 1, 0,-1], [0,0,0], [ 1,-1, 1], [ 3.2, 18, 0]] + ] +]; + +module raspberry_pi_4(blower=false) { + extrude_plate(board_dim[2], holes_pos, hole_d, ring_off, clr=c_green_pcb, clr_ring=c_yellow) + raspberry_pi_4_plate_2d(); + + // Must use outer "if" statement so children of conditional are each treated as separate child. + if (blower) { + set_components(board_dim, comp_info(blower)) { + microhdmi(dim=microhdmi_dim); + microhdmi(dim=microhdmi_dim); + jack(dim=jack_dim); + microsdcard(dim=microsdcard_dim); + microsdslot(dim=microsdslot_dim); + usbc(dim=usbc_dim); + pin_header_pitch254(dim=gpio_dim, n=20, m=2); + serialcon_rpi(dim=serialcon_dim); + serialcon_rpi(dim=serialcon_dim); + cpu(dim=cpu_dim, clr=c_metal); + + ethernet(dim=ethernet_dim, swap_led=true); + usbx2(dim=usbx2_dim); + usbx2(dim=usbx2_dim, clr=c_usb_blue); + %cube(btm_cutout_dim, center=true); + %duct(); + } + } else { + set_components(board_dim, comp_info(blower)) { + microhdmi(dim=microhdmi_dim); + microhdmi(dim=microhdmi_dim); + jack(dim=jack_dim); + microsdcard(dim=microsdcard_dim); + microsdslot(dim=microsdslot_dim); + usbc(dim=usbc_dim); + pin_header_pitch254(dim=gpio_dim, n=20, m=2); + serialcon_rpi(dim=serialcon_dim); + serialcon_rpi(dim=serialcon_dim); + cpu(dim=cpu_dim, clr=c_metal); + + ethernet(dim=ethernet_dim, swap_led=true); + usbx2(dim=usbx2_dim); + usbx2(dim=usbx2_dim, clr=c_usb_blue); + %cube(ethusb_dim, center=true); + %cube(usbusb_dim, center=true); + } + } +} + +function raspberry_pi_4_info(blower=false) = [ + ["board_dim", board_dim], + ["components", comp_info(blower)], + ["holes_d", hole_d], + ["holes_pos", holes_pos], +]; + + +blower = false; +demo_board(board_dim) { + raspberry_pi_4(blower); + *#bounding_box(board_dim, comp_info(blower)); +} diff --git a/case.scad b/case.scad index 81b3909..f38d176 100644 --- a/case.scad +++ b/case.scad @@ -59,7 +59,7 @@ module _vents(vents, w=2.1) { start = -length/2 + off + w/2; translate(pos) { intersection() { - circle(d=max(dim), center=true); + circle(d=max(dim)); for (i = [0:n_vents-1]) translate([0, start + i*w*2]) square([dim[0], w], center=true); diff --git a/cases/gif/bbb.gif b/cases/gif/bbb.gif index 63f97a9..8cb3b0d 100644 Binary files a/cases/gif/bbb.gif and b/cases/gif/bbb.gif differ diff --git a/cases/gif/hikey.gif b/cases/gif/hikey.gif index 26ad183..4674b78 100644 Binary files a/cases/gif/hikey.gif and b/cases/gif/hikey.gif differ diff --git a/cases/gif/nanopi_neo2.gif b/cases/gif/nanopi_neo2.gif index f788db9..a3343b9 100644 Binary files a/cases/gif/nanopi_neo2.gif and b/cases/gif/nanopi_neo2.gif differ diff --git a/cases/gif/orangepi_zero.gif b/cases/gif/orangepi_zero.gif index 6fb5ee7..8f98548 100644 Binary files a/cases/gif/orangepi_zero.gif and b/cases/gif/orangepi_zero.gif differ diff --git a/cases/gif/rpi3.gif b/cases/gif/rpi3.gif index 7739878..ec0085e 100644 Binary files a/cases/gif/rpi3.gif and b/cases/gif/rpi3.gif differ diff --git a/cases/gif/rpi4.gif b/cases/gif/rpi4.gif new file mode 100644 index 0000000..13275f8 Binary files /dev/null and b/cases/gif/rpi4.gif differ diff --git a/cases/gif/rpi4_blower.gif b/cases/gif/rpi4_blower.gif new file mode 100644 index 0000000..1ebc8f2 Binary files /dev/null and b/cases/gif/rpi4_blower.gif differ diff --git a/cases/gif/wemos_esp8266.gif b/cases/gif/wemos_esp8266.gif new file mode 100644 index 0000000..aa4c565 Binary files /dev/null and b/cases/gif/wemos_esp8266.gif differ diff --git a/cases/rpi4.scad b/cases/rpi4.scad new file mode 100644 index 0000000..5a20528 --- /dev/null +++ b/cases/rpi4.scad @@ -0,0 +1,39 @@ +// Copyright (c) 2017 Clément Bœsch +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use <../boards/rpi4.scad> +use <../case.scad> +use <../utils.scad> + +board_dim = map_get(raspberry_pi_4_info(), "board_dim"); + +vents = [ + [ + "bottom", default_bottom_vents(board_dim), + ],[ + "top", [ + ["dim", [board_dim[0] * .3, board_dim[1] * .7]], + ["pos", [-18, -4.5]], + ] + ] +]; + +cfg = [ + ["min_z", 3], + ["max_z", 9], + ["vents", vents], +]; + +mode = "demo"; +case("rpi4", cfg, mode); diff --git a/cases/rpi4_blower.scad b/cases/rpi4_blower.scad new file mode 100644 index 0000000..dc90850 --- /dev/null +++ b/cases/rpi4_blower.scad @@ -0,0 +1,70 @@ +// Copyright (c) 2017 Clément Bœsch +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use <../boards/rpi4.scad> +use <../case.scad> +use <../utils.scad> +use <../electronics/misc.scad> + +board_dim = map_get(raspberry_pi_4_info(blower=true), "board_dim"); + +vents = [ + [ + "bottom", [], + ] +]; + +cfg = [ + ["min_z", 2.5], + ["max_z", 15], + ["vents", vents], +]; + + +// Uncomment to manually export case bottom +// with extra vent holes out of the side (recommended) +/* +!difference() { + case("rpi4_blower", cfg, "bottom"); + dslot = 4; + sep = 2; + translate([-43,0,13]) + rotate([0,-90]) rotate(-90) linear_extrude(100) { + for(i=[-1:1]) hull() { + translate([(dslot+sep)*i,-4]) circle(d=dslot, $fn=40); + translate([(dslot+sep)*i,4]) circle(d=dslot, $fn=40); + } + for(i=[-4,-3,-2,2,3,4]) hull() { + translate([(dslot+sep)*i,-9]) circle(d=dslot, $fn=40); + translate([(dslot+sep)*i,4]) circle(d=dslot, $fn=40); + } + } +} +//*/ + +mode = "demo"; +case("rpi4_blower", cfg, mode); + +// Uncomment to export printed duct separately +//!duct(); + +/* +// External dependency on NopSCADLib only if blower fan mockup is wanted +// (does not animate with case demo) +$t=1; +include <../NopSCADlib/core.scad> +include <../NopSCADlib/vitamins/blowers.scad> +translate([-5.8,4.5,17.825]) rotate(-90) translate([-10,0,0]) + blower(RB5015); +//*/ \ No newline at end of file diff --git a/electronics/_internal.scad b/electronics/_internal.scad index d179b87..3222cc9 100644 --- a/electronics/_internal.scad +++ b/electronics/_internal.scad @@ -16,10 +16,11 @@ include <../globals.scad> $vpr = [50, 0, 90]; -module components_demo(pad=30) { +module components_demo(pad=30, rowsfirst=false) { n = $children; - cols = ceil(sqrt(n)); - rows = ceil(n / cols); + // provide option to arranage by rows befor columns + cols = !rowsfirst ? ceil(sqrt(n)) : ceil(n / ceil(sqrt(n))); + rows = rowsfirst ? ceil(sqrt(n)) : ceil(n / ceil(sqrt(n))); offx = pad * (rows - 1) / 2; offy = pad * (cols - 1) / 2; for (i = [0:n-1]) { diff --git a/electronics/gif/hdmi.gif b/electronics/gif/hdmi.gif index 40fcd03..2aa51e1 100644 Binary files a/electronics/gif/hdmi.gif and b/electronics/gif/hdmi.gif differ diff --git a/electronics/gif/usb.gif b/electronics/gif/usb.gif index 9c3162e..74c265f 100644 Binary files a/electronics/gif/usb.gif and b/electronics/gif/usb.gif differ diff --git a/electronics/hdmi.scad b/electronics/hdmi.scad index e264795..ea23a26 100644 --- a/electronics/hdmi.scad +++ b/electronics/hdmi.scad @@ -45,31 +45,87 @@ module hdmi(dim=[12, 15, 6]) { } } -module microhdmi(dim=[7.5, 6.5, 3]) { - // TODO + +module horz_fold(a,l,w,t) { + rotate(a=a, v=[0,1,0]) translate([l/2,0,sign(a)*t/2]) cube([l, w, t], center=true); + intersection() { // fold radius + translate([0,0,0]) rotate([90,0,0]) cylinder(r=t, h=w,center=true); + translate([t/2,0,sign(a)*t/2]) cube([t,w,t], center=true); + } +} + +module vert_fold(a,l,w,t) { + rotate(a=a, v=[0,0,1]) translate([l/2,-sign(a)*t/2,0]) cube([l, t, w], center=true); + intersection() { // fold radius + translate([0,0,0]) rotate([0,0,90]) cylinder(r=t, h=w,center=true); + translate([t/2,-sign(a)*t/2,0]) cube([t,t,w], center=true); + } +} + +// VALCON HD-RA-DSF12-TR from RPi4 +// dim is dimensions of connector before folds +module microhdmi(dim=[7.3, 6.5, 3.25], l_fold=0.77, t=0.3) { + tab_h = 0.6; + tab_w1 = 4.3; + tab_w2 = 3.7; + inner_w1 = 5.9; + inner_w2 = tab_w1; + inner_h = 2.3; + l = dim[0]; w = dim[1]; h = dim[2]; - t = .25; - rotate([0, 0, 180]) // XXX - color(c_metal) { - difference() { - cube(dim, center=true); - translate([-t/2,0,0]) - cube([l,w-t,h-t], center=true); - } - } + l2 = l + l_fold; + + recess_tab = 1.53; + l_tab = l-recess_tab; + l_plug = 0.77; + p = 0.55; + a_fold = 30; + z = (l_fold-t*sin(a_fold)) / cos(a_fold); - // cube(dim, center=true); + translate([l2/2,0,0]) { + tab_chamfer = (tab_w1-tab_w2)/2; + tabPoints = [ + [-tab_w1/2,tab_h/2], [tab_w1/2,tab_h/2], + [tab_w1/2,tab_chamfer-tab_h/2], [tab_w2/2,-tab_h/2], + [-tab_w2/2,-tab_h/2], [-tab_w1/2,tab_chamfer-tab_h/2] + ]; + inner_chamfer = (inner_w1-inner_w2)/2; + innerPoints = [ + [-inner_w1/2,inner_h/2], [inner_w1/2,inner_h/2], + [inner_w1/2,inner_chamfer-inner_h/2], [inner_w2/2,-inner_h/2], + [-inner_w2/2,-inner_h/2], [-inner_w1/2,inner_chamfer-inner_h/2] + ]; + if (l_fold > 0) color(c_metal) { + translate([-l_fold,0, inner_h/2+t]) horz_fold(-a_fold, z, inner_w1, t); + translate([-l_fold,0,-inner_h/2-t]) horz_fold( a_fold, z, inner_w2, t); + translate([-l_fold,-w/2,inner_chamfer/2]) vert_fold(-a_fold, z, inner_h-inner_chamfer, t); + translate([-l_fold, w/2,inner_chamfer/2]) vert_fold( a_fold, z, inner_h-inner_chamfer, t); + } + translate([-l2,0,0]) { + color(c_black) rotate([90,0,90]) { + linear_extrude(height=l_tab) polygon(tabPoints); + linear_extrude(height=l_plug) polygon(innerPoints); + } + color(c_metal) rotate([90,0,90]) + linear_extrude(height=l) difference() { + offset(t) polygon(innerPoints); + polygon(innerPoints); + } + } + } } function hdmi_info() = [ ["category", "hdmi"], ["watch", "horizon"], ]; + function microhdmi_info() = hdmi_info(); + components_demo() { hdmi(); microhdmi(); diff --git a/electronics/misc.scad b/electronics/misc.scad index 16f3de2..a8813bb 100644 --- a/electronics/misc.scad +++ b/electronics/misc.scad @@ -34,7 +34,7 @@ module capacitor(dim=[6, 6, 5]) { } } -module chip(dim=[10, 5, 2]) { // TODO +module chip(dim=[10, 5, 2]) { color(c_black) cube(dim, center=true); } @@ -140,6 +140,67 @@ module serialcon_rpi(dim=[2.5, 22, 5.5]) { } } +module duct_profile(dim, th=1.2, oneside=false) { + if (oneside) { + translate([-dim[0]/2-th,0]) square([th,dim[1]]); + translate([-dim[0]/2-th,dim[1]]) square([dim[0]+2*th,th]); + translate([dim[0]/2,0]) square([th,dim[1]]); + } else { + difference() { + square(dim+th*[2,2], center=true); + square(dim, center=true); + } + } +} + +module duct(dim_inlet=[20,15, 1.2], dim_outlet=[20,15,3], th=1.2) { + $fn=120; + // full distance ~14.4 + inx = dim_inlet[0]; + iny = dim_inlet[1]; + inz = dim_inlet[2]; + inxy = [inx,iny]; + outx = dim_outlet[0]; + outy = dim_outlet[1]; + outz = dim_outlet[2]; + outxy = [outx,outy]; + + translate([iny/2,0]) { + rotate([90,0,90]) linear_extrude(inz) + duct_profile(inxy, th, true); + rotate([90,0,0]) rotate_extrude(angle=-90) + rotate(90) duct_profile(inxy, th, true); + } + // reducer + rotate(90) difference() { + hull() { + cube([inx+2*th,iny+2*th,0.001], center=true); + translate([0,0,-outz]) cube([outx+2*th,outy+2*th,0.001], center=true); + } + hull() { + translate([0,0,0.01]) cube([inx,iny,0.001], center=true); + translate([0,0,-outz-0.01]) cube([outx,outy,0.001], center=true); + } + } + // bump to stop from falling through case top + group() { + d = th; + $fn = 32; + translate([-iny/2-th,0,d/2]) rotate([90,0,0]) + linear_extrude(inx+2*th, center=true) { + rotate(180/$fn) circle(d=d); + translate([0,-d/2]) square([d/3,d]); + } + for(i=[0,1]) mirror([0,i,0]) + translate([0,-inx/2-th,d/2]) { + rotate([0,90,0]) linear_extrude(iny+2*th, center=true) { + rotate(180/$fn) circle(d=d); + } + translate([-iny/2-th,0]) sphere(d=d); + } + } +} + function antenna_info() = [ ["category", "misc"], ["watch", "nowhere"], @@ -180,6 +241,12 @@ function serialcon_rpi_info() = [ ["watch", "sky"], ]; +function duct_info() = [ + ["category", "misc"], + ["watch", "sky"], +]; + + components_demo(pad=40) { antenna(); capacitor(); @@ -189,4 +256,5 @@ components_demo(pad=40) { led(); serialcon_rpi(); rt_bbb(); + duct(); } diff --git a/electronics/usb.scad b/electronics/usb.scad index 71d6058..ed688a3 100644 --- a/electronics/usb.scad +++ b/electronics/usb.scad @@ -67,7 +67,7 @@ module usbx2(dim=[18, 14.5, 16], clr=c_black, has_folding=true) { cube([l, w, 3.5]); } -module microusb(dim=[6, 10, 6]) { +module microusb(dim=[6, 8, 3]) { jack_dim = [6, 8, 3]; l = jack_dim[0]; w = jack_dim[1]; @@ -78,8 +78,8 @@ module microusb(dim=[6, 10, 6]) { p_h = dim[2]; rotate([0, 0, 180]) translate(jack_dim * -.5) { // XXX color(c_metal) { - translate([l-1, (w-p_w)/2, (h-p_h)/2]) - cube([1, p_w, p_h]); + translate([l-1,0,0]) rotate([90, 0, 90]) linear_extrude(1) + polygon(microusb_polygon_pos); rotate([90, 0, 90]) { linear_extrude(height=l-1) { difference() { @@ -96,6 +96,7 @@ module microusb(dim=[6, 10, 6]) { } } + module miniusb(dim=[7.1, 8, 4]) { // TODO: merge with microusb (XXX: HDMI?) l = dim[0]; @@ -108,7 +109,8 @@ module miniusb(dim=[7.1, 8, 4]) { [0, h-1.5]]; translate(dim * -.5) { // XXX color(c_metal) { - cube([l-depth, w, h]); + rotate([90, 0, 90]) linear_extrude(l-depth) + polygon(otg_polygon_pos); translate([l-depth, 0, 0]) { rotate([90, 0, 90]) { linear_extrude(height=depth) { @@ -127,6 +129,56 @@ module miniusb(dim=[7.1, 8, 4]) { } } +module usbc_inner_profile(d,sep) { + hull() { + translate([-sep/2,0]) circle(d=d); + translate([ sep/2,0]) circle(d=d); + } +} + +// VALCON CSP-USC16-TR on RPi4 +module usbc(dim=[7.35, 8.94, 3.2], th=0.3) { + d2 = 2.56; // usb-c spec inner receptacle height + l = dim[0]; + w = dim[1]; + h = dim[2]; + + d = d2 + 2*th; // outer height/diameter + zoff = h-d; + + sep = 8.34-d2; + + l_leg1 = 1.4; + l_leg2 = 1.1; + h_leg = h/2; + + recess_tab = 0.4; + l_tab = l-recess_tab; + w_tab = 6.69; + h_tab = 0.7; + l_plug = 2.5; + + translate([l/2,0,0]) { + color(c_black) + translate([-l_tab-recess_tab,-w_tab/2,-h_tab/2]) + cube([l_tab,w_tab,h_tab]); + union() { + color(c_metal) for(i=[0,1]) mirror([0,i,0]) { + translate([-l_leg1-2.20,w/2-th,-h_leg]) cube([l_leg1,th,h_leg+zoff]); + translate([-l_leg2-6.22,w/2-th,-h_leg]) cube([l_leg2,th,h_leg+zoff]); + } + translate([0,0,zoff]) rotate([90,0,-90]) { + color(c_metal) linear_extrude(height=l) difference() { + offset(th) usbc_inner_profile(d2, sep); + usbc_inner_profile(d2, sep); + } + color(c_black) translate([0,0,l-l_plug]) linear_extrude(height=l_plug) + usbc_inner_profile(d2, sep); + } + } + } +} + function usb_info() = [ ["category", "usb"], ["watch", "horizon"], @@ -134,10 +186,15 @@ function usb_info() = [ function usbx2_info() = usb_info(); function microusb_info() = usb_info(); function miniusb_info() = usb_info(); +function usbc_info() = usb_info(); -components_demo(pad=40) { +// easier to keep in view with rows first for 5 components +components_demo(pad=30, rowsfirst=true) { usb(); usbx2(); microusb(); miniusb(); + usbc(); } + + diff --git a/globals.scad b/globals.scad index ec895b6..7829158 100644 --- a/globals.scad +++ b/globals.scad @@ -25,3 +25,4 @@ c_green_pcb = [.00,.50,.25]; c_metal = [.70,.70,.70]; c_yellow = [.70,.70,.30]; c_darkblue = [.20,.30,.40]; +c_usb_blue = [.20,.60, 1]; diff --git a/pics/rpi4.jpg b/pics/rpi4.jpg new file mode 100644 index 0000000..81e84ca Binary files /dev/null and b/pics/rpi4.jpg differ diff --git a/pics/rpi4_blower.jpg b/pics/rpi4_blower.jpg new file mode 100644 index 0000000..f8b0e28 Binary files /dev/null and b/pics/rpi4_blower.jpg differ diff --git a/pics/small/rpi4.jpg b/pics/small/rpi4.jpg new file mode 100644 index 0000000..6e0a096 Binary files /dev/null and b/pics/small/rpi4.jpg differ diff --git a/pics/small/rpi4_blower.jpg b/pics/small/rpi4_blower.jpg new file mode 100644 index 0000000..598503f Binary files /dev/null and b/pics/small/rpi4_blower.jpg differ diff --git a/utils.scad b/utils.scad index c17afd4..92bf59a 100644 --- a/utils.scad +++ b/utils.scad @@ -82,6 +82,8 @@ module bounding_box(board_dim, comp_info_list, padding, extruded_dim=50) { dim = comp_info[1]; watch = map_get(info, "watch"); category = map_get(info, "category"); + // allow components to override default padding in special cases + padding = len(comp_info)==7 ? comp_info[6] : padding; /* extrude mask and its inverse */ ex_mask = [watch == "horizon" ? 1 : 0, 0, watch == "sky" ? 1 : 0]; @@ -94,7 +96,7 @@ module bounding_box(board_dim, comp_info_list, padding, extruded_dim=50) { translate(box_tr) { minkowski() { cube(box_dim, center=true); - sphere(d=2*padding, center=true); + sphere(d=2*padding); } } }