diff --git a/OpenBikeSensor3DPrintableCase-stl-v0.3.16.zip b/OpenBikeSensor3DPrintableCase-stl-v0.3.16.zip deleted file mode 100644 index 568797c..0000000 Binary files a/OpenBikeSensor3DPrintableCase-stl-v0.3.16.zip and /dev/null differ diff --git a/lib/utils.scad b/lib/utils.scad index fcbb500..7a6640a 100644 --- a/lib/utils.scad +++ b/lib/utils.scad @@ -144,4 +144,52 @@ module load_svg(filename) { else { import(filename); } -} \ No newline at end of file +} + + +/* +The code below is from keyv2 +https://github.com/rsheldiii/KeyV2 + +which is licensed under GPL + +We only need the round cherry key stem +*/ + + + +module rounded_cherry_stem(depth, slop, throw) { + difference() { + cylinder(d = $rounded_cherry_stem_d, h = depth); + + // inside cross + // translation purely for aesthetic purposes, to get rid of that awful lattice + inside_cherry_cross($stem_inner_slop); + } +} + +module inside_cherry_cross(slop) { + // inside cross + // translation purely for aesthetic purposes, to get rid of that awful lattice + translate([0, 0, -SMALLEST_POSSIBLE]) { + linear_extrude(height = $stem_throw) { + square(cherry_cross(slop, extra_vertical)[0], center = true); + square(cherry_cross(slop, extra_vertical)[1], center = true); + } + } + + // Guides to assist insertion and mitigate first layer squishing + if ($cherry_bevel) { + for (i = cherry_cross(slop, extra_vertical)) hull() { + linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center = true); + translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center = true); + } + } +} + +function cherry_cross(slop, extra_vertical = 0) = [ + // horizontal tine + [4.03 + slop, 1.25 + slop / 3], + // vertical tine + [1.15 + slop / 3, 4.23 + extra_vertical + slop / 3 + SMALLEST_POSSIBLE], + ]; diff --git a/src/LiteCase/HandlebarButton.scad b/src/LiteCase/HandlebarButton.scad new file mode 100644 index 0000000..d31b267 --- /dev/null +++ b/src/LiteCase/HandlebarButton.scad @@ -0,0 +1,135 @@ +include <../../variables.scad> +use <../../lib/Round-Anything/polyround.scad> + +use <../../lib/utils.scad> + + +$fn = 60; +z = [0, 0, 1]; +y = [0, 1, 0]; +x = [1, 0, 0]; +cz = 1.2; +h = 15; +cxy = 13.7; +size = [cxy, cxy, h]; +z1 = -h / 2; +sizeb = [cxy + 1, cxy, cz]; +z2 = -cz * 1.5; +sizet = [cxy + 2, cxy + 2, 4]; +sizef = [cxy + 5, cxy + 5, h]; +z4 = -sizef[2] / 2; +SMALLEST_POSSIBLE = 0.01; + +//if ($preview) import("/home/paulg/Downloads/kailh_low.stl"); +module hole() { + translate(z1 * z)cube(size, center = true); + translate(z2 * z)cube(sizeb, center = true); + translate(2 * z)cube(sizet, center = true); +} + +module handlebar() +{ + translate((50) / 2 * y - 18.5 * z)rotate([90, 0, 0])cylinder(d = 25.4, h = 50); +} + +module cable() { + hull() { + translate([4.5, 0, -5])rotate([90, 0, 0])cylinder(d = 4, h = 20); + translate([4.5, 0, -12])rotate([90, 0, 0])cylinder(d = 4, h = 20); + } +} + +module hookprofile() { + hull()for (i = [-1, 1])translate([0, i * 3])circle(d = 2.5); +} + +module support(zoffset) { + hull() { + translate([-1.25, 0, -0.2])linear_extrude(0.2)hookprofile(); + translate([2.5, 0, -0.2])linear_extrude(0.2)hookprofile(); + } + hull() { + translate([2.5, 0, -0.01])linear_extrude(0.01)hookprofile(); + translate([2.5, 0, -zoffset + 2.5])linear_extrude(0.2)hookprofile(); + translate([2.2, 0, -zoffset + 2.5])rotate([0, 90, 0])linear_extrude(0.6)hookprofile(); + } +} +module hookbase(zoffset) { + translate(-zoffset * z)rotate(-[90, 0, 0]) { + rotate_extrude(angle = 180) translate([2.5, 0]) hookprofile(); + hull() { + translate([2.2, 0, 0])rotate([90, 0, 90])linear_extrude(0.6)hookprofile(); + translate([2.5, 0, 0])rotate([90, 0, 00])linear_extrude(0.2)hookprofile(); + } + } + support(zoffset); + +} + + + +module button(detail = true) { + difference() { + union() { + translate(z4 * z)cube(sizef, center = true); + if (detail) { + translate(0.5 * [cxy + 5 + 2.5, 0, 0])hookbase(6); + mirror([1, 0, 0])translate(0.5 * [cxy + 5 + 2.5, 0, 0])hookbase(6); + } + } + + if (detail) { + hole(); + handlebar(); + cable(); + } + } + +} + +button(); + + + + +module buttoncutter(spacing = .5) { + translate(-(spacing + 3.5) * z)minkowski() { + cube(spacing, center = true); + union() {button(detail = false); + hull() { + linear_extrude(1)translate((-cxy / 2 - 1) * (x + y))square([cxy + 2, cxy + 2]); + translate(z * 2.5)linear_extrude(1)translate((-cxy / 2) * (x + y))square([cxy, cxy]); + } + } + } +} + +module roundedsquare(sizes, r = 2) { + points = [[0, 0, r], + [sizes[0], 0, r], + [sizes[0], sizes[1], r], + [0, sizes[1], r] + ]; + echo(points); + translate(0.5 * [-sizes[0], -sizes[1]])polygon(polyRound(points)); +} + + +module buttontop(wall = 3) { + translate(-6 * z)rounded_cherry_stem(6, 0.2, 4); + translate(-6 * z)rounded_cherry_stem(6, 0.2, 4); + difference() { + hull() { + translate(-z)linear_extrude(1)roundedsquare([cxy + 3, cxy + 3]); + translate(-5 * z)linear_extrude(1)translate((-(cxy + 5 + wall) / 2) * (x + y))square([cxy + 5 + wall, cxy + + 5 + wall]); + translate(-11 * z)linear_extrude(1)translate((-(cxy + 5 + wall) / 2) * (x + y))square([cxy + 5 + wall, cxy + + 5 + wall]); + + } + translate(-z)buttoncutter(); + translate(-4*z)cable(); + } +} + +translate(-30 * y)buttontop(); \ No newline at end of file diff --git a/src/LiteCase/LiteCase.scad b/src/LiteCase/LiteCase.scad new file mode 100644 index 0000000..8c7e8c0 --- /dev/null +++ b/src/LiteCase/LiteCase.scad @@ -0,0 +1,225 @@ +use <../../lib/Round-Anything/polyround.scad> + +use <../Mounting/StandardMountAdapter.scad> + + +corner_x = 24; +boardcorner_x = 17; +boardcorner_y = 23; +square_x = 5; +lite_l = 45; +lite_w = 80 - 18; + + +// 0,0,0: Mitte des Lite-PCB, auf der Seite mit dem OpenBIkeSensor logo, x: Richtung USB-Port, Z: Richtung Ultraschallsensoren +$fn = 20; + +Lite_PCB_x = 44; +Lite_PCB_y = 29.2; +Lite_PCB_z = 1.7; +Lite_PCB_Dimensions = [Lite_PCB_x, Lite_PCB_y, Lite_PCB_z]; + +Lite_ESP_socket_x = 38; +Lite_ESP_socket_y = 2.54; +Lite_ESP_socket_z = 9 + Lite_PCB_z + 1.8; +Lite_ESP_socket_dimensions = [Lite_ESP_socket_x, Lite_ESP_socket_y, Lite_ESP_socket_z]; + +Lite_transducer_position = [23.8, 0, 20.6]; +Lite_transducer_variance = 1.2; +Lite_transducer_diameter = 16 + Lite_transducer_variance; +Lite_transducer_diameter_small = 12.5 + Lite_transducer_variance; + +Lite_ESP_position_x = 0; +Lite_ESP_position_y = 0; +Lite_ESP_position_z = - 16.2; + +Lite_ESP_dimensions = [53, 29, 4.8]; + +Lite_USB_position_x = 55; +Lite_USB_position_y = 0; +Lite_USB_position_z = - 14.5; + +Lite_screwmount_top = 4; +Lite_screwmount_bottom = 6; +Lite_screwmount_height = Lite_screwmount_top + Lite_screwmount_bottom; + +Lite_USB = [Lite_USB_position_x, Lite_USB_position_y, Lite_USB_position_z]; + +Lite_ESP_position = [Lite_ESP_position_x, Lite_ESP_position_y, Lite_ESP_position_z]; + +sensor_x = - Lite_transducer_position[2] + .5; +sensor_y = Lite_transducer_position[0]; + +function angle_three_points_2d(pa, pb, pc) = asin(cross(pb - pa, pb - pc) / (norm(pb - pa) * norm(pb - pc))); + +module rounded_cube(x, y, z, r, r2, center = true) { + t = center ? - [x / 2, y / 2, z / 2]: [0, 0, 0]; + translate(t)polyRoundExtrude([[0, 0, max(r, r2)], [0, y, max(r, r2)], [x, y, max(r, r2)], [x, 0, max(r, r2)]], z, r, r2); +} + +module SidePolygon() { + corners = [ + [square_x, - lite_w / 2, 9], + // chose radius so the corners match + [- corner_x, - 0, (corner_x - boardcorner_x) / (1 / sin(angle_three_points_2d([0, 0], [- corner_x, - 0], [square_x, lite_w / 2])) - 1)], + [square_x, lite_w / 2, 9], + [lite_l, lite_w / 2, 5], + [lite_l, - lite_w / 2, 5] + ]; + translate([sensor_x, sensor_y])polygon(polyRound(corners, fn = 150)); +} + +module MidPolygon() { + corners = [[square_x, - lite_w / 2, 5], [- boardcorner_x, - boardcorner_y, 5], [- boardcorner_x, boardcorner_y, 5], [square_x, lite_w / 2, 5], [lite_l, lite_w / 2, 5], [lite_l, - + lite_w / 2, 5]]; + translate([sensor_x, sensor_y]) polygon(polyRound(corners)); +} + +module LidCutter() { + translate([40, 0, Lite_ESP_position_z + 0.8])cube([120, 90, 0.1], center = true); +} + +module Box() { + hull() { + for (i = [- 1, 1]) { + translate([0, 0, i * 9 - (i + 1) / 2])linear_extrude(1)MidPolygon(); + translate([0, 0, i * 18 - (i + 1) / 2])linear_extrude(1)SidePolygon(); + } + } +} + +module ESP() { + difference() { + color("black")translate([24.6, 0, 0.2])cube(Lite_ESP_dimensions, center = true); + for (i = [- 1, 1])for (j = [- 1, 1]) { + translate([i * 24.6 + 22.6, j * 12.5 - 2.5, - 4.7])cube([4, 5, 5]); + } + } +} + +module Ultrasonic(i, onlyboards = false, h = 30) { + translate([0, 0, - h / 2 + 34 / 2]) { + color("blue") translate([23.9, i * 7.3, 17.99])cube([42.5, 1.4, h], center = true); + hull() { + translate([Lite_transducer_position[0], 0, 14.99])cube([42.5, 21.5, h], center = true); + translate([Lite_transducer_position[0], 0, 16.99])cube([42.5, 16.5, h], center = true); + translate([Lite_transducer_position[0], 0, 10.99])cube([49.5, 18.5, h], center = true); + } + intersection() { + translate([0, 0, + h / 2 - 34 / 2])hull() { + translate(Lite_transducer_position - [0, 8 * i, 100])rotate([i * 90, 0, 0])cylinder(d1 = Lite_transducer_diameter + 12, d2 = Lite_transducer_diameter, h = 8.5); + translate(Lite_transducer_position - [0, 8 * i, 0])rotate([i * 90, 0, 0])cylinder(d1 = Lite_transducer_diameter + 12, d2 = Lite_transducer_diameter, h = 8.5); + } + color("blue") translate([23.9, i * 7, 17.99])cube([41.5, 60, h + 14], center = true); + + } + } + translate(Lite_transducer_position - [0, 8 * i, 0])rotate([i * 90, 0, 0])cylinder(d = Lite_transducer_diameter_small, h = 40); +} + +module USB_hole() { + translate(Lite_USB) { + translate([0, 0, - 2.25]) + rounded_cube(45, 12.5, 8, 0, 0, center = true); + rounded_cube(45, 5, 12.5, 2.5, 0, center = true); + } +} + +module Screwbump(size = 6, hole_diameter = 3.8, height = 6, bottom = true, toppart = 2.1, insert = 4) { + outer_polygon = [[size, 0, 0], [- size, 0, 0], [- size, size, size], [0, 3 * size, size], [size, size, size]]; + difference() { + hull() { + translate([0, 0, 0])polyRoundExtrude(outer_polygon, 1, 0, 0); + + translate([0, 0, height - 1])polyRoundExtrude(outer_polygon, 1, 0, 0); + if (bottom)translate([0, - 0.01, 1.3 * height])rotate([90, 0, 0])cylinder(d = size, h = 0.1); + } + translate([0, size, toppart])cylinder(d = insert, h = height - toppart); + translate([0, size, - .01])cylinder(d = hole_diameter, h = toppart); + } +} + + +module LiteElectronics(onlyboards = false) { + // the rendered model from stls (not closed, only for preview) + //if (!$preview) translate([15, 0, 0])rotate([180, 00, 00])rotate([0, 0, 90])import("../../lib/OpenBikeSensor-Lite-PCB-0.1.2.stl"); + + // board cube + color("green")translate(- [0, Lite_PCB_y / 2, Lite_PCB_z])cube(Lite_PCB_Dimensions, center = false); + color("green")translate(- [0.2, Lite_PCB_y / 2 + 0.2, Lite_PCB_z + 14])cube(Lite_PCB_Dimensions + [0.4, 0.4, 14], center = false); + + + // sockets for ESP + for (i = [- 1, 1]) color("darkgrey")translate([3.5, i * Lite_PCB_y / 2 - (i + 1) * Lite_ESP_socket_y / 2 - i * 0.45, - Lite_ESP_socket_dimensions[2] + 1.8]) + cube(Lite_ESP_socket_dimensions); + + translate(Lite_ESP_position)ESP(); + + // printability chamfers above ESP + hull() { + translate([24.6, 0, Lite_ESP_position_z - 2])cube([45, 29, 1], center = true); + translate([24.6, 0, Lite_ESP_position_z - 4.3])cube([45, 18.5, 5.01], center = true); + } + translate([0, 0, 0])hull() { + translate([24.6, 0, Lite_ESP_position_z - 2])cube([Lite_ESP_dimensions[0], 20, 0.5], center = true); + translate([25., 0, Lite_ESP_position_z - 4.3])cube([45, 18.5, 0.1], center = true); + } + for (i = [- 1, 1])Ultrasonic(i, onlyboards = onlyboards, h = 50); + USB_hole(); +} + + +module lite_case() { + difference() { + union() { + translate([-7, 0, Lite_ESP_position_z + 0.8 + 0.05 - Lite_screwmount_top])rotate([0, 0, 90]) + Screwbump(size = 4, hole_diameter = 3.2, height = Lite_screwmount_height, bottom = true, toppart = + Lite_screwmount_top); + translate([lite_w - 7.3, 12, Lite_ESP_position_z + 0.8 + 0.05 - Lite_screwmount_top])rotate([0, 0, -90]) + Screwbump(size = 4, hole_diameter = 3.2, height = Lite_screwmount_height, bottom = true, toppart = + Lite_screwmount_top); + translate([lite_w - 7.3, -12, Lite_ESP_position_z + 0.8 + 0.05 - Lite_screwmount_top])rotate([0, 0, -90]) + Screwbump(size = 4, hole_diameter = 3.2, height = Lite_screwmount_height, bottom = true, toppart = + Lite_screwmount_top); + translate([23.8, -3.5, -17.9])rotate([180, 0, 90])StandardMountAdapter(screwholes = false, channels = false, + twoholes = false); + difference() { + union() { + rotate([90, 90, 0])Box(); + difference() { + translate(Lite_USB + [0, 0, -3.5 - 1.6 + 1]) { + rounded_cube(28, 16.5, 6.5, 0, 1.5, center = true); + + difference() { + #rounded_cube(30, 15, 6.5, 0, 1.5, center = true); + translate([8, -20, -5])cube([4, 60, 20]); + } + } + translate(Lite_USB + [10, 0, 0])cube([4, 20, 12.5], center = true); + } + } + hull() translate([23.8, -3.5, -18])rotate([180, 0, 90])StandardMountAdapter(screwholes = false, channels = + false); + + } + } + LiteElectronics(); + LidCutter(); + } + +} + +// split into conveniently printable parts and orient for printing. +rotate([0,180,0])translate([-30,0,-Lite_ESP_position_z-0.8])difference() { + lite_case(); + + translate([40, 0, Lite_ESP_position_z + 0.8+49.95])cube([120, 90, 100], center = true); +} + +rotate([0,180,0])translate([-30,40,Lite_ESP_position_z-lite_l/2+1.6])intersection() { + lite_case(); + + translate([40, 0, Lite_ESP_position_z + 0.8+49.95])cube([120, 90, 100], center = true); +} + +if ($preview) translate([80, 0, 0])LiteElectronics(); \ No newline at end of file diff --git a/src/LiteCase/LiteSensorSpacer.scad b/src/LiteCase/LiteSensorSpacer.scad new file mode 100644 index 0000000..b08bfd4 --- /dev/null +++ b/src/LiteCase/LiteSensorSpacer.scad @@ -0,0 +1,10 @@ +difference(){ + union() { + cube([4, 20, 8.7]); + translate([11+5,0,0])cube([4, 20, 8.7]); + translate([0,1.8+(16-1-1.4)/2,2.2])cube([18,2,5]); + } + #translate([-1,1.8,6.7])cube([40,1.4,10]); + #translate([-1,2+16-1.2,6.7])cube([40,1.4,10]); + #translate([0,1.8+(16-1-1.4)/2-2,-3])cube([22,6,5]); +} diff --git a/src/Mounting/StandardMountAdapter.scad b/src/Mounting/StandardMountAdapter.scad index 8fd89a2..5dff7bd 100644 --- a/src/Mounting/StandardMountAdapter.scad +++ b/src/Mounting/StandardMountAdapter.scad @@ -30,7 +30,7 @@ module StandardMountAdapterScrewHoles(head_depth=6, depth=100) { children(); } -module StandardMountAdapterBody() { +module StandardMountAdapterBody(twoholes=true) { module _half_base_shape(width=StandardMountAdapter_width) { union () { // base @@ -52,12 +52,12 @@ module StandardMountAdapterBody() { } } - module _body_half() { + module _body_half(hole=true) { difference() { _half_base_shape(); // locking pin hole - translate([0, StandardMountAdapter_length/2, StandardMountAdapter_thickness]) + if (hole) translate([0, StandardMountAdapter_length/2, StandardMountAdapter_thickness]) rotate([-90, 0, 0]) LockingPinHole(); } @@ -65,18 +65,18 @@ module StandardMountAdapterBody() { union () { - _body_half(); + _body_half(hole=twoholes); rotate([0, 0, 180]) _body_half(); } } -module StandardMountAdapter(channels=true) { +module StandardMountAdapter(channels=true, screwholes=true, twoholes=true) { difference() { - StandardMountAdapterBody(); + StandardMountAdapterBody(twoholes=twoholes); - translate([0, 0, StandardMountAdapter_thickness]) + if(screwholes)translate([0, 0, StandardMountAdapter_thickness]) StandardMountAdapterScrewHoles() ScrewHoleM3(depth=100, head_depth= StandardMountAdapter_thickness - (8 - m3_hex_nut_thickness)/2 ); diff --git a/variables.scad b/variables.scad index 65abd05..834279e 100644 --- a/variables.scad +++ b/variables.scad @@ -301,3 +301,14 @@ logo_generate_templates = false; // set to true to generate 2D template SVGs logo_name = "OpenBikeSensor"; // name of a folder inside `logo/` logo_mode = "normal"; // "normal" or "inverted" logo_part = "main"; // "main" or "highlight" + + +// Lite case + +// Lite handlebar button +SMALLEST_POSSIBLE = .01; +$stem_throw = 4; +$cherry_bevel = true; +$stem_inner_slop = 0.2; +$rounded_cherry_stem_d = 5.5; +extra_vertical = 0.2; \ No newline at end of file