Created
March 9, 2021 16:24
-
-
Save jparkhill/ec81c365406e50423ada061f8256bd50 to your computer and use it in GitHub Desktop.
phone holder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// **************************************************************************** | |
// Customizable Smartphone Holders | |
// to mount your smartphone to a tripod or elsewhere using an action cam hook | |
// Author: Peter Holzwarth | |
// **************************************************************************** | |
// https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language | |
SmartphoneHolder([PhoneName, PhoneWidth, PhoneHeight, PhoneDepth, | |
PhoneCornerRoundingRadius, PhoneEdgeRoundingRadius, | |
PhoneCamPos, CamSlotHeight], MountPos); | |
// for manual rendering: | |
// SmartphoneHolder(phone=PhoneiPhone8,mountPos="bottom"); | |
// render only the middle hook | |
// MiddleHook("female"); | |
// parameters for thingiverse customizer: | |
/* [Phone] */ | |
// Name of the phone | |
PhoneName= "MiMix2"; | |
// Width of the phone | |
PhoneWidth= 76.7; | |
// Height of the phone | |
PhoneHeight= 165.8; | |
// Depth/ thickness of the phone - add 0,5mm here! | |
PhoneDepth=8.8; | |
// Rounding radius of the four corners | |
PhoneCornerRoundingRadius= 10; | |
// Rounding radius of the edges at all sides | |
PhoneEdgeRoundingRadius= 4.; | |
// Position of the camera, when looking from the front | |
PhoneCamPos= 0; // [0:Mid,1:Left,2:Right] | |
// Height of the space for the camera (only required if on left/right side): | |
CamSlotHeight= 18; | |
/* [Mounting] */ | |
// Mount at bottom or mid of holder | |
MountPos= "mid"; // [bottom,mid] | |
// Bracket thickness | |
th= 2; | |
// Bottom thickness | |
bt= 4; | |
// Precision of curves | |
$fn=85; | |
/* [Hidden] */ | |
// constants for the camera position | |
CamPosMid= 0; | |
CamPosLeft= 1; | |
CamPosRight= 2; | |
// you may use these pre-defined models in the call below | |
PhoneSamsungS4= ["Samsung S4", 70, 137, 8, 12, 2, CamPosMid]; | |
PhoneSamsungS5= ["Samsung S5", 73, 143, 8.5, 12, 2, CamPosMid]; | |
PhoneSamsungS6= ["Samsung S6", 70, 144, 8, 12, 2, CamPosMid]; | |
PhoneSamsungS7= ["Samsung S7", 71, 144, 8, 12, 2, CamPosMid]; | |
PhoneSamsungS8= ["Samsung S8", 68, 149.5, 8.5, 12, 2.5, CamPosMid]; | |
// Blank holder | |
//translate([PhoneWidth/2,PhoneHeight/4,(th+bt)/2]) | |
//union(){ | |
// translate([0,4,(th+bt)]) | |
// rotate([-90,0,0]) | |
// rotate([0,90,0]) | |
// goldbar(length=2*26/3, width=(25.5/3-0.3), height=((th+bt)/2-0.3), angle=-70.); | |
// difference(){ | |
// cubeR([26,26,th+bt], 2, true); | |
// translate([0,0,-10]) | |
// fourScrews(16,16,3,80); | |
// } | |
//}; | |
// Loop holder. | |
//translate([PhoneWidth/2,0,13-(th+bt)/2]) | |
//rotate([0,90,90]) | |
//union(){ | |
// translate([0,4,(th+bt)]) | |
// rotate([-90,0,0]) | |
// rotate([0,90,0]) | |
// translate([0,0.3,0]) | |
// goldbar(length=2*26/3, width=(25.5/3-0.3), height=((th+bt)/2-0.3), angle=-70.); | |
// translate([0,3,-13]) | |
// rotate([90,0,0]) | |
// ringx(h=(th+bt),od=26,id=18); | |
// difference(){ | |
// cubeR([26,26,th+bt], 2, true); | |
//// translate([0,0,-10]) | |
//// fourScrews(16,16,3,80); | |
// } | |
//}; | |
//Cable tie holder | |
//translate([PhoneWidth/2,0,13-(th+bt)/2]) | |
//rotate([0,90,90]) | |
//union(){ | |
// translate([0,4,(th+bt)]) | |
// rotate([-90,0,0]) | |
// rotate([0,90,0]) | |
// translate([0,0.3,0]) | |
// goldbar(length=2*26/3, width=(25.5/3-0.3), height=((th+bt)/2-0.3), angle=-70.); | |
// translate([0,3,-13]) | |
// rotate([90,0,0]) | |
// ringx(h=(th+bt),od=26,id=18); | |
// difference(){ | |
// cubeR([26,26,th+bt], 2, true); | |
// translate([0,0,-10]) | |
// fourScrews(16,16,3,80); | |
// } | |
//}; | |
module ringx(h=10,od = 10,id = 5,de = 0.1,sr=1 | |
) | |
{ | |
minkowski(){ | |
sphere(sr,$fn=9); | |
difference() { | |
cylinder(h=h, r=od/2-sr,$fn=24); | |
translate([0, 0, -de]) | |
cylinder(h=h+2*de, r=id/2+sr,$fn=24); | |
} | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// Holder | |
module SmartphoneHolder(phone=PhoneSamsungS6, mountPos="mid") { | |
SmartphoneHolderI(phone, mountPos); | |
} | |
function parametersHaveErrors(phone) = | |
phone[1]+phone[2]+phone[3]+phone[4]+phone[5]==undef; | |
module SmartphoneHolderI(phone, mountPos) { | |
// the four corners | |
// lower left | |
if (phone[6]!=CamPosLeft) { | |
HolderCorner(phone); | |
} else { | |
HolderEdge(phone); | |
} | |
// lower right | |
translate([phone[2]+2*th,0,0]) rotate([0,0,90]) | |
HolderCorner(phone); | |
// upper left | |
if (phone[6]!=CamPosRight) { | |
translate([0,phone[1]+2*th,0]) rotate([0,0,-90]) | |
HolderCorner(phone); | |
} else { | |
translate([0,phone[1]+2*th,0]) | |
mirror([0,1,0]) HolderEdge(phone); | |
} | |
// upper right | |
translate([phone[2]+2*th,phone[1]+2*th,0]) rotate([0,0,180]) | |
HolderCorner(phone); | |
difference(){ | |
union(){ | |
// the oval half rings | |
rd= phone[4]+th; | |
// left half ring | |
difference() { | |
translate([th+2,th+phone[1]/2,0]) rotate([0,0,-90]) | |
halfOvalRing(phone[1]/2,phone[2]/2,bt+th,th,phone[5]); | |
// remove outer roundings from the oval rings | |
roundCut(phone); | |
translate([0,phone[1]+2*th,-0.01]) rotate([0,0,-90]) | |
roundCut(phone); | |
} | |
// right half ring | |
difference() { | |
translate([th+phone[2]-2,th+phone[1]/2,0]) rotate([0,0,90]) | |
halfOvalRing(phone[1]/2,phone[2]/2,bt+th,th,phone[5]); | |
translate([phone[2]+2*th,0,-0.01]) rotate([0,0,90]) | |
roundCut(phone); | |
translate([phone[2]+2*th,phone[1]+2*th,-0.01]) rotate([0,0,180]) | |
roundCut(phone); | |
} | |
translate([th+phone[2]/2,th+phone[1]/2,0]) | |
translate([0,0,(th+bt)/2]) | |
cubeR([26,26,th+bt], 2, true); | |
} | |
translate([th+phone[2]/2,th+phone[1]/2,0]) | |
translate([-4,4,(th+bt)/2]) | |
rotate([-90,0,0]) | |
rotate([0,90,0]) | |
goldbar(length=3*26/4, width=26/3, height=(th+bt)/2, angle=-70.); | |
} | |
} | |
module male_slottedcube(dims, rnd=1, centerR= false) { | |
union(){ | |
translate(centerR?[-dims[0]/2,-dims[1]/2,-dims[2]/2]:[]) { | |
hull() { | |
translate([rnd,rnd,rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,rnd,rnd]) sphere(r=rnd); | |
translate([rnd,dims[1]-rnd,rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,dims[1]-rnd,rnd]) sphere(r=rnd); | |
translate([rnd,rnd,dims[2]-rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,rnd,dims[2]-rnd]) sphere(r=rnd); | |
translate([rnd,dims[1]-rnd,dims[2]-rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,dims[1]-rnd,dims[2]-rnd]) sphere(r=rnd); | |
} | |
} | |
translate([0.,0.,dims[2]]) | |
mirror([0.,0.,1.]) | |
translate([-dims[1]/6,0.,0.]) | |
rotate([90.,0.,0.]) | |
goldbar(length=dims[0]/2, width=dims[1]/3, height=dims[2]/2, angle=-70.); | |
} | |
} | |
module female_slottedcube(dims, rnd=1, centerR= false) { | |
difference(){ | |
translate(centerR?[-dims[0]/2,-dims[1]/2,-dims[2]/2]:[]) { | |
hull() { | |
translate([rnd,rnd,rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,rnd,rnd]) sphere(r=rnd); | |
translate([rnd,dims[1]-rnd,rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,dims[1]-rnd,rnd]) sphere(r=rnd); | |
translate([rnd,rnd,dims[2]-rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,rnd,dims[2]-rnd]) sphere(r=rnd); | |
translate([rnd,dims[1]-rnd,dims[2]-rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,dims[1]-rnd,dims[2]-rnd]) sphere(r=rnd); | |
} | |
} | |
translate([-dims[1]/6,-dims[0]/4,0.]) | |
rotate([90.,0.,0.]) goldbar(length=dims[0], width=dims[1]/3, height=dims[2]/2, angle=-70.); | |
} | |
} | |
module goldbar(length=30, width=20, height=10, angle=60){ | |
// Angle is fixed at 60 | |
linear_extrude(height = length, center = true, convexity = 10) | |
polygon(points=[[0,0],[width,0],[width - cos(angle)*height,height],[cos(angle)*height,height]]); | |
} | |
module roundCut(phone) { | |
rd= phone[4]+th; | |
difference() { | |
cube([rd, rd, rd+th+bt]); | |
translate([rd,rd,-0.01]) cylinder(r=phone[4],h=rd+th+bt+0.02); | |
} | |
} | |
module MiddleHook(hooks) { | |
h= 20; | |
difference() { | |
union() { | |
translate([0,0,(th+bt)/2]) cubeR([26,26,th+bt],2, true); | |
if (hooks == "male") { | |
translate([0,0,h]) ActionCamRingsMale(h, true); | |
} else { | |
translate([0,0,h]) ActionCamRingsFemale(h, true); | |
} | |
} | |
translate([0,0,-0.01]) fourScrews(16,16,3,th+bt+0.02); | |
translate([0,0,(th+bt)/2]) fourScrews(16,16,6.3,(th+bt)/2+2,6); | |
} | |
} | |
// phone=PhoneSamsungS6; | |
// ovalRing(phone[1]/2,phone[2]/2,bt+th,2+th,phone[5],180); | |
// halfOvalRing(phone[1]/2,phone[2]/2,bt+th,2+th,phone[5],180); | |
// //////////////////////////////////////////////////////////////// | |
// Oval ring with a constant diameter | |
// Used to form the arms | |
module halfOvalRing(w, d, h, rth, rr) { | |
difference() { | |
difference() { | |
scale([1,d/w,1]) fring(w-rth/2, h); | |
translate([-0.01,-0.01,-0.01]) scale([1,(d-rth)/(w-rth),1]) difference() { | |
cylinder(r=w-rth, h=h+0.02); | |
translate([0,0,h/2]) ring(w-rth, h); | |
} | |
} | |
translate([-w-th-0.01,-d-3*th-0.05,-0.01]) | |
cube([2*(w+th), d+3*th+0.05, h+0.03]); | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// One corner of the holder | |
module HolderCorner(phone) { | |
difference() { | |
hull() { | |
wl= max(phone[4]+th,10); | |
tl= max(phone[5],3); | |
// corner | |
translate([phone[4]+th,phone[4]+th,0]) rotate([0,0,180]) | |
qwheel(phone[4]+th+2.5,phone[3]+2*th+bt,phone[5]); | |
// x longhole | |
translate([wl,tl,phone[3]+phone[5]+bt]) rotate([0,90,0]) | |
longHole(radius=tl, length=phone[3]-2*tl+2*th+bt, | |
height=2); | |
// y longhole | |
translate([tl,wl,phone[3]+phone[5]+bt]) rotate([0,90,90]) | |
longHole(radius=tl, length=phone[3]-2*tl+2*th+bt, | |
height=2); | |
} | |
translate([th,th,th+bt]) Smartphone(phone); | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// Edge, used for smartphones with the camera at one side | |
module HolderEdge(phone) { | |
h= bt+th; | |
y2= phone[2]/2-sqrt((phone[2]/2)*(phone[2]/2)-phone[7]*phone[7])+2*(bt+th); | |
difference() { | |
union() { | |
// upper part - short to not cover the display much | |
translate([phone[7],0,0]) cubeR([15,8,phone[3]+2*th+bt],2, false); | |
// lower part - longer to cover the arm | |
translate([phone[7],0,0]) cubeR([15,y2,h+2],2, false); | |
} | |
translate([th,th,th+bt]) Smartphone(phone); | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// Smartphone model | |
module Smartphone(phone=PhoneSamsungS6) { | |
hull() { | |
translate([phone[2]-phone[4],phone[1]-phone[4],0]) | |
qwheel(phone[4],phone[3],phone[5]); | |
translate([phone[2]-phone[4],phone[4],0]) rotate([0,0,-90]) | |
qwheel(phone[4],phone[3],phone[5]); | |
translate([phone[4],phone[4],0]) rotate([0,0,180]) | |
qwheel(phone[4],phone[3],phone[5]); | |
translate([phone[4],phone[1]-phone[4],0]) rotate([0,0,90]) | |
qwheel(phone[4],phone[3],phone[5]); | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// a quater wheel with an outer wheel radius, an outer height and a rounding radius | |
module qwheel(wr, h, rr, center=false) { | |
translate([0,0,center?-h/2:0]) { | |
hull() { | |
translate([0,0,h-rr]) qwheelBike(wr, rr); | |
translate([0,0,rr]) qwheelBike(wr, rr); | |
} | |
} | |
} | |
// quater ring, also works with older OpenSCAD versions | |
module qwheelBike(wr, rr) { | |
difference() { | |
rotate_extrude(convexity= 2) translate([wr-rr, 0, 0]) circle(r=rr); | |
translate([-wr-0.01,-wr-0.01,-rr-0.01]) cube([2*wr+0.02,wr+0.01,2*rr+0.02]); | |
translate([-wr-0.01,-wr-0.01,-rr-0.01]) cube([wr+0.01,2*wr+0.02,2*rr+0.02]); | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// rounded button - lower part is a cylinder, upper part like a filled ring | |
// r= outer radius | |
// h= height | |
// rr= upper rounding | |
module buttonRound(r, h, rr) { | |
hull() { | |
translate([0,0,h-rr]) wheelBike(r, rr); | |
cylinder(r=r,h=h-rr); | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// a ring with a radius and a thickness | |
// else same as wheelBike | |
// r - radius | |
// th - thickness | |
module ring(r, th) { | |
rotate_extrude(convexity= 4, $fn= 100) | |
translate([r, 0, 0]) | |
circle(r = th/2, $fn = 100); | |
} | |
// //////////////////////////////////////////////////////////////// | |
// filled ring - like a round cheese | |
// fring(20,4); | |
module fring(r, th) { | |
rotate_extrude(convexity= 4, $fn= 100) { | |
translate([r, th/2, 0]) | |
circle(r = th/2, $fn = 100); | |
square([r,th]); | |
} | |
} | |
// generic long hole | |
module longHole(radius, length, height) { | |
hull() { | |
cylinder(r=radius, h=height); | |
translate([length,0,0]) cylinder(r=radius, h=height); | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// T-slot for mounting onto | |
// //////////////////////////////////////////////////////////////// | |
// cube with rounded corners | |
module cubeR(dims, rnd=1, centerR= false) { | |
translate(centerR?[-dims[0]/2,-dims[1]/2,-dims[2]/2]:[]) { | |
hull() { | |
translate([rnd,rnd,rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,rnd,rnd]) sphere(r=rnd); | |
translate([rnd,dims[1]-rnd,rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,dims[1]-rnd,rnd]) sphere(r=rnd); | |
translate([rnd,rnd,dims[2]-rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,rnd,dims[2]-rnd]) sphere(r=rnd); | |
translate([rnd,dims[1]-rnd,dims[2]-rnd]) sphere(r=rnd); | |
translate([dims[0]-rnd,dims[1]-rnd,dims[2]-rnd]) sphere(r=rnd); | |
} | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// two rings for action cam mount | |
module ActionCamRingsMale(l, base, adj=-0.25, center= true) { | |
translate(center ? [(-9-adj)/2,0,0] : [0,6,l]) { | |
if (base) { | |
translate([0,-6,-l]) cube([9+adj, 12, 3]); | |
} | |
for (i= [0, 6]) { | |
translate ([i, 0, 0]) ActionCamOneRing(l, adj); | |
} | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// three rings for action cam mount | |
module ActionCamRingsFemale(l, base, adj= -0.25, center= true) { | |
translate(center ? [(-15-adj)/2,0,0] : [0,6,l]) { | |
if (base) { | |
translate([0,-6,-l]) cube([15+adj, 12, 3]); | |
} | |
for (i= [0, 6, 12]) { | |
translate ([i, 0, 0]) ActionCamOneRing(l, adj); | |
} | |
} | |
} | |
// one ring, helper for action cam hooks | |
module ActionCamOneRing(l, adj) { | |
rotate([90, 0, 90]) difference() { | |
hull() { | |
cylinder(r=6, h=3+adj); | |
translate([-6, -l, 0]) cube([12,1,3+adj]); | |
} | |
translate([0,0,-0.01]) cylinder(r=3, h=3.02+adj); | |
} | |
} | |
// four holes in a square | |
// x, y: distances of mid points | |
// d: screw diameter | |
// h: nut height | |
module fourScrews(x, y, d, h, fn=20) { | |
translate([x/2,y/2,0]) cylinder(r=d/2,h=h,$fn=fn); | |
translate([-x/2,y/2,0]) cylinder(r=d/2,h=h,$fn=fn); | |
translate([x/2,-y/2,0]) cylinder(r=d/2,h=h,$fn=fn); | |
translate([-x/2,-y/2,0]) cylinder(r=d/2,h=h,$fn=fn); | |
} | |
// //////////////////////////////////////////////////////////////// | |
// A parallelpiped slot to join halves with difference. | |
module slot() { | |
} | |
// //////////////////////////////////////////////////////////////// | |
// a pipe - a hollow cylinder | |
module pipe(outerRadius, thickness, height) { | |
difference() { | |
cylinder(h=height, r=outerRadius); | |
translate([0, 0, -0.1]) cylinder(h=height+0.2, r=outerRadius-thickness); | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// a half pipe | |
module halfPipe(outerRadius, thickness, height) { | |
difference() { | |
pipe(outerRadius, thickness, height); | |
translate([-outerRadius, -outerRadius, -0.01]) | |
cube([2*outerRadius, outerRadius, height+0.02], center=false); | |
} | |
} | |
// //////////////////////////////////////////////////////////////// | |
// a quarter of a pipe | |
module quarterPipe(outerRadius, thickness, height) { | |
difference() { | |
pipe(outerRadius, thickness, height); | |
translate([-outerRadius, -outerRadius, -0.01]) | |
cube([2*outerRadius, outerRadius, height+0.02], center=false); | |
translate([-outerRadius, 0, -0.01]) | |
cube([outerRadius, outerRadius, height+0.02], center=false); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment