Our Larval Engineer has been diligently procrastinating on her summer project to add ground effect lighting to her longboard. I’m hereby depriving her of the opportunity to learn enough OpenSCAD to build a case from scratch:

This is upside-down from its in-use position, but she’ll have it in this orientation on the bench. Four 10-32 screws clamp the whole affair together and hold it to a bottom aluminum plate with threads to suit; that plate also gets bolted between the longboard and the rear truck.
The general idea is that four 2 A·h lithium prismatic cells live in the bottom slice with their protection circuit, sandwiched between two aluminum plates that should protect them from all but catastrophic impact. The circuit board (which ought to be a PCB, but we’ll go with hand wiring for the first iteration) gets clamped in the recess between the two upper slices, above the upper aluminum plate. A polycarbonate sheet on top provides visibility for the Arduino blinky LED inside and shows off the circuitry to one and all.
I think a ridge on each long wall should suffice to hold the cells against the end wall; we don’t have the cells in hand to figure that out yet. She gets to add internal partitions, cable cutouts, and suchlike.
Oh. “Ground effect lighting” means ten RGB LED strips glued under the longboard deck. Her innovation is to make the LED color depend on the speed, which can range upward to scary-fast. It’s a simple matter of software, using a Hall effect sensor for input. This will look much better after dark, but she’s pretty much nocturnal anyway.
The OpenSCAD source code:
// Longboard Ground Effect Lighting Controller Case // Ed Nisley KE4ZNU // Karen Nisley KC2SYU // July 2012 // Layout options Layout = "Show"; // Overall layout: Fit Show // Printing plates: Build1 .. Buildn (see bottom!) // Parts: BatteryLayer PCBLayer1 PCBLayer2 // Shapes: CaseShell PCBEnvelope ShowGap = 5; // spacing between parts in Show layout //----- // Extrusion parameters must match reality! ThreadThick = 0.25; ThreadWidth = 2.0 * ThreadThick; HoleWindage = 0.2; //-- Handy stuff function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); Protrusion = 0.1; // make holes end cleanly inch = 25.4; Tap10_32 = 0.159 * inch; Clear10_32 = 0.190 * inch; Head10_32 = 0.373 * inch; Head10_32Thick = 0.110 * inch; Nut10_32Dia = 0.433 * inch; Nut10_32Thick = 0.130 * inch; Washer10_32OD = 0.381 * inch; Washer10_32ID = 0.204 * inch; //---------------------- // Dimensions CellWidth = 50.0; // Lithium-ion cell dimensions CellLength = 60.0; CellThick = 6.0; CellClearance = 1.5; // on all sides CellTabClearance = 10.0; // for connections BatteryCount = 4; // cells in the battery BatteryHeight = BatteryCount*CellThick + 2*CellClearance; PCMWidth = 16.0; // Battery protection board PCMLength = 50.0; PCMThick = 4.0; // at terminal end of cells PillarOD = Washer10_32OD + 2*0.5; // screw pillar diameter PillarOffset = (PillarOD/2) / sqrt(2.0); // distance to case inside corner WallThick = 6.0; // case wall thickness PinOD = 1.4; // alignment pin size CaseOALength = CellLength + CellClearance + CellTabClearance + PCMThick + 2*WallThick; CaseInsideLength = CaseOALength - 2*WallThick; echo("Box Length outside: ",CaseOALength); echo(" inside: ",CaseInsideLength); CaseOAWidth = CellWidth + 2*CellClearance + 2*WallThick; CaseInsideWidth = CaseOAWidth - 2*WallThick; echo("Box Width outside: ",CaseOAWidth); echo(" inside: ",CaseInsideWidth); CaseOAHeight = BatteryCount * CellThick + CellClearance; PCBThick = 1.0; // PCB thickness PCBMargin = 3.0; // clamping margin around PCB edge PartHeight = 10.0; // height of components above PCB WiringThick = 4.0; // wiring below PCB echo("PCB thickness:",PCBThick); echo(" clamp margin: ",PCBMargin); echo(" wiring: ",WiringThick); echo(" components: ",PartHeight); PCBLayer1Thick = IntegerMultiple(WiringThick + PCBThick/2,ThreadThick); PCBLayer2Thick = IntegerMultiple(PartHeight + PCBThick/2,ThreadThick); echo("Battery compartment height: ",BatteryHeight); echo("PCB Layer 1 height: ",PCBLayer1Thick); echo("PCB Layer 2 height: ",PCBLayer2Thick); PlateThick = 1/16 * inch; // aluminum mount / armor plates echo("Total height: ",2*PlateThick + BatteryHeight + PCBLayer1Thick + PCBLayer2Thick); //---------------------- // 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); } module ShowPegGrid(Space = 10.0,Size = 1.0) { Range = floor(50 / Space); for (x=[-Range:Range]) for (y=[-Range:Range]) translate([x*Space,y*Space,Size/2]) %cube(Size,center=true); } //------------------- // Shapes module CaseShell(h=1.0) { difference() { union() { translate([0,0,h/2]) cube([CaseOALength,CaseOAWidth,h],center=true); for (x=[-1,1]) for (y=[-1,1]) translate([x*(PillarOffset + CaseInsideLength/2), y*(PillarOffset + CaseInsideWidth/2), h/2]) cylinder(r=PillarOD/2,h,center=true,$fn=4*6); } for (x=[-1,1]) // screw holes on corners for (y=[-1,1]) translate([x*(PillarOffset + CaseInsideLength/2), y*(PillarOffset + CaseInsideWidth/2), -Protrusion]) PolyCyl(Clear10_32,(h + 2*Protrusion),8); for (x=[-1,1]) // alignment pins in width walls translate([x*(CaseOALength - WallThick)/2,0,-Protrusion]) rotate(45) PolyCyl(PinOD,(h + 2*Protrusion)); for (y=[-1,1]) // alignment pins in length walls translate([0,y*(CaseOAWidth - WallThick)/2,-Protrusion]) rotate(45) PolyCyl(PinOD,(h + 2*Protrusion)); } } module BatteryLayer() { difference() { CaseShell(BatteryHeight); translate([0,0,BatteryHeight/2]) cube([CaseOALength - 2*WallThick, CaseOAWidth - 2*WallThick, BatteryHeight + 2*Protrusion], center=true); } } module PCBEnvelope() { union() { translate([0,0,WiringThick + PCBThick + PartHeight/2]) cube([CaseInsideLength - 2*PCBMargin, CaseInsideWidth - 2*PCBMargin, PartHeight + 2*Protrusion], center=true); translate([0,0,WiringThick + PCBThick/2]) cube([CaseInsideLength,CaseInsideWidth,PCBThick],center=true); translate([0,0,WiringThick/2]) cube([CaseInsideLength - 2*PCBMargin, CaseInsideWidth - 2*PCBMargin, WiringThick + 2*Protrusion], center=true); } } module PCBLayer1() { difference() { CaseShell(PCBLayer1Thick); PCBEnvelope(); } } module PCBLayer2() { difference() { CaseShell(PCBLayer2Thick); translate([0,0,-(WiringThick + PCBThick/2)]) PCBEnvelope(); } } module Aluminum() { translate([0,0,PlateThick/2]) cube([1.1*CaseOALength,1.1*CaseOAWidth,PlateThick - Protrusion],center=true); } //------------------- // Build things... ShowPegGrid(); if ("Battery" == Layout) Battery(); if ("CaseShell" == Layout) CaseShell(CaseOAHeight); if ("BatteryLayer" == Layout) BatteryLayer(); if ("PCBEnvelope" == Layout) PCBEnvelope(); if ("PCBLayer1" == Layout) PCBLayer1(); if ("PCBLayer2" == Layout) PCBLayer2(); if ("Fit" == Layout) { BatteryLayer(); translate([0,0,BatteryHeight + PlateThick]) color("Green") PCBLayer1(); translate([0,0,BatteryHeight + PlateThick + PCBLayer1Thick]) color("Cyan") PCBLayer2(); } if ("Show" == Layout) { BatteryLayer(); translate([0,0,BatteryHeight + PlateThick + ShowGap]) color("Green") PCBLayer1(); translate([0,0,BatteryHeight + PlateThick + PCBLayer1Thick + 2*ShowGap]) color("Cyan") PCBLayer2(); } if ("Build1" == Layout) rotate(90) BatteryLayer(); if ("Build2" == Layout) rotate(90) PCBLayer1(); if ("Build3" == Layout) translate([0,0,PCBLayer2Thick]) rotate([0,180,90]) PCBLayer2();
aluminum plate with threads to suit
You’re anchoring screws in a high-vibration, high-impact environment with the scant few threads’ engagement you’ll get in an aluminum plate? Seems to me they’d tear out after a little while. However, I can’t think of a good way to put ordinary hex nuts
on the ends, as that would require recesses in the longboard to accommodate them. Hmmm.
We used 10-24 all-thread rods anchored with JB Weld, as I didn’t have any 2-1/2 inch 10-32 screws. She tapped a test coupon, clamped it in the vise, and gave the (un-glued) all-thread a mighty yanking, all to no avail. I don’t like it, but it will survive longer than anything else I can think of and it’s as good as it’ll get.
The outer end of the all-thread gets nylon locking nuts over spring washers to keep the case stack in compression.
Which was, shall we say, vetoed early in the design process… [wince]
A thicker plate moves the truck too far from the longboard; there are complex issues of balance and responsiveness and riding technique that I do not profess to understand.
I’m not entirely pleased with the overall design, but the battery’s as well-armored as I can make it within the other constraints.
The big fear: a wire shaking loose from a cell or the battery protection board, shorting a cell outside the polyfuse and protection circuitry, ending with a catastrophic lithium cell failure inside an ABS plastic case. We’ll put a dab of flexy acrylic adhesive on those joints, pack that part of the case with foam to immobilize the wires, cross our fingers and eyes, and hope for the best.
It is a way complex project and she’s learned a lot more than she expected… [grin]
I just learned of this. http://joostn.github.com/OpenJsCad/
Perhaps someone will find it useful.
I vaguely recall a mention of that on the OpenSCAD mailing list a while back; I liked the notion of not having a bunch of local dependencies for the installation. So many languages, so little time … [grin]