The LED parts box disgorged some single-color Pirhana-style LEDs:

Didn’t quite catch the blink, but the Ping-Pong ball radome lights up just as you’d expect.
The radome sits on a stripped-down RGB LED spider:
The circuitry is the same as the First Light version, with a 1 MΩ resistor stabilizing the LED ballast resistor:
Those are 1 µF ceramic caps in the astable section, so I’m no longer abusing electrolytics, and a stylin’ 100 nF film cap metering out the LED pulse up above.
Just for pretty, I’ve been using yellow / black wires for the battery connections and matching the LED color with its cathode lead.
The OpenSCAD source code as a GitHub Gist:
| // Holder for Li-Ion battery packs | |
| // Ed Nisley KE4ZNU January 2013 | |
| // 2018-11-15 Adapted for 1.5 mm pogo pins, battery data table | |
| // 2018-12 RGB LED spider, general cleanups | |
| /* [Layout options] */ | |
| BatteryName = "NP-BX1"; // [NP-BX1,NB-5L,NB-6L] | |
| RGBCircuit = false; // false = 1 strut pair, true = 2 pairs | |
| Layout = "Spider"; // [Build,Show,Fit,Case,Lid,Pins,RGBSpider,Spider] | |
| /* [Extrusion parameters] – must match reality! */ | |
| // Print with +2 shells and 3 solid layers | |
| ThreadThick = 0.25; | |
| ThreadWidth = 0.40; | |
| HoleWindage = 0.2; | |
| function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); | |
| function IntegerLessMultiple(Size,Unit) = Unit * floor(Size / Unit); | |
| Protrusion = 0.1; // make holes end cleanly | |
| /* [Hidden] */ | |
| inch = 25.4; | |
| BuildOffset = 3.0; // clearance for build layout | |
| Gap = 2.0; // separation for Fit parts | |
| //- Basic dimensions | |
| WallThick = 4*ThreadWidth; // holder sidewalls | |
| BaseThick = 6*ThreadThick; // bottom of holder to bottom of battery | |
| TopThick = 6*ThreadThick; // top of battery to top of holder | |
| //- Battery dimensions – rationalized from several samples | |
| // Coordinate origin at battery corner with contacts, key openings downward | |
| T_NAME = 0; // Name must fit recess, so don't get loquacious | |
| T_SIZE = 1; | |
| T_CONTACTS = 2; | |
| T_KEYS = 3; | |
| BatteryData = [ | |
| ["NP-BX1",[43.0,30.0,9.5],[[-0.75,6.0,6.2,"+"],[-0.75,16.0,6.2,"-"]],[[1.70,3.70,2.90],[1.70,3.60,2.90]]], | |
| ["NB-5L", [45.0,32.0,8.0],[[-0.82,4.5,3.5,"-"],[-0.82,11.0,3.5,"+"]],[[2.2,0.75,2.0],[2.2,2.8,2.0]]], | |
| ["NB-6L",[42.5,35.5,7.0],[[-0.85,5.50,3.05,"-"],[-0.85,11.90,3.05,"+"]],[[2.0,0.70,2.8],[2.0,2.00,2.8]]], | |
| ]; | |
| echo(str("Battery: ",BatteryName)); | |
| BatteryIndex = search([BatteryName],BatteryData,1,0)[0]; | |
| echo(str(" Index: ",BatteryIndex)); | |
| BatterySize = BatteryData[BatteryIndex][T_SIZE]; // X = length, Y = width, Z = thickness | |
| echo(str(" Size: ",BatterySize)); | |
| Contacts = BatteryData[BatteryIndex][T_CONTACTS]; // relative to battery edge, front, and bottom | |
| echo(str(" Contacts: ",Contacts)); | |
| ContactOC = Contacts[1].y – Contacts[0].y; // + and – terminals for pogo pin contacts | |
| ContactCenter = Contacts[0].y + ContactOC/2; | |
| KeyBlocks = BatteryData[BatteryIndex][T_KEYS]; // recesses in battery face set X position | |
| echo(str(" Keys: ",KeyBlocks)); | |
| //- Pin dimensions | |
| ID = 0; | |
| OD = 1; | |
| LENGTH = 2; | |
| PinShank = [1.5,2.0,6.5]; // shank, flange, compressed length | |
| PinFlange = [1.5,2.0,0.5]; // flange, length included in PinShank | |
| PinTip = [0.9,0.9,2.5]; // extended spring-loaded tip | |
| WireOD = 1.7; // wiring from pins to circuitry | |
| PinChannel = WireOD; // cut behind flange for solder overflow | |
| PinRecess = 3.0; // recess behind pin flange end for epoxy fill | |
| echo(str("Contact tip dia: ",PinTip[OD])); | |
| echo(str(" .. shank dia: ",PinShank[ID])); | |
| OverTravel = 0.5; // space beyond battery face at X origin | |
| //- Holder dimensions | |
| GuideRadius = ThreadWidth; // friction fit ridges | |
| GuideOffset = 7; // from compartment corners | |
| LidOverhang = 2.0; // atop of battery for retention | |
| LidClearance = LidOverhang * (BatterySize.z/BatterySize.x); // … clearance above battery for tilting | |
| echo(str("Lid clearance: ",LidClearance)); | |
| CaseSize = [BatterySize.x + PinShank[LENGTH] + OverTravel + PinRecess + GuideRadius + WallThick, | |
| BatterySize.y + 2*WallThick + 2*GuideRadius, | |
| BatterySize.z + BaseThick + TopThick + LidClearance]; | |
| echo(str("Case size: ",CaseSize)); | |
| CaseOffset = [-(PinShank[LENGTH] + OverTravel + PinRecess),-(WallThick + GuideRadius),0]; // position around battery | |
| ThumbRadius = 10.0; // thumb opening at end of battery | |
| CornerRadius = 3*ThreadThick; // nice corner rounding | |
| LidSize = [-CaseOffset.x + LidOverhang,CaseSize.y,TopThick]; | |
| LidOffset = [0.0,CaseOffset.y,0]; | |
| //- Wire struts | |
| StrutDia = 1.6; // AWG 14 = 1.6 mm | |
| StrutSides = 3*4; | |
| StrutBase = [StrutDia,StrutDia + 4*WallThick,CaseSize.z – TopThick]; // ID = wire, OD = buildable | |
| //StrutOC = [IntegerLessMultiple(BatterySize.x – StrutBase[OD],5.0), // set easy OC wire spacing | |
| // IntegerMultiple(CaseSize.y + StrutBase[OD],5.0)]; | |
| StrutOC = [IntegerLessMultiple(CaseSize.x – 2*CornerRadius -2*StrutBase[OD],5.0), | |
| IntegerMultiple(CaseSize.y + StrutBase[OD],5.0)]; | |
| StrutOffset = [CaseSize.x/2 + CaseOffset.x,BatterySize.y/2]; // from case centerlines | |
| StrutAngle = atan(StrutOC.y/StrutOC.x); | |
| echo(str("Strut OC: ",StrutOC)); | |
| //- RGB / Pirhana / Neopixel-ish LEDs | |
| RGBBody = [8.0,8.0,5.0]; // Z = body height | |
| PixelPCB = [4.0,10.0,3.0]; // Neopixel-ish PCBs, ID = chip window | |
| RGBPin = 5.0; // pin length | |
| RGBPinsOC = [5.0,5.0]; // pin layout | |
| RGBRecess = RGBBody.z + RGBPin/2; // maximum LED recess depth | |
| BallOD = 40.0; // radome sphere | |
| BallSides = 4*StrutSides; // nice number of sides | |
| BallPillar = [norm([RGBBody.x,RGBBody.y]), | |
| norm([RGBBody.x,RGBBody.y]) + 4*WallThick, | |
| StrutBase[OD] + RGBBody.z]; | |
| BallChordM = BallOD/2 – sqrt(pow(BallOD/2,2) – (pow(BallPillar[OD],2))/4); | |
| echo(str("Ball chord depth: ",BallChordM)); | |
| //———————- | |
| // Useful routines | |
| module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes | |
| Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2); | |
| FixDia = Dia / cos(180/Sides); | |
| cylinder(r=(FixDia + HoleWindage)/2,h=Height,$fn=Sides); | |
| } | |
| //——————- | |
| //– Guides for tighter friction fit | |
| module Guides() { | |
| translate([GuideOffset,-GuideRadius,0]) | |
| PolyCyl(2*GuideRadius,(BatterySize.z – Protrusion),4); | |
| translate([GuideOffset,(BatterySize.y + GuideRadius),0]) | |
| PolyCyl(2*GuideRadius,(BatterySize.z – Protrusion),4); | |
| translate([(BatterySize.x – GuideOffset),-GuideRadius,0]) | |
| PolyCyl(2*GuideRadius,(BatterySize.z – Protrusion),4); | |
| translate([(BatterySize.x – GuideOffset),(BatterySize.y + GuideRadius),0]) | |
| PolyCyl(2*GuideRadius,(BatterySize.z – Protrusion),4); | |
| translate([(BatterySize.x + GuideRadius),GuideOffset/2,0]) | |
| PolyCyl(2*GuideRadius,(BatterySize.z – Protrusion),4); | |
| translate([(BatterySize.x + GuideRadius),(BatterySize.y – GuideOffset/2),0]) | |
| PolyCyl(2*GuideRadius,(BatterySize.z – Protrusion),4); | |
| } | |
| //– Contact pins | |
| // Rotated to put them in their natural oriention | |
| // Aligned to put tip base / end of shank at Overtravel limit | |
| module PinShape() { | |
| translate([-(PinShank[LENGTH] + OverTravel),0,0]) | |
| rotate([0,90,0]) | |
| rotate(180/6) | |
| union() { | |
| PolyCyl(PinTip[OD],PinShank[LENGTH] + PinTip[LENGTH],6); | |
| PolyCyl(PinShank[ID],PinShank[LENGTH] + Protrusion,6); // slight extension for clean cuts | |
| PolyCyl(PinFlange[OD],PinFlange[LENGTH],6); | |
| } | |
| } | |
| // Position pins to put end of shank at battery face | |
| // Does not include recess access into case | |
| module PinAssembly() { | |
| union() { | |
| for (p = Contacts) | |
| translate([0,p.y,p.z]) | |
| PinShape(); | |
| translate([-(PinShank[LENGTH] + OverTravel) + PinChannel/2, // solder space | |
| ContactCenter, | |
| Contacts[0].z]) | |
| cube([PinChannel, | |
| (Contacts[1].y – Contacts[0].y + PinFlange[OD]), | |
| PinFlange[OD]],center=true); | |
| for (j=[-1,1]) // wire channels | |
| translate([-(PinShank[LENGTH] + OverTravel – PinChannel/2), | |
| j*ContactOC/4 + ContactCenter, | |
| Contacts[0].z – PinFlange[OD]/2]) | |
| rotate(180/6) | |
| PolyCyl(WireOD,CaseSize.z,6); | |
| } | |
| } | |
| //– Case with origin at battery corner | |
| module Case() { | |
| difference() { | |
| union() { | |
| difference() { | |
| union() { | |
| translate([(CaseSize.x/2 + CaseOffset.x), // basic case shape | |
| (CaseSize.y/2 + CaseOffset.y), | |
| (CaseSize.z/2 – BaseThick)]) | |
| hull() | |
| for (i=[-1,1], j=[-1,1], k=[-1,1]) | |
| translate([i*(CaseSize.x/2 – CornerRadius), | |
| j*(CaseSize.y/2 – CornerRadius), | |
| k*(CaseSize.z/2 – CornerRadius)]) | |
| sphere(r=CornerRadius/cos(180/8),$fn=8); // cos() fixes undersize spheres! | |
| for (i= RGBCircuit ? [-1,1] : -1) { // strut bases | |
| hull() | |
| for (j=[-1,1]) | |
| translate([i*StrutOC.x/2 + StrutOffset.x,j*StrutOC.y/2 + StrutOffset.y,-BaseThick]) | |
| rotate(180/StrutSides) | |
| cylinder(d=StrutBase[OD],h=StrutBase[LENGTH],$fn=StrutSides); | |
| translate([i*StrutOC.x/2 + StrutOffset.x,StrutOffset.y,StrutBase[LENGTH]/2 – BaseThick]) | |
| cube([2*StrutBase[OD],StrutOC.y,StrutBase[LENGTH]],center=true); // blocks for fairing | |
| for (j=[-1,1]) // hemisphere caps | |
| translate([i*StrutOC.x/2 + StrutOffset.x, | |
| j*StrutOC.y/2 + StrutOffset.y, | |
| StrutBase[LENGTH] – BaseThick]) | |
| rotate(180/StrutSides) | |
| sphere(d=StrutBase[OD]/cos(180/StrutSides),$fn=StrutSides); | |
| } | |
| } | |
| translate([-OverTravel,-GuideRadius,0]) | |
| cube([(BatterySize.x + GuideRadius + OverTravel), | |
| (BatterySize.y + 2*GuideRadius), | |
| (BatterySize.z + LidClearance + Protrusion)]); // battery space | |
| translate([BatterySize.x/2,BatterySize.y/2,0]) // recess around battery name | |
| cube([0.8*BatterySize.x,8,2*ThreadThick],center=true); | |
| translate([CaseOffset.x + CaseSize.x/2,BatterySize.y/2,-BaseThick + ThreadThick – Protrusion]) // recess around battery name | |
| cube([0.75*CaseSize.x,8,2*ThreadThick],center=true); | |
| } | |
| Guides(); // improve friction fit | |
| translate([-OverTravel,-GuideRadius,0]) // battery keying blocks | |
| cube(KeyBlocks[0] + [OverTravel,GuideRadius,0],center=false); | |
| translate([-OverTravel,(BatterySize.y – KeyBlocks[1].y),0]) | |
| cube(KeyBlocks[1] + [OverTravel,GuideRadius,0],center=false); | |
| translate([BatterySize.x/2,BatterySize.y/2,-ThreadThick]) | |
| linear_extrude(height=2*ThreadThick,convexity=10) | |
| text(text=BatteryName,size=5,spacing=1.20,font="Arial:style:Bold",halign="center",valign="center"); | |
| translate([CaseOffset.x + CaseSize.x/2,BatterySize.y/2,-BaseThick]) | |
| linear_extrude(height=2*ThreadThick + Protrusion,convexity=10) | |
| mirror([0,1,0]) | |
| text(text="KE4ZNU",size=6,spacing=1.20,font="Arial:style:Bold",halign="center",valign="center"); | |
| } | |
| translate([2*CaseOffset.x, // battery top access | |
| (CaseOffset.y – Protrusion), | |
| BatterySize.z + LidClearance]) | |
| cube([2*CaseSize.x,(CaseSize.y + 2*Protrusion),2*TopThick]); | |
| for (i2 = RGBCircuit ? [-1,1] : -1) { // strut wire holes and fairing | |
| for (j=[-1,1]) | |
| translate([i2*StrutOC.x/2 + StrutOffset.x,j*StrutOC.y/2 + StrutOffset.y,0]) | |
| rotate(180/StrutSides) | |
| PolyCyl(StrutBase[ID],2*StrutBase[LENGTH],StrutSides); | |
| for (i=[-1,1], j=[-1,1]) | |
| translate([i*StrutBase[OD] + (i2*StrutOC.x/2 + StrutOffset.x), | |
| j*StrutOC.y/2 + StrutOffset.y, | |
| -(BaseThick + Protrusion)]) | |
| rotate(180/StrutSides) | |
| PolyCyl(StrutBase[OD],StrutBase[LENGTH] + 2*Protrusion,StrutSides); | |
| } | |
| translate([(BatterySize.x – Protrusion), // remove thumb notch | |
| (CaseSize.y/2 + CaseOffset.y), | |
| (ThumbRadius)]) | |
| rotate([90,0,0]) | |
| rotate([0,90,0]) | |
| cylinder(r=ThumbRadius, | |
| h=(WallThick + GuideRadius + 2*Protrusion), | |
| $fn=22); | |
| PinAssembly(); // pins and wiring | |
| translate([CaseOffset.x + PinRecess + Protrusion,(Contacts[1].y + Contacts[0].y)/2,Contacts[0].z]) | |
| translate([-PinRecess,0,0]) | |
| cube([2*PinRecess, | |
| (Contacts[1].y – Contacts[0].y + PinFlange[OD]/cos(180/6) + 2*HoleWindage), | |
| 2*PinFlange[OD]],center=true); // pin insertion hole | |
| } | |
| } | |
| // Lid position offset to match case | |
| // The polarity indicator recesses are pure bodges | |
| module Lid() { | |
| union() { | |
| difference() { | |
| translate([-LidSize.x/2 + LidOffset.x + LidOverhang,LidSize.y/2 + LidOffset.y,0]) | |
| difference() { | |
| hull() | |
| for (i=[-1,1], j=[-1,1], k=[-1,1]) | |
| translate([i*(LidSize.x/2 – CornerRadius), | |
| j*(LidSize.y/2 – CornerRadius), | |
| k*(LidSize.z – CornerRadius)]) // double thickness for flat bottom | |
| sphere(r=CornerRadius,$fn=8); | |
| translate([0,0,-LidSize.z/2]) // remove bottom | |
| cube([(LidSize.x + 2*Protrusion),(LidSize.y + 2*Protrusion),LidSize.z],center=true); | |
| translate([LidSize.x/8,0,0]) | |
| cube([LidSize.x/4,0.75*LidSize.y,4*ThreadThick],center=true); // epoxy recess | |
| } | |
| translate([0,0,-(Contacts[0].z + PinFlange[OD])]) // punch wire holes | |
| PinAssembly(); | |
| for (n=[0,1]) // polarity recesses | |
| translate([-LidOverhang/2 – 0.40,Contacts[n].y,LidSize.z – ThreadThick/2]) | |
| cube([4,4.5,ThreadThick + Protrusion],center=true); | |
| } | |
| for (n=[0,1]) // polarity indicators | |
| translate([-LidOverhang/2,Contacts[n].y,LidSize.z – 1*ThreadThick]) // … proud of surface | |
| rotate(90) | |
| linear_extrude(height=2*ThreadThick,convexity=10) | |
| text(text=Contacts[n][3],size=5,font="Arial:style:Bold",halign="center",valign="center"); | |
| } | |
| } | |
| // Spider for RGB LED + radome atop vertical struts | |
| module RGBSpider() { | |
| difference() { | |
| union() { | |
| for (i=[-1,1], j=[-1,1]) { | |
| translate([i*StrutOC.x/2,j*StrutOC.y/2,StrutBase[OD]/2]) | |
| rotate(180/StrutSides) // doesn't quite match crosspieces; close enough | |
| sphere(d=StrutBase[OD]/cos(180/StrutSides),$fn=StrutSides); | |
| translate([i*StrutOC.x/2,j*StrutOC.y/2,0]) | |
| rotate(180/StrutSides) | |
| cylinder(d=StrutBase[OD],h=StrutBase[OD]/2,$fn=StrutSides); | |
| } | |
| for (m=[-1,1]) // connecting bars | |
| rotate(m*StrutAngle) | |
| translate([0,0,StrutBase[OD]/4]) | |
| cube([norm(StrutOC),StrutBase[OD],StrutBase[OD]/2],center=true); | |
| translate([0,0,0]) // pillar for RGB LED and ball | |
| cylinder(d=BallPillar[OD],h=BallPillar[LENGTH],$fn=BallSides); | |
| } | |
| for (i=[-1,1], j=[-1,1]) // strut wires | |
| translate([i*StrutOC.x/2,j*StrutOC.y/2,-Protrusion]) | |
| rotate(0) | |
| PolyCyl(StrutBase[ID],StrutBase[OD]/2,6); | |
| for (m=[-1,1], n=[0,1]) // RGBA wires through bars | |
| rotate(m*StrutAngle + n*180) | |
| translate([StrutOC.x/3,0,-Protrusion]) | |
| PolyCyl(StrutBase[ID],StrutBase[OD],6); | |
| translate([0,0,BallOD/2 + BallPillar[LENGTH] – BallChordM]) // ball inset | |
| sphere(d=BallOD); | |
| translate([0,0,2*RGBBody.z + (BallPillar[LENGTH] – BallChordM) – RGBRecess]) // LED inset | |
| cube(RGBBody + [HoleWindage,HoleWindage,3*RGBBody.z],center=true); // XY clearance + huge height for E-Z cut | |
| translate([0,0,StrutBase[OD]/2]) // Neopixel recess | |
| PolyCyl(PixelPCB[OD],3*RGBBody.z,BallSides/2); | |
| for (m=[-1,1]) // RGBA wires through pillar | |
| rotate(m*StrutAngle) | |
| translate([0,0,StrutBase[OD]/2 + WireOD/2 + 0*Protrusion]) | |
| cube([norm(StrutOC)/2,WireOD,WireOD],center=true); | |
| } | |
| } | |
| // Spider for single LED atop struts, with the ball | |
| // Aligned to struts at terminal end of battery on Y axis | |
| module Spider() { | |
| difference() { | |
| union() { | |
| for (j=[-1,1]) { | |
| translate([-StrutOC.x/2,j*StrutOC.y/2,StrutBase[OD]/2]) | |
| rotate(180/StrutSides) | |
| sphere(d=StrutBase[OD]/cos(180/StrutSides),$fn=StrutSides); | |
| translate([-StrutOC.x/2,j*StrutOC.y/2,0]) | |
| rotate(180/StrutSides) | |
| cylinder(d=StrutBase[OD],h=StrutBase[OD]/2,$fn=StrutSides); | |
| } | |
| translate([-StrutOC.x/2,0,StrutBase[OD]/4]) // connecting bars | |
| cube([StrutBase[OD]*cos(180/StrutSides),StrutOC.y,StrutBase[OD]/2],center=true); | |
| translate([-StrutOC.x/2,0,0]) // pillar for RGB LED and ball | |
| cylinder(d=BallPillar[OD],h=BallPillar[LENGTH],$fn=BallSides); | |
| } | |
| for (j=[-1,1]) // strut wires | |
| translate([-StrutOC.x/2,j*StrutOC.y/2,-Protrusion]) | |
| rotate(0) | |
| PolyCyl(StrutBase[ID],StrutBase[OD]/2,6); | |
| translate([-StrutOC.x/2,0,0]) // wires through bars | |
| for (n=[-1,1]) | |
| rotate(n*90) | |
| translate([StrutOC.x/3,0,-Protrusion]) | |
| PolyCyl(StrutBase[ID],StrutBase[OD],6); | |
| translate([-StrutOC.x/2,0,-Protrusion]) // center hole for Neopixel | |
| rotate(180/6) | |
| PolyCyl(StrutBase[ID],StrutBase[OD],6); | |
| translate([-StrutOC.x/2,0,BallOD/2 + BallPillar[LENGTH] – BallChordM]) // ball inset | |
| sphere(d=BallOD); | |
| translate([-StrutOC.x/2,0,2*RGBBody.z + (BallPillar[LENGTH] – BallChordM) – RGBRecess]) // LED inset | |
| cube(RGBBody + [HoleWindage,HoleWindage,3*RGBBody.z],center=true); // XY clearance + huge height for E-Z cut | |
| translate([-StrutOC.x/2,0,StrutBase[OD]/2]) // Neopixel recess | |
| PolyCyl(PixelPCB[OD],3*RGBBody.z,BallSides/2); | |
| translate([-StrutOC.x/2,0,StrutBase[OD]/2 + WireOD/2 + 0*Protrusion]) // wire channels | |
| cube([WireOD,StrutOC.y/2,WireOD],center=true); | |
| } | |
| } | |
| //——————- | |
| // Build it! | |
| if (Layout == "Case") | |
| Case(); | |
| if (Layout == "Lid") | |
| Lid(); | |
| if (Layout == "RGBSpider") { | |
| RGBSpider(); | |
| } | |
| if (Layout == "Spider") { | |
| Spider(); | |
| } | |
| if (Layout == "Pins") { | |
| color("Silver",0.5) | |
| PinShape(); | |
| PinAssembly(); | |
| } | |
| if (Layout == "Fit") { // reveal pin assembly | |
| difference() { | |
| Case(); | |
| translate([(CaseOffset.x – Protrusion), | |
| Contacts[1].y, | |
| Contacts[1].z]) | |
| cube([(-CaseOffset.x + Protrusion),CaseSize.y,CaseSize.z]); | |
| translate([(CaseOffset.x – Protrusion), | |
| (CaseOffset.y – Protrusion), | |
| 0]) | |
| cube([(-CaseOffset.x + Protrusion), | |
| Contacts[0].y + Protrusion – CaseOffset.y, | |
| CaseSize.z]); | |
| } | |
| translate([0,0,BatterySize.z + Gap]) | |
| Lid(); | |
| color("Silver",0.15) | |
| PinAssembly(); | |
| if (RGBCircuit) { | |
| translate([StrutOC.x/2,BatterySize.y/2,2*BatterySize.z]) | |
| difference() { | |
| RGBSpider(); | |
| rotate(180-StrutAngle) | |
| translate([0,0,-Protrusion]) | |
| cube([norm(StrutOC),StrutBase[OD],2*BallPillar.z],center=false); | |
| } | |
| color("Green",0.35) | |
| translate([StrutOC.x/2,BatterySize.y/2,2*BatterySize.z + BallOD/2 + BallPillar[LENGTH] – BallChordM]) | |
| sphere(d=BallOD); | |
| } | |
| else { | |
| difference() { | |
| translate([StrutOC.x/2,BatterySize.y/2,2*BatterySize.z]) | |
| Spider(); | |
| translate([-BallPillar[OD],BatterySize.y/2,2*BatterySize.z – Protrusion]) | |
| cube([BallPillar[OD],StrutOC.y,2*BallPillar.z],center=false); | |
| } | |
| color("Green",0.35) | |
| translate([0,BatterySize.y/2,2*BatterySize.z + BallOD/2 + BallPillar[LENGTH] – BallChordM]) | |
| sphere(d=BallOD); | |
| } | |
| } | |
| if (Layout == "Build") { | |
| rotate(90) { | |
| translate([-BatterySize.x/2,-BatterySize.y/2,BaseThick]) | |
| Case(); | |
| translate([-CaseSize.x + LidSize.x,-(LidSize.y/2 + LidOffset.y),0]) | |
| Lid(); | |
| if (RGBCircuit) | |
| translate([StrutOC.x + BatterySize.x/2,0,0]) | |
| RGBSpider(); | |
| else | |
| translate([StrutOC.x + BatterySize.x/2,0,0]) | |
| Spider(); | |
| } | |
| } | |
| if (Layout == "Show") { | |
| Case(); | |
| translate([0,0,(BatterySize.z + Gap)]) | |
| Lid(); | |
| color("Silver",0.25) | |
| PinAssembly(); | |
| if (RGBCircuit) { | |
| translate([StrutOC.x/2,BatterySize.y/2,2*BatterySize.z]) | |
| RGBSpider(); | |
| color("Green",0.35) | |
| translate([StrutOC.x/2,BatterySize.y/2,2*BatterySize.z + BallOD/2 + BallPillar[LENGTH] – BallChordM]) | |
| sphere(d=BallOD); | |
| } | |
| else { | |
| translate([StrutOC.x/2,BatterySize.y/2,2*BatterySize.z]) | |
| Spider(); | |
| color("Green",0.35) | |
| translate([0,BatterySize.y/2,2*BatterySize.z + BallOD/2 + BallPillar[LENGTH] – BallChordM]) | |
| sphere(d=BallOD); | |
| } | |
| } | |


Comments
2 responses to “Astable Multivibrator: Monochrome Pirhana LED”
[…] the astable blinking green, I had to do […]
[…] final test shows the 2011-F pack may power an LED blinky, but not much […]