Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
129f1890df | ||
|
5a274cdb03 | ||
|
3e5afb4ebd | ||
|
09336f1d0d | ||
|
58fc149bbe | ||
|
659c75c628 | ||
|
ebde72fab1 | ||
|
4d0931df73 | ||
|
f17455be4f | ||
|
b85aee5fe1 | ||
|
a7c184e6cb | ||
|
f1c4576519 | ||
|
61dbc1e75a | ||
|
8b61f86eb6 | ||
|
384480e824 | ||
|
78e7a2b34a | ||
|
eddd8f28e7 | ||
|
fd03cb0b30 | ||
|
bf2050ef08 | ||
|
4f94f1d14c | ||
|
0295678c71 | ||
|
1c72dd1dbc | ||
|
0c48f112a1 | ||
|
af395dbe35 | ||
|
ebf44a1045 | ||
|
7e5ecf72c2 | ||
|
9b15bc71dc | ||
|
b4ecb1c922 | ||
|
4d14bc667e | ||
|
462a22943a | ||
|
d8329f5401 | ||
|
118fe703b5 | ||
|
383bcd084e | ||
|
6a6c5c57d2 | ||
|
c259f393e3 | ||
|
edb9f88fd9 | ||
|
0cee713849 | ||
|
85b27cd915 |
@ -8,6 +8,14 @@ Pip-Boy inspired phone holder built around the PINE64 PinePhone.
|
|||||||
- OpenScad
|
- OpenScad
|
||||||
- [BOSL library](https://github.com/revarbat/BOSL)
|
- [BOSL library](https://github.com/revarbat/BOSL)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
### PIP slideout back cover
|
||||||
|
The back cover is composed of two interconnected components, printed in place (PIP). This allows the cover to expand and retract again, automatically connecting any connectors fixed to the cover.
|
||||||
|

|
||||||
|
|
||||||
|
The inner construction makes sure the back cover remains sturdy and the two pieces are inseparable. See the "xray":
|
||||||
|

|
||||||
|
|
||||||
## Build Instructions
|
## Build Instructions
|
||||||
See [Instructions Readme](instructions/README.md).
|
See [Instructions Readme](instructions/README.md).
|
||||||
|
|
||||||
|
BIN
feature_bottom_pip.png
Normal file
BIN
feature_bottom_pip.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 83 KiB |
BIN
feature_bottom_pip_xray.png
Normal file
BIN
feature_bottom_pip_xray.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
BIN
frame00000.png
BIN
frame00000.png
Binary file not shown.
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 92 KiB |
218
main.scad
218
main.scad
@ -1,218 +0,0 @@
|
|||||||
// dependency: https://github.com/revarbat/BOSL
|
|
||||||
include <BOSL/constants.scad>
|
|
||||||
use <BOSL/transforms.scad>
|
|
||||||
use <BOSL/shapes.scad>
|
|
||||||
use <BOSL/masks.scad>
|
|
||||||
|
|
||||||
// DEBUG:
|
|
||||||
//validation = 1;
|
|
||||||
//xray = 1;
|
|
||||||
|
|
||||||
// EXPORT:
|
|
||||||
MODEL_HARNESS_LEFT=1;
|
|
||||||
MODEL_HARNESS_RIGHT=2;
|
|
||||||
MODEL_HARNESS_TOP=3;
|
|
||||||
export=2; // [0:5]
|
|
||||||
function is_not_export() = is_undef(export) || export == 0;
|
|
||||||
function is_export() = !is_not_export();
|
|
||||||
function is_model_strict(m) = is_export() && export == m;
|
|
||||||
function is_model(m) = is_not_export() || export == m;
|
|
||||||
|
|
||||||
function get_phone_size() = [160, 76.7, 10];
|
|
||||||
|
|
||||||
rim_edge_thickness=0.8;
|
|
||||||
rim_edge_tolerance=0.6;
|
|
||||||
|
|
||||||
module phone() {
|
|
||||||
s=get_phone_size();
|
|
||||||
color("gray")
|
|
||||||
cuboid(s, fillet=5);
|
|
||||||
}
|
|
||||||
module arm() {
|
|
||||||
$fn=6;
|
|
||||||
s=[210, 55, 50];
|
|
||||||
color("SaddleBrown")
|
|
||||||
down(s.z/2 + get_phone_size().z/2) cuboid(s, fillet=20);
|
|
||||||
}
|
|
||||||
|
|
||||||
module phone_harness() {
|
|
||||||
ops=get_phone_size();
|
|
||||||
ps=[ops.x+0.2, ops.y+0.2, ops.z+0.2];
|
|
||||||
w=1;
|
|
||||||
f=2;
|
|
||||||
rf=5;
|
|
||||||
hs=[ps.x+w*2, ps.y+w*2, ps.z+w*2];
|
|
||||||
|
|
||||||
module shell() {
|
|
||||||
$fn = $preview ? 6 : 30;
|
|
||||||
difference() {
|
|
||||||
cuboid(hs, fillet=f);
|
|
||||||
cuboid(ps, fillet=f);
|
|
||||||
}
|
|
||||||
shell_rim();
|
|
||||||
}
|
|
||||||
module shell_rim() {
|
|
||||||
$fn = $preview ? 6 : 30;
|
|
||||||
w=2;
|
|
||||||
s=[hs.x+2*w, hs.y+2*w, 6];
|
|
||||||
intersection() {
|
|
||||||
difference() {
|
|
||||||
cuboid(s, fillet=rf, edges=EDGES_Z_ALL);
|
|
||||||
cuboid(ps, fillet=f, edges=EDGES_Z_ALL);
|
|
||||||
}
|
|
||||||
cuboid(s, fillet=1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module shell_rim_edge(thickness, groove, tolerance=rim_edge_tolerance) {
|
|
||||||
$fn = $preview ? 6 : 30;
|
|
||||||
w=thickness + (groove ? tolerance : 0);
|
|
||||||
offset=(groove ? 0 : tolerance/2);
|
|
||||||
res=[hs.x+2*(w+offset), hs.y+2*(w+offset), 4.5];
|
|
||||||
resi=[hs.x+2*offset, hs.y+2*offset, res.z+1];
|
|
||||||
up(0.5) difference() {
|
|
||||||
intersection() {
|
|
||||||
cuboid(res, fillet=rf, edges=EDGES_Z_ALL);
|
|
||||||
cuboid(res, fillet=(groove?1:2), edges=EDGES_BOTTOM);
|
|
||||||
}
|
|
||||||
cuboid(resi, fillet=rf, edges=EDGES_Z_ALL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module screen_cutout() {
|
|
||||||
s=[138, 69, 10];
|
|
||||||
up(s.z/2) cuboid(s, fillet=3, edges=EDGES_Z_ALL);
|
|
||||||
}
|
|
||||||
top_offset=6.5;
|
|
||||||
module speaker_cutout() {
|
|
||||||
s=[3, 12, 10];
|
|
||||||
right(ps.x/2 - top_offset) up(ps.z/2) cuboid(s, fillet=1);
|
|
||||||
}
|
|
||||||
module front_camera_cutout() {
|
|
||||||
$fn = $preview ? 6 : 30;
|
|
||||||
d=5;
|
|
||||||
s=[d, d, 10];
|
|
||||||
right(ps.x/2 - top_offset) fwd(11) cylinder(d=s.x, h=s.z);
|
|
||||||
}
|
|
||||||
module leds_cutout() {
|
|
||||||
s=[4, 14, 10];
|
|
||||||
right(ps.x/2 - top_offset) up(ps.z/2) back(23) cuboid(s, fillet=1);
|
|
||||||
}
|
|
||||||
module top_cutout() {
|
|
||||||
screen_cutout();
|
|
||||||
speaker_cutout();
|
|
||||||
front_camera_cutout();
|
|
||||||
leds_cutout();
|
|
||||||
}
|
|
||||||
|
|
||||||
module back_camera_cutout() {
|
|
||||||
s=[13, 25, 10];
|
|
||||||
right(ps.x/2 - 8) fwd(ps.y/2 - 23) down(ps.z/2) cuboid(s, fillet=6, edges=EDGES_Z_ALL);
|
|
||||||
}
|
|
||||||
module bottom_cutout() {
|
|
||||||
back_camera_cutout();
|
|
||||||
}
|
|
||||||
|
|
||||||
module headphones_cutout() {
|
|
||||||
$fn = $preview ? 10 : 30;
|
|
||||||
d=9;
|
|
||||||
p=[ps.x/2, ps.y/2-24, -1];
|
|
||||||
h=10;
|
|
||||||
translate(p) yrot(90) down(h/2) cylinder(h=h, d=d);
|
|
||||||
}
|
|
||||||
module right_cutout() {
|
|
||||||
headphones_cutout();
|
|
||||||
}
|
|
||||||
|
|
||||||
module usbc_cutout() {
|
|
||||||
s=[10, 20, 6];
|
|
||||||
left(ps.x/2) down(2) cuboid(s, fillet=1);
|
|
||||||
}
|
|
||||||
module left_cutout() {
|
|
||||||
usbc_cutout();
|
|
||||||
}
|
|
||||||
|
|
||||||
module buttons_cutout() {
|
|
||||||
s=[42, 10, 5];
|
|
||||||
fwd(ps.y/2) right(ps.x/2 - 44.5) cuboid(s, fillet=1);
|
|
||||||
}
|
|
||||||
module front_cutout() {
|
|
||||||
buttons_cutout();
|
|
||||||
}
|
|
||||||
|
|
||||||
module shell_cutouts() {
|
|
||||||
top_cutout();
|
|
||||||
bottom_cutout();
|
|
||||||
left_cutout();
|
|
||||||
right_cutout();
|
|
||||||
front_cutout();
|
|
||||||
}
|
|
||||||
|
|
||||||
divider=[30, 0, 2.3];
|
|
||||||
module model_harness_left() {
|
|
||||||
intersection() {
|
|
||||||
intersection() {
|
|
||||||
translate(divider) downcube([1000, 1000, 1000]);
|
|
||||||
translate(divider) leftcube([1000, 1000, 1000]);
|
|
||||||
}
|
|
||||||
difference() {
|
|
||||||
shell();
|
|
||||||
shell_rim_edge(rim_edge_thickness, groove=true, tolerance=rim_edge_tolerance);
|
|
||||||
shell_cutouts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module model_harness_right() {
|
|
||||||
intersection() {
|
|
||||||
intersection() {
|
|
||||||
translate(divider) downcube([1000, 1000, 1000]);
|
|
||||||
translate(divider) rightcube([1000, 1000, 1000]);
|
|
||||||
}
|
|
||||||
difference() {
|
|
||||||
shell();
|
|
||||||
shell_rim_edge(rim_edge_thickness, groove=true, tolerance=rim_edge_tolerance);
|
|
||||||
shell_cutouts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module model_harness_top() {
|
|
||||||
intersection() {
|
|
||||||
translate(divider) upcube([1000, 1000, 1000]);
|
|
||||||
difference() {
|
|
||||||
shell();
|
|
||||||
shell_cutouts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
difference() {
|
|
||||||
shell_rim_edge(rim_edge_thickness, groove=false);
|
|
||||||
shell_cutouts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_model(MODEL_HARNESS_LEFT)) model_harness_left();
|
|
||||||
if (is_model(MODEL_HARNESS_RIGHT)) model_harness_right();
|
|
||||||
if (is_model(MODEL_HARNESS_TOP)) model_harness_top();
|
|
||||||
}
|
|
||||||
|
|
||||||
module model() {
|
|
||||||
phone_harness();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_undef(validation)) {
|
|
||||||
intersection() {
|
|
||||||
phone();
|
|
||||||
model();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
intersection() {
|
|
||||||
if (!is_undef(xray)) {
|
|
||||||
span_cube([0,1000*xray], [0,1000*xray], [-1000,1000]);
|
|
||||||
}
|
|
||||||
union() {
|
|
||||||
if (is_not_export()) {
|
|
||||||
//phone();
|
|
||||||
//arm();
|
|
||||||
}
|
|
||||||
model();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
22
src/common.scad
Normal file
22
src/common.scad
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use <BOSL/shapes.scad>
|
||||||
|
include <BOSL/constants.scad>
|
||||||
|
|
||||||
|
module cubi(s, fillet=0, edges=EDGES_ALL) {
|
||||||
|
if ($preview) {
|
||||||
|
cube(s, center=true);
|
||||||
|
} else {
|
||||||
|
cuboid(s, fillet=fillet, edges=edges);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module screwhole(d, h, head=true) {
|
||||||
|
$fn=$preview ? 5 : 20;
|
||||||
|
translate([0, 0, h]) cylinder(d=d*1.5, h=d*0.5);
|
||||||
|
split=h*0.5;
|
||||||
|
translate([0, 0, split]) cylinder(d=d, h=(h-split));
|
||||||
|
cylinder(d2=d, d1=d*0.1, h=split);
|
||||||
|
cylinder(d2=d*0.6, d1=d*0.6, h=split/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function vec_sum(v, w) = [v.x + w.x, v.y + w.y, v.z + w.z];
|
||||||
|
|
32
src/export.scad
Normal file
32
src/export.scad
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
export=0; // <-- prepend to the main file to activate the export
|
||||||
|
*/
|
||||||
|
|
||||||
|
function is_not_export() = is_undef(export) || export == 0;
|
||||||
|
function is_export() = !is_not_export();
|
||||||
|
function is_model_strict(m) = is_export() && export == m;
|
||||||
|
function is_model(m) = is_not_export() || export == m;
|
||||||
|
|
||||||
|
MODEL_DEMO=0;
|
||||||
|
|
||||||
|
// Harness
|
||||||
|
MODEL_HARNESS_LEFT=101;
|
||||||
|
MODEL_HARNESS_RIGHT=102;
|
||||||
|
MODEL_HARNESS_BOTTOM=103;
|
||||||
|
MODEL_HARNESS_BOTTOM_PIP=104;
|
||||||
|
MODEL_HARNESS_TOP=105;
|
||||||
|
MODEL_HARNESS_SLIDER_FRONT=106;
|
||||||
|
MODEL_HARNESS_SLIDER_BACK=107;
|
||||||
|
MODEL_HARNESS_BUTTONS=108;
|
||||||
|
|
||||||
|
// Platform
|
||||||
|
MODEL_PLATFORM_HARNESS=201;
|
||||||
|
MODEL_PLATFORM_STRAP=202;
|
||||||
|
|
||||||
|
// Strap
|
||||||
|
MODEL_LINKS=301;
|
||||||
|
MODEL_CLIP_A=302;
|
||||||
|
MODEL_CLIP_B=303;
|
||||||
|
MODEL_CLIP_RATCHETING=304;
|
||||||
|
MODEL_CLIP_RATCHETING_A=305;
|
||||||
|
MODEL_CLIP_RATCHETING_B=306;
|
425
src/harness.scad
Normal file
425
src/harness.scad
Normal file
@ -0,0 +1,425 @@
|
|||||||
|
include <export.scad>
|
||||||
|
|
||||||
|
// dependency: https://github.com/revarbat/BOSL
|
||||||
|
include <BOSL/constants.scad>
|
||||||
|
use <BOSL/transforms.scad>
|
||||||
|
use <BOSL/shapes.scad>
|
||||||
|
use <BOSL/masks.scad>
|
||||||
|
use <BOSL/sliders.scad>
|
||||||
|
|
||||||
|
use <specs_phone.scad>
|
||||||
|
use <specs_harness.scad>
|
||||||
|
use <specs_platform.scad>
|
||||||
|
|
||||||
|
// DEBUG:
|
||||||
|
//validation = 1;
|
||||||
|
XRAY_POSITIVE=1;
|
||||||
|
XRAY_BACKPLANE=2;
|
||||||
|
XRAY_BOTTOM=3;
|
||||||
|
//xray = 2;
|
||||||
|
|
||||||
|
function use_slideout_backplane() = is_model_strict(MODEL_HARNESS_BOTTOM_PIP) || is_model_strict(MODEL_HARNESS_LEFT) || is_model_strict(MODEL_HARNESS_RIGHT);
|
||||||
|
|
||||||
|
backplane_pip_slideout=10;
|
||||||
|
|
||||||
|
use <common.scad>
|
||||||
|
|
||||||
|
module dotted_grill_cutout(vents_area, vents_x=10, vents_y=10, mesh=1.5, cut_corners=false) {
|
||||||
|
function is_corner(x, y, xm, ym) = (x == 0 || x == xm) && (y == 0 || y == ym);
|
||||||
|
vent_size=[vents_area.x/vents_x-mesh, vents_area.y/vents_y-mesh, vents_area.z];
|
||||||
|
translate([-vents_area.x/2 - vent_size.x/2, vents_area.y/2 - vent_size.y/2, 0])
|
||||||
|
for (x=[0:vents_x-1]) {
|
||||||
|
for (y=[0:vents_y-1]) {
|
||||||
|
if (!cut_corners || !is_corner(x, y, vents_x-1, vents_y-1)) {
|
||||||
|
right(x*(vent_size.x+mesh))
|
||||||
|
fwd(y*(vent_size.y+mesh))
|
||||||
|
cubi(vent_size, fillet=min(vent_size.x/2, vent_size.y/2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module phone() {
|
||||||
|
s=get_phone_size();
|
||||||
|
color("gray")
|
||||||
|
cubi(s, fillet=5);
|
||||||
|
}
|
||||||
|
module arm() {
|
||||||
|
$fn=6;
|
||||||
|
s=[210, 55, 50];
|
||||||
|
color("SaddleBrown")
|
||||||
|
down(s.z/2 + get_phone_size().z/2) cubi(s, fillet=20);
|
||||||
|
}
|
||||||
|
|
||||||
|
module phone_harness() {
|
||||||
|
ops=get_phone_size();
|
||||||
|
ps=[ops.x+0.2, ops.y+0.2, ops.z+0.2];
|
||||||
|
shell_wall=3;
|
||||||
|
shell_rim_wall=3;
|
||||||
|
rim_edge_thickness=1.5;
|
||||||
|
rim_edge_tolerance=0.4;
|
||||||
|
expose_back_camera=true;
|
||||||
|
screwmount_screw=3;
|
||||||
|
harness_divider=[1, 0, 1.3];
|
||||||
|
harness_size=[ps.x+shell_wall*2, ps.y+shell_wall*2, ps.z+shell_wall*2];
|
||||||
|
rim_size=[harness_size.x+2*shell_rim_wall, harness_size.y+2*shell_rim_wall, 8];
|
||||||
|
|
||||||
|
w=shell_wall;
|
||||||
|
f=2;
|
||||||
|
rf=5;
|
||||||
|
hs=harness_size;
|
||||||
|
backplane_rim_size=[40, ps.y*0.95, shell_wall/2];
|
||||||
|
backplane_teeth=6;
|
||||||
|
|
||||||
|
// ==== SHELL ====
|
||||||
|
|
||||||
|
module shell() {
|
||||||
|
$fn = $preview ? 6 : 30;
|
||||||
|
difference() {
|
||||||
|
cubi(hs, fillet=f);
|
||||||
|
cubi(ps, fillet=f);
|
||||||
|
}
|
||||||
|
shell_rim();
|
||||||
|
shell_screwmounts();
|
||||||
|
}
|
||||||
|
module shell_rim() {
|
||||||
|
$fn = $preview ? 6 : 30;
|
||||||
|
w=shell_rim_wall;
|
||||||
|
s=rim_size;
|
||||||
|
intersection() {
|
||||||
|
difference() {
|
||||||
|
cubi(s, fillet=rf, edges=EDGES_Z_ALL);
|
||||||
|
cubi(ps, fillet=f, edges=EDGES_Z_ALL);
|
||||||
|
}
|
||||||
|
cubi(s, fillet=1);
|
||||||
|
}
|
||||||
|
rail_extension=10;
|
||||||
|
fwd(hs.y/2) xrot(90) harness_rail(slider_len_front+rail_extension);
|
||||||
|
back(hs.y/2) xrot(-90) harness_rail(slider_len_back+rail_extension);
|
||||||
|
}
|
||||||
|
module shell_rim_edge(thickness, groove, tolerance=rim_edge_tolerance) {
|
||||||
|
$fn = $preview ? 6 : 30;
|
||||||
|
w=thickness + (groove ? tolerance : 0);
|
||||||
|
offset=(groove ? 0 : tolerance/2);
|
||||||
|
res=[hs.x+2*(w+offset), hs.y+2*(w+offset), 3];
|
||||||
|
resi=[hs.x+2*offset, hs.y+2*offset, res.z+1];
|
||||||
|
up(0.0) difference() {
|
||||||
|
intersection() {
|
||||||
|
cubi(res, fillet=rf, edges=EDGES_Z_ALL);
|
||||||
|
cubi(res, fillet=(groove?1:1.5), edges=EDGES_BOTTOM);
|
||||||
|
}
|
||||||
|
cubi(resi, fillet=rf, edges=EDGES_Z_ALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module foreach_screwmount() {
|
||||||
|
for(x = [0:1]) for (y = [0:1]) {
|
||||||
|
translate([(-0.5+x)*ps.x, (-0.5+y)*ps.y, -hs.z/2])
|
||||||
|
children();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module shell_screwmounts() {
|
||||||
|
$fn = $preview ? 6 : 30;
|
||||||
|
r=3;
|
||||||
|
foreach_screwmount() {
|
||||||
|
cylinder(r=r, h=hs.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module shell_screwmounts_holes() {
|
||||||
|
$fn = $preview ? 6 : 30;
|
||||||
|
foreach_screwmount() {
|
||||||
|
up(w) cylinder(d2=screwmount_screw, d1=screwmount_screw*0.5, h=hs.z+1);
|
||||||
|
up(hs.z-1) cylinder(d=screwmount_screw+1.5, h=5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module shell_backplane(groove) {
|
||||||
|
module groove_scale() { scale([groove?1.05:1, groove?1.05:1, groove?1.2:1]) children(); }
|
||||||
|
|
||||||
|
if (use_slideout_backplane()) {
|
||||||
|
down(hs.z/2 - shell_wall/3) up(backplane_rim_size.z/2) right(harness_divider.x) {
|
||||||
|
back(backplane_rim_size.y/2) {
|
||||||
|
teeth=backplane_teeth;
|
||||||
|
segment=backplane_rim_size.y/teeth;
|
||||||
|
tooth_size=[backplane_rim_size.x, segment/2, backplane_rim_size.z];
|
||||||
|
joiner_base=5;
|
||||||
|
joiner_size=[joiner_base + (groove?backplane_pip_slideout:0), segment*1.5, backplane_rim_size.z];
|
||||||
|
for (i = [0:teeth-1]) {
|
||||||
|
fwd(i*segment) fwd(tooth_size.y) {
|
||||||
|
groove_scale() cubi(tooth_size, fillet=0.5, edges=EDGES_X_ALL);
|
||||||
|
if (i%2 == 0) {
|
||||||
|
left(backplane_rim_size.x/2 + joiner_base/2) fwd(joiner_size.y/3) left(-joiner_size.x/2) groove_scale() cubi(joiner_size, fillet=2, edges=EDGES_Z_ALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==== SHELL SLIDER AND RAIL ====
|
||||||
|
|
||||||
|
rail_angle=36;
|
||||||
|
rail_wall=1;
|
||||||
|
slider_slop=0.1;
|
||||||
|
slider_len_back=hs.x*0.3;
|
||||||
|
slider_len_front=hs.x*0.15;
|
||||||
|
module harness_slider(l) {
|
||||||
|
base=2;
|
||||||
|
ss=[l, shell_rim_wall, rim_size.z+rail_wall*2];
|
||||||
|
up(ss.y + base) xrot(180) difference() {
|
||||||
|
slider(l=ss.x, w=ss.z, h=ss.y, base=base, chamfer=0.9, wall=2, ang=rail_angle, slop=slider_slop, orient=ORIENT_X, align=V_UP);
|
||||||
|
screws=2;
|
||||||
|
screws_area_l=0.7*l;
|
||||||
|
for (i=[0:screws-1]) {
|
||||||
|
$fn=$preview ? 6 : 16;
|
||||||
|
right(-screws_area_l/2 + screws_area_l/(screws-1) * i) cylinder(d2=screwmount_screw*0.5, d1=screwmount_screw, h=ss.y*0.7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module harness_rail(l) {
|
||||||
|
sw=2;
|
||||||
|
ss=[l, shell_rim_wall, rim_size.z+rail_wall*2];
|
||||||
|
rail(l=ss.x, w=ss.z, h=ss.y, chamfer=0.5, ang=rail_angle, orient=ORIENT_X, align=V_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==== SHELL CUTOUTS ====
|
||||||
|
module shell_cutouts() {
|
||||||
|
top_cutout();
|
||||||
|
bottom_cutout();
|
||||||
|
left_cutout();
|
||||||
|
right_cutout();
|
||||||
|
front_cutout();
|
||||||
|
shell_screwmounts_holes();
|
||||||
|
}
|
||||||
|
// -- TOP --
|
||||||
|
module screen_cutout() {
|
||||||
|
$fn=$preview ? 4 : 12;
|
||||||
|
s=[138, 69, 12];
|
||||||
|
b = 10;
|
||||||
|
s1=[s.x, s.y];
|
||||||
|
s2=[s.x+b, s.y+b];
|
||||||
|
h=s.z;
|
||||||
|
up(5) rounded_prismoid(size1=s1, size2=s2, h=h, r1=1, r2=15);
|
||||||
|
}
|
||||||
|
top_offset=6.5;
|
||||||
|
module top_speaker_cutout() {
|
||||||
|
s=[3, 12, 100];
|
||||||
|
right(ps.x/2 - top_offset) up(s.z/2 - ps.z/3) cubi(s, fillet=1);
|
||||||
|
}
|
||||||
|
module front_camera_cutout() {
|
||||||
|
$fn = $preview ? 6 : 30;
|
||||||
|
d=5;
|
||||||
|
s=[d, d, 100];
|
||||||
|
right(ps.x/2 - top_offset) fwd(11.5) cylinder(d=s.x, h=s.z);
|
||||||
|
}
|
||||||
|
module leds_cutout() {
|
||||||
|
s=[4, 14, 100];
|
||||||
|
right(ps.x/2 - top_offset) up(s.z/2 - ps.z/3) back(23) cubi(s, fillet=1);
|
||||||
|
}
|
||||||
|
module top_cutout() {
|
||||||
|
screen_cutout();
|
||||||
|
top_speaker_cutout();
|
||||||
|
front_camera_cutout();
|
||||||
|
leds_cutout();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- BOTTOM --
|
||||||
|
module back_camera_cutout() {
|
||||||
|
s=[13, 25, expose_back_camera ? 100 : 11];
|
||||||
|
right(ps.x/2 - 7.5) fwd(ps.y/2 - 24.5) down(s.z/2 - ps.z/3) cubi(s, fillet=6, edges=EDGES_Z_ALL);
|
||||||
|
}
|
||||||
|
module bottom_speaker_cutout() {
|
||||||
|
s=[8, 49, 100];
|
||||||
|
left(ps.x/2 - 13)
|
||||||
|
down(s.z/2 - ps.z/3)
|
||||||
|
dotted_grill_cutout(s, vents_x=4, vents_y=8, cut_corners=true, mesh=1);
|
||||||
|
}
|
||||||
|
module bottom_vents_cutout() {
|
||||||
|
vents_x=10;
|
||||||
|
vents_y=6;
|
||||||
|
vents_area=[35, 50, 10];
|
||||||
|
vents_pos=[45, 0, -ps.z/2];
|
||||||
|
mesh=1.5;
|
||||||
|
translate(vents_pos)
|
||||||
|
dotted_grill_cutout(vents_area, vents_x=vents_x, vents_y=vents_y, mesh=mesh, cut_corners=true);
|
||||||
|
}
|
||||||
|
module bottom_cutout() {
|
||||||
|
back_camera_cutout();
|
||||||
|
bottom_speaker_cutout();
|
||||||
|
bottom_vents_cutout();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- RIGHT --
|
||||||
|
module headphones_cutout() {
|
||||||
|
$fn = $preview ? 10 : 30;
|
||||||
|
d1=8.8;
|
||||||
|
d2=14;
|
||||||
|
p=[ps.x/2, ps.y/2-24, -0.88];
|
||||||
|
h=22;
|
||||||
|
translate(p) yrot(90) down(10) cylinder(h=h, d1=d1, d2=d2);
|
||||||
|
}
|
||||||
|
module right_cutout() {
|
||||||
|
headphones_cutout();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- LEFT --
|
||||||
|
module usbc_cutout() {
|
||||||
|
s=[20, 20, 7];
|
||||||
|
left(ps.x/2) down(2) cubi(s, fillet=1);
|
||||||
|
}
|
||||||
|
module left_cutout() {
|
||||||
|
usbc_cutout();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- FRONT --
|
||||||
|
buttons_cutout_size=[42, 100, 4.5];
|
||||||
|
buttons_cutout_pos=[ps.x/2 - 44.5, -ps.y/2 - 3, 0.25];
|
||||||
|
module buttons_cutout() {
|
||||||
|
s=buttons_cutout_size;
|
||||||
|
p=buttons_cutout_pos;
|
||||||
|
translate(p) cubi(s, fillet=1);
|
||||||
|
}
|
||||||
|
module front_cutout() {
|
||||||
|
buttons_cutout();
|
||||||
|
}
|
||||||
|
module front_buttons(socket) {
|
||||||
|
s=[buttons_cutout_size.x-2, 4, buttons_cutout_size.z-0.5];
|
||||||
|
p=buttons_cutout_pos;
|
||||||
|
t=socket ? 0.2 : 0;
|
||||||
|
pin_size=[3 + t, 3 + t, s.z+2 + t/2];
|
||||||
|
touch_size=[2, s.y, 2];
|
||||||
|
touch_power_size=[3, touch_size.y, touch_size.z];
|
||||||
|
translate(p) {
|
||||||
|
cs=[4, s.y, s.z];
|
||||||
|
left(5) {
|
||||||
|
bs=[13, s.y, s.z];
|
||||||
|
left(bs.x/6) cubi(pin_size);
|
||||||
|
left(bs.x/2) {
|
||||||
|
difference() {
|
||||||
|
cubi(bs);
|
||||||
|
back(1) cubi(cs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fwd(1) left(bs.x*0.8) cubi(touch_power_size, fillet=1);
|
||||||
|
}
|
||||||
|
right(8) {
|
||||||
|
bs=[18, s.y, s.z];
|
||||||
|
cubi(pin_size);
|
||||||
|
difference() {
|
||||||
|
cubi(bs);
|
||||||
|
back(1) {
|
||||||
|
left(bs.x/4) cubi(cs);
|
||||||
|
right(bs.x/4) cubi(cs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fwd(1) {
|
||||||
|
left(bs.x*0.4) cubi(touch_size, fillet=1);
|
||||||
|
right(bs.x*0.4) cubi(touch_size, fillet=1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==== MODEL ====
|
||||||
|
|
||||||
|
divider=harness_divider;
|
||||||
|
module model_harness_left() {
|
||||||
|
intersection() {
|
||||||
|
intersection() {
|
||||||
|
translate(divider) downcube([1000, 1000, 1000]);
|
||||||
|
translate(divider) leftcube([1000, 1000, 1000]);
|
||||||
|
}
|
||||||
|
difference() {
|
||||||
|
shell();
|
||||||
|
shell_rim_edge(rim_edge_thickness, groove=true, tolerance=rim_edge_tolerance);
|
||||||
|
shell_cutouts();
|
||||||
|
shell_backplane(groove=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module model_harness_right() {
|
||||||
|
intersection() {
|
||||||
|
intersection() {
|
||||||
|
translate(divider) downcube([1000, 1000, 1000]);
|
||||||
|
translate(divider) rightcube([1000, 1000, 1000]);
|
||||||
|
}
|
||||||
|
difference() {
|
||||||
|
shell();
|
||||||
|
shell_rim_edge(rim_edge_thickness, groove=true, tolerance=rim_edge_tolerance);
|
||||||
|
shell_cutouts();
|
||||||
|
front_buttons(socket=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shell_backplane(groove=false);
|
||||||
|
}
|
||||||
|
module model_harness_top() {
|
||||||
|
intersection() {
|
||||||
|
translate(divider) upcube([1000, 1000, 1000]);
|
||||||
|
difference() {
|
||||||
|
shell();
|
||||||
|
shell_cutouts();
|
||||||
|
front_buttons(socket=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
difference() {
|
||||||
|
shell_rim_edge(rim_edge_thickness, groove=false);
|
||||||
|
shell_cutouts();
|
||||||
|
front_buttons(socket=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module model_harness_slider_front() {
|
||||||
|
difference() {
|
||||||
|
fwd(hs.y/2) xrot(90) harness_slider(slider_len_front);
|
||||||
|
front_cutout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module model_harness_slider_back() {
|
||||||
|
back(hs.y/2) xrot(-90) harness_slider(slider_len_back);
|
||||||
|
}
|
||||||
|
module model_harness_buttons() {
|
||||||
|
front_buttons(socket=false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_model(MODEL_HARNESS_LEFT)) model_harness_left();
|
||||||
|
if (is_model(MODEL_HARNESS_RIGHT)) model_harness_right();
|
||||||
|
if (is_model_strict(MODEL_HARNESS_BOTTOM)) {
|
||||||
|
model_harness_left();
|
||||||
|
model_harness_right();
|
||||||
|
}
|
||||||
|
if (is_model_strict(MODEL_HARNESS_BOTTOM_PIP)) {
|
||||||
|
model_harness_left();
|
||||||
|
right(backplane_pip_slideout) model_harness_right();
|
||||||
|
}
|
||||||
|
if (is_model(MODEL_HARNESS_TOP)) model_harness_top();
|
||||||
|
if (is_model(MODEL_HARNESS_SLIDER_FRONT)) model_harness_slider_front();
|
||||||
|
if (is_model(MODEL_HARNESS_SLIDER_BACK)) model_harness_slider_back();
|
||||||
|
if (is_model(MODEL_HARNESS_BUTTONS)) model_harness_buttons();
|
||||||
|
}
|
||||||
|
|
||||||
|
module model() {
|
||||||
|
up(get_harness_size().z/2) phone_harness();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_undef(validation)) {
|
||||||
|
intersection() {
|
||||||
|
phone();
|
||||||
|
model();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
intersection() {
|
||||||
|
if (!is_undef(xray)) {
|
||||||
|
if (xray == XRAY_POSITIVE) {
|
||||||
|
span_cube([0,1000], [0,1000], [-1000,1000]);
|
||||||
|
} else if (abs(xray) == XRAY_BACKPLANE) {
|
||||||
|
span_cube([-1000,1000], [-1000,1000], [-1000*sign(xray),-6]);
|
||||||
|
} else if (xray == XRAY_BOTTOM) {
|
||||||
|
span_cube([-1000,1000], [-1000,1000], [-1000,0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
union() {
|
||||||
|
if (is_not_export()) {
|
||||||
|
//phone();
|
||||||
|
//arm();
|
||||||
|
}
|
||||||
|
model();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
src/main.scad
Normal file
6
src/main.scad
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export=0;
|
||||||
|
include <export.scad>
|
||||||
|
|
||||||
|
include <harness.scad>
|
||||||
|
include <platform.scad>
|
||||||
|
include <strap.scad>
|
134
src/platform.scad
Normal file
134
src/platform.scad
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
include <export.scad>
|
||||||
|
//export=MODEL_PLATFORM_HARNESS;
|
||||||
|
//export=MODEL_PLATFORM_STRAP;
|
||||||
|
|
||||||
|
// dependency: https://github.com/revarbat/BOSL
|
||||||
|
include <BOSL/constants.scad>
|
||||||
|
use <BOSL/transforms.scad>
|
||||||
|
use <BOSL/shapes.scad>
|
||||||
|
use <BOSL/masks.scad>
|
||||||
|
use <BOSL/sliders.scad>
|
||||||
|
|
||||||
|
use <specs_platform.scad>
|
||||||
|
use <specs_strap.scad>
|
||||||
|
|
||||||
|
use <common.scad>
|
||||||
|
use <strap_common.scad>
|
||||||
|
use <platform_common.scad>
|
||||||
|
|
||||||
|
// DEBUG:
|
||||||
|
//validation = 1;
|
||||||
|
//xray = 1;
|
||||||
|
|
||||||
|
// PROP >>
|
||||||
|
module prop_arm() {
|
||||||
|
$fn=$preview ? 10 : 30;
|
||||||
|
arm_size=[200, 55, 40];
|
||||||
|
color("gray")
|
||||||
|
down(arm_size.z/2) {
|
||||||
|
cuboid(arm_size, fillet=16, edges=EDGES_X_ALL);
|
||||||
|
left(arm_size.x*0.6) scale([1, 1, 0.8]) yrot(90) cylinder(d1=arm_size.y*1.4, d2=arm_size.y*0.95, h=arm_size.x/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module model_prop_arm() {
|
||||||
|
if (is_not_export()) down(3) prop_arm();
|
||||||
|
}
|
||||||
|
// <<<
|
||||||
|
|
||||||
|
// Blocks:
|
||||||
|
module platform(base) {
|
||||||
|
size=get_platform_size();
|
||||||
|
base_size=size;
|
||||||
|
wall=get_platform_wall();
|
||||||
|
top_size=get_platform_top_size();
|
||||||
|
top=!base;
|
||||||
|
|
||||||
|
module platform_screwholes() {
|
||||||
|
module screwhole_one() {
|
||||||
|
fwd(base_size.y/2) xrot(90) down(get_platform_screwhole_h()) screwhole(d=get_platform_screwhole_d(), h=get_platform_screwhole_h());
|
||||||
|
}
|
||||||
|
module screwhole_sided() {
|
||||||
|
offset=16;
|
||||||
|
left(offset) screwhole_one();
|
||||||
|
right(offset) screwhole_one();
|
||||||
|
}
|
||||||
|
up(top_size.z/5) {
|
||||||
|
screwhole_sided();
|
||||||
|
scale([1,-1,1]) screwhole_sided();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module base_platform_cutout_for_top() {
|
||||||
|
base_top_diff=[base_size.x-top_size.x, base_size.y-top_size.y];
|
||||||
|
guiding=1;
|
||||||
|
top_slack=[0.2, 0.2, 0];
|
||||||
|
translate(get_platform_top_pos()) {
|
||||||
|
cube(vec_sum(top_size, top_slack), center=true);
|
||||||
|
down(top_size.z/2 - 2)
|
||||||
|
prismoid(size1=[top_size.x,top_size.y], size2=[top_size.x+base_top_diff.x*guiding,top_size.y+base_top_diff.y*guiding], h=top_size.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module base_platform() {
|
||||||
|
module base_platform_core() {
|
||||||
|
braced_thinning_wall(h=size.y, l=size.x, thick=size.z, wall=0, strut=wall, orient=ORIENT_X_90);
|
||||||
|
}
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
base_platform_core();
|
||||||
|
base_platform_cutout_for_top();
|
||||||
|
platform_screwholes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module top_platform() {
|
||||||
|
difference() {
|
||||||
|
up((base_size.z-top_size.z)/2)
|
||||||
|
up(top_size.z/2) intersection() {
|
||||||
|
scale([1,1,4]) braced_thinning_wall(h=top_size.y, l=top_size.x, thick=top_size.z, wall=0, strut=wall/4, orient=ORIENT_X_90);
|
||||||
|
down(top_size.z/2) scale([2,2,1]) cube(top_size, center=true);
|
||||||
|
}
|
||||||
|
platform_screwholes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module strap_connectors() {
|
||||||
|
//down(size.z/2)
|
||||||
|
difference() {
|
||||||
|
foreach_platform_strap_connector() {
|
||||||
|
link_connector_pin();
|
||||||
|
}
|
||||||
|
base_platform_cutout_for_top();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color(top?"Olive":"YellowGreen")
|
||||||
|
if (base) {
|
||||||
|
base_platform();
|
||||||
|
strap_connectors();
|
||||||
|
} else {
|
||||||
|
top_platform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Models:
|
||||||
|
module model_platform_harness() {
|
||||||
|
platform(base=false);
|
||||||
|
}
|
||||||
|
|
||||||
|
module model_platform_strap() {
|
||||||
|
platform(base=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation:
|
||||||
|
/*intersection() {
|
||||||
|
model_platform_harness();
|
||||||
|
model_platform_strap();
|
||||||
|
}*/
|
||||||
|
// Export:
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
if (is_model(MODEL_PLATFORM_HARNESS)) model_platform_harness();
|
||||||
|
if (is_model(MODEL_PLATFORM_STRAP)) model_platform_strap();
|
||||||
|
//if (is_model(MODEL_DEMO)) model_prop_arm();
|
||||||
|
}
|
||||||
|
// xray:
|
||||||
|
//left(500+5) cube([1000, 1000, 1000], center=true);
|
||||||
|
}
|
21
src/platform_common.scad
Normal file
21
src/platform_common.scad
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// dependency: https://github.com/revarbat/BOSL
|
||||||
|
include <BOSL/constants.scad>
|
||||||
|
use <BOSL/transforms.scad>
|
||||||
|
use <BOSL/shapes.scad>
|
||||||
|
use <BOSL/masks.scad>
|
||||||
|
use <BOSL/sliders.scad>
|
||||||
|
|
||||||
|
use <specs_platform.scad>
|
||||||
|
use <specs_strap.scad>
|
||||||
|
|
||||||
|
use <strap_common.scad>
|
||||||
|
|
||||||
|
module foreach_platform_strap_connector() {
|
||||||
|
offset=get_platform_strap_connector_offset();
|
||||||
|
for (i=[0:3]) {
|
||||||
|
translate([((i%2*(-2)+1) * offset.x), -((round(i/2)%2*(-2)+1) * offset.y), offset.z])
|
||||||
|
zrot(90 + (round(i/2)%2*180))
|
||||||
|
children();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
9
src/specs_harness.scad
Normal file
9
src/specs_harness.scad
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use <specs_phone.scad>
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
function get_harness_size() = [
|
||||||
|
get_phone_size().x + 10,
|
||||||
|
get_phone_size().y + 10,
|
||||||
|
get_phone_size().z + 10,
|
||||||
|
];
|
||||||
|
|
2
src/specs_phone.scad
Normal file
2
src/specs_phone.scad
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
function get_phone_size() = [161.2, 77.2, 10];
|
||||||
|
|
22
src/specs_platform.scad
Normal file
22
src/specs_platform.scad
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use <specs_phone.scad>
|
||||||
|
use <specs_strap.scad>
|
||||||
|
|
||||||
|
function get_platform_size() = [
|
||||||
|
get_phone_size().x - 30,
|
||||||
|
get_phone_size().y - 5,
|
||||||
|
get_platform_wall()*3
|
||||||
|
];
|
||||||
|
function get_platform_top_size() = [
|
||||||
|
get_platform_size().x - 2*get_platform_wall(),
|
||||||
|
get_platform_size().y - 2*get_platform_wall(),
|
||||||
|
get_platform_size().z - get_platform_wall()];
|
||||||
|
function get_platform_top_pos() = [0, 0, (get_platform_size().z-get_platform_top_size().z)/2];
|
||||||
|
function get_platform_wall() = 3;
|
||||||
|
function get_platform_strap_connector_offset() = [
|
||||||
|
(get_platform_size().x/2 - get_link_segment_size().y/2) - 3,
|
||||||
|
get_platform_size().y/2 + 4,
|
||||||
|
-get_link_segment_size().z/2 + 0.5
|
||||||
|
];
|
||||||
|
function get_platform_screwhole_d() = 3.2;
|
||||||
|
function get_platform_screwhole_h() = 10;
|
||||||
|
|
11
src/specs_strap.scad
Normal file
11
src/specs_strap.scad
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
function get_link_segment_size() = [15, 30, 5];
|
||||||
|
function get_link_pin_diameter() = 2;
|
||||||
|
function get_link_socket_slack() = [1, 4, 1];
|
||||||
|
function get_link_joiner_arm_size() = [get_link_segment_size().x - 2, 3, get_link_segment_size().z];
|
||||||
|
function get_link_socket_size() = [get_link_segment_size().z,
|
||||||
|
get_link_segment_size().y - get_link_joiner_arm_size().y*2,
|
||||||
|
get_link_segment_size().z];
|
||||||
|
|
||||||
|
function get_link_clip_size() = [get_link_pin_diameter()*5, get_link_segment_size().y - 5, get_link_segment_size().z];
|
||||||
|
function get_link_socket_roundgap() = 2;
|
||||||
|
|
292
src/strap.scad
Normal file
292
src/strap.scad
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
links_count=2; // [1..20]
|
||||||
|
include_terminal=true; // [true,false]
|
||||||
|
include_screwhole=true; // [true,false]
|
||||||
|
clip_screwhole=2;
|
||||||
|
|
||||||
|
include <export.scad>
|
||||||
|
//export=MODEL_LINKS;
|
||||||
|
//export=MODEL_CLIP_A;
|
||||||
|
//export=MODEL_CLIP_B;
|
||||||
|
//export=MODEL_CLIP_RATCHETING_A;
|
||||||
|
//export=MODEL_CLIP_RATCHETING_B;
|
||||||
|
|
||||||
|
use <BOSL/transforms.scad>
|
||||||
|
use <BOSL/shapes.scad>
|
||||||
|
include <BOSL/constants.scad>
|
||||||
|
|
||||||
|
use <specs_strap.scad>
|
||||||
|
use <specs_platform.scad>
|
||||||
|
|
||||||
|
use <common.scad>
|
||||||
|
use <strap_common.scad>
|
||||||
|
use <platform_common.scad>
|
||||||
|
|
||||||
|
if (is_model_strict(MODEL_LINKS)) {
|
||||||
|
echo("===============================");
|
||||||
|
echo(str("Strap length: ", (links_count * get_link_segment_size().x), " mm"));
|
||||||
|
echo("===============================");
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(get_link_segment_size().x >= 10, "Link segment is too short.");
|
||||||
|
assert(get_link_segment_size().z >= (get_link_pin_diameter() + get_link_socket_slack().z + 1), "Link segment is too thin.");
|
||||||
|
|
||||||
|
module link(terminal=false) {
|
||||||
|
$fn=$preview?4:20;
|
||||||
|
module link_joiner() {
|
||||||
|
gap=get_link_socket_roundgap();
|
||||||
|
segment_size=get_link_segment_size();
|
||||||
|
arm_size=get_link_joiner_arm_size();
|
||||||
|
|
||||||
|
module pin_to_socket_joiner() {
|
||||||
|
joiner_size=[segment_size.x-get_link_socket_size().x+get_link_socket_size().x*0.2,
|
||||||
|
segment_size.y-4,
|
||||||
|
segment_size.z];
|
||||||
|
difference() {
|
||||||
|
right(joiner_size.x/2 + 4.5) cuboid(joiner_size, fillet=1, edges=EDGES_Z_ALL + EDGES_BOTTOM);
|
||||||
|
right(segment_size.x) scale([1, 2, 1]) pin_socket_area();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pin_to_socket_joiner();
|
||||||
|
}
|
||||||
|
|
||||||
|
link_connector_pin();
|
||||||
|
if (terminal) {
|
||||||
|
right(get_link_segment_size().x + 2) zrot(180) link_connector_pin();
|
||||||
|
} else {
|
||||||
|
link_joiner();
|
||||||
|
right(get_link_segment_size().x) link_connector_socket();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module link_chain(links_count, include_terminal=true) {
|
||||||
|
for (i = [0:links_count-1]) {
|
||||||
|
terminal=(i==links_count-1) && include_terminal;
|
||||||
|
right(i*get_link_segment_size().x) link(terminal=terminal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module clip() {
|
||||||
|
$fn=$preview?4:20;
|
||||||
|
socket_size=get_link_socket_size();
|
||||||
|
clip_size=get_link_clip_size();
|
||||||
|
pin_diam=get_link_pin_diameter();
|
||||||
|
slot_slack=get_link_socket_slack();
|
||||||
|
size=[clip_size.x+socket_size.x, clip_size.y, clip_size.z];
|
||||||
|
slot_size=[clip_size.x+slot_slack.x, size.y+1, pin_diam+slot_slack.z];
|
||||||
|
entry_size=[slot_size.x, clip_size.y+1, clip_size.z];
|
||||||
|
entry_pos=[0, 0, 1.5];
|
||||||
|
|
||||||
|
module socket_area() {
|
||||||
|
$fn=$preview? 10 : 20;
|
||||||
|
xrot(90) down(size.y/2) cylinder(d=size.z, h=size.y);
|
||||||
|
}
|
||||||
|
module socket_cutout() {
|
||||||
|
$fn=$preview? 10 : 20;
|
||||||
|
xrot(90) down(slot_size.y/2) cylinder(d=slot_size.z, h=slot_size.y);
|
||||||
|
}
|
||||||
|
module cover() {
|
||||||
|
translate(entry_pos) cube(entry_size, center=true);
|
||||||
|
}
|
||||||
|
module joiner(groove) {
|
||||||
|
slack=groove?0.2:0;
|
||||||
|
joiner_size=[entry_size.x-6+slack, entry_size.y-6+slack, entry_size.z-3+slack];
|
||||||
|
joiner_pos=[entry_pos.x, entry_pos.y, entry_pos.z - entry_size.z/2 + joiner_size.z/2];
|
||||||
|
difference() {
|
||||||
|
translate(joiner_pos) cube(joiner_size, center=true);
|
||||||
|
screw_cutout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module screw_cutout() {
|
||||||
|
if (include_screwhole) down(clip_size.z/2) screwhole(d=clip_screwhole, h=clip_size.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
module model() {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
right(clip_size.x/2) socket_area();
|
||||||
|
left(clip_size.x/2) socket_area();
|
||||||
|
cube(clip_size, center=true);
|
||||||
|
}
|
||||||
|
right(clip_size.x/2) socket_cutout();
|
||||||
|
left(clip_size.x/2) socket_cutout();
|
||||||
|
screw_cutout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
left(socket_size.x/2)
|
||||||
|
{
|
||||||
|
if (is_model(MODEL_CLIP_A)) {
|
||||||
|
difference() {
|
||||||
|
model();
|
||||||
|
cover();
|
||||||
|
}
|
||||||
|
joiner(groove=false);
|
||||||
|
}
|
||||||
|
if (is_model(MODEL_CLIP_B)) {
|
||||||
|
difference() {
|
||||||
|
intersection() {
|
||||||
|
model();
|
||||||
|
cover();
|
||||||
|
}
|
||||||
|
joiner(groove=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module clip_ratcheting(ratchet_length=28) {
|
||||||
|
$fn=$preview?4:20;
|
||||||
|
socket_size=get_link_socket_size();
|
||||||
|
clip_size=get_link_clip_size();
|
||||||
|
pin_diam=get_link_pin_diameter();
|
||||||
|
slot_slack=get_link_socket_slack();
|
||||||
|
size=[clip_size.x+socket_size.x, clip_size.y, clip_size.z];
|
||||||
|
slot_size=[clip_size.x+slot_slack.x + 0.2, size.y+1, pin_diam+slot_slack.z];
|
||||||
|
entry_size=[slot_size.x-5, clip_size.y+1, clip_size.z];
|
||||||
|
connector_size=[25, 0, 0];
|
||||||
|
module hookRight() {
|
||||||
|
right(connector_size.x/2) zrot(180) link_connector_pin();
|
||||||
|
}
|
||||||
|
module hookLeft() {
|
||||||
|
left(connector_size.x/2) link_connector_pin();
|
||||||
|
}
|
||||||
|
wall=2;
|
||||||
|
tooth_size=[4, 3, 3];
|
||||||
|
module tooth() {
|
||||||
|
s=[tooth_size.x, tooth_size.z, tooth_size.y];
|
||||||
|
up(tooth_size.z/2) xrot(-90) right_triangle(s);
|
||||||
|
}
|
||||||
|
module teethFwd() {
|
||||||
|
tooth_count = ratchet_length/tooth_size.x;
|
||||||
|
fwd((clip_size.y-wall*2)/2)
|
||||||
|
right(ratchet_length/2) {
|
||||||
|
for (i=[1:tooth_count]) {
|
||||||
|
left(i*tooth_size.x) tooth();
|
||||||
|
}
|
||||||
|
cap_size=[ratchet_length, tooth_size.y, 1];
|
||||||
|
up(tooth_size.z/2 + cap_size.z/2) left(cap_size.x/2) back(tooth_size.y/2) {
|
||||||
|
difference() {
|
||||||
|
cube(cap_size, center=true);
|
||||||
|
translate([0.1, 0.1, 0]) back(tooth_size.y/2) right(ratchet_length/2) zrot(180) tooth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module teethBack() {
|
||||||
|
scale([1, -1, 1]) teethFwd();
|
||||||
|
}
|
||||||
|
module ratchetLeft() {
|
||||||
|
right(ratchet_length/2) {
|
||||||
|
difference() {
|
||||||
|
cube([ratchet_length, clip_size.y, clip_size.z], center=true);
|
||||||
|
up(wall/2) cube([ratchet_length, clip_size.y-wall*2, clip_size.z], center=true);
|
||||||
|
right(ratchet_length/2+1) {
|
||||||
|
slideRailGuide(groove=true);
|
||||||
|
scale([1,-1,1]) slideRailGuide(groove=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
teethFwd();
|
||||||
|
teethBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ratchet_tooth_count=2;
|
||||||
|
ratchet_wall=2.5;
|
||||||
|
ratchet_slack=0.3;
|
||||||
|
rail_slack=0.2;
|
||||||
|
ratchet_tooth_scale_z=0.8;
|
||||||
|
module ratchetTeethFront() {
|
||||||
|
module ratchetButton() {
|
||||||
|
size=[8,wall*4,4];
|
||||||
|
up(size.z+1) fwd(wall*2 - ratchet_wall) cuboid(size, fillet=1, edges=EDGES_FRONT);
|
||||||
|
up(2) back(ratchet_wall/2) cube([size.x, ratchet_wall, tooth_size.z*ratchet_tooth_scale_z + size.z], center=true);
|
||||||
|
}
|
||||||
|
fwd((clip_size.y-wall*2)/2 - tooth_size.y - ratchet_slack)
|
||||||
|
left(ratchet_length) {
|
||||||
|
for (i=[0:ratchet_tooth_count-1]) {
|
||||||
|
right(i*tooth_size.x) scale([-1,-1*(1-i/5),ratchet_tooth_scale_z]) tooth();
|
||||||
|
}
|
||||||
|
ratchetButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
module ratchetWall() {
|
||||||
|
up(tooth_size.z/2) left(ratchet_length/2 + wall - wall/2) fwd(clip_size.y/2-wall-tooth_size.y-ratchet_wall/2 - ratchet_slack)
|
||||||
|
down(wall/2+0.5) cube([ratchet_length + wall, ratchet_wall, tooth_size.z*ratchet_tooth_scale_z], center=true);
|
||||||
|
}
|
||||||
|
ratchetWall();
|
||||||
|
}
|
||||||
|
module ratchetTeethBack() {
|
||||||
|
scale([1,-1,1]) ratchetTeethFront();
|
||||||
|
}
|
||||||
|
module ratchetRight() {
|
||||||
|
left(wall) cube([wall*2, clip_size.y + rail_slack*2, clip_size.z], center=true);
|
||||||
|
|
||||||
|
ratchetTeethFront();
|
||||||
|
ratchetTeethBack();
|
||||||
|
}
|
||||||
|
module slideRailGuide(groove) {
|
||||||
|
size=[ratchet_length, wall, wall];
|
||||||
|
fwd(clip_size.y/2 + rail_slack)
|
||||||
|
left(size.x/2) scale(groove?1.5:1) cuboid(size, fillet=0.5);
|
||||||
|
}
|
||||||
|
module slideRailLeft() {
|
||||||
|
size=[ratchet_length, clip_size.y/2 - ratchet_wall*2 - wall/2 - ratchet_slack - tooth_size.y, clip_size.z];
|
||||||
|
right(size.x/2) cube(size, center=true);
|
||||||
|
}
|
||||||
|
module slideRailRight() {
|
||||||
|
size=[ratchet_length + 3, wall*1.5, clip_size.z];
|
||||||
|
module railFront() {
|
||||||
|
fwd(clip_size.y/2 + size.y/2 + rail_slack) left(size.x/2)
|
||||||
|
cuboid(size, fillet=1, edges=EDGES_FRONT);
|
||||||
|
slideRailGuide(groove=false);
|
||||||
|
}
|
||||||
|
module railBack() {
|
||||||
|
scale([1, -1, 1]) railFront();
|
||||||
|
}
|
||||||
|
railFront();
|
||||||
|
railBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
right(size.x + connector_size.x - 2) {
|
||||||
|
left(2)
|
||||||
|
if (is_model(MODEL_CLIP_RATCHETING_A) || is_model(MODEL_CLIP_RATCHETING)) {
|
||||||
|
left(ratchet_length + wall + 1) {
|
||||||
|
hookLeft();
|
||||||
|
left(0.1) {
|
||||||
|
ratchetLeft();
|
||||||
|
slideRailLeft();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
right(is_model(MODEL_DEMO) ? ratchet_length + 5 : 0)
|
||||||
|
if (is_model(MODEL_CLIP_RATCHETING_B) || is_model(MODEL_CLIP_RATCHETING)) {
|
||||||
|
ratchetRight();
|
||||||
|
hookRight();
|
||||||
|
slideRailRight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Export ===
|
||||||
|
if (is_model(MODEL_DEMO)) {
|
||||||
|
foreach_platform_strap_connector() {
|
||||||
|
zrot(180) down(get_link_segment_size().z/2) {
|
||||||
|
link_chain(links_count, include_terminal=include_terminal);
|
||||||
|
/*right(links_count * get_link_segment_size().x + get_link_clip_size().x) {
|
||||||
|
clip();
|
||||||
|
right(get_link_clip_size().x) clip_ratcheting();
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (is_model(MODEL_CLIP_A) || is_model(MODEL_CLIP_B)) {
|
||||||
|
left(get_link_clip_size().x) clip();
|
||||||
|
}
|
||||||
|
if (is_model(MODEL_CLIP_RATCHETING) || is_model(MODEL_CLIP_RATCHETING_A) || is_model(MODEL_CLIP_RATCHETING_B)) {
|
||||||
|
left(get_link_clip_size().x * 2 + 3) clip_ratcheting();
|
||||||
|
}
|
||||||
|
if (is_model(MODEL_LINKS)) for (i = [0:links_count-1]) {
|
||||||
|
terminal=(i==links_count-1) && include_terminal;
|
||||||
|
right(i*get_link_segment_size().x) link(terminal=terminal);
|
||||||
|
}
|
||||||
|
}
|
68
src/strap_common.scad
Normal file
68
src/strap_common.scad
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
include <export.scad>
|
||||||
|
|
||||||
|
use <BOSL/transforms.scad>
|
||||||
|
use <BOSL/shapes.scad>
|
||||||
|
include <BOSL/constants.scad>
|
||||||
|
|
||||||
|
use <specs_strap.scad>
|
||||||
|
|
||||||
|
use <common.scad>
|
||||||
|
|
||||||
|
module pin() {
|
||||||
|
segment_size=get_link_segment_size();
|
||||||
|
h=segment_size.y;
|
||||||
|
d=get_link_pin_diameter();
|
||||||
|
back(h/2) xrot(90) cylinder(h=h, d=d, $fn=$preview ? 10 : 30);
|
||||||
|
}
|
||||||
|
module pin_socket_area() {
|
||||||
|
segment_size=get_link_segment_size();
|
||||||
|
h=segment_size.y-get_link_socket_slack().y;
|
||||||
|
d=segment_size.z;
|
||||||
|
back(h/2) xrot(90) cylinder(h=h, d=d, $fn=$preview ? 10 : 30);
|
||||||
|
}
|
||||||
|
module pin_socket() {
|
||||||
|
difference() {
|
||||||
|
pin_socket_area();
|
||||||
|
scaleup = [
|
||||||
|
((get_link_pin_diameter() + get_link_socket_slack().x) / get_link_pin_diameter()),
|
||||||
|
((get_link_pin_diameter() + get_link_socket_slack().y) / get_link_pin_diameter()),
|
||||||
|
((get_link_pin_diameter() + get_link_socket_slack().z) / get_link_pin_diameter())
|
||||||
|
];
|
||||||
|
scale(scaleup) pin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module arm() {
|
||||||
|
segment_size=get_link_segment_size();
|
||||||
|
arm_size=get_link_joiner_arm_size();
|
||||||
|
fwd(segment_size.y/2 + arm_size.y/2 - 1) right(arm_size.x/2 - 1) cubi(arm_size, fillet=1, edges=EDGES_FRONT + EDGES_Y_ALL);
|
||||||
|
}
|
||||||
|
module armFront() {
|
||||||
|
arm();
|
||||||
|
}
|
||||||
|
module armBack() {
|
||||||
|
scale([1, -1, 1]) arm();
|
||||||
|
}
|
||||||
|
module armJoiner() {
|
||||||
|
gap=get_link_socket_roundgap();
|
||||||
|
arm_size=get_link_joiner_arm_size();
|
||||||
|
segment_size=get_link_segment_size();
|
||||||
|
joiner_size=[arm_size.x-get_link_socket_size().x, segment_size.y, segment_size.z];
|
||||||
|
right(joiner_size.x/2 + get_link_socket_size().x/2 + gap) cubi(joiner_size, fillet=1, edges=EDGES_Z_ALL + EDGES_BOTTOM);
|
||||||
|
}
|
||||||
|
module link_arms() {
|
||||||
|
$fn=$preview?4:20;
|
||||||
|
armFront();
|
||||||
|
armBack();
|
||||||
|
armJoiner();
|
||||||
|
}
|
||||||
|
|
||||||
|
module link_connector_pin() {
|
||||||
|
pin();
|
||||||
|
link_arms();
|
||||||
|
}
|
||||||
|
|
||||||
|
module link_connector_socket() {
|
||||||
|
pin_socket();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user