Skip to content

Instantly share code, notes, and snippets.

@jparkhill
Created March 9, 2021 16:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jparkhill/ec81c365406e50423ada061f8256bd50 to your computer and use it in GitHub Desktop.
Save jparkhill/ec81c365406e50423ada061f8256bd50 to your computer and use it in GitHub Desktop.
phone holder
// ****************************************************************************
// 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