3D-printing is becoming an increasingly ubiquitous tool. It’s especially useful for fabricating objects that you might uniquely need: objects that are useful to you, but almost no one else. I’ve had a few. Currently I own an Artillery Sidewinder X1, which I’ve had for a year. I use it so often that I’ve needed to rebuild the extruder assembly once, but besides that it’s been a very capable device.

I print all sorts of stuff. Little models for kids to paint, fruit juicers, musubi mashers. However, amongst all the things, I print one particular thing about 10x more. It saves me thousands of dollars a year, far more than the cost of a 3D printer. The object, is a humble phone case:

case

This phone case is slightly strengthened relative to an original design by Peter Holzwarth. It’s easily customizable thanks to the simple language for functional 3d geometry definition, openSCAD (which is FOSS).

Anytime I get a new phone for myself, my kids, etc. I pull out some 4$ Harbor Freight calipers. I adjust the height width and depth in the code and I print one of these cases out. If the phone is dropped, this case works like a bike-helmet. A corner pops off and the phone is fine. Then I print another. It also holds the phone a few millimeters off a surface, such that the phone is held above any spills. It holds most objects away from the screen and prevents scratches too.

case

I have printed about 20-25 of these, saving about 20-25 phone screens. Using this case, a 5 year old can have a phone without a broken screen. It’s pretty remarkable. The code for this thing below.

// ****************************************************************************
// 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);
}
}
view raw phonecase hosted with ❤ by GitHub