Rework case to be rounded
This commit is contained in:
parent
a5e691eab3
commit
ac984445f9
|
@ -1,4 +1,4 @@
|
||||||
default: adapter-case.stl adapter-lid.stl
|
default: body.stl cap.stl
|
||||||
|
|
||||||
%.stl: %.scad
|
%.stl: case.scad
|
||||||
openscad -o $@ $<
|
openscad -o $@ -D TARGET=\"$*\" $<
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
// Make circles lovely and round
|
|
||||||
$fa = 1; $fs = 0.5;
|
|
||||||
|
|
||||||
module stacker() {
|
|
||||||
translate([0, 0, -5]) {
|
|
||||||
difference() {
|
|
||||||
union() {
|
|
||||||
import("seeed_xaio_case.stl", convexity=3);
|
|
||||||
translate([-12.1, -2, 6]) cube([1.3, 4, 4]); // Plug up the component hole in the back
|
|
||||||
translate([11.45, 0, 5]) cube([1.3, 10, 4], center=true); // Plug up the USB hole
|
|
||||||
}
|
|
||||||
cube([30, 25, 10], center=true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module lid() {
|
|
||||||
intersection() {
|
|
||||||
import("seeed_xaio_case.stl", convexity=3);
|
|
||||||
cube([30, 30, 4], center=true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module trs_support() {
|
|
||||||
intersection() {
|
|
||||||
cube([12, 25, 12], center=true);
|
|
||||||
rotate(-45, [0, 1, 0]) cube([12, 25, 12], center=true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module pig_ear() {
|
|
||||||
intersection() {
|
|
||||||
cylinder(h=4, r1=2, r2=1, center=true);
|
|
||||||
translate([0, -10, 0]) cube([20, 20, 20]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
difference() {
|
|
||||||
union() {
|
|
||||||
import("seeed_xaio_case.stl", convexity=3);
|
|
||||||
|
|
||||||
translate([-12.1, -2, 6]) cube([1.3, 4, 4]); // Plug up the component hole in the back
|
|
||||||
|
|
||||||
// Overlap these to get rid of the slots inside
|
|
||||||
translate([0, 0, 07.5]) stacker();
|
|
||||||
translate([0, 0, 10.0]) stacker();
|
|
||||||
translate([0, 0, 12.5]) stacker();
|
|
||||||
translate([0, 0, 15.0]) stacker();
|
|
||||||
translate([0, 0, 17.5]) stacker();
|
|
||||||
translate([0, 0, 20.0]) stacker();
|
|
||||||
translate([0, 0, 23]) lid();
|
|
||||||
|
|
||||||
// Add some support for inserting the TRS plug
|
|
||||||
intersection() {
|
|
||||||
union() {
|
|
||||||
translate([13, 10, 16]) rotate(60, [0, 0, 1]) trs_support();
|
|
||||||
translate([13, -10, 16]) rotate(-60, [0, 0, 1]) trs_support();
|
|
||||||
}
|
|
||||||
cube([21.8, 19, 60], center=true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shelf for board to rest against
|
|
||||||
difference() {
|
|
||||||
translate([-8, 0, 9.2]) cube([6, 19, 1], center=true);
|
|
||||||
translate([-6, 0, 9.2]) rotate(45, [0, 0, 1]) cube(15, center=true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pig Parts
|
|
||||||
translate([-12, 4, 22]) sphere(r=1.3);
|
|
||||||
translate([-12, -4, 22]) sphere(r=1.3);
|
|
||||||
if (false) {
|
|
||||||
translate([-8, 5, 25]) pig_ear();
|
|
||||||
translate([-8, -5, 25]) pig_ear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pig grin
|
|
||||||
intersection() {
|
|
||||||
translate([0, 0, 15]) rotate(90, [0, 1, 0]) {
|
|
||||||
difference() {
|
|
||||||
cylinder(h=50, d=20, center=true);
|
|
||||||
cylinder(h=50, d=19, center=true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
translate([-18.7, 0, 0]) cube(7);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cut off the bottom
|
|
||||||
cube([30, 30, 4.01], center=true);
|
|
||||||
|
|
||||||
// Channel in the back to make it easier to squeeze in the XIAO
|
|
||||||
translate([-4.5, 0, 7.6]) intersection() {
|
|
||||||
cube([13, 18.3, 1.8], center=true);
|
|
||||||
cylinder(d=21, h=300, center=true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Channels for bottom insertion part thingy
|
|
||||||
translate([0, 0, 3.6]) cube([17, 18.8, 1.2], center=true);
|
|
||||||
|
|
||||||
// Carve out above USB C port
|
|
||||||
translate([10, -4.79, 0]) cube([5, 9.58, 5]);
|
|
||||||
|
|
||||||
// Paddle contacts
|
|
||||||
translate([0, 0, 12]) {
|
|
||||||
// 8-32x 1/4 screws
|
|
||||||
rotate(90, [1, 0, 0]) cylinder(h=30, d=4.0, center=true);
|
|
||||||
|
|
||||||
// Hookup wire
|
|
||||||
translate([0, 0, -2.5]) cube([1, 30, 0.8], center=true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3.5mm TRS jack
|
|
||||||
translate([10, 0, 18]) rotate(90, [0, 1, 0]) cylinder(h=3, d=6.0);
|
|
||||||
|
|
||||||
// Piezo buzzer
|
|
||||||
translate([0, 0, 13]) {
|
|
||||||
translate([-12, 3.5, 0]) cube([5, 1, 1], center=true);
|
|
||||||
translate([-12, -3.5, 0]) cube([5, 1, 1], center=true);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
// Make circles lovely and round
|
|
||||||
$fa = 1; $fs = 0.5;
|
|
||||||
|
|
||||||
module fancycube(vec, h) {
|
|
||||||
translate([r / 2, r / 2, 0]) {
|
|
||||||
difference() {
|
|
||||||
cube([r + 0.01, r + 0.01, h], center = true);
|
|
||||||
|
|
||||||
translate([r/2, r/2, 0])
|
|
||||||
cylinder(r = r, h = h + 1, center = true);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
union() {
|
|
||||||
translate([0, 0, 11]) rotate(180, [1, 0, 0]) import("seeed_xaio_lid.stl", convexity=3);
|
|
||||||
translate([2, -4.5, 0]) cube([8, 9, 4]);
|
|
||||||
fillet(200, 1);
|
|
||||||
}
|
|
|
@ -0,0 +1,181 @@
|
||||||
|
// Make circles lovely and round
|
||||||
|
$fa = 1; $fs = 0.1;
|
||||||
|
|
||||||
|
outer_dimensions = [24.2, 21, 27];
|
||||||
|
outer_radius = 3.7;
|
||||||
|
wall_width = [1.3, 1.3, 1.3];
|
||||||
|
inner_dimensions = outer_dimensions - (wall_width * 2);
|
||||||
|
inner_radius = outer_radius * 0.64;
|
||||||
|
z_elevate = [[0, 0, 0], [0, 0, 0], [0, 0, 0.5]]; // Multiply by this to bring bottom to z=0
|
||||||
|
center = [[-0.5, 0, 0], [0, -0.5, 0], [0, 0, 0]]; // Multiply by this to center something on the xy axes
|
||||||
|
xiao_elevation = 5.2; // Center of the PCB
|
||||||
|
pcb_thickness = 1.8;
|
||||||
|
channel = [16, 1, 1]; // Difensions of cap channel
|
||||||
|
channel_height = 2; // How far into the case the clips need to go
|
||||||
|
cap_thickness = 1.3;
|
||||||
|
|
||||||
|
// More information: https://danielupshaw.com/openscad-rounded-corners/
|
||||||
|
module roundedcube_simple(size=[1, 1, 1], center=false, r=0.5) {
|
||||||
|
// If single value, convert to [x, y, z] vector
|
||||||
|
size = (size[0] == undef) ? [size, size, size] : size;
|
||||||
|
|
||||||
|
translate = (center == false) ?
|
||||||
|
[r, r, r] :
|
||||||
|
[
|
||||||
|
r - (size[0] / 2),
|
||||||
|
r - (size[1] / 2),
|
||||||
|
r - (size[2] / 2)
|
||||||
|
];
|
||||||
|
|
||||||
|
translate(v = translate)
|
||||||
|
minkowski() {
|
||||||
|
cube(size = [
|
||||||
|
size[0] - (r * 2),
|
||||||
|
size[1] - (r * 2),
|
||||||
|
size[2] - (r * 2)
|
||||||
|
]);
|
||||||
|
sphere(r = r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module trs_support() {
|
||||||
|
intersection() {
|
||||||
|
cube([10, 30, 12], center=true);
|
||||||
|
rotate(-45, [0, 1, 0]) cube([10, 30, 12], center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module usb_c() {
|
||||||
|
cube([10, 6.5, 3.15], center=true);
|
||||||
|
translate([0, -3.25, 0]) rotate(90, [0, 1, 0]) cylinder(d=3.15, h=10, center=true);
|
||||||
|
translate([0, 3.25, 0]) rotate(90, [0, 1, 0]) cylinder(d=3.15, h=10, center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module case() {
|
||||||
|
difference() {
|
||||||
|
translate((outer_dimensions * z_elevate) + ([0, 0, -1] * outer_radius)) difference() {
|
||||||
|
roundedcube_simple(outer_dimensions, center=true, r=outer_radius);
|
||||||
|
roundedcube_simple(inner_dimensions, center=true, r=inner_radius);
|
||||||
|
translate(-outer_dimensions/2) cube([100, 100, outer_radius]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// USB C port
|
||||||
|
translate([inner_dimensions[0]/2, 0, 0]) {
|
||||||
|
translate([0, 0, xiao_elevation - 3.15/2]) usb_c();
|
||||||
|
cube([10, 9.65, xiao_elevation*2 - 3.15], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module body() {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
case();
|
||||||
|
|
||||||
|
// Add some supports
|
||||||
|
intersection() {
|
||||||
|
union() {
|
||||||
|
translate([13, 10, 13]) rotate(60, [0, 0, 1]) trs_support();
|
||||||
|
translate([13, -10, 13]) rotate(-60, [0, 0, 1]) trs_support();
|
||||||
|
|
||||||
|
// Shelf for board to rest against
|
||||||
|
difference() {
|
||||||
|
translate([-8, 0, xiao_elevation]) cube([6, 19, 4], center=true);
|
||||||
|
translate([-6, 0, xiao_elevation]) rotate(45, [0, 0, 1]) cube(15, center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
translate(outer_dimensions * center) roundedcube_simple(outer_dimensions, r=outer_radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Eyes
|
||||||
|
translate([-12, 4, 18]) sphere(r=1.2);
|
||||||
|
translate([-12, -4, 18]) sphere(r=1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Smirk grin
|
||||||
|
intersection() {
|
||||||
|
translate([0, 0, 11]) rotate(90, [0, 1, 0]) {
|
||||||
|
difference() {
|
||||||
|
cylinder(h=50, d=20, center=true);
|
||||||
|
cylinder(h=50, d=19, center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
translate([-18.7, 0, 0]) cube(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Channel in the back to make it easier to squeeze in the XIAO
|
||||||
|
translate([-4.5, 0, xiao_elevation]) intersection() {
|
||||||
|
cube([13, 100, pcb_thickness], center=true);
|
||||||
|
roundedcube_simple(inner_dimensions, center=true, r=inner_radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Channels for bottom insertion part thingy
|
||||||
|
for (i = [-0.5, 0.5]) {
|
||||||
|
translate([0, inner_dimensions[1]*i, channel_height-channel[2]/2]) {
|
||||||
|
cube(channel, center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paddle contacts
|
||||||
|
translate([0, 0, 10]) {
|
||||||
|
// 8-32x 1/4 screws
|
||||||
|
rotate(90, [1, 0, 0]) cylinder(h=30, d=4.0, center=true);
|
||||||
|
|
||||||
|
// Hookup wire
|
||||||
|
translate([0, 0, -2.5]) cube([1, 30, 0.8], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.5mm TRS jack
|
||||||
|
translate([10, 0, 14]) rotate(90, [0, 1, 0]) cylinder(h=3, d=6.0);
|
||||||
|
|
||||||
|
// Piezo buzzer
|
||||||
|
translate([0, 0, 10]) {
|
||||||
|
translate([-12, 3.5, 0]) cube([5, 1, 1], center=true);
|
||||||
|
translate([-12, -3.5, 0]) cube([5, 1, 1], center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module cap() {
|
||||||
|
inner = inner_dimensions * 0.97; // leave 5% slop
|
||||||
|
union() {
|
||||||
|
intersection() {
|
||||||
|
roundedcube_simple(outer_dimensions, center=true, r=outer_radius);
|
||||||
|
translate([0, 0, cap_thickness/2]) cube([100, 100, cap_thickness], center=true);
|
||||||
|
}
|
||||||
|
intersection() {
|
||||||
|
roundedcube_simple(inner, center=true, r=inner_radius);
|
||||||
|
translate(center * inner) cube([100, 100, cap_thickness+2.2]);
|
||||||
|
}
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
for (i = [-0.5, 0.5]) {
|
||||||
|
translate([0, inner[1]*i, cap_thickness + channel_height - channel[2]*0.4]) { // 40% of channel z for slop
|
||||||
|
difference() {
|
||||||
|
cube(channel, center=true);
|
||||||
|
translate([0, channel[1]*i, channel[2]/2]) rotate(90*i, [1, 0, 0]) {
|
||||||
|
cube([channel[0], channel[1], channel[2]], center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cube([5, 200, 200], center=true);
|
||||||
|
for (i = [-1, 1]) {
|
||||||
|
translate([9.5*i, 0, 0]) cube([5, 200, 200], center=true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TARGET == "body") {
|
||||||
|
body();
|
||||||
|
} else if (TARGET == "cap") {
|
||||||
|
cap();
|
||||||
|
} else {
|
||||||
|
color([0, 0.5, 0.5]) body();
|
||||||
|
color([0.5, 0, 0.5]) translate([0, 0, -cap_thickness]) cap();
|
||||||
|
}
|
BIN
case/case.stl
BIN
case/case.stl
Binary file not shown.
|
@ -1,521 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
>>> COMPACT 3D-PRINTED PADDLES <<<
|
|
||||||
Torbjørn Skauli, LA4ZCA (tskauli@gmail.com)
|
|
||||||
v2.0, December 2018
|
|
||||||
Iambic paddles designed for 3D-printing. The design is simple, but provides precise movement with adjustable force and travel. Design features include a printed rocker hinge, force adjustment by a sliding spring, travel adjustment using a modified screw, ergonomic grip and general simplicity and precision.
|
|
||||||
Changes in v2.0: The paddles have been made narrower, and the base is thinner. There is an option to remove the bottom mounting holes. The base extends under the paddles to protect them from being pushed upwards. The cable exit is on the side, to fit mounting on the QCX transceiver.
|
|
||||||
TODO:
|
|
||||||
-Arms 1-2 mm higher, spring channel longer towards contacts?
|
|
||||||
Materials:
|
|
||||||
- 3 printed parts
|
|
||||||
- 2 screws M3x5mm, cylinder head, with washers for adjustment if needed
|
|
||||||
- 1 screw M4 x 18-20mm, cylinder head, with lockwasher and nut
|
|
||||||
- Compression spring, 6-8 mm in diameter
|
|
||||||
- Compression spring, 4-5 mm in diameter
|
|
||||||
- Cable with plug as required, up to 3.5 mm diameter
|
|
||||||
Note: Nickel plated brass screws have been found to give the most reliable contact operation. Dimensions of screws, springs and cable can be changed in the code.
|
|
||||||
Assembly:
|
|
||||||
- First, prepare the 3D-printed parts by removing support material in the arm spring well and in the ends of the cable holes. Also remove any protuding edges and bumps by gently filing the surfaces.
|
|
||||||
- Place the large spring so that it is held between the paddles approximately in the middle of the spring well. Also place the small spring in the holes at the hinge. Temporarily slide the two paddles in place. Check the spring force on the paddles and adjust as desired by either moving the spring along the well or by bending the spring to change its length. Make sure that the small spring keeps the arms in place at the hinges during use.
|
|
||||||
- Remove 6-8 cm of the outer isolation (if present) of the cable and 1 cm of the inner isolation of each wire. Insert the cable from the back through the diagonal hole, and temporarily pull it out from the side "window". Insert the cable back into the other hole and press the cable bend into the window so that the outer isolation ends in the interior wiring well. This forms a strain relief.
|
|
||||||
- Prepare a 18-20 mm M4 screw with cylindrical head by grinding the outer 5 mm to flatten two opposing sides. Preferably align the flattened screw end with the slot in the screw head.
|
|
||||||
- Enter two M3 screws with cylindrical heads into the paddle arms, with the heads facing inwards. Clamp the dot and dash wire ends under these screw heads.
|
|
||||||
- Enter the M4 screw from the bottom and clamp the ground wire underneath the lockwasher. Tighten the nut quite firmly, while allowing a small amount of adjustment of the screw angle to set the travel distance.
|
|
||||||
- Place the spring between the paddles and slide them in place. Adjust travel by rotating the M4 screw. If the travel is asymmetric, it may be necessary to correct the difference by placing a washer under the head of one of the M3 screws in the paddle arms.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//*************** Rendering output control
|
|
||||||
mountholes=true;//Whether to have mounting holes in bottom
|
|
||||||
cacc=4; // accuracy of circles, multiplier for $fn. Use cacc=1 for dev/debug, =2-4 for final.
|
|
||||||
preview=0; // =0 for print layout,
|
|
||||||
// =1 or =2 for 1- or 2-arm assembly preview,
|
|
||||||
// =3 for base only
|
|
||||||
// =4 for arms print layout,
|
|
||||||
// =5 base+attachment preview
|
|
||||||
// =6 base modified for attachment to other cabinet
|
|
||||||
// =7 attachment for inclusion in other cabinet
|
|
||||||
// =8 rotation stopper for inclusion in other cabinet
|
|
||||||
|
|
||||||
//**************** main parameters of the design
|
|
||||||
wxbase=24; // overall width, sets arm thickness etc.
|
|
||||||
lybasemin=40; // length excl. knobs (normally 40, made longer below for QCX)
|
|
||||||
hzarm=20; // height of main part of arm
|
|
||||||
wallt=2; // wall thikckness
|
|
||||||
wallmin=2; // min wall thickness under cable holes
|
|
||||||
|
|
||||||
dfinger=30; // approx diameter of finger for curved knob. Also knob length.
|
|
||||||
lyknob=25; // total length of knob
|
|
||||||
rround=1; // radius of rounded edges on knob
|
|
||||||
txknobmin=2; // min. thickness of knob
|
|
||||||
|
|
||||||
yhinge=6.5; // y position of hinge relative to back
|
|
||||||
dxwedge=4; // height of hinge wedge
|
|
||||||
ahinginn=50; // angles for inner and outer part of hinges
|
|
||||||
ahingout=80;
|
|
||||||
dstopper=1.5; // diameter of stopper on top of hinge that keeps arm down
|
|
||||||
|
|
||||||
armsep=0.75; // arm separation from all walls
|
|
||||||
dyarmrests=2; // y width of resting and bounding surfaces for arms
|
|
||||||
minstroke=0.25; // minimum stroke length (at full dia of center screw)
|
|
||||||
|
|
||||||
//**************** parameters for non-printed parts
|
|
||||||
dscrew1=4; // screw dia, also scales screw head height
|
|
||||||
dscrew2=3; // screw dia, also scales screw head height
|
|
||||||
hscrhrel=2/3; // screw head height and diam rel to diameter
|
|
||||||
dscrhrel=7/4;
|
|
||||||
dzcontact=0.1; // extra height of all screws
|
|
||||||
dzsprwell=-1; // height adjustment of spring well
|
|
||||||
dcable=4; // cable diameter
|
|
||||||
dspring=9.5; // spring diameter
|
|
||||||
dhingespring=5; // diameter of spring keeping hinge in place
|
|
||||||
|
|
||||||
//*************** Parameters for cabinet attachment, needed to make integrated paddle
|
|
||||||
daxis=6; // Diameter of rotation axis tube
|
|
||||||
lyflange=22; // Length and height of flange on axis tube
|
|
||||||
hzflange=13;
|
|
||||||
atthick=1.5;
|
|
||||||
rotsnaph=1; // Height of snaps for paddle attachment rotation
|
|
||||||
rotstop=7; // Size of rotation stopper shelf
|
|
||||||
|
|
||||||
//**************** parameters for rendering
|
|
||||||
gap=0.2; // gap for loose fit
|
|
||||||
tol=0.025; // general tolerance
|
|
||||||
nil=0.001; // Negligible distance, to correct rendering
|
|
||||||
|
|
||||||
|
|
||||||
lybase=lybasemin; // length of basee ex. knobs
|
|
||||||
echo("Length of base (mm):",lybase);
|
|
||||||
hzwall=hzarm+armsep; // total height of walls
|
|
||||||
hzbase=2*wallmin+dcable; // height of base under arms
|
|
||||||
ycontact=lybase-1*dscrew1; // position of contact screw
|
|
||||||
|
|
||||||
wxarm=wxbase/2-wallt-armsep-hscrhrel*dscrew2-minstroke-dscrew1/2; // arm thickness is the remaining space after removing many contributions to total width
|
|
||||||
echo("Total height (mm):",hzwall+hzbase);
|
|
||||||
echo("Total width for QCX (mm):",wxbase+dcable);
|
|
||||||
echo("Max length of contact screws in arms (mm):",wxarm);
|
|
||||||
echo("Min length of contact screw in base (mm):",hzbase-hscrhrel*dscrew1+armsep+hzarm/2+dscrew2*dscrhrel/2);
|
|
||||||
echo("Min length to flatten contact screw in base (mm):",dscrew2*dscrhrel);
|
|
||||||
wxknob=wxarm+wallt+armsep+hscrhrel*dscrew2;
|
|
||||||
dxknob=hscrhrel*dscrew2; // x offset toward center rel to main arm
|
|
||||||
hzknob=hzarm; // height of knobs
|
|
||||||
lyarm=lybase-wallt-armsep/2; // knob spaced armsep/2 from base front
|
|
||||||
|
|
||||||
y0sprwell=yhinge-wallt-armsep+dxwedge*tan(ahingout/2); // starting pos of spring channel
|
|
||||||
sprfloort=wallt; // thickness of floor underneath spring
|
|
||||||
sprlen=wxbase-2*(wallt+armsep+sprfloort); // length of spring
|
|
||||||
|
|
||||||
dxtip=wxbase/4; // diameter of rounded tip with attachment hole
|
|
||||||
dytip=(wxbase-dxtip)/2; // length of tip ex rouned part
|
|
||||||
rtip=dxtip*sqrt(2)/2; // radius of tip
|
|
||||||
ycentip=lybase+dytip-rtip/sqrt(2); // center of rounded tip
|
|
||||||
|
|
||||||
module teardropHole(lh,rh){ // Hole with 45-degree teardrop shape
|
|
||||||
rotate([90,0,0])
|
|
||||||
rotate([0,0,45])
|
|
||||||
union(){
|
|
||||||
cylinder(h=lh,r1=rh,r2=rh,$fn=8*cacc);
|
|
||||||
cube([rh,rh,lh]);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
module snap45(snaph,snapl){ // bumps to snap parts together, max angle 45 degrees
|
|
||||||
// snapl is length of bump, passed as parameter to allow tolerance
|
|
||||||
difference(){
|
|
||||||
rsnap=snaph/(1-1/sqrt(2));
|
|
||||||
translate([rsnap-snaph,-snapl/2,0])
|
|
||||||
rotate([-90,0,0])
|
|
||||||
cylinder(h=snapl,r=rsnap,$fn=5*cacc);
|
|
||||||
translate([nil,-snapl/2,-rsnap])
|
|
||||||
cube([2*rsnap,snapl,2*rsnap]);
|
|
||||||
};
|
|
||||||
}; // end snap
|
|
||||||
module wedge(a,wx,hz){ // Equilateral triangular block
|
|
||||||
//top angle a(deg), length hz and triangle height wx in x direction
|
|
||||||
linear_extrude(height=hz)
|
|
||||||
polygon([[0,0],[wx,wx*tan(a/2)],[wx,-wx*tan(a/2)]]);
|
|
||||||
};
|
|
||||||
module cone45(dc){ // cone for stopper that keeps arm down, 45-degree slope
|
|
||||||
rotate([180,0,0])
|
|
||||||
cylinder(d1=dc,d2=0,h=dc*1.0,$fn=8*cacc);
|
|
||||||
};
|
|
||||||
module wedge_hinge(){ //wedge on wall for hinge, with cutout so that arm rests on top and bottom
|
|
||||||
// cutout for stopper cone
|
|
||||||
translate([0,0,hzwall])
|
|
||||||
cone45(dstopper);
|
|
||||||
// wedge with cutout, centered on the edge between cone and armrest,
|
|
||||||
// to make arm better supported against up-down tilt
|
|
||||||
difference(){
|
|
||||||
wedge(a=ahinginn,wx=dxwedge,hz=hzwall);
|
|
||||||
translate([-hzarm/2/sqrt(2),hzarm/2,hzarm/2+armsep-dstopper*0.75/2])
|
|
||||||
rotate([90,0,0])
|
|
||||||
cylinder(h=hzarm,d=hzarm,$fn=12*cacc);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
module bump45(bumph){ // Spherical bump with at most 45 degree angle
|
|
||||||
rotate([0,180,0])
|
|
||||||
difference(){
|
|
||||||
amax=60; // max overhang angle on bump, not necessarily 45 degerees
|
|
||||||
rsnap=bumph/(1-cos(amax));
|
|
||||||
translate([rsnap-bumph,0,0])
|
|
||||||
sphere(r=rsnap,$fn=5*cacc);
|
|
||||||
translate([nil,-rsnap,-rsnap])
|
|
||||||
cube([2*rsnap,2*rsnap,2*rsnap]);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
module rotsnaps(snaph){ // Rotation snaps for paddle
|
|
||||||
rrot=(hzbase+hzwall)/2*sqrt(2)-snaph/(1-1/sqrt(2))-wallt;
|
|
||||||
for (a=[45:90:360])
|
|
||||||
rotate([a,0,0])
|
|
||||||
translate([0,rrot,0])
|
|
||||||
bump45(snaph);
|
|
||||||
};
|
|
||||||
module base_add(){ // parts of base that add to shape
|
|
||||||
// base plate
|
|
||||||
translate([-wxbase/2,0,0])
|
|
||||||
cube([wxbase,lybase+lyknob-rround,hzbase]);
|
|
||||||
|
|
||||||
//rounded front
|
|
||||||
translate([-wxbase/2+rround,lybase+lyknob-rround,0])
|
|
||||||
minkowski(){
|
|
||||||
cube([wxbase-2*rround,tol,hzbase]);
|
|
||||||
// rounding cy
|
|
||||||
cylinder(r=rround,h=tol,$fn=cacc*4);
|
|
||||||
};
|
|
||||||
|
|
||||||
// walls
|
|
||||||
translate([0,0,hzbase])
|
|
||||||
difference(){
|
|
||||||
translate([-wxbase/2,0,0])
|
|
||||||
cube([wxbase,lybase,hzwall]);
|
|
||||||
translate([-wxbase/2+wallt,wallt,0])
|
|
||||||
cube([wxbase-2*wallt,lybase,hzwall+tol]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//wedge 1
|
|
||||||
translate([wxbase/2-wallt-dxwedge,yhinge,hzbase])
|
|
||||||
wedge_hinge();
|
|
||||||
//wedge 2
|
|
||||||
translate([-(wxbase/2-wallt-dxwedge),yhinge,hzbase])
|
|
||||||
rotate([0,0,180])
|
|
||||||
wedge_hinge();
|
|
||||||
|
|
||||||
// bottom arm resting surface, height armsep above base top
|
|
||||||
translate([0,yhinge,hzbase])
|
|
||||||
cube([wxbase-2*wallt-2*dxwedge-2,dyarmrests,2*armsep],center=true);
|
|
||||||
|
|
||||||
// front arm lower resting surface, normally with 2*gap airgap
|
|
||||||
translate([-wxbase/2,lybase-dyarmrests,hzbase])
|
|
||||||
cube([(wxbase-2*dscrew1)/2,dyarmrests,armsep-2*gap]);
|
|
||||||
translate([wxbase/2,lybase,hzbase])
|
|
||||||
rotate([0,0,180])
|
|
||||||
cube([(wxbase-2*dscrew1)/2,dyarmrests,armsep-2*gap]);
|
|
||||||
|
|
||||||
// outer end stops, 2mm wide
|
|
||||||
translate([-(wxbase/2-wallt),lybase-dyarmrests,hzbase])
|
|
||||||
cube([armsep,dyarmrests,hzwall]);
|
|
||||||
translate([(wxbase/2-wallt)-armsep,lybase-dyarmrests,hzbase])
|
|
||||||
cube([armsep,dyarmrests,hzwall]);
|
|
||||||
|
|
||||||
// extra column for center screw stability
|
|
||||||
translate([0,ycontact,hzbase])
|
|
||||||
cylinder(d=dscrew1*dscrhrel*1.5,h=dscrew1/2+dzcontact,$fn=8*cacc);
|
|
||||||
|
|
||||||
// QCX attachment: add 1x cable dia of wall thickness and rotation axis
|
|
||||||
if (preview>=5){
|
|
||||||
|
|
||||||
// Thicker wall
|
|
||||||
translate([wxbase/2,0,0])
|
|
||||||
cube([dcable,lybase,hzbase+hzwall]);
|
|
||||||
|
|
||||||
// Rotation stopper
|
|
||||||
translate([wxbase/2,lybase,0])
|
|
||||||
cube([dcable,rotstop,hzbase]);
|
|
||||||
|
|
||||||
// snaps for paddle rotation
|
|
||||||
translate([wxbase/2+dcable,lybase/2,(hzbase+hzwall)/2])
|
|
||||||
rotsnaps(rotsnaph);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
module base_sub(){ // parts of base that cut away from shape
|
|
||||||
|
|
||||||
// center contact screw hole
|
|
||||||
translate([0,ycontact,0])
|
|
||||||
cylinder(d=dscrew1,h=hzbase*9,$fn=8*cacc);
|
|
||||||
|
|
||||||
// center contact screw head recess (20% enlarged) filled in by cylinder to avoid need for support
|
|
||||||
translate([0,ycontact,0])
|
|
||||||
cylinder(d=dscrew1*dscrhrel*1.2,h=dscrew1*hscrhrel*1.2,$fn=8*cacc);
|
|
||||||
|
|
||||||
// Front mounting screw hole with recess
|
|
||||||
if (mountholes && preview<5){
|
|
||||||
translate([0,ycentip,0])
|
|
||||||
cylinder(d=dscrew1+gap,h=hzbase,$fn=8*cacc);
|
|
||||||
translate([0,ycentip,wallt])
|
|
||||||
cylinder(d=dscrew1*dscrhrel*1.2,h=hzbase,$fn=8*cacc);
|
|
||||||
};
|
|
||||||
|
|
||||||
// wire well
|
|
||||||
wellw=wxbase/2; // wire well width and length
|
|
||||||
translate([wellw/2,ycontact-2*dscrew1,wallt])
|
|
||||||
rotate([0,0,180])
|
|
||||||
cube([wellw,wellw,hzbase]);
|
|
||||||
|
|
||||||
// Back mounting screw hole in well
|
|
||||||
if (mountholes && preview<5){
|
|
||||||
translate([0,ycontact-2*dscrew1-wellw/2,0])
|
|
||||||
cylinder(d=dscrew1+gap,h=hzbase,$fn=8*cacc);
|
|
||||||
};
|
|
||||||
|
|
||||||
//cable holes
|
|
||||||
if (preview<5) // Free standing paddle, no attachment
|
|
||||||
translate([-(wxbase/2-dcable/4),ycontact-2*dscrew1-wellw-dcable/2,dcable/2+wallmin]){
|
|
||||||
// cable hole 1
|
|
||||||
translate([0,-dcable/2,0])
|
|
||||||
rotate([0,0,90])
|
|
||||||
teardropHole(lh=wxbase*2,rh=dcable/2);
|
|
||||||
// cable hole 2
|
|
||||||
rotate([0,0,45+90])
|
|
||||||
teardropHole(lh=wxbase/sqrt(2)/2,rh=dcable/2);
|
|
||||||
//cable access opening
|
|
||||||
cube([dcable,2*dcable,dcable],center=true);
|
|
||||||
}
|
|
||||||
else{ // Cable routing for QCX
|
|
||||||
// cable hole from well
|
|
||||||
translate([0,lybase/2+dcable,dcable/2+wallmin])
|
|
||||||
rotate([0,0,90])
|
|
||||||
teardropHole(lh=wxbase,rh=dcable/2);
|
|
||||||
|
|
||||||
//cable access opening, printable without support, using breakaway wall
|
|
||||||
for (i=[-1,1])
|
|
||||||
translate([wxbase/2+0*wallt/2,lybase/2+i*(gap+dcable/2), wallmin]){
|
|
||||||
cube([dcable,dcable,dcable]);
|
|
||||||
translate([0,dcable/2,1.5*dcable])rotate([0,90,0])wedge(90,dcable/2,dcable);
|
|
||||||
};
|
|
||||||
|
|
||||||
//vertical cable hole
|
|
||||||
translate([wxbase/2+dcable-(wallt+dcable)/2,lybase/2,wallmin]){
|
|
||||||
hhole=hzbase+hzwall/2;
|
|
||||||
cylinder(d=dcable,h=hhole); // main hole
|
|
||||||
translate([0,0,hhole])
|
|
||||||
cylinder(d1=dcable,d2=0,h=dcable); // tapered top to avoid support
|
|
||||||
};
|
|
||||||
|
|
||||||
// rotation axis
|
|
||||||
translate([wxbase/2-dcable,lybase/2,(hzbase+hzwall)/2]){
|
|
||||||
// Axis hole
|
|
||||||
rotate([0,90,0])
|
|
||||||
cylinder(d=daxis+gap,h=99,$fn=8*cacc);
|
|
||||||
// Rotation snap
|
|
||||||
};
|
|
||||||
|
|
||||||
// Room for square flange soldered onto rotation axis
|
|
||||||
translate([wxbase/2-wallt,(lybase-lyflange)/2,(hzbase+hzwall-hzflange)/2]){
|
|
||||||
cube([dcable,lyflange,hzflange]);
|
|
||||||
translate([-tol,0,hzflange-tol])
|
|
||||||
rotate([90,-135,180])
|
|
||||||
wedge(90,dcable/sqrt(2),lyflange);
|
|
||||||
};
|
|
||||||
|
|
||||||
}; // End QCX attachment
|
|
||||||
|
|
||||||
};
|
|
||||||
module base(){ // complete base part
|
|
||||||
difference(){
|
|
||||||
base_add();
|
|
||||||
base_sub();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
module attachment(){ // attachment that can be included in QCX (or other) cabinet
|
|
||||||
difference(){
|
|
||||||
union(){
|
|
||||||
|
|
||||||
// Attachment part of wall
|
|
||||||
translate([0,-2*rotstop,0])
|
|
||||||
cube([atthick,2*rotstop+lybase,hzbase+hzwall]);
|
|
||||||
|
|
||||||
}; // end union
|
|
||||||
|
|
||||||
// Axis hole
|
|
||||||
translate([0,lybase/2,(hzbase+hzwall)/2])
|
|
||||||
rotate([0,90,0])
|
|
||||||
cylinder(d=daxis+gap,h=99,$fn=8*cacc);
|
|
||||||
|
|
||||||
// snaps for paddle rotation, slightly tight to avoid play
|
|
||||||
translate([0,lybase/2,(hzbase+hzwall)/2])
|
|
||||||
rotsnaps(rotsnaph-gap/3);
|
|
||||||
|
|
||||||
}; // end difference
|
|
||||||
};
|
|
||||||
module rotlimit(){ // Rotation stopper for attachment, to be included in cabinet
|
|
||||||
|
|
||||||
limdim=wallt+dcable; // width of stopper cube, equal to stopper on paddle base
|
|
||||||
|
|
||||||
// stopper knob
|
|
||||||
translate([-dcable,lybase/2-limdim/2,(hzbase+hzwall)/2-limdim/2])// move to hole
|
|
||||||
rotate([0*30,0,0]) // rotate if desired
|
|
||||||
translate([0,-lybase/2-limdim/2-rotstop,(hzbase+hzwall)/2-limdim/2])
|
|
||||||
cube([dcable,limdim,limdim]);
|
|
||||||
|
|
||||||
};
|
|
||||||
module rotlimitEXPORT(){ // Rotation stopper for attachment, to be included in cabinet
|
|
||||||
translate([0,-lybase,-hzbase-hzwall])
|
|
||||||
rotlimit();
|
|
||||||
};
|
|
||||||
module attachmentEXPORT(){ // Rotation stopper for attachment, to be included in cabinet
|
|
||||||
translate([0,-lybase,-hzbase-hzwall])
|
|
||||||
attachment();
|
|
||||||
};
|
|
||||||
function attachHeightEXPORT()=hzbase+hzwall; // Export total height
|
|
||||||
module arm_add(){ // arm base shape, without knob
|
|
||||||
|
|
||||||
// main arm
|
|
||||||
cube([wxarm,lyarm,hzarm]);
|
|
||||||
|
|
||||||
// extra material for supporting hinge spring
|
|
||||||
translate([-dxknob,0,0])
|
|
||||||
cube([dxknob,y0sprwell,hzarm]);
|
|
||||||
|
|
||||||
// extra material near top of arm, for stiffness and appearance
|
|
||||||
hzarmextra=hzarm/2-dzcontact-(dscrew2*dscrhrel*1.3);
|
|
||||||
translate([-dxknob,0,hzarm-(hzarmextra-dxknob)]){
|
|
||||||
cube([dxknob,lyarm,hzarmextra-dxknob]);
|
|
||||||
|
|
||||||
// 45 deg underside of extra material, to avoid generation of support
|
|
||||||
translate([dxknob,0,0])
|
|
||||||
rotate([90,45,180])
|
|
||||||
wedge(90,dxknob/sqrt(2),lyarm);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
module arm_sub(){ // arm shaping
|
|
||||||
// hinge groove
|
|
||||||
translate([wxarm-dxwedge+armsep,yhinge-wallt-armsep,0])
|
|
||||||
wedge(a=ahingout,wx=dxwedge,hz=hzarm);
|
|
||||||
|
|
||||||
// hinge stopper cutout
|
|
||||||
translate([wxarm-dxwedge+armsep,yhinge-wallt-armsep,hzarm])
|
|
||||||
cone45(dstopper+2*gap);
|
|
||||||
|
|
||||||
// tension spring channel
|
|
||||||
translate([0,y0sprwell,(hzarm-dspring)/2+dzsprwell]){
|
|
||||||
cube([wxarm-sprfloort,ycontact-y0sprwell-2.5*dscrew1,dspring]);
|
|
||||||
translate([-tol,0,dspring-tol])
|
|
||||||
rotate([90,-135,180])
|
|
||||||
wedge(90,(wxarm-sprfloort)/sqrt(2),ycontact-y0sprwell-2.5*dscrew1);
|
|
||||||
};
|
|
||||||
|
|
||||||
// contact screw hole
|
|
||||||
translate([-tol,ycontact-wallt-armsep,hzarm/2+dzcontact])
|
|
||||||
rotate([0,0,90])
|
|
||||||
teardropHole(lh=wxarm*2,rh=dscrew2/2-gap);
|
|
||||||
|
|
||||||
// hole for spring keeping hinge in place
|
|
||||||
translate([-dxknob-tol,yhinge-wallt-armsep,hzarm/2])
|
|
||||||
rotate([0,0,90])
|
|
||||||
teardropHole(lh=dxknob+wxarm-dxwedge+armsep-sprfloort+tol,rh=dhingespring/2);
|
|
||||||
|
|
||||||
// extra space for center screw column
|
|
||||||
translate([-(wxbase/2-wallt-armsep-wxarm),ycontact-wallt-armsep,0])
|
|
||||||
cylinder(d=dscrew1*dscrhrel*1.5+2*minstroke+dscrew1,h=dscrew1/2+dzcontact+dscrew1*hscrhrel*1.25,$fn=8*cacc);
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
module knob_curved(){ // finger-curved and rounded knob
|
|
||||||
intersection(){ // cutting to outer shape
|
|
||||||
minkowski(){ // rounding of edges
|
|
||||||
|
|
||||||
// un-rounded knob shrunk by rounding radius
|
|
||||||
difference(){ // shaping finger rest
|
|
||||||
|
|
||||||
// knob, to be shaped by subtraction
|
|
||||||
translate([-dxknob,lyarm,0])
|
|
||||||
cube([wxknob-rround,lyknob-rround,hzknob-rround]);
|
|
||||||
|
|
||||||
// shaping of knob
|
|
||||||
translate([-dxknob+txknobmin+dfinger/2,lyarm+0*wallt+dfinger/2,dfinger/2+0*wallt])
|
|
||||||
minkowski(){
|
|
||||||
cube([tol,wxbase,wxbase]);
|
|
||||||
sphere(r=dfinger/2,$fn=8*cacc);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
// rounding sphere
|
|
||||||
sphere(r=rround,$fn=cacc*4);
|
|
||||||
};
|
|
||||||
// outer bound of knob
|
|
||||||
translate([-dxknob,lyarm,0])
|
|
||||||
cube([wxknob,dfinger,hzknob]);
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
module arm(){ // Generate final shape according to preview and cacc settings
|
|
||||||
difference(){
|
|
||||||
union(){
|
|
||||||
knob_curved();
|
|
||||||
arm_add();
|
|
||||||
};
|
|
||||||
arm_sub();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
module build_all(){
|
|
||||||
|
|
||||||
if(preview==1){
|
|
||||||
base();
|
|
||||||
translate([wxbase/2-wallt-armsep-wxarm,wallt+armsep,hzbase+armsep])
|
|
||||||
arm();
|
|
||||||
}
|
|
||||||
else if (preview==2){
|
|
||||||
base();
|
|
||||||
translate([wxbase/2-wallt-armsep-wxarm,wallt+armsep,hzbase+armsep])
|
|
||||||
arm();
|
|
||||||
|
|
||||||
translate([-(wxbase/2-wallt-armsep-wxarm),wallt+armsep,hzbase+armsep])
|
|
||||||
scale([-1,1,1])
|
|
||||||
arm();
|
|
||||||
}
|
|
||||||
else if (preview==3){
|
|
||||||
base();
|
|
||||||
}
|
|
||||||
else if (preview==4){
|
|
||||||
translate([wxbase/2+wxknob+1,0,0])
|
|
||||||
scale([-1,1,1])
|
|
||||||
arm();
|
|
||||||
|
|
||||||
translate([wxbase/2+2*wxknob+2,0,0])
|
|
||||||
arm();
|
|
||||||
}
|
|
||||||
else if (preview==5){
|
|
||||||
base();
|
|
||||||
translate([wxbase/2+dcable+10,0,0]){ // spacing for rendering, for preview of fit
|
|
||||||
attachment();
|
|
||||||
rotlimit();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (preview==6){ // Base with additions for attachment
|
|
||||||
base();
|
|
||||||
}
|
|
||||||
else if (preview==7){ // Attachment for inclusion in cabinet
|
|
||||||
attachmentEXPORT();
|
|
||||||
}
|
|
||||||
else if (preview==8){ // Rotation stopper for inclusion in cabinet
|
|
||||||
rotlimitEXPORT();
|
|
||||||
}
|
|
||||||
else if (preview==9){ // Rotation stopper for inclusion in cabinet
|
|
||||||
attachmentEXPORT();
|
|
||||||
rotlimitEXPORT();
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
base();
|
|
||||||
translate([wxbase/2+wxknob+1,0,0])
|
|
||||||
scale([-1,1,1])
|
|
||||||
arm();
|
|
||||||
|
|
||||||
translate([wxbase/2+2*wxknob+2,0,0])
|
|
||||||
arm();
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
build_all();
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue