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) |  |
| [Orange Pi Zero](boards/orangepi_zero.scad) |  |
| [Raspberry Pi 3](boards/rpi3.scad) |  |
+| [Raspberry Pi 4](boards/rpi4.scad) |  |
Corresponding cases
@@ -34,6 +35,8 @@ Corresponding cases
| [NanoPi Neo 2](cases/nanopi_neo2.scad) |  | [VERIFIED](pics/nanopi_neo2.jpg):
 |
| [Orange Pi Zero](cases/orangepi_zero.scad) |  | [VERIFIED](pics/orangepi_zero.jpg):
 |
| [Raspberry Pi 3](cases/rpi3.scad) |  | [VERIFIED](pics/rpi3.jpg):
 |
+| [Raspberry Pi 4](cases/rpi4.scad) |  | [VERIFIED](pics/rpi4.jpg):
 |
+| [Raspberry Pi 4](cases/rpi4_blower.scad)(blower fan case) |  | [VERIFIED](pics/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);
}
}
}