commit dfdd8c480b90a39c633f228ed0b6df86150060bb Author: Luke Hubmayer-Werner Date: Tue Jun 13 21:21:33 2023 +0930 Initial commit diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6f20855 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "scad-utils"] + path = scad-utils + url = https://github.com/OskarLinde/scad-utils.git diff --git a/2Banger Parts/compile.py b/2Banger Parts/compile.py new file mode 100644 index 0000000..e734922 --- /dev/null +++ b/2Banger Parts/compile.py @@ -0,0 +1,26 @@ +from subprocess import Popen + +fret_pairs = [ + # Old lengths that are unfortunately too long (Up Box caps out at 205mm tall!) + (-4, 0), # Bass + ( 1, 7), # Start of guitar + ( 8, 19), # Rougly similar length to above + # New shorter segmentation ~120mm tall max + (-4, -3), # 91.7217mm + (-2, 0), # 119.166mm + ( 1, 3), # 100.206mm + ( 4, 7), # 109.258mm + ( 8, 12), # 105.444mm + (13, 19), # 104.732mm + (20, 30), # 98.839mm + # Alternates for testing + (0,0), # Just to see what it looks like, would redesign for 0-fret anyway + (20,20), # Short debug print + ] + +print("Compiling .stl files for fret pairs: ", fret_pairs) +processes = [Popen(["openscad", "-o", f"fret_tube_{i}_{j}.stl", "-D", f"I={i}", "-D", f"J={j}", "fret_tube_I_J.scad"]) for (i,j) in fret_pairs] +for p in processes: + p.wait() + +print("Finished compiling!") diff --git a/2Banger Parts/fret_tube_I_J.scad b/2Banger Parts/fret_tube_I_J.scad new file mode 100644 index 0000000..95e632a --- /dev/null +++ b/2Banger Parts/fret_tube_I_J.scad @@ -0,0 +1,5 @@ +use <../2Banger_fret_tube.scad> +// I = 0; // Override with -D 'I=... J=...' +// J = 24; // Override with -D +echo(str("Called with I=", I, " J=", J)) +tube(from_fret = I, to_fret = J); \ No newline at end of file diff --git a/2BangerCommon.scad b/2BangerCommon.scad new file mode 100644 index 0000000..d9c4831 --- /dev/null +++ b/2BangerCommon.scad @@ -0,0 +1,33 @@ +include + +$fn = $preview ? 32 : 512; +mink_fn = $preview ? 12 : 128; +mink_fn_2d = $preview ? 32 : 256; + + +function tang_points(a0 = -160, a1 = -90, r = 13) = + concat( + [[r*cos(a1), r*sin(a0)]], + [for (a = [a0:a1]) [r*cos(a), r*sin(a)]] + ); + +module tang_block(a0 = -160, a1 = -90, r = 13) + translate(T_circumcenter) + polygon(tang_points(a0=a0, a1=a1, r=r)); + +module tang_outline(offset = -0.1, base_width = 1) { + difference() { + offset((base_width+offset)/2) tang_block(); + offset(-(base_width+offset)/2) tang_block(); + } +} + +module tapered_tang_groove(depth, taper = 1, offset = 0.1, base_width = 1) { + difference() { + hull() { + linear_extrude(depth) offset((base_width+offset)/2) tang_block(); + translate([0,0,depth]) linear_extrude(taper) offset(-(base_width)/2) tang_block(); + } + linear_extrude(depth + taper) offset(-(base_width+offset)/2) tang_block(); + } +} diff --git a/2Banger_cap.scad b/2Banger_cap.scad new file mode 100644 index 0000000..484ac0a --- /dev/null +++ b/2Banger_cap.scad @@ -0,0 +1,23 @@ +include <2BangerCommon.scad> + +module cap(length = 10) { + module solid_cap(cap_taper = 1) { + hull() { + minkowski($fn = mink_fn) { + sphere(cap_taper, $fn = mink_fn); + translate([0,0,cap_taper]) linear_extrude(0.01) offset(-1) cap_outline(); + } + linear_extrude(0.01) offset(-1) cap_outline(); + translate([0,0,cap_taper]) linear_extrude(length-cap_taper) cap_outline(); + } + } + + difference() { + solid_cap(); + translate([0,0,Cap_Thick]) linear_extrude(length) T_hole(); + tapered_T_hole(z0 = length-1, z1 = length, o0 = 0, o1 = 1); + translate([-10,10,length-0.5]) linear_extrude(1) text("04²", size=5, halign="center", valign="center", font="Noto Sans"); + } +} + +cap(); \ No newline at end of file diff --git a/2Banger_fret_tube.scad b/2Banger_fret_tube.scad new file mode 100644 index 0000000..9581381 --- /dev/null +++ b/2Banger_fret_tube.scad @@ -0,0 +1,101 @@ +include +include <2BangerCommon.scad> + +fret_width = 2.4; //2.8; // Jumbo = 0.11", 0.055" tall + +module tube(from_fret, to_fret, tang_depth = 3) { + z_min = (fret_scale_length(to_fret) + fret_scale_length(to_fret+1))/2; + z_max = (fret_scale_length(from_fret) + fret_scale_length(from_fret-1))/2; + z_offset = z_min; + Cap_Length = z_max - z_min; + echo(str("Cap length from fret ", from_fret, " to ", to_fret, " is ", Cap_Length, "mm")); + + module solid_tube(cap_taper = 1.5, fingerboard_min_thick = 2.5, fingerboard_max_thick = 5, fret_angle = 60) { // Fret angle of 45° is normal, anything over 60 will not work correctly + module fret_bumps(w=50) { + translate([0,0,-z_offset]) for (fret = [from_fret:to_fret]) + translate([fingerboard_max_thick - fret_width/2, w/2, fret_scale_length(fret)]) + rotate([90,0,0]) cylinder(h = w, r = fret_width/2); + } + + module scallops(w=50) { + for (fret = [from_fret:to_fret+1]) + let( + f_prev = fret_scale_length(fret-1) - z_offset, + f_next = fret_scale_length(fret) - z_offset, + o = fret_width/2 * sin(fret_angle), + x0 = f_prev - o, + x1 = f_next + o, + y0 = fingerboard_min_thick, + y1 = fingerboard_max_thick - (fret_width/2 * cos(fret_angle)), + pts = [[x0, y1], [x1, y1], [(x0+x1)/2, y0]], + cc = tri_circumcenter(pts), + r = norm([x0, y1] - cc) + ) { + translate([0,-w/2,0]) + rotate([-90,-90,0]) + translate(cc) cylinder(h = w, r = r); + } + } + + module basic_fretboard() { + intersection() { + hull() { + minkowski($fn = mink_fn) { + sphere(cap_taper, $fn = mink_fn); + translate([0,0,cap_taper]) linear_extrude(0.01) offset(-cap_taper) + cap_outline(fingerboard_min_thick = fingerboard_min_thick, fingerboard_max_thick = fingerboard_max_thick); + } + minkowski($fn = mink_fn) { + sphere(cap_taper, $fn = mink_fn); + translate([0,0,Cap_Length-cap_taper]) linear_extrude(0.01) offset(-cap_taper) + cap_outline(fingerboard_min_thick = fingerboard_min_thick, fingerboard_max_thick = fingerboard_max_thick); + } + linear_extrude(Cap_Length) offset(-1) cap_outline(); + translate([0,0,cap_taper]) linear_extrude(Cap_Length-cap_taper*2) + cap_outline(fingerboard_min_thick = fingerboard_min_thick, fingerboard_max_thick = fingerboard_max_thick); + } + union() { + fret_bumps(); + translate([-50,-50,0]) cube([50 + fingerboard_max_thick - (fret_width/2 * cos(fret_angle)), 100, Cap_Length]); + } + } + } + + // Make a solid tube and then subtract the notches + difference() { + union() { + basic_fretboard(); + translate([0,0,Cap_Length]) linear_extrude(tang_depth) tang_outline(-0.1); + } + difference() { + scallops(); + fret_bumps(); + } + tapered_tang_groove(depth = tang_depth + 0.5, taper = 0); + tapered_tang_groove(depth = 0.5, taper = 0, offset = 0.5); + } + // color("red") scallops(); + } + + difference() { + solid_tube(1.5); + linear_extrude(Cap_Length) T_hole(); + tapered_T_hole(z0 = 0, z1 = 3); + tapered_T_hole(z0 = Cap_Length-3, z1 = Cap_Length+0.0001, o0 = 0, o1 = 1); + // Version number + translate([-10,10,Cap_Length-0.5]) linear_extrude(1) text("05²", size=5, halign="center", valign="center", font="Noto Sans"); + // Fret number markers + for (fret = [from_fret:to_fret]) + translate([-3,-16,fret_scale_length(fret)-z_offset]) rotate([90,25,16]) linear_extrude(100) text(str(fret), size=4, halign="center", valign="center", font="Noto Sans"); + } +} + + +tube(from_fret = 0, to_fret = 0); +translate([50, 0]) tube(from_fret = -4, to_fret = -3); +translate([100, 0]) tube(from_fret = -2, to_fret = 0); +translate([150, 0]) tube(from_fret = 1, to_fret = 3); +translate([200, 0]) tube(from_fret = 4, to_fret = 7); +translate([250, 0]) tube(from_fret = 8, to_fret = 12); +translate([300, 0]) tube(from_fret = 13, to_fret = 19); +translate([350, 0]) tube(from_fret = 20, to_fret = 30); diff --git a/AluTCommon.scad b/AluTCommon.scad new file mode 100644 index 0000000..aa71437 --- /dev/null +++ b/AluTCommon.scad @@ -0,0 +1,74 @@ +include +use + +L_minor = 1/2 * 25.4; +L_major = 3/4 * 25.4; +L_thick = 1.8; //9/128 * 25.4; //1/16 * 25.4; +T_flat_top = L_minor * 2; // 1" +T_spine = L_major; // 3/4" +T_tolerance = 0.285; +// Cap_Length = 150; +Cap_Thick = 3; +Cap_Spine = T_spine + Cap_Thick; + + +points = [[-T_spine, 0], [0, -L_minor], [0, L_minor]]; + +function tri_circumcenter(pts) = + let( + v0 = pts[1] - pts[0], + v1 = pts[2] - pts[1], + d0 = (pts[1] + pts[0])/2 * v0, + d1 = (pts[2] + pts[1])/2 * v1, + det = -cross(v0, v1) + ) + [cross([d1, d0], [v1.y, v0.y]), cross([d0, d1], [v0.x, v1.x])] / det; + +T_circumcenter = tri_circumcenter(points); +tube_radius = Cap_Spine + T_circumcenter[0]; + +module cap_outline(radius = 1.5, fingerboard_min_thick = 2.5, fingerboard_max_thick = 5) { + minkowski($fn = mink_fn_2d) { + circle(r = radius); + difference() { + translate(T_circumcenter) circle(r = tube_radius - radius); + translate([fingerboard_max_thick - radius, -50]) square([100,100]); + } + } +} + + +function T_hole_points(r = 4, a_step = 5, offset = 0) = + let( + x0 = T_tolerance + offset, + x1 = x0 - L_thick - (T_tolerance*2) - (offset*2), + x2 = -T_spine - T_tolerance - offset, + y_out = L_minor + T_tolerance + offset, + y_in = L_thick + T_tolerance + offset, + top_points = [ + [x1, -y_out], + [x0, -y_out], + [x0, y_out], + [x1, y_out] + ], + bottom_points = [ + [x2, y_in], + [x2, -y_in], + ], + joint_corner_left = [x1, -y_in], + joint_corner_right = [x1, y_in], + join_points_left = [for (a = [0:a_step:90]) joint_corner_left + [-r * (1-sin(a)), -r * (1-cos(a))]], + join_points_right = [for (a = [0:a_step:90]) joint_corner_right + [-r * (1-cos(a)), r * (1-sin(a))]] + ) + concat(top_points, join_points_right, bottom_points, join_points_left); + +module T_hole(r = 4, a_step = 5, offset = 0) + polygon(T_hole_points(r=r, a_step=a_step, offset=offset)); + +module tapered_T_hole(z0 = 0, z1 = 4, o0 = 1, o1 = 0) { + // z1 must > z0 for faces to work + pts0 = [for (pt = T_hole_points(offset = o0)) concat(pt, z0)]; + pts1 = [for (pt = T_hole_points(offset = o1)) concat(pt, z1)]; + skin([pts0, pts1]); +} + diff --git a/BassTunerHolder.scad b/BassTunerHolder.scad new file mode 100644 index 0000000..62593fb --- /dev/null +++ b/BassTunerHolder.scad @@ -0,0 +1,199 @@ +Tuner_Spacing_4 = 64; +Post_Hole_Dia = 14.75; // 14 + tolerance +Post_Hole_Depth = 14; +Post_Top_Dia = 9; +Post_Top_Height = 17; +Tuner_Body_Dia = 17; // 16.5 + tolerance +Tuner_Body_R = Tuner_Body_Dia/2; // 16.5 + tolerance +Tuner_Body_Width = 21; +Tuner_Body_Thickness = 10; // 9.5 + tolerance +Tuner_Body_Rect_Len = Tuner_Body_Width-Tuner_Body_R; +Tuner_Tab_Angle = 60; +Tuner_Tab_Hole_Dia = 2.5; +Tuner_Tab_Thickness = 2; +Tuner_Tab_Total = 27.5; +Tuner_Tab_Hole_Inset = 2; +Tuner_Tab_Hole_Outset = (Tuner_Tab_Total-Tuner_Body_Rect_Len)-Tuner_Tab_Hole_Inset; +Engrave_String = "01γ"; +// Font = "Ani"; +Font = "GFS Didot"; +// Font = "GFS Neohellenic"; +// Font = "Liberation Mono"; +// Font = "Noto Sans"; + +module cyl(d=10, z0=-100, z1=100, $fn=64) + translate([0,0,z0]) + cylinder(h=z1-z0, r=d/2, $fn=$fn); +module c(d=10, z=0, $fn=64) // 3d circle + translate([0,0,z]) + cylinder(h=0.00001, r=d/2, $fn=$fn); + +module tuner_tab_hole(shrink=0) { + translate([0, -Tuner_Tab_Hole_Outset+Tuner_Tab_Hole_Dia/2]) + circle((Tuner_Tab_Hole_Dia-shrink)/2, $fn=32); +} + +module tuner_outline(shrink=0) { + union() { + hull() { + translate([0, -Tuner_Tab_Hole_Outset]) + circle((Tuner_Tab_Hole_Dia+Tuner_Tab_Hole_Inset-shrink)/2, $fn=32); + circle(Tuner_Body_R-shrink/2, $fn=64); + } + translate([-Tuner_Body_R+shrink/2, 0]) + square([Tuner_Body_Dia-shrink, Tuner_Body_Rect_Len-shrink/2]); + } +} + +// color("blue") tuner_outline(-1.5); +// translate([0,0,0.001]) +// color("red") tuner_outline(0); + +module tuner_body() { + linear_extrude(Tuner_Body_Thickness) union() { + translate([-Tuner_Body_R, 0]) + square([Tuner_Body_Dia, Tuner_Body_Rect_Len]); + circle(Tuner_Body_R, $fn=32); + } + translate([0, 0, Tuner_Body_Thickness-Tuner_Tab_Thickness]) + linear_extrude(Tuner_Tab_Thickness) difference() { + hull() { + translate([0, -Tuner_Tab_Hole_Outset]) + circle((Tuner_Tab_Hole_Dia+Tuner_Tab_Hole_Inset)/2, $fn=32); + circle(Tuner_Body_R, $fn=64); + } + tuner_tab_hole(); + } + // handle + color(c = "red") + translate([0, Tuner_Body_Rect_Len-Tuner_Body_Thickness/2, Tuner_Body_Thickness/2]) + rotate([0,-90,0]) + cylinder(h = 40, r = Tuner_Body_Thickness/2); +} + +module tuner_post() { + cylinder(h = Post_Hole_Depth, r = Post_Hole_Dia/2, $fn=64); + color("cyan") + translate([0, 0, Post_Hole_Depth]) + difference() { + cylinder(h = Post_Top_Height, r = Post_Top_Dia/2); + translate([-1,-5, Post_Top_Height-6]) cube([2,10,7]); + } +} + +module tuner() { + tuner_body(); + translate([0, 0, Tuner_Body_Thickness]) + tuner_post(); +} + +module tuner_arrange() + for (a = [90:30:180]) + rotate([0,0,a]) + translate([-31, 31, 0]) + children(); + +module handle_cutouts() { + tuner_arrange() + translate([0, Tuner_Body_Rect_Len-Tuner_Body_Thickness/2, Tuner_Body_Thickness/2]) + rotate([-90, 0, 90]) linear_extrude(40) hull() { + circle(Tuner_Body_Thickness/2, $fn=32); + translate([-Tuner_Body_Thickness/2, 0]) square([Tuner_Body_Thickness, 20]); + } +} + +module retainer_outline() + // polygon([[-50, -10], [-45, -35], [-20, -55], [20, -55], [45, -35], [50, -10]]); + polygon(concat([for (i = [-52:1:45]) [60*sin(i), -60*cos(i)]], [[40,-5], [-40, -5], [-47, -18]])); + + +module part() { + module layer_bolt_holes_outer(dia=3.05, z0=-100, z1=100) + for (a = [-120:30:-60]) + rotate([0,0,a]) + translate([55,0,z0]) + cylinder(h=z1-z0, r=dia/2, $fn=64); + module layer_bolt_holes_inner(dia=3.05, z0=-100, z1=100) + for (x = [-20,0,20]) + translate([x,-10,z0]) + cylinder(h=z1-z0, r=dia/2, $fn=64); + + module bottom_engraving() + // translate([0,-26,1]) rotate([0,180,0]) linear_extrude(30) + translate([0,-28,1]) rotate([15,180,0]) linear_extrude(30) + text(text = Engrave_String, size = 5, halign="center", valign="center", font=Font); + + // Top half + difference() { + color("blue") + translate([0, 0, Tuner_Body_Thickness]) + linear_extrude(Post_Hole_Depth-0.001) + retainer_outline(); + tuner_arrange() tuner(); + // tuner screw holes + tuner_arrange() + linear_extrude(Tuner_Body_Thickness+Post_Hole_Depth-1) + tuner_tab_hole(shrink=0.5); + // layer bolt holes + layer_bolt_holes_outer(); + layer_bolt_holes_outer(dia=7.05, z0=Tuner_Body_Thickness+Post_Hole_Depth-4); // 5.4 OD for bolt head, 7 for M3 washer + layer_bolt_holes_inner(); + layer_bolt_holes_inner(dia=7.05, z0=Tuner_Body_Thickness+Post_Hole_Depth-4); + // engraving + translate([0,-20,Tuner_Body_Thickness+Post_Hole_Depth-1]) + linear_extrude(5) text(text = Engrave_String, size = 12, halign="center", valign="center", font=Font); + } + // Bottom half + color("grey") + difference() { + linear_extrude(Tuner_Body_Thickness) difference() { + retainer_outline(); + // tuner body holes + translate([0, 0, -20]) + tuner_arrange() + tuner_outline(-1.5); + } + // layer bolt holes + layer_bolt_holes_outer(); + layer_bolt_holes_outer(dia=5.1, z1=5+1.5); // Heat insert is 5mm tall, we will use 20mm bolt for these holes + layer_bolt_holes_inner(); + // tuning handle finger bit + handle_cutouts(); + // engraving + bottom_engraving(); + } + // Mounting + color("aqua") + difference() { + translate([0,0,-12]) linear_extrude(12) difference() { + retainer_outline(); + tuner_arrange() tuner_outline(-1.5); + } + // reinforcing layer bolt holes + layer_bolt_holes_inner(); + layer_bolt_holes_inner(dia=7.05, z1=(Tuner_Body_Thickness+Post_Hole_Depth-4)-29+5); // Heat insert is 5mm tall, we will use 30mm bolt for these holes + // mounting holes + for (x = [-30, -10, 10, 30]) + translate([x,0,-5]) + rotate([90,0,0]) { + cylinder(h=100, r=2.5, $fn=32); + // translate([0,0,10]) cylinder(h=20, r=3.8, $fn=32); // Bolt head + // translate([0,0,11]) cylinder(h=20, r=4.7, $fn=32); // Washer + translate([0,0,11]) cylinder(h=20, r=2.55, $fn=32); // Heat Insert + } + // mounting hollow + cyl_offset = [0,-36,-13]; + translate(cyl_offset) rotate([0,90,0]) cyl(d=28, $fn=128); + translate([-100,-100+cyl_offset[1],-50]) cube([200,100,100]); + for (i = [-1,1]) hull() { + translate([0,-18,-15]) rotate([0,90,0]) c(d=32, z=50*i, $fn=128); + translate(cyl_offset) rotate([0,90,0]) c(d=28, z=14*i, $fn=128); + translate(cyl_offset) rotate([0,90,0]) c(d=28, z=50*i, $fn=128); + } + bottom_engraving(); + } +} +part(); + +// tuner_arrange() tuner(); +// handle_cutouts(); diff --git a/GuitarFretboards.scad b/GuitarFretboards.scad new file mode 100644 index 0000000..81b16ce --- /dev/null +++ b/GuitarFretboards.scad @@ -0,0 +1,181 @@ +// Fender standard is 25.5" +Guitar_Scale_Length_In = 25.5; +// Convert to mm (1" = 25.4mm) +//Guitar_Scale_Length_mm = Guitar_Scale_Length_In * 25.4; +// This conversion ends up with 647.7mm, but 648mm has nice round number 865mm on the -5 fret too! Regular P-bass is 864mm +Guitar_Scale_Length_mm = 648; +// Extending the Strat by 5 frets gives a P-Bass +Bass_Fret = -5; + +PBass_Nut_Width_In = 1.625; // (43mm) +JBass_Nut_Width_In = 1.5; // (38mm) +Strat_Nut_Width_In = 1.65; // (42mm) + +function fret_scale_length(n) = Guitar_Scale_Length_mm * 2^(-n/12); +function lerp(start, end, amount) = start + (end-start)*amount; + +echo(str("Guitar scale length is ", fret_scale_length(0), "mm")); +echo(str("Bass scale length is ", fret_scale_length(Bass_Fret), "mm")); + +// Our modules need to fit in our 25x20cm build area +// This can be obtained by [-5,0), [0,7), [7,19), [19,bridge] modules. + +module radiused_chord(w, r, points=12) { + // w <= abs(r)*2 + // Negative r possible for mirroring across y-axis + angle = asin(0.5*w/r); + angles = [ + for (i = [0:points-1]) + let (f = -0.5 + i/(points-1)) + f * 2 * angle + ]; + x0 = r*cos(angle); + coords = [ + for (th = angles) + let ( + x = r*cos(th) - x0, + y = r*sin(th) + ) + [x,y] + ]; + polygon(coords); +} + +module c_text(s, size) + text(s, size=size, halign="center", valign="center", font="Noto Sans"); + +epsilon = 0.0001; +module to3d() +{linear_extrude(epsilon) children();} + +nut_width = 38; +bridge_width = nut_width + 40; + +fretboard_radius = 5.5*25.4; +neck_radius = 20; +color("red") +rotate([0,90]) hull(){ +translate([0,0,fret_scale_length(Bass_Fret)/4]) + to3d() radiused_chord(lerp(bridge_width, nut_width, 1/4), -fretboard_radius); +translate([0,0,fret_scale_length(Bass_Fret)]) + to3d() radiused_chord(nut_width, -fretboard_radius); +} +// color("blue") +// rotate([0,90]) hull(){ +// translate([0,-bridge_width/2,0]) +// cube([20, bridge_width, 1]); +// translate([0,0,fret_scale_length(Bass_Fret)]) +// to3d() scale([0.25,1]) radiused_chord(nut_width, neck_radius); +// } + +module frets_and_markers(min_fret=-5, max_fret=36, width=bridge_width) { + // Fret wire placeholder model + for (x = [for (i = [min_fret:max_fret]) fret_scale_length(i)]) + translate([x, -width/2, 0]) + cube([1, width, 12]); + + // Fret dots + for (octave = [0:3]) + for (fret = [3, 5, 7, 9]) { + i = fret + (octave*12); + if (i > min_fret && i <= max_fret) + translate([(fret_scale_length(i)+fret_scale_length(i-1))/2,0,0]) + //cylinder(h=10, r=4); + linear_extrude(10) c_text(str(fret), size=8); + } + // Octave markers + for (i = [0, 12, 24, 36]) if (i > min_fret && i <= max_fret) hull(){ + translate([(fret_scale_length(i)+fret_scale_length(i-1))/2,20,0]) cylinder(h=10, r=3); + translate([(fret_scale_length(i)+fret_scale_length(i-1))/2,-20,0]) cylinder(h=10, r=1); + } + // Bass extension + if (min_fret < -1) + for (i = [min_fret+1:-1]) + translate([(fret_scale_length(i)+fret_scale_length(i-1))/2,0,0]) + linear_extrude(10) c_text(str(i), size=12); +} + +Module_Length = 220; // Printer can do up to 250mm, the bass fret run is 217mm. Don't forget overlapping joins! +Module_Overhang = 20; +Module_Bridge_Offset = -15; //80 240 + +module Connector() { + translate([0,0,-15]) + linear_extrude(10) + polygon([[0,5],[0,-5],[Module_Overhang,-15],[Module_Overhang,15]]); +} + +module Body(thickness=20, width=90) { + color("blue", 0.5) + translate([Module_Bridge_Offset, -width/2, -thickness]) + cube([Module_Length, width, thickness]); + frets_and_markers(20, 24); + translate([Module_Bridge_Offset+Module_Length, 0, 0]) Connector(); + + // Bridge + translate([-20, -bridge_width/2, 3]) + cube([20, bridge_width, 10]); +} + +module Neck1(thickness=18, width=70) { + color([0,0.5,1], 0.5) + translate([Module_Bridge_Offset+Module_Length, -width/2, -thickness]) + cube([Module_Length, width, thickness]); + frets_and_markers(8, 20); + translate([Module_Bridge_Offset+Module_Length*2, 0, 0]) Connector(); +} + +module Neck2(thickness=17, width=60) { + color([0.5,0,1], 0.5) + translate([Module_Bridge_Offset+Module_Length*2, -width/2, -thickness]) + cube([Module_Length, width, thickness]); + frets_and_markers(1, 7); + translate([Module_Bridge_Offset+Module_Length*3, 0, 0]) Connector(); +} + +module Neck_Bass(thickness=16, width=40) { + color([1,0,0.5], 0.5) + translate([Module_Bridge_Offset+Module_Length*3, -width/2, -thickness]) + cube([Module_Length+Module_Overhang, width, thickness]); + frets_and_markers(-5, 0); +} + + +// Structural Aluminium +density_6063 = 2.7; // 6063 alloy is around 2.7g/cm3 +echo(str("Weight of one 12mm x 3mm x 1m bar is ", density_6063*1.2*0.3*100, "g")); +echo(str("Weight of three 12mm x 3mm x 1m bar is ", density_6063*3.6*0.3*100, "g")); +echo(str("Weight of one 12x3 and two 10x3 x 1m bars is ", density_6063*3.2*0.3*100, "g")); +echo(str("Weight of one 12mm x 12mm x 1.5mm x 1m channel is roughly ", density_6063*1.2*0.15*100*3, "g")); +echo(str("Weight of one 16mm x 16mm x 1.5mm x 1m channel is roughly ", density_6063*1.6*0.15*100*3, "g")); + +module Parallel_Bars(spacing=18, x0=-80) { + // for (y = [-1.5-spacing, -1.5, -1.5+spacing]) + // translate([x0, y, -12]) cube([1000,3,12]); // 12mm x 3mm bar, 1m length + translate([x0, -1.5, -12]) cube([1000,3,12]); // 12mm x 3mm bar, 1m length + for (y = [-1.5-spacing, -1.5+spacing]) + translate([x0, y, -10]) cube([1000,3,10]); // 12mm x 3mm bar, 1m length +} +module Alu_Channel(x0=-80) { + thickness = 1.5; + y0 = -thickness/2; + //12x12x1.5 channel + translate([x0, -6, -thickness]) cube([1000, 12, thickness]); + for (y = [y0-6, y0+6]) + translate([x0, y, -12]) cube([1000, thickness, 12]); +} + +// frets_and_markers(-5, 29); +Body(); Neck1(); Neck2(); +Neck_Bass(); +Parallel_Bars(); + +translate([0,150,0]) Body(); +translate([0,250,0]) Neck1(); +translate([0,150,0]) Neck2(); +translate([0,250,0]) Neck_Bass(); + +translate([0,-150,0]) { + Body(); Neck1(); Neck2(); + Alu_Channel(); +} diff --git a/PBassPickupHolder.scad b/PBassPickupHolder.scad new file mode 100644 index 0000000..ad27ca6 --- /dev/null +++ b/PBassPickupHolder.scad @@ -0,0 +1,232 @@ +Pickup_Length = 58; // Tolerance +Pickup_Width = 28.5; // Tolerance +Pickup_Height = 20; +Pickup_Offset = -37.5; +Magnet_Height = 3; +Corner_Radius = 1.5; // Half-guessed +Hole_Spacing = 65; +Cavity_Width = 64; // Tolerance + +Tang_Height = 1.5; +Tang_Groove_Height = Tang_Height + 0.25; + +body_h = 20; + +Engrave_String = "P01β²"; +Font = "GFS Didot"; +// Font_JP = "New Tegomin"; +Font_JP = "Yuji Boku"; + + +module cyl(d=10, z0=-100, z1=100, $fn=128) + translate([0,0,z0]) + cylinder(h=z1-z0, r=d/2, $fn=$fn); +module circ(r=10) circle(r=r, $fn=128); + + +pl1 = Pickup_Length/2 - Corner_Radius; +pw1 = Pickup_Width/2 - Corner_Radius; +module half_pickup() { + difference() { + union() { + // translate([-Pickup_Length/2, -Pickup_Width/2, 0]) cube([Pickup_Length, Pickup_Width, Pickup_Height]); + color([0.3, 0.3, 0.3]) hull() + for (x = [-pl1, pl1]) + for (y = [-pw1, pw1]) + translate([x, y, 0]) + cyl(d=Corner_Radius*2, z0=Magnet_Height, z1=Pickup_Height); + for (x = [-29, 29]) + color([0.3, 0.3, 0.3]) + translate([x, 0, 0]) + cyl(d=12, z0=6, z1=16); + color([0.5, 0.5, 0.6]) + translate([-20, -5, 0]) + cube([40, 10, Magnet_Height]); + for (x = [-14.25:9.5:14.25]) + color([0.7, 0.75, 0.8]) + translate([x, 0, 0]) + cyl(d=4, z0=Pickup_Height, z1=Pickup_Height+2); + } + for (x = [-Hole_Spacing/2, Hole_Spacing/2]) + translate([x, 0, 0]) + cyl(d=3); + } +} + +module for_each_pickup() { + for (off = [[0, 0], [Pickup_Offset, Pickup_Width]]) translate(off) children(); +} + +module split_pickup() { + for_each_pickup() half_pickup(); +} + +module pickup_outline(grow=0.5) { + union() { + hull() { + for (x = [-pl1-grow, pl1+grow]) + for (y = [-pw1-grow, pw1+grow]) + translate([x, y]) + circ(r=Corner_Radius); + } + for (x = [-29, 29]) + translate([x, 0]) + circ(r=6+grow); + } +} + +module body_outline(shrink=0, body_r=8) { + union() { + hull() { + // Base Plate + for (x = [-60+body_r, 20-body_r]) + for (y = [-18+body_r, Cavity_Width-18-body_r]) + translate([x,y]) + circ(body_r - shrink); + for (off = [[0, 0], [Pickup_Offset, Pickup_Width]]) translate(off) + for (x = [-29, 29]) translate([x, 0]) + circ((12+5)/2 - shrink); + // Jack Plate + translate([-67, 20]) circ(6 - shrink); + // Pad pickup corners + dist = Pickup_Length/2 + 5 - body_r; + translate([dist, -18+body_r]) circ(body_r - shrink); + translate([Pickup_Offset - dist, Cavity_Width-18-body_r]) circ(body_r - shrink); + } + hull() { + translate([-67, 20]) circ(6 - shrink); + translate([-67, -9]) circ(6 - shrink); + translate([-60+body_r, -18+body_r]) circ(body_r - shrink); + } + } +} + +module tang(margin=0.1) { // Negative margin as subtraction for the slot + difference() { + body_outline(shrink=1+margin); + body_outline(shrink=2-margin); + translate([45, 0]) square(40+margin, center=true); + translate([-83, 32]) square(40+margin, center=true); + }; + translate([-60,11.5]) square([27-margin, 1-margin]); + translate([-6,17]) square([27-margin, 1-margin]); +} + +// color("blue") translate([-60, -18, -1]) cube([80, Cavity_Width, 1]); +module lower() { + difference() { + union() { + taper = 5; + translate([0,0,taper]) minkowski($fn = $preview ? 8 : 64) { + sphere(r = taper, $fn = $preview ? 8 : 64); + linear_extrude(0.0001) body_outline(shrink=taper); + } + // hull() { + // linear_extrude(taper) body_outline(shrink=3); + translate([0,0,taper]) linear_extrude(body_h-taper) body_outline(); + // } + // tang + color("blue") + translate([0,0,body_h]) + linear_extrude(Tang_Height) + tang(); + } + // Subtractions + // Jack cavity + hull() { + translate([-69, -10, 2.5]) cube([15, 20, 20]); + translate([-69, -10, 10]) cube([35, 20, 20]); + } + // Jack hole + translate([0,0,14]) rotate([0,-90,0]) cyl(d=11,z0=60); + // Wire channels + translate([0,0,5]) linear_extrude(body_h) union() { + translate([-35, 7]) square([25,6], center=true); + translate([-66, 13]) square([6,20], center=true); + } + // M4 holes to mount to body + for (off = [[Pickup_Offset-5, 0], [5, Pickup_Width]]) translate(off) { + cyl(d=4); + cyl(d=9.5, z0=5); + } + for_each_pickup() { + // Pickup adjustment brass insert holes + for (x = [-Hole_Spacing/2, Hole_Spacing/2]) + translate([x, 0, 0]) { + cyl(5.1); + hull(){ + cyl(5.25, z0=7, z1=10); + cyl(6, z0=9, z1=20); + } + } + // Pickup outlines + translate([0,0,10]) linear_extrude(100) pickup_outline(); + } + translate([4, 38, body_h-2]) linear_extrude(5) + text(text = Engrave_String, size = 6, halign="center", valign="center", font=Font); + translate([14, 28, body_h-2]) linear_extrude(5) + text(text = "下", size = 8, halign="center", valign="center", font=Font_JP); + } +} + +module upper(wall_height=3.5, roof_height=2.5) { + module elec_cavity() { + hull() { + for (off = [[-27, -11], [-52, -11], [-66, -8], [-66, 7], [-27, 7]]) + translate(off) circ(r=2.5); + } + } + module walls() { + difference() { + body_outline(); + for_each_pickup() pickup_outline(); + elec_cavity(); + } + } + + module roof() { + difference() { + body_outline(); + for_each_pickup() pickup_outline(); + } + } + + difference() { + union() { + linear_extrude(Tang_Groove_Height) difference() { + walls(); + tang(-0.1); + } + h = wall_height - Tang_Groove_Height; + translate([0, 0, Tang_Groove_Height]) + linear_extrude(h) + walls(); + intersection() { + translate([0,0,wall_height]) linear_extrude(roof_height) roof(); + translate([0,0,wall_height]) + minkowski($fn = $preview ? 8 : 64) { + sphere(roof_height, $fn = $preview ? 8 : 64); + linear_extrude(0.001) body_outline(shrink=roof_height); + } + } + } + linear_extrude(100) for_each_pickup() pickup_outline(); + // Engravings + translate([0, 0, wall_height+0.5]) linear_extrude(100) { + translate([-2,22]) + text(text = "LHW", size = 4, font=Font); + translate([-6,17]) + text(text = "2023-03-29", size = 4, font=Font); + translate([-50,0]) + text(text = Engrave_String, size = 6, halign="center", valign="center", font=Font); + translate([-50,-8]) + text(text = "上", size = 8, halign="center", valign="center", font=Font_JP); + } + // Jack hole + translate([0,0,14-body_h]) rotate([0,-90,0]) cyl(d=11+2,z0=60); + } +} + +// lower(); +upper(); +// translate([0,0,10]) split_pickup(); diff --git a/Tiertime.gcode b/Tiertime.gcode new file mode 100644 index 0000000..e38dcd0 --- /dev/null +++ b/Tiertime.gcode @@ -0,0 +1,69 @@ +;===========================; +; List of supported G-codes ; +;===========================; +; G0: linear Move +; G4: Dwell +; G28: Move to Origin (Home) +; G90: Set to Absolute Positioning +; G91: Set to Relative Positioning +; G92: Set Position, only support A axis reset. +; M0: Stop or Unconditional stop +; M1: Sleep or Conditional stop +; M2: Program End +; M25: Pause SD print +; M42: Switch I/O pin +; M73: Set build percentage +; M80: ATX Power On +; M81: ATX Power Off +; M82: Set extruder to absolute mode +; M83: Set extruder to relative mode +; M92: Set axis_steps_per_unit +; M104: Set Extruder Temperature +; M109: Set Extruder Temperature and Wait, Example M109 S215 +; M140: Set Bed Temperature (Fast) +; M141: Set Chamber Temperature (Fast) +; M190: Wait for bed temperature to reach target temp +; M191: Wait for chamber temperature to reach target temp +; M204: Set default acceleration +; M206: Offset axes + +;==========================; +; List of relevant G-codes ; +;==========================; +; M92: Set axis_steps_per_unit +; e.g. M92 X87.489 Y87.489 Z87.489 E420:420 +; M204: Set default acceleration +; M206: Offset axes +; +; G90: Set to Absolute Positioning (default) +; G91: Set to Relative Positioning +; G92: Set Position, "only support A axis reset." - in other machines, this can set new absolute origin +; M82: Set extruder to absolute mode (default) +; M83: Set extruder to relative mode +; +; M190: Wait for bed temperature to reach target temp +; M109: Set Extruder Temperature and Wait, Example M109 S215 +; +; G0: linear Move - this is rapid linear move on other systems, G1 is normal speed linear move for them +; e.g. G0 X000 Y000 Z000 E000 F000 +; F is feed rate, E is extruder +; Traditionally, S is used for "power", which may be laser power or spindle speed. N/A here. +; G4: Dwell (ms) +; e.g. G4 P1000 +; G28: Move to Origin (Home) +; e.g. G28 +; e.g. G28 X Y +; +; M0: Stop or Unconditional stop +; M1: Sleep or Conditional stop +; M2: Program End +; M73: Set build percentage +; e.g. M73 P100 +; +; M80: ATX Power On +; M81: ATX Power Off +; +; +; M140: Set Bed Temperature (Fast) - does not wait! +; e.g. M140 S65 R40 (set to 65°C, wait until 40°C) +; M104: Set Extruder Temperature diff --git a/common.scad b/common.scad new file mode 100644 index 0000000..c3e8273 --- /dev/null +++ b/common.scad @@ -0,0 +1,3 @@ +Guitar_Scale_Length_mm = 648; +function fret_scale_length(n) = Guitar_Scale_Length_mm * 2^(-n/12); +function lerp(start, end, amount) = start + (end-start)*amount; diff --git a/scad-utils b/scad-utils new file mode 160000 index 0000000..27c7ede --- /dev/null +++ b/scad-utils @@ -0,0 +1 @@ +Subproject commit 27c7ede3b7298f0a629553033e2a78e13e627bef diff --git a/skin.scad b/skin.scad new file mode 100644 index 0000000..b1fe662 --- /dev/null +++ b/skin.scad @@ -0,0 +1,75 @@ +use +use + +// Skin a set of profiles with a polyhedral mesh +module skin(profiles, loop=false /* unimplemented */) { + P = max_len(profiles); + N = len(profiles); + + profiles = [ + for (p = profiles) + for (pp = augment_profile(to_3d(p),P)) + pp + ]; + + function quad(i,P,o) = [[o+i, o+i+P, o+i%P+P+1], [o+i, o+i%P+P+1, o+i%P+1]]; + + function profile_triangles(tindex) = [ + for (index = [0:P-1]) + let (qs = quad(index+1, P, P*(tindex-1)-1)) + for (q = qs) q + ]; + + triangles = [ + for(index = [1:N-1]) + for(t = profile_triangles(index)) + t + ]; + + start_cap = [range([0:P-1])]; + end_cap = [range([P*N-1 : -1 : P*(N-1)])]; + + polyhedron(convexity=2, points=profiles, faces=concat(start_cap, triangles, end_cap)); +} + +// Augments the profile with steiner points making the total number of vertices n +function augment_profile(profile, n) = + subdivide(profile,insert_extra_vertices_0([profile_lengths(profile),dup(0,len(profile))],n-len(profile))[1]); + +function subdivide(profile,subdivisions) = let (N=len(profile)) [ + for (i = [0:N-1]) + let(n = len(subdivisions)>0 ? subdivisions[i] : subdivisions) + for (p = interpolate(profile[i],profile[(i+1)%N],n+1)) + p +]; + +function interpolate(a,b,subdivisions) = [ + for (index = [0:subdivisions-1]) + let(t = index/subdivisions) + a*(1-t)+b*t +]; + +function distribute_extra_vertex(lengths_count,ma_=-1) = ma_<0 ? distribute_extra_vertex(lengths_count, max_element(lengths_count[0])) : + concat([set(lengths_count[0],ma_,lengths_count[0][ma_] * (lengths_count[1][ma_]+1) / (lengths_count[1][ma_]+2))], [increment(lengths_count[1],max_element(lengths_count[0]),1)]); + +function insert_extra_vertices_0(lengths_count,n_extra) = n_extra <= 0 ? lengths_count : + insert_extra_vertices_0(distribute_extra_vertex(lengths_count),n_extra-1); + +// Find the index of the maximum element of arr +function max_element(arr,ma_,ma_i_=-1,i_=0) = i_ >= len(arr) ? ma_i_ : + i_ == 0 || arr[i_] > ma_ ? max_element(arr,arr[i_],i_,i_+1) : max_element(arr,ma_,ma_i_,i_+1); + +function max_len(arr) = max([for (i=arr) len(i)]); + +function increment(arr,i,x=1) = set(arr,i,arr[i]+x); + +function profile_lengths(profile) = [ + for (i = [0:len(profile)-1]) + profile_segment_length(profile,i) +]; + +function profile_segment_length(profile,i) = norm(profile[(i+1)%len(profile)] - profile[i]); + +// Generates an array with n copies of value (default 0) +function dup(value=0,n) = [for (i = [1:n]) value]; +