+// 18650 is ~18mm diameter, ~65mm length,
+batt_diam = 18 + 0.3;
+batt_len = 65+1;
+batt_clip_h = 0.75 * batt_diam;
+wall = 2.2;
+base_h = 4;
+cable_sep = 2.5;
+
+eps = 0.01;
+infty = 300;
+
+pcb_len = 36;
+pcb_thick = 1.3;
+pcb_groove = 2;
+pcb_width = 11;
+
+wire_thick = 2;
+wire_sep = 3;
+cable_out_diam = 4;
+
+side_protrusion_len = 10;
+side_protrusion_diam = 2;
+
+base_batt_extend = wall+pcb_thick; // extend the base on the battery side
+
+cover_sep = 0.2;
+
+uswitch_diam = 2.5;
+led_diam = 3.2;
+s2_xoff = -160 * 25.4/1000;
+led_xoff = 90 * 25.4/1000;
+s1_xoff = 340 * 25.4/1000;
+
+pcb_clip_w = 7;
+pcb_clip_off = led_xoff + pcb_clip_w/2;
+
+module base() {
+ translate([0, 0, base_h/2]) {
+ hull() {
+ cube([batt_len + 2*wall + 2*cable_sep, batt_diam + 2*wall, base_h], center=true);
+ // under the PCB
+ translate([0, -batt_diam/2-wall-pcb_thick/2-wall/2, 0])
+ cube([pcb_len + 2*wall, pcb_thick + wall + eps, base_h], center=true);
+ // battery-side extension
+ translate([0, batt_diam/2 + wall + base_batt_extend, -base_h/4+side_protrusion_diam/4])
+ cube([batt_len + 2*wall, eps, base_h/2+side_protrusion_diam/2], center=true);
+ };
+ };
+}
+module base_protrusions() {
+ // pcb-side side protrusion
+ translate([-side_protrusion_len/2, -batt_diam/2-2*wall-pcb_thick, base_h/2])
+ rotate([0, 90, 0])
+ cylinder(r = side_protrusion_diam/2, h = side_protrusion_len, $fn = 6);
+
+ // battery-side side protrusion
+ translate([-side_protrusion_len/2, batt_diam/2+wall+base_batt_extend, base_h/2])
+ rotate([0, 90, 0])
+ cylinder(r = side_protrusion_diam/2, h = side_protrusion_len, $fn = 6);
+};
+
+module pcb_clips() {
+ // rear part of the PCB holder (behind S1)
+ translate([pcb_clip_off, -batt_diam/2-wall-pcb_thick+eps, 0])
+ cube([pcb_clip_w, pcb_thick+wall, pcb_width + wall + base_h - pcb_groove]);
+ // side part of the PCB holder (near the battery wires)
+ translate([-pcb_len/2-wall, -batt_diam/2-pcb_thick-2*wall, 0])
+ cube([pcb_groove+wall, pcb_thick+2*wall+eps, pcb_width + wall + base_h - pcb_groove]);
+};
+
+module batt_clips() {
+ difference() {
+ union() {
+ // rear part of the battery clip
+ translate([-(batt_len/2-pcb_len/2+pcb_groove+wall)/2-pcb_len/2+pcb_groove, 0, batt_clip_h/2+wall/2])
+ cube([batt_len/2-pcb_len/2+pcb_groove + wall, batt_diam + 2*wall, batt_clip_h + wall], center=true);
+ // front (+) part of the battery clip
+ translate([batt_len/2+wall/2, 0, batt_clip_h/2+wall/2])
+ hull() {
+ cube([wall, batt_diam + 2*wall, batt_clip_h + wall], center=true);
+ translate([-10/2, 0, -batt_clip_h/2])
+ cube([10, batt_diam+2*wall, wall], center=true);
+ };
+ // middle clips
+ translate([pcb_clip_off+pcb_clip_w/2, 0, batt_clip_h/2+wall/2])
+ hull() {
+ cube([pcb_clip_w, batt_diam + 2*wall, batt_clip_h + wall], center=true);
+ translate([0, 0, -batt_clip_h/2])
+ cube([2*pcb_clip_w, batt_diam+2*wall, wall], center=true);
+ };
+ }
+ // top part rounded
+ difference() {
+ translate([0, 0, infty/4 + wall + batt_diam/2])
+ cube([infty/2, infty/2, infty/2], center=true);
+ translate([-infty/2, 0, batt_diam/2+wall])
+ rotate([0, 90, 0])
+ cylinder(r=batt_diam/2+wall, h = infty);
+ };
+ };
+};
+
+module battery() {
+ // battery
+ translate([-batt_len/2, 0, batt_diam/2+wall])
+ rotate([0, 90, 0])
+ cylinder(r=batt_diam/2, h = batt_len);
+};
+
+module main() {
+ difference() {
+ union() {
+ base();
+ base_protrusions();
+ pcb_clips();
+ batt_clips();
+ };
+ // the PCB itself
+ translate([0, -batt_diam/2-wall-pcb_thick/2, base_h - pcb_groove + pcb_width/2])
+ cube([pcb_len, pcb_thick, pcb_width], center=true);
+ // battery
+ battery();
+ // 4 wire holes at the battery ends
+ for (j=[-wire_sep/2, wire_sep/2])
+ for (i=[-wire_sep/2, wire_sep/2])
+ translate([-infty/2, i, batt_diam/2 + wall+j])
+ rotate([0, 90, 0])
+ rotate([0, 0, 90])
+ cylinder(r=wire_thick/2, h = infty, $fn=6);
+
+ // holes for wire from battery to the PCB
+ translate([-infty/2, -batt_diam/2, wall + pcb_groove + wire_thick/2])
+ rotate([0, 90, 0])
+ rotate([0, 0, 90])
+ cylinder(r=wire_thick/2, h = infty, $fn=6);
+ // hole for the cable outlet
+ translate([-pcb_len/2+pcb_groove+cable_out_diam/2, -batt_diam/2-pcb_thick-2*wall, -infty/2])
+ cylinder(r=cable_out_diam/2, h = infty, $fn=6);
+ // holes for binding to the shoe
+ for (x = [
+ pcb_len/2 + wall + wire_thick/2 + wire_sep,
+ pcb_len/2 + wall + wire_thick/2,
+ -pcb_len/2 - wall - wire_thick/2 - wire_sep,,
+ -pcb_len/2 - wall - wire_thick/2 ]) {
+ for (y = [-1,1]) {
+ translate([x, y*(batt_diam/2 + wall + wire_thick/2), -infty/2])
+ cylinder(r=wire_thick/2, h=infty, $fn=6);
+ };
+ };
+ };
+};
+
+module cover_internal() {
+ hull() {
+ base();
+ // battery + wall + cable space
+ translate([-batt_len/2-wall, 0, batt_diam/2+wall])
+ rotate([0, 90, 0])
+ cylinder(r=batt_diam/2+wall, h = batt_len + 2*wall);
+ // space for PCB
+ translate([-pcb_len/2-wall, -batt_diam/2-2*wall-pcb_thick, base_h-pcb_groove])
+ cube([pcb_len+2*wall, wall+pcb_thick, pcb_width+wall]);
+ };
+};
+
+module cover_hole() {
+ difference() {
+ cover_internal();
+ translate([-infty/2, -infty/2, wall + batt_clip_h])
+ cube(infty);
+ };
+ base_protrusions();
+ // battery();
+ translate([-batt_len/2-cable_sep, 0, batt_diam/2+wall])
+ rotate([0, 90, 0])
+ cylinder(r=batt_diam/2, h = batt_len + 2*cable_sep);
+};
+
+module cover() {
+ difference() {
+ minkowski() {
+ cover_internal();
+ sphere(wall+cover_sep, $fn=16);
+ }
+ minkowski() {
+ cover_hole();
+ sphere(cover_sep, $fn=8);
+ };
+ // s2 hole
+ translate([s2_xoff, 0, base_h-pcb_groove + pcb_width/2])
+ rotate([90, 0, 0])
+ cylinder(r=uswitch_diam/2, h = infty, $fn=6);
+ // LED hole
+ translate([led_xoff, 0, base_h-pcb_groove + pcb_width/2])
+ rotate([90, 0, 0])
+ cylinder(r=led_diam/2, h = infty, $fn=6);
+ // s1 hole
+ translate([s1_xoff, 0, base_h-pcb_groove + pcb_width/2])
+ rotate([90, 0, 0])
+ cylinder(r=uswitch_diam/2, h = infty, $fn=6);
+ // xy plane
+ translate([0, 0, -infty/2]) cube(infty, center=true);
+ }
+};
+
+translate([0, -19, 0])
+ main($fn=128);
+
+// translate([0, -40, 0])
+// cover_hole();
+
+// cover($fn=128);
+// translate([0, 17, batt_diam + 3*wall + cover_sep])
+// rotate([180, 0, 0])
+// cover($fn=128);
+
+translate([0, 19, 0])
+ cover($fn=128);