Longboard Lighting Case: Final Edition

After our Larval Engineer allowed as how OpenSCAD’s learning curve was rather too steep, I punched a few holes in the solid model of the case for the Longboard Ground Effect Lighting controller:

Longboard Case Solid Model - with holes

Longboard Case Solid Model – with holes

Those rounded corners sucked the Kapton tape right off the build platform as the massive shape shrank. The top layer was the worst offender, with 1.4 mm of clearance (shown with that tapered scale) under one corner:

Longboard case - warped corner

Longboard case – warped corner

The warping doesn’t matter much, because the case will be compression-loaded by screws and wave washers in the corners. We may need to fill or level the warp to keep the polycarbonate cover flat, though.

I thought about putting a support structure in the rectangular power switch opening, then decided to just try it and see what happens. It turned out fine; this view looks up toward the as-printed top of the opening (the camera’s barrel distortion makes the curve on the bottom surface look worse than it is):

Longboard case - switch hole overhang

Longboard case – switch hole overhang

Four stacked lithium cells produce upwards of 14.8 V, considerably more than those poor 12 V LED strips prefer to see, so I had her take some current vs. voltage data. She figured out how to convert 10-bit ADC values into battery voltage, after which she could, if she wanted to, beat her Arduino sketch into limiting the maximum PWM duty cycle to hold the LED power dissipation down to a reasonable number. Right now, it’s set to a fixed 25% and is way bright.

Longboard with variable RGB LED Ground Effect lighting

Longboard with variable RGB LED Ground Effect lighting

A truly crappy First Light video taken in the driveway is there. She’s been doing the Happy Dance all day… and promises to document the whole project in gruesome detail.

The OpenSCAD source code:

// Longboard Ground Effect Lighting Controller Case
// Ed Nisley KE4ZNU
// Karen Nisley KC2SYU
// August 2012

// Layout options

Layout = "Build3";
					// 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 = 15.0;				// for connections

CellHoldWidth = 6.0;					// edge to tabs
CellHoldLength = 4*ThreadWidth;

CellCount = 4;						// cells in the battery

BatteryHeight = CellCount*CellThick + 2*CellClearance;
BatteryLength = CellLength + 2*CellClearance;
BatteryWidth = CellWidth + 2*CellClearance;

PCMWidth = 16.0;						// Battery protection module
PCMLength = 51.0;
PCMThick = 4.0;							// at terminal end of cells

PillarOD = Washer10_32OD + 2*1.0;		// screw pillar diameter
PillarOffset = (PillarOD/2) / sqrt(2.0);	// distance to case inside corner

WallThick = 7.5;						// case wall thickness

PinOD = 1.4;							// alignment pin size

CaseInsideLength = BatteryLength + CellTabClearance + PCMThick;
CaseOALength = CaseInsideLength + 2*WallThick;
echo("Box Length outside: ",CaseOALength);
echo("            inside: ",CaseInsideLength);

WiringLength = CaseInsideLength - CellLength - CellHoldLength - PCMThick;	// wiring space at PCM
echo("Wiring length: ",WiringLength);

CaseInsideWidth = BatteryWidth;
CaseOAWidth = CaseInsideWidth + 2*WallThick;
echo("Box Width outside: ",CaseOAWidth);
echo("           inside: ",CaseInsideWidth);
echo("Screw OC length: ",CaseInsideLength + 2*PillarOffset);
echo("          width: ",CaseInsideWidth + 2*PillarOffset);

PCBThick = 2.0;							// PCB thickness
PCBMargin = 3.0;						// clamping margin around PCB edge
PartHeight = 17.0;						// height of components above PCB (mind the switch!)
WiringThick = 5.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);

ChargePlugOD = 11.5;					// battery charger plug
ChargeJackHeightOC = 6.5;				// coaxial jack center pin height from PCB

SwitchLength = 20.0;					// master power switch
SwitchWidth = 13.0;

WheelCableOD = 3.0;						// 3-conductor from wheel rotation sensor

LEDCableWidth = 10.0;					// 6 conductor loose wires to LED strips
LEDCableThick = 2.0;

//----------------------
// 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]) {
	  union() {
		translate([-(CaseInsideLength/2 - BatteryLength/2),0,0])
		  cube([BatteryLength,
			   BatteryWidth,
			   BatteryHeight + 2*Protrusion],
			   center=true);
		cube([CaseInsideLength,
			 (BatteryWidth - 2*CellHoldWidth),
			 BatteryHeight + 2*Protrusion],
			 center = true);
		translate([(CaseInsideLength/2 - WiringLength/2),0,0])
		  cube([WiringLength,
				max(BatteryWidth,PCMLength),
				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();
	translate([25,0,(PCBThick/2 + ChargeJackHeightOC)])
	  rotate([90,0,0])
		PolyCyl(ChargePlugOD,CaseOAWidth);
	translate([25,CaseOAWidth/2,PCBLayer2Thick/2])
	  rotate([90,0,0])
		cube([SwitchLength,SwitchWidth,CaseOAWidth],center=true);
	translate([-CaseOALength/2,0,PCBThick/2])
	  rotate([0,-90,0])
		cube([2*WheelCableOD,WheelCableOD,CaseOALength],center=true);
	translate([CaseOALength/2,0,PCBThick/2])
	  rotate([90,0,90])
		cube([LEDCableWidth,2*LEDCableThick,CaseOALength],center=true);
  }

}

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(something here!!!);

if ("BatteryLayer" == Layout)
  BatteryLayer();

if ("PCBEnvelope" == Layout)
  PCBEnvelope();

if ("PCBLayer1" == Layout)
  PCBLayer1();

if ("PCBLayer2" == Layout)
  PCBLayer2();

if ("Fit" == Layout) {
  color("LightBlue") BatteryLayer();
  translate([0,0,BatteryHeight + PlateThick])
	color("Green") PCBLayer1();
  translate([0,0,BatteryHeight + PlateThick + PCBLayer1Thick])
	color("Cyan") PCBLayer2();
}

if ("Show" == Layout) {
  color("LightBlue") 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();

About these ads

,

  1. #1 by Jetguy on 24-August-2012 - 09:12

    Time to start printing in PLA? Be sure to make the mod to that stainless tube on the MK6 to increase the thermal resistance and keep the filament cool. Maybe add a 40mm fan for good measure. PLA seems to get very soft as low as 120-130C. Once it get’s soft, it expands like a wedge in the PTFE tube.

    • #2 by Ed on 24-August-2012 - 10:20

      Time to start printing in PLA?

      I thought about that, but I’ve decided that the printer is what the printer is. Trying to improve it really isn’t worth the effort: incremental fixes won’t buy very much at all.

      I should either buy or build a printer that works better, but that’s low on the list right now. It works well enough for what I want to do…

  2. #3 by madbodger on 24-August-2012 - 21:28

    Are you ever going to post the OpenSCAD code for larval engineers? I could use another pair of hands around here!

    • #4 by Ed on 24-August-2012 - 21:38

      She’s on her way to school; all I have left is her portrait.

      They’re such long leadtime items that it’s too late to spin up another…

  1. Longboard Speed-Sensing Ground Effect Lighting « The Smell of Molten Projects in the Morning
  2. Longboard Electronics Case: Now With Mouse Ears « The Smell of Molten Projects in the Morning