openscad battery holder
use the openscad
/ [Main Settings] /
show_rails = true;
show_rail_front = true;
show_rail_back = true;
show_top_block = true;
show_bottom_block = true;
lay_flat_for_print = false;
/ [Global Tolerance Control] /
// Increase this by 0.05 if parts are impossible to press together
overall_tolerance = 0.15;
/ [Battery & Gap] /
battery_gap = 65.0;
// Tightened cell diameter (standard is 18.6, 18.8 allows for wrap)
cell_d = 18.7;
cell_spacing = 20.2;
/ [Rail Settings] /
rail_overlap = 5.0;
// Tight fit for the dovetail rails
rail_clearance = 0.15;
rail_A_rotation = 180;
rail_B_rotation = 0;
/ [Hardware: Press-Fit M3] /
total_h = 12.0;
wall = 3.0;
corner_radius = 2.0;
// Tight M3 bolt hole
m3_bolt_d = 3.2;
// Snug fit for M3 Nut (Standard is 5.5mm flat-to-flat)
m3_nut_d = 5.8;
m3_nut_h = 2.4;
/ [Hidden] /
strip_w = 10.5;
strip_t = 1.5;
body_x = cell_spacing + cell_d + (wall 2);
body_y = cell_d + (wall 2);
t_depth = 2.2;
rail_len = battery_gap + (rail_overlap * 2);
// --- MAIN EXECUTION ---
if (show_top_block) {
translate(lay_flat_for_print ? [0, body_y*1.5, total_h/2] : [0, 0, battery_gap/2 + total_h/2])
battery_block();
}
if (show_bottom_block) {
translate(lay_flat_for_print ? [0, -body_y*1.5, total_h/2] : [0, 0, -(battery_gap/2 + total_h/2)])
mirror([0, 0, 1]) battery_block();
}
if (show_rails) {
if (lay_flat_for_print) {
if (show_rail_front)
translate([body_x0.8, 0, t_depth]) rotate([0, -90, 0]) rail(rail_len);
if (show_rail_back)
translate([body_x1.2, 0, t_depth]) rotate([0, -90, 0]) rail(rail_len);
} else {
if (show_rail_front) {
translate([0, body_y/2, 0])
rotate([0, 0, rail_A_rotation])
rail(rail_len);
}
if (show_rail_back) {
translate([0, -body_y/2, 0])
rotate([0, 0, rail_B_rotation])
rail(rail_len);
}
}
}
// --- MODULES ---
module battery_block() {
puzzle_offset = 14.0;
difference() {
union() {
linear_extrude(height=total_h, center=true)
offset(r=corner_radius, $fn=32)
square([body_x - corner_radius2, body_y - corner_radius2], center=true);
// Male side tabs translate([body_x/2, 0, 0]) rotate([0,0,90]) micro_trap(female=false); translate([puzzle_offset, body_y/2, 0]) rotate([0, 0, 180]) micro_trap(female=false); translate([-puzzle_offset, -body_y/2, 0]) rotate([0, 0, 0]) micro_trap(female=false); } channel_z = total_h/2 - 4.0; translate([0, 0, channel_z]) { cube([body_x + 40, strip_w, strip_t], center=true); for(i = [-1, 1]) translate([i * cell_spacing/2, 0, 0]) cube([strip_w, body_y + 40, strip_t], center=true); } // Female slots (tight fit) translate([-body_x/2, 0, 0]) rotate([0,0,90]) micro_trap(female=true); translate([-puzzle_offset, body_y/2, 0]) micro_trap(female=true); translate([puzzle_offset, -body_y/2, 0]) rotate([0,0,180]) micro_trap(female=true); translate([0, body_y/2, 0]) micro_trap(female=true); translate([0, -body_y/2, 0]) rotate([0,0,180]) micro_trap(female=true); for(i = [-1, 1]) { translate([i * cell_spacing/2, 0, 0]) { // Cell pocket translate([0, 0, -total_h/2 - 0.1]) cylinder(d=cell_d, h=total_h - 4.5, $fn=80); // Bolt hole cylinder(d=m3_bolt_d, h=total_h + 10, center=true, $fn=32); // Press-fit Nut Trap translate([0, 0, channel_z + strip_t/2 + m3_nut_h/2 - 0.1]) rotate([0, 0, 30]) cylinder(d=m3_nut_d / cos(30), h=m3_nut_h, center=true, $fn=6); } }}}
module rail(len) {
linear_extrude(height=len, center=true)
micro_trap_profile(female=false);
}
module micro_trap_profile(female=false) {
// Uses combined tolerances for a friction fit
clr = (female) ? (rail_clearance + overall_tolerance) : 0;
base_w = 6.5 + (clr2);
top_w = 4.5 + (clr2);
polygon([[-top_w/2, 0], [top_w/2, 0], [base_w/2, -t_depth], [-base_w/2, -t_depth]]);
}
module micro_trap(female=false, h=total_h) {
linear_extrude(height=h, center=true)
micro_trap_profile(female=female);
}