diff --git a/bike-lights/case/bike-light-enclosure.scad b/bike-lights/case/bike-light-enclosure.scad new file mode 100644 index 0000000..5388911 --- /dev/null +++ b/bike-lights/case/bike-light-enclosure.scad @@ -0,0 +1,174 @@ +width = 65; +length = 75; +height = 16; +wall_thickness = 2; +guide_thickness = 1; +power_width = 21; +output_width = 37.5; +half_wall_thickness = wall_thickness / 2; +standoff_thickness = 10; +hole_diameter = 3; +// The radius of a nut in mm. However, based on my measurements, I'm not actually sure I have this right. The short height of a nut is 7.86mm. Derive from there. +nut_radius = 8.5 * cos(30) / 2; +nut_height = 2.69; // mm +screw_radius = 2; +handlebar_radius = 15; +clasp_thickness = 4; +clasp_width = 35; +circular_face_count = 48; + +module hexagon(r, h) { + pi = 3.1415926; + polyhedron( + points=[ + [r, 0, 0], + [r * cos(60), r * sin(60), 0], + [r * cos(120), r * sin(120), 0], + [r * cos(180), r * sin(180), 0], + [r * cos(240), r * sin(240), 0], + [r * cos(300), r * sin(300), 0], + + [r, 0, h], + [r * cos(60), r * sin(60), h], + [r * cos(120), r * sin(120), h], + [r * cos(180), r * sin(180), h], + [r * cos(240), r * sin(240), h], + [r * cos(300), r * sin(300), h], + ], + faces=[ + [0, 1, 2, 3, 4, 5], + [11, 10, 9, 8, 7, 6], + [6, 7, 1, 0], + [7, 8, 2, 1], + [8, 9, 3, 2], + [9, 10, 4, 3], + [10, 11, 5, 4], + [11, 6, 0, 5], + ] + ); +} + +// Nut holders are blocks that have a hole drilled through them and a hexagonal-shaped cavity. The idea is to +module nut_holder() { + difference() { + translate([-4.5, -4.5, -2]) cube([9, 9, 4]); + union() { + translate([0, 0, -1]) hexagon(nut_radius, 2); + cylinder(h = 6, r = screw_radius, center = true, $fn = 24); + } + } +} + +module screw_hole() { + union() { + translate([0, 0, 4]) cylinder(h = 2.1, r = screw_radius * 2, center = true, $fn = 24); + cylinder(h = 6, r = screw_radius, center = true, $fn = 24); + } +} + +module base() { + cube([width, length, wall_thickness]); +} + +module face() { + union() { + cube([width, length, wall_thickness / 2]); + translate([wall_thickness, wall_thickness, wall_thickness / 2]) cube([width-wall_thickness*2, length-wall_thickness*2, wall_thickness / 2]); + translate([4.5 + wall_thickness, 4.5 + wall_thickness, 4]) nut_holder(); + translate([width - 4.5 - wall_thickness, 4.5 + wall_thickness, 4]) nut_holder(); + translate([width - 4.5 - wall_thickness, length - 4.5 - wall_thickness, 4]) nut_holder(); + translate([4.5 + wall_thickness, length - 4.5 - wall_thickness, 4]) nut_holder(); + } +} + +module wall(length) { + cube([length, height, wall_thickness]); +} + +module power_wall() { + difference() { + wall(65); + translate([9, 2, -.5]) cube([power_width, height, wall_thickness + 1]); + } +} + +module output_wall() { + difference() { + wall(65); + translate([9, 2, -.5]) cube([output_width, height, wall_thickness + 1]); + } +} + +// Use hexagons as cutouts into which I can install a hex nut. This isn't quite right yet, but close. +// hexagon(nut_radius, 1); + +// cube([standoff_thickness, standoff_thickness, 2]); + +/* +difference() { + union() { + base(); + rotate([90, 0, 90]) wall(75); + // translate([width - wall_thickness, 0, 0]) rotate([90, 0, 90]) wall(length); + // rotate([90, 0, 0]) power_wall(); + // translate([0, length, 0]) rotate([90, 0, 0]) output_wall(); + // translate([wall_thickness, + // wall_thickness, + // wall_thickness]) standoff(); + // translate([width - wall_thickness - standoff_thickness, + // wall_thickness, + // wall_thickness]) standoff(); + // translate([wall_thickness, + // length - wall_thickness - standoff_thickness, + // wall_thickness]) standoff(); + // translate([width - wall_thickness - standoff_thickness, + // length - wall_thickness - standoff_thickness, + // wall_thickness]) standoff(); + } + // translate([-half_wall_thickness, -wall_thickness - half_wall_thickness, height - half_wall_thickness]) cube([wall_thickness, length + wall_thickness * 2, wall_thickness]); + // translate([width - half_wall_thickness, -wall_thickness - half_wall_thickness, height - half_wall_thickness]) cube([wall_thickness, length + wall_thickness * 2, wall_thickness]); + // translate([-half_wall_thickness, -half_wall_thickness, height - half_wall_thickness]) rotate([0, 0, 270]) cube([wall_thickness, width + wall_thickness * 2, wall_thickness]); + // translate([-half_wall_thickness, length + half_wall_thickness, height - half_wall_thickness]) rotate([0, 0, 270]) cube([wall_thickness, width + wall_thickness * 2, wall_thickness]); +} +*/ + +module box() { + difference() { + union() { + cube([width, length, wall_thickness * 2]); + translate([0, 0, wall_thickness]) rotate([90, 0, 90]) wall(length); + translate([width - wall_thickness, 0, wall_thickness]) rotate([90, 0, 90]) wall(length); + translate([0, wall_thickness, wall_thickness]) rotate([90, 0, 0]) wall(width); + translate([0, length, wall_thickness]) rotate([90, 0, 0]) wall(width); + } + translate([4.5 + wall_thickness, 4.5 + wall_thickness, 4]) rotate([180, 0, 0]) screw_hole(); + translate([width - 4.5 - wall_thickness, 4.5 + wall_thickness, 4]) rotate([180, 0, 0]) screw_hole(); + translate([width - 4.5 - wall_thickness, length - 4.5 - wall_thickness, 4]) rotate([180, 0, 0]) screw_hole(); + translate([4.5 + wall_thickness, length - 4.5 - wall_thickness, 4]) rotate([180, 0, 0]) screw_hole(); + } +} + +module top_clasp() { + difference() { + union() { + cylinder(h = clasp_width, r = handlebar_radius + clasp_thickness, center = true, $fn = circular_face_count); + translate([0, 0, -clasp_width / 2]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([0, 0, -clasp_width / 2 + 4]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([0, 0, clasp_width / 2]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([0, 0, clasp_width / 2 - 4]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([-handlebar_radius-5, -10, -clasp_width / 2 + 6]) cube([6, 20, clasp_width - 12]); + } + translate([-0.5, 0, 0]) cylinder(h = clasp_width+2, r = handlebar_radius + 1, center = true, $fn = circular_face_count); + translate([-0.5, -handlebar_radius - 10, -clasp_width / 2 - 1]) cube([handlebar_radius + 10, handlebar_radius * 2 + 20, clasp_width + 2]); + } +} + +module body() { + union() { + box(); + translate([width / 2, length / 2, -5 - handlebar_radius]) rotate([0, 90, 90]) top_clasp(); + } +} + +body(); +translate([width + 10, 0, 0]) face(); diff --git a/bike-lights/case/clasp.scad b/bike-lights/case/clasp.scad new file mode 100644 index 0000000..eda1002 --- /dev/null +++ b/bike-lights/case/clasp.scad @@ -0,0 +1,21 @@ +handlebar_radius = 15; +clasp_thickness = 4; +circular_face_count = 48; +clasp_width = 35; + +module top_clasp() { + difference() { + union() { + cylinder(h = clasp_width, r = handlebar_radius + clasp_thickness, center = true, $fn = circular_face_count); + translate([0, 0, -clasp_width / 2]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([0, 0, -clasp_width / 2 + 4]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([0, 0, clasp_width / 2]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([0, 0, clasp_width / 2 - 4]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([-handlebar_radius-5, -10, -clasp_width / 2 + 6]) cube([6, 20, clasp_width - 12]); + } + translate([-0.5, 0, 0]) cylinder(h = clasp_width+2, r = handlebar_radius + 1, center = true, $fn = circular_face_count); + translate([-0.5, -handlebar_radius - 10, -clasp_width / 2 - 1]) cube([handlebar_radius + 10, handlebar_radius * 2 + 20, clasp_width + 2]); + } +} + +top_clasp(); diff --git a/bike-lights/case/common.scad b/bike-lights/case/common.scad index 75ba697..a142752 100644 --- a/bike-lights/case/common.scad +++ b/bike-lights/case/common.scad @@ -1,3 +1,8 @@ + +module hexagon(r, h) { + cylinder(r = r, h = h, center = 2, $fn = 6); +} + module pill(length, bevel) { hull() { translate([0, 0, (-length / 2) + bevel]) sphere(r = bevel); @@ -5,6 +10,27 @@ module pill(length, bevel) { } } +module rounded_cube(dimensions, bevel = 0) { + x = dimensions[0]; + y = dimensions[1]; + z = dimensions[2]; + + if (bevel > 0) { + hull() { + translate([-x / 2 + bevel, -y / 2 + bevel, -z / 2 + bevel]) sphere(r = bevel); + translate([ x / 2 - bevel, -y / 2 + bevel, -z / 2 + bevel]) sphere(r = bevel); + translate([ x / 2 - bevel, y / 2 - bevel, -z / 2 + bevel]) sphere(r = bevel); + translate([-x / 2 + bevel, y / 2 - bevel, -z / 2 + bevel]) sphere(r = bevel); + translate([-x / 2 + bevel, -y / 2 + bevel, z / 2 - bevel]) sphere(r = bevel); + translate([ x / 2 - bevel, -y / 2 + bevel, z / 2 - bevel]) sphere(r = bevel); + translate([ x / 2 - bevel, y / 2 - bevel, z / 2 - bevel]) sphere(r = bevel); + translate([-x / 2 + bevel, y / 2 - bevel, z / 2 - bevel]) sphere(r = bevel); + } + } else { + cube(dimensions, center = true); + } +} + module box_face(dimensions, bevel = 0) { x = dimensions[0]; y = dimensions[1]; @@ -48,6 +74,7 @@ module box(length, width, height, bevel = 0) { rotate([90, 0, 0]) rotate([0, 90, 0]) box_face([width, height, wall_thickness], bevel); + translate([length - wall_thickness + bevel, 0, bevel]) rotate([90, 0, 0]) rotate([0, 90, 0]) @@ -55,3 +82,11 @@ module box(length, width, height, bevel = 0) { } } +module box_side_slider(length, width, height) { + difference() { + box_face([width - wall_thickness * 2 + 4, height, wall_thickness], bevel); + translate([-1, -1, 1]) cube([4-threshold, height+2, 4-threshold]); + color("red") translate([width - wall_thickness * 2 + 1, -1, 1]) cube([4-threshold, height+2, 4-threshold]); + } +} + diff --git a/bike-lights/case/control_panel.scad b/bike-lights/case/control_panel.scad index de323bc..4c7b182 100644 --- a/bike-lights/case/control_panel.scad +++ b/bike-lights/case/control_panel.scad @@ -4,7 +4,7 @@ threshold = 0.1; board_length = 92; board_width = 72; board_height = 21.5; -wall_thickness = 2; +wall_thickness = 4; bevel = 0.5; hinge_radius = 2.5; @@ -13,16 +13,63 @@ case_width = board_width + wall_thickness * 2; case_length = board_length + wall_thickness * 2; case_height = board_height + wall_thickness; +handlebar_radius = 15; +clasp_thickness = 4; +circular_face_count = 48; +clasp_width = 35; + include <./common.scad>; +module top_clasp() { + difference() { + union() { + cylinder(h = clasp_width, r = handlebar_radius + clasp_thickness, center = true, $fn = circular_face_count); + translate([0, 0, -clasp_width / 2]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([0, 0, -clasp_width / 2 + 4]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([0, 0, clasp_width / 2]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([0, 0, clasp_width / 2 - 4]) cylinder(h = 1, r = handlebar_radius + clasp_thickness + 1, center = true, $fn = circular_face_count); + translate([-handlebar_radius-5, -10, -clasp_width / 2 + 6]) cube([6, 20, clasp_width - 12]); + } + translate([-0.5, 0, 0]) cylinder(h = clasp_width+2, r = handlebar_radius + 1, center = true, $fn = circular_face_count); + translate([-0.5, -handlebar_radius - 10, -clasp_width / 2 - 1]) cube([handlebar_radius + 10, handlebar_radius * 2 + 20, clasp_width + 2]); + } +} + module hinge(length) { difference() { union() { - cylinder(h = length, r = hinge_radius); - translate([0, -hinge_radius, 0]) - cube([hinge_radius, hinge_radius * 2, length]); + cube([hinge_radius * 2, length, hinge_radius], center = true); + translate([0, 0, -1.5]) rotate([90, 0, 0]) cylinder(h = length, r = hinge_radius, center = true); } - translate([0, 0, -threshold / 2]) cylinder(h = length + threshold, r = 1); + translate([0, threshold / 2, -1.5]) rotate([90, 0, 0]) cylinder(h = length + threshold * 2, r = 1, center = true); + } +} + +module base_case(length, width, height, bevel = 0) { + difference() { + union() { + channel(length + wall_thickness / 2, width, height, bevel); + + translate([-bevel, 0, bevel]) + rotate([90, 0, 0]) + rotate([0, 90, 0]) + box_face([width, height, wall_thickness], bevel); + + // These are the sleds at the bottom of the case that should hold the lower of the two boards down + color("blue") translate([0, wall_thickness - 2, wall_thickness + 4]) cube([length - 8, 4, wall_thickness / 2]); + color("blue") translate([wall_thickness - 2, wall_thickness - 4, wall_thickness + 4]) cube([4, width, wall_thickness / 2]); + color("blue") translate([length - 25, width - wall_thickness * 3 / 2, wall_thickness + 6]) cube([16, wall_thickness, wall_thickness / 2]); + } + + // This makes an indent at the bottom to accomodate solder joins + translate([wall_thickness + 2, wall_thickness + 2, wall_thickness / 2]) cube([length, width - wall_thickness * 2 - 4, wall_thickness / 2 + threshold]); + + // This creates a cutout that lets the power plug slide in better. + translate([wall_thickness, width - wall_thickness, wall_thickness]) cube([length, 2, 6]); + + // These two put in the slots that should allow the fourth wall to be slotted into place. + color("red") translate([length - 1, wall_thickness - 2, 4]) cube([2, 2, height]); + color("red") translate([length - 1, width - wall_thickness, 4]) cube([2, 2, height]); } } @@ -33,11 +80,16 @@ module main_case() { difference() { union() { - box(case_length, + base_case(case_length, case_width, case_height, bevel); + translate([-bevel, 0, bevel]) + rotate([90, 0, 0]) + rotate([0, 90, 0]) + box_face([case_width, case_height, wall_thickness], bevel); + translate([0, -hinge_radius - bevel + threshold, hinge_z_offset + bevel]) rotate([90, 0, 0]) rotate([0, 90, 0]) @@ -65,31 +117,94 @@ module main_case() { rotate([0, 180, 0]) linear_extrude(1) text("right", size = 3); + // translate([case_length / 2, case_width / 2, -20]) rotate([0, 90, 0]) top_clasp(); } - color("green", 1) translate([8.5 + wall_thickness, case_width - wall_thickness - threshold, wall_thickness]) - cube([60, wall_thickness * 2, 7]); + translate([case_length / 2, case_width / 2, -threshold]) hexagon(4.5, 6); + + # translate([8.5 + wall_thickness, case_width - wall_thickness - threshold, wall_thickness]) + # cube([60, wall_thickness * 2, 7]); + } +} + +module lamp() { + union() { + translate([0, 0, -0.5]) cube([12.9 + threshold, 8, 4], center = true); + translate([0, 0, .88]) cube([5 + threshold, 5 + threshold, 1.56], center = true); + /* + translate([0, 0, -1.56]) cube([12.9, 7.6, wall_thickness], center = true); + */ + } +} + +module button() { + union() { + cube([3.5 + threshold, 6.1 + threshold, 4 + threshold], center = true); + translate([0, 0, -0.5]) cube([1.2, 7, 3 + threshold], center = true); } } module lid() { lid_width = case_width + hinge_radius * 2 + wall_thickness; + hinge_length = case_length / 4; union() { difference() { - box_face([case_length, + rounded_cube([case_length, lid_width, wall_thickness], bevel); - translate([(case_length - 60) / 2, 14 + hinge_radius * 2, -threshold / 2]) - cube([60, 16, wall_thickness + threshold]); + translate([0, lid_width / 5, 0.4]) lamp(); + translate([-15, lid_width / 5, 0.4]) lamp(); + translate([15, lid_width / 5, 0.4]) lamp(); + translate([-30, lid_width / 5, 0]) button(); + translate([30, lid_width / 5, 0]) button(); + + translate([0, lid_width / 5, -2]) cube([20, 7, 3], center = true); + + color("black") translate([-2, lid_width / 5 - 5, -2]) rotate([0, 0, 90]) rotate([0, 90, 0]) cylinder(h=5, r = 1, center = true, $fn = circular_face_count); + color("black") translate([-17, lid_width / 5 - 5, -2]) rotate([0, 0, 90]) rotate([0, 90, 0]) cylinder(h=5, r = 1, center = true, $fn = circular_face_count); + color("black") translate([13, lid_width / 5 - 5, -2]) rotate([0, 0, 90]) rotate([0, 90, 0]) cylinder(h=5, r = 1, center = true, $fn = circular_face_count); + color("black") translate([-30, lid_width / 5 - 5, -2]) rotate([0, 0, 90]) rotate([0, 90, 0]) cylinder(h=5, r = 1, center = true, $fn = circular_face_count); + color("black") translate([30, lid_width / 5 - 5, -2]) rotate([0, 0, 90]) rotate([0, 90, 0]) cylinder(h=5, r = 1, center = true, $fn = circular_face_count); + color("black") translate([0, 10, -2]) rotate([0, 90, 0]) cylinder(h = 62, r = 1, center = true, $fn = circular_face_count); + + color("red") translate([-33, 21, -2]) rotate([0, 90, 0]) cylinder(h = 5, r = 1, center = true, $fn = circular_face_count); + color("red") translate([-35, 13, -2]) rotate([0, 0, 90]) rotate([0, 90, 0]) cylinder(h = 18, r = 1, center = true, $fn = circular_face_count); + color("red") translate([33, 21, -2]) rotate([0, 90, 0]) cylinder(h = 5, r = 1, center = true, $fn = circular_face_count); + color("red") translate([35, 13, -2]) rotate([0, 0, 90]) rotate([0, 90, 0]) cylinder(h = 18, r = 1, center = true, $fn = circular_face_count); + color("red") translate([0, 5, -2]) rotate([0, 90, 0]) cylinder(h = 70, r = 1, center = true, $fn = circular_face_count); } - translate([case_length / 4 + 1, hinge_radius - 0.4, -hinge_radius]) - rotate([180, 0, 0]) - rotate([0, 90, 0]) hinge(case_length / 2 - 2); + translate([case_length / 2 - hinge_length / 2, lid_width / 2 - wall_thickness / 2 - 0.5, -wall_thickness / 2]) rotate([0, 0, 90]) hinge(hinge_length); + translate([-case_length / 2 + hinge_length / 2, lid_width / 2 - wall_thickness / 2 - 0.5, -wall_thickness / 2]) rotate([0, 0, 90]) hinge(hinge_length); + + translate([0, -lid_width / 2 + bevel, -3]) rounded_cube([20, wall_thickness / 2, 10], bevel); + color("blue") translate([-9, -lid_width / 2 + 1.5, -6]) rotate([90, 0, 0]) rotate([0, 90, 0]) linear_extrude(18) circle(1, $fn = 3); + color("blue") translate([-9, -lid_width / 2 + 1.5, -7]) rotate([90, 0, 0]) rotate([0, 90, 0]) linear_extrude(18) circle(1, $fn = 3); + } +} + +module box_side() { + box_side_slider(case_length, case_width, case_height); +} + +module case_base() { + difference() { + rounded_cube([case_length, case_width, wall_thickness + 2], bevel = 0.5); + translate([wall_thickness, 0, 2]) rounded_cube([case_length + threshold, board_width + threshold, 2 + threshold]); + + // These give a screw-hole in the center which will allow the clamp to be attached + translate([0, 0, -1]) hexagon(4.5, 2); + translate([0, 0, -wall_thickness / 2]) cylinder(r = 2, h = wall_thickness + threshold, center = true); + + // and now a bit of an indentation to help the clip remain in place + translate([0, 0, -4.5]) cube([clasp_width + threshold, clasp_width + threshold, wall_thickness], center = true); + + // here are some grooves along the edges that can be used to piece parts together + translate([wall_thickness / 2, case_width / 2 - wall_thickness / 2, wall_thickness / 2]) + cube([board_length + wall_thickness, wall_thickness / 2, wall_thickness / 2 + threshold], center = true); + translate([wall_thickness / 2, -case_width / 2 + wall_thickness / 2, wall_thickness / 2]) + cube([board_length + wall_thickness, wall_thickness / 2, wall_thickness / 2 + threshold], center = true); } } -// main_case(); -// color("red", 1) translate([0, 0, case_height + wall_thickness / 2]) lid(); -// color("red", 1) translate([0, 0, 40]) lid(); diff --git a/bike-lights/case/control_panel_case.scad b/bike-lights/case/control_panel_case.scad index 9ba0bf7..6b496af 100644 --- a/bike-lights/case/control_panel_case.scad +++ b/bike-lights/case/control_panel_case.scad @@ -1,4 +1,11 @@ include <./control_panel.scad> -main_case(); +/* +difference() { + color("blue") rounded_cube([5, 5, 5], bevel = 0.5); + translate([0, 0, 1]) rounded_cube([4, 4, 4]); +}; +*/ + +case_base(); diff --git a/bike-lights/case/control_panel_lid.scad b/bike-lights/case/control_panel_lid.scad index 6824eca..f5b6756 100644 --- a/bike-lights/case/control_panel_lid.scad +++ b/bike-lights/case/control_panel_lid.scad @@ -2,4 +2,5 @@ include <./control_panel.scad> lid(); +// lamp(); diff --git a/bike-lights/case/control_panel_slider.scad b/bike-lights/case/control_panel_slider.scad new file mode 100644 index 0000000..77e6488 --- /dev/null +++ b/bike-lights/case/control_panel_slider.scad @@ -0,0 +1,4 @@ + +include <./control_panel.scad> + +box_side();