From f77a87db7276c503d21300730f1bd232bdf19d5a Mon Sep 17 00:00:00 2001 From: ingo Date: Tue, 7 Apr 2026 11:34:42 +0200 Subject: [PATCH] First checkin --- README.md | 27 ++++++- batteries.code-workspace | 8 ++ batteries.scad | 165 +++++++++++++++++++++++++++++++++++++++ images/batteries.png | Bin 0 -> 8536 bytes 4 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 batteries.code-workspace create mode 100644 batteries.scad create mode 100644 images/batteries.png diff --git a/README.md b/README.md index b6f14e2..0f60704 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,28 @@ # batteries -Customizable battery storage \ No newline at end of file +Customizable battery holders for different sizes connectable to each other. + +Instead of holes or cubes for each battery, there is a width of the +battery holder and a long cutout centered on the width. The cutout size +is choosen by the maximum number of batteries of the selected type which +fit into the cutout (battery diameter + a small offset) +Each holder holds one type of battery in at least one line. +The battery holders may have two holes on one side and two connectors +on the other side to connect the different holders. The position of the +box is important for the connectors to be appied. + +standalone +: no connectors are applied + +top +: only the connectors are appied at the bottom of the box + +center +: holes are appied at the top and connectors are applied at the bottom of the box + +bottom +: wholes are applied at the top of the box + +A single row looks like this: + +![image of a single row](/images/batteries.png) \ No newline at end of file diff --git a/batteries.code-workspace b/batteries.code-workspace new file mode 100644 index 0000000..876a149 --- /dev/null +++ b/batteries.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/batteries.scad b/batteries.scad new file mode 100644 index 0000000..3ce272d --- /dev/null +++ b/batteries.scad @@ -0,0 +1,165 @@ +// ------------------------------------------------------------------------ +// Customizable battery holder. +// Instead of holes or cubes for each battery, there is a width of the +// battery holder and a long cutout centered on the width. The cutout size +// is choosen by the maximum number of batteries of the selected type which +// fit into the cutout (battery diameter + a small offset) +// Each holder holds one type of battery in at least one line. +// The battery holders may have two holes on one side and two connectors +// on the other side to connect the different holders. The position of the +// box is important for the connectors to be appied. +// standalone : no connectors are applied +// top : only the connectors are appied at the bottom of the box +// center : holes are appied at the top and connectors are applied +// at the bottom of the box +// bottom : wholes are applied at the top of the box +// ______________________________ +// | 0 0 | +// | -------------------------- | +// | | | | +// | -------------------------- | +// |______________________________| +// 0 0 +// +// If all the boxes have the same width, they can be connected, no matter +// how big the batteries are. +// ------------------------------------------------------------------------ + +//--------------------------- configurator -------------------------------- +/* [Battery type] */ +// The type of the batteries +Battery_type = "None"; // [None, Mono, Block, CR123A, AA, AAA] +/* [Box options] */ +// The width of the box +Width = 110; +// The number of rows of the box +Rows = 2; // [1:10] +// The height of the box +Height = 30; +// Position of the box +Position = "standalone"; // [standalone, top, center, bottom] + +/* [Hidden] */ +$fn=52; + +// ********************** +// ** Static Settings: ** +// ********************** + +// You may redefine the local settings depending on your 3D printer + +// Attributes of the batteries: +// A description, the width or diameter, the length or diameter and the height +// The atttributes are selected by the Battery_type of the configurator. +// Remark: The battery height is currently not used. +battery = object([ + ["None", ["no output", 0.0, 0.0, 0.0]], + ["Mono", ["Mono cell", 25.3, 25.3, 49.6]], + ["Block", ["9V Block", 16.7, 25.7, 47.2]], + ["CR123A", ["CR123A cell", 16.6, 16.6, 34.2]], + ["AA", ["AA cell", 14.5, 14.5, 50.7]], + ["AAA", ["AAA cell", 10.4, 10.4, 44.5]] + ]); + +// Some other often used settings +BASE_THICKNESS = 2.0; +WALL_THICKNESS = 3; +INNER_WALL = 1; +PIN_SIZE = 1.5; +HOLE_SIZE = PIN_SIZE + 0.3; +PIN_HEIGHT = Height * 0.9; + +// ********************* +// ** Helper Modules: ** +// ********************* + +// ------------------------------------------------------------------------ +// Connector to connect the battery holders wit each other. +// ------------------------------------------------------------------------ +module connector (height, pinwidth, center = false, rotate = true) { + d = pinwidth * 1.5; + len = pinwidth + d / 2; + offset = (d - len) / 2; + + target = center ? + [-offset, 0, 0] : // centered around the cylinder with pin! + [d / 2, -d / 2, height / 2]; // cylinder tangents on the x and y axis + + translate(target) { + rotate([0, 0, rotate ? 90 : 0]) { + translate ([pinwidth / 2, 0, 0]) + cube ([pinwidth, pinwidth, height], center=true); + cylinder(h = height, d = d, center=true); + } + } +} + +// ------------------------------------------------------------------------ +// calculate the length of the box for the number of rows +// ------------------------------------------------------------------------ +function boxlen(battery_len, rows) = battery_len * rows + INNER_WALL * (rows - 1) + 2 * WALL_THICKNESS; + +// ------------------------------------------------------------------------ +// draw a battery box without the pins +// ------------------------------------------------------------------------ +module batterybox(width, rows, height, type) { + len = boxlen(type[2], rows); + inner_cnt = floor(width / (type[1] + 0.2)); + inner_width = inner_cnt * (type[1] + 0.2); + inner_x = (width - inner_width) / 2; + + difference() { + cube([width, len, height]); + translate([inner_x, WALL_THICKNESS, BASE_THICKNESS]) + cube([inner_width, type[2] * rows + INNER_WALL * (rows - 1), height]); + } + for (y = [WALL_THICKNESS + type[2] : INNER_WALL + type[2] : len - 2 * WALL_THICKNESS]) { + translate([0, y, 0]) + cube([width, INNER_WALL, height]); + } +} + +// ------------------------------------------------------------------------ +// position the pins at the bottom or top of the box +// ------------------------------------------------------------------------ +module locate_pins(type, rows, height, width, size, pos, pin_dist = 5) { + translate ([0, (pos == "bottom" ? boxlen(type[2], rows) : 0), 0]) { + translate ([pin_dist, 0, 0]) + connector(height = height, pinwidth = size); + translate ([width - pin_dist * 1.5 , 0, 0]) + connector(height = height, pinwidth = size); + } +} +// ------------------------------------------------------------------------ +// bring the modules together and set the configurator values ... +// ------------------------------------------------------------------------ +module main() { + if (Battery_type != "None") { + battery_type = battery[Battery_type]; + difference() { + batterybox(width = Width, + rows = Rows, + height = Height, + type = battery_type); + if (Position == "bottom" || Position == "center") + locate_pins(type = battery_type, + rows = Rows, + width = Width, + height = PIN_HEIGHT, + size = HOLE_SIZE, + pos = "bottom"); + } + if (Position == "top" || Position == "center") + locate_pins(type = battery_type, + rows = Rows, + width = Width, + height = PIN_HEIGHT, + size = PIN_SIZE, + pos = "top"); + } +} + +// ------------------------------------------------------------------------ +// Do it! +// ------------------------------------------------------------------------ +main(); \ No newline at end of file diff --git a/images/batteries.png b/images/batteries.png new file mode 100644 index 0000000000000000000000000000000000000000..da843d391bcab0d56d28cd478596b0ee0810bcd8 GIT binary patch literal 8536 zcmZ`;c|4T+_kYF+5gAluLdo8x5;L?=w#c9?QJ2ytvJEN8Wh8|x*;))qi!GtlH7%Cx zbt7F%+{V(3h>|QJ#P58b(f9Ygzt`*chcWX!=kq@2ywCfb&u8X|vavD~6<#TfVVJ1- zPUAfo#z%!eF(CoC^4Q_DDTWau+>MNE%#Dl`eEocmxqBYPFx7-V5=wVf*+|t`+umKX zEW$yRb2(GL!^DJqVp+7!>K5Vq`q!S1i==K^tEL%u?!=21@ilqjmx>F-3eG7^5jgS+ zR?(V!IDeRDn&hvL8?HMuN$z^KRD9*KET^q>!)7n-bj!#NcAj)##L_D19YUn*PPJ)k z?>0Ry`H2;du3wCA~`$4zf8ZF@0s+xU)gf! zs+1*Gsuef3L4f~M*s)G}S^TQ(GkjASVH%}Fg}RIm>%TvH{T9T(#GAO{ofoZxsCk-E zpR}6!P~(UD;t0NPA*S8Q#2qDu^Qn}QHa#nO#*zm003w;p$2EE7GCcaVtntau_syx@ zOT9Mw-O=Aq4THJ}9NJ}OjD5pKv5|(@xaDwVvF}bNe+(0=Mt_794KZ1`D0tGGW+FI9 zSSG$q?%Vn!E^tZaq>1B6BOfoXquwVmBfq1rCyyRcIPHG&xPqBE&1P?y*a{4j*D^QW zZWs8^P$wAcOMZ+Q_?T9%*GFB$4a81AL3(KLLEcZ#fPmPC1+>e~e68UIx zy5MX2lm0IMuCb8W5DgQ#6J={ZXY`+WbGBq+vha%_W@w^Z#*Z;72$(pMBwXmhFd_1< ze^?k1Q}D&GEBaq|VHo$x$Y}QP&#Cdc@*$DGB_+vNy@L1hpFaFznA9rDn(PDnU1(&i zb}92rn>};G3j*UcC+qY3HNKd_42z`4EWX9ZcwKqyMnFmhfsw~C{ghu9EsP0AGBZOO z_FeD63|&cw68$#;tg5Q_p0bQYbS?9RYhrQQV(=hMIb7}o@o-Fg*B&!jge^0U2x#4| zOvP*h*}b#$#bitzVo-6g!)%3xt`&U(*%@nnFB;`V81 zrN>7`UOh1F9z3QMe<_VX4JTrXH8kUD`MICz9@{8jc0GdjigjJZZ`#ddk>MC!+qB(M zg<70{Z~E{#B7m5k8Y(NbykApFBLiIcsndk zOU|@C-0QfTpy0hRmKnK8jmFDF84HAG;=f-p&c22Cwslgv`6F z^MJcfC$voBVuQX$o>QB>nf439&D5e?cclR7q_o?Rs*MRdSxT2_<(p;ccLnYmvVkv> zvL2rxL%k|1B_+9jpb;Wl!_8_b8t^}-{nyh$1)!yxc8evGXx@lu6k?vIYq#*bU3ph1 zfudULnzYf^IBwZ8jFVNL(z1I`=}xx-4Gmb8D#~o3CwT;E-)pU^0}smFV==i6(qYXW zD80+}?T+T(3u{#JK^Gm>G~xR-w0jAMfj&ukl2Loi<6Eh%ub#f*7i8?NsV(z?x}x8e2eqJS`lp8#MmF;R;<9 zy$5Zk*VaK8`SZ8(R(o2c^;o9pzXaJDvWx6;k)sOJP&IIrgjely%{;e2&(p$XcZ0e+ zj?oXUywu$j!PU;`71k%{wttOhJ*o$H3QSfm-NSZ&kLAa*0w6O+PWN#wtsyMw>?geb zj{A8;nqFcqugscQ+-T>WLS$MsNI2w@`V%&>D<~vz$T4NxII)ed^9;n)MvbR%8YVh?tHWwfv%J5n|;nkfWv>NvkqraX>IOrPz;o*TxedGf zVKy*WBweXxlzYGf1a4!`hOi)r9Cc6LJv$i+pP*qoK-=1}^ZgdwD0)T!9vPGWGJe9q??Yxv=+A07qk=A_oi z8lbej$(H@vw6UaY!a~wjJ7BEM#i3gk2&Nmw)3s&w?pM>|fD;0JEahtBC1y-zUk+

LBy|8$o>94^r?yy2=HD?1v+3^?h$H$_TU z%jLNoiBvu}GFg|BQ6_tJezIY`8zF~OT+Vn=3S6FriuFesJRz%Cd)Cx#^V`^%zE!UOR9wwPgOh7QKFp4^>uEdb z`L@9XJTFR&puMYC`~JM)>(I=D(Y`ld*)tEz_CmSH(TmHSA8X zo!-u2mP~N|`93K&%YG?2so2ME>}=}Tmj3lqp;0XqkRP$3Q$wrnB-WBhKF-f%^?ZIW zmEYXoC^tK6mHtok%V=U+z?*KKh7->>1osAiK2azoPiZFB7I!_L?y4;5>?kWQNWIW> z8R=xTE8EyO_}Gl#$aQ{t633fqA{djs?c28p#QB-=T=TRo4|JvoTp`pzMx!kA)vYyu z=*g{*TmOO}u3M?xF_ZV3_nOfy2g$Ceuc~8N9ldX8b;R2Ji^ZhPppQV^ik@vnpBN(> ziv?o}m8nRn&@~`jr}wi2Zih-vEn01|2w6f4rTT5f!SIjg8&bWyg1)`|Mi!G6Asec2p`${t+(NH`ouL;#-E z4f}2ceX;y~?&Z)kdQu0T9qMU-Xj|Vx;BITg>4T<)iBg=kT1apGU=T0S!99?Dck5lI&ePbSVFZwM0F*3DT=Iz#_)5PLkJf(r9PoC0$ulBx4r ze*L!B4%39V#bOGG5E(^J=w9|xlqzzqy@Q>+Qny&^?d8v+wYCm+coUkk^S|WQHCDf; z$ffo4o&-RCL8wI52yi(^2VxA0Ky~wYH&s zJhhMlM!Du0@825`n;l_~p?j4mhZ0JN+evx1Npi^^L~3%#I!a7*T!mg(fv-LBEc zcu+xzj^nvmX}$H7vgUm6DdS{1GUr^l#i_OMAUiLWF4q}F?uBGw7AHdum(TwA8dwpS zzgIltV~s9>9uD-0qy+KEryL@!Ilz0cF?3}%Me89koh#hz^p z+b4|UDn8KmwEn@gjovV58B1`9(vz~ciAiURLBK~yluD2(GuR8tkk5)Lf>MieE*OE* zZtMfCTxCT;uI=o6321HT z+oxRRHJm3aH0|kl{i_><=|)WYVWn0F_PRZTsPDlYPO(_vOl?=`)#KOHac!Vs&~O}H zM}?WW20uR!*LKg<6n36HmsbtLys>AYzayD?2j&JR6**rC+}t0;+W4PuLy!DC<2^Kd zpks1K0C+f0Q|BlTv#w9>kDs*&{-UVDWp{At-u;fjQ${MB`1wJD;`!efiNOc~+t{L9 zILk)L9`M8&4Ipp4U<#cl#I!?G0B4ewtBg((yfSmZ15Si%(qYtHaLTiVBMOj$zegaV zm8Lx~=_r-Tb$A7Puq6|QQ>fI0iU+3B+06(o`CWoQGy~w&QV8sn47>oo{(hGWTGk{ig!4PUbg%S_12+PBT zqoD@xc})vO;_V2}mWE!d{3H)7 z%wGYzEgW$`fh0-<^cG2%2d2vd%ZKkRh-_etZ3oA76d$b*u?11$BEV^c59kiEQt%Z= z3hiADS`Zgtj}HeVcC=UsVdO35xki8x z76)Ie3y~>!qsUT`EiW>h)_+Ha1cFkj7RA-8`|rqf7E)nlqCg-ju}T5($XkH=2~`Wu z3%L5AnC*Bm!2@gcJ2X{b0q24TL>?)Nf`v3m$O8o`q6Te_s6*vs@(u*zR0tYU3NH#H zSq3kLRFFwd?Bckh%nBS1EdB!r;#`2!ytGihhhWc%GC%mg5Ff{U7&!%sK{M|DuM=rI2A7#Xl7cU~1~zme zI2Mwn^TsZ5({c#1#We}v6$vYa$r@_BqM!`2ZsG+!z7D+QRw)O-I#=Q*DJsw!&I3`Kpd)1uy1bQy1VLX|E9eAT$dgeeRdP!L z?p2HWCLdC!x_E~z$7#QrS+U`9W(4@I6!>I4p`i}ou+I7D<`)kVZ$r)c=7a>BbaGG02=+*(jvAfo#A2uhtw%>_izVVz#XM0BMsxt!p9sLL5 zwL<2?%l5?9(kwv1*!a=A%j{p7$El%C

bnXPK3_CnsfE} z7V*ZJHOXzcr=9?f6k9}aG|SG;A?q)vDAhKc)+$BarQmC9b;6aa2Eu6y?ukr$%28H= z&5U^YRf3!E8nGKy*FRdu@ix#RLi;D>!%1lyp`8@Gu`oqH_=Ted=&2U1kPdnxSm#y8 zIkp>@+4?J8E}qR^bw4hkk%sZPh4s6zk~;-8{TwbWEHT^=R;=Dn|0j-_%!6=s2(sLA z=*Ml&rNH3l=|wV%-r~BL+4UtOmr{Elp*@%*a5J}pq~}#ldxdN1=B1RqcBIZWJKHvU z&aq~sq?0-_)2puaE|JxBQI(_<*YALgK0roV$!gvhe_TC@B8$rmV-Ak*5q(qY>we## zD#Wzs3b+!RE}FkOeJmO=#UkWr!q0mwCn=oJ@%zn(Ii$DmqhE2kUKblSp}>r;#e9#W z`Jr|@sG6=qCB6N;9k}@uR{%qq&kSOQ#qHRgO)o!$7Zsp}VGQzRf3F`&mV!+Fu5jPr zx2OC{i!^FM>8g={IVH-tt;8E|->3E(cN(aIo7I^SEGev-i{It1h9+36UkL8}!}0 zj2naKMA$>D^3>wYD!_XLzm@xnx!7fTpU>00w3esthuMP~RiaL`s#X+stzJ)Y-NV%l zGu9nDqwzZekudlmyKe%|1lveNNGdO>uW5({isU>lxj@ z67GSrxm`=2HL( z#6)B-Mgak_i>zn~+M#kPN88gnpUezx4xMN(%{cpcFrDb*&uw!tHhzBA&EU^!oQspO zX&bV1yv#x2lJ571sJ+2R#ZHEY5UO7`y2PyiAeHzUPG6PjY z?jFe;u6&Tl2gkOwwQyHHx`=?@chSJIT*R$QoEMyxQG#~gi9L5&A~5n`E*$T@bFy!I z)TjT;ZO$KT#GW{H?MUfWAGztAsWqSB3M!+F$M+_>{IB$6oDVFJK+?M{!_g$WLL%_? z3?epCP;Oaw@2|*~?);fE)j098@%r`4O`gEy?AleR}xW%mK{4$y| zRXxmyKELcpiuaZev?F8uV)n+3`LwT<1jPKqk-?9hRzBq)_b);2l&+PExJ~RHIePlT z?0ZT`Gerg&z0#S_39SD4%oiSzMy93Q4N3F>9$IE^bBeQ0e}FhMh5FxUhTH;CKnh~@ zXY9XEX|LeI)>YFuu>mX;d{qtnu9UJXAF4Hs@1_HHM`ZNI=>C1<9G{^t&Qx27#<1tI zeJ}dmB_fI0JwLk(7|YO^$(c%4tOd}v=(MtoJANoa1bb9zKblFpp{^pF*PqKoB0dX@D$+vg4 zzn<<7{i9~ZQbyLbo^j6{*m~$hjPK$)MUb5#W&g~~-rvt{ysQ=cwX!lJbo8y4D-k1Z zd?C}MoCG2Tb?3px0I9)d10R|G0xFpU*V9bgko3pv_*F8GF4zSY7n;MKaWmAxPI0QT zUo&P-y%*MDnD8NZpbHO0em!r7=U?cV^uj;s=6NC^V|iqcyNDq?U&qW%tc(kG96a|w Dp)==3 literal 0 HcmV?d00001