Advertisements

Improved Gas Cartridge Fins

A trio of N2O cartridges / capsules made their way into the Basement Laboratory and cried out to be fitted with fins:

N2O Capsule Fins - installed

N2O Capsule Fins – installed

My original model tinkered up a cartridge from solid object primitives, but I’ve since discovered that cheating produces a much better and faster and easier result for cylindrical objects:

N2O Capsule - solid model - bottom view

N2O Capsule – solid model – bottom view

The trick is getting an image of the original object from the side, taken from far enough away to flatten the perspective:

N2O capsule - side view

N2O capsule – side view

Then overlay and scale a grid to match the actual length:

N2O capsule - grid overlay

N2O capsule – grid overlay

The grid has 1 mm per minor square, centered along the cartridge’s axis, and zeroed at the tip; I rotated the cartridge image by half a degree to line it up with the grid.

Print it out on actual paper so you can eyeball the measurements and write ’em where you need ’em:

N2O capsule - grid overlay - printed

N2O capsule – grid overlay – printed

Which becomes an OpenSCAD polygon definition:

RADIUS = 0;				// subscript for radius values
HEIGHT = 1;				//   ... height above Z=0 at seal flange

//-- N2O 8 g capsule

CartridgeOutline = [			// X values = measured radius, Y as distance from tip
	[0.0,0.0],					//  0 cartridge seal tip
	[2.5,0.1],					//  1 seal disk
	[3.5,0.5],[4.0,1.0],		//  2 tip end
	[4.2,2.0],[4.3,3.0],		//  4 tip
	[4.3,6.0],					//  6 chamfer
	[4.5,8.0],					//  7 taper
	[4.9,9.0],					//  8
	[5.5,10.0],					//  9
	[6.0,11.0],					// 10
	[6.7,12.0],					// 11
	[7.1,13.0],					// 12
	[7.5,14.0],					// 13
	[8.0,15.0],					// 14
	[8.4,16.0],					// 15
	[8.8,17.0],					// 16
	[9.0,18.0],[9.0,58.0],		// 17 body
	[0.0,65.0]					// 19 dummy end cone
	];

TipLength = CartridgeOutline[6][HEIGHT];
TipOD = 2*CartridgeOutline[5][RADIUS];
	
BodyOD = 2*CartridgeOutline[17][RADIUS];
BodyOAL = CartridgeOutline[19][HEIGHT];

Because the rounded end of the cartridge doesn’t matter, I turned it into a cone.

Twirl that around the Z axis and It Just Works:

module Cartridge() {

 rotate_extrude($fn=CartridgeSides)
 polygon(points=CartridgeOutline);

}

Which then punches a matching dent in the fin structure:

Gas Capsule Fins - Slic3r preview

Gas Capsule Fins – Slic3r preview

The lead picture doesn’t quite match the Slic3r preview, as I found the single-width diagonal fins weren’t strong enough. Making them two (nominal) threads wide lets Slic3r lay down three thinner threads in the same space:

Gas Capsule Fins - thicker - Slic3r preview

Gas Capsule Fins – thicker – Slic3r preview

That’s letting Slic3r automagically determine the infill and perimeter thread width to make the answer come out right. As nearly as I can tell, the slicing algorithms have become smart enough to get the right answer nearly all of the time, so I can-and-should relinquish more control over the details.

The OpenSCAD source code:

// CO2 capsule tail fins
// Ed Nisley KE4ZNU - October 2015

Layout = "Build"; // Show Build FinBlock Cartridge Fit

//-------
//- Extrusion parameters must match reality!
// Print with +0 shells and 3 solid layers

ThreadThick = 0.25;
ThreadWidth = 0.40;

HoleWindage = 0.2;

Protrusion = 0.1; // make holes end cleanly

function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);

//-------
// Capsule dimensions

CartridgeSides = 12*4; // number of sides

RADIUS = 0; // subscript for radius values
HEIGHT = 1; // ... height above Z=0 at seal flange

//-- N2O 8 g capsule

RW = HoleWindage/2; // enlarge radius by just enough

CartridgeOutline = [ // X values = measured radius, Y as distance from tip
 [0.0,0.0], // 0 cartridge seal tip
 [2.5 + RW,0.1], // 1 seal disk
 [3.5 + RW,0.5],[4.0 + RW,1.0], // 2 tip end
 [4.2 + RW,2.0],[4.3 + RW,3.0], // 4 tip
 [4.3 + RW,6.0], // 6 chamfer
 [4.5 + RW,8.0], // 7 taper
 [4.9 + RW,9.0], // 8
 [5.5 + RW,10.0], // 9
 [6.0 + RW,11.0], // 10
 [6.7 + RW,12.0], // 11
 [7.1 + RW,13.0], // 12
 [7.5 + RW,14.0], // 13
 [8.0 + RW,15.0], // 14
 [8.4 + RW,16.0], // 15
 [8.8 + RW,17.0], // 16
 [9.0 + RW,18.0],[9.0 + RW,58.0], // 17 body
 [0.0,65.0] // 19 dummy end cone
 ];

TipLength = CartridgeOutline[6][HEIGHT];
TipOD = 2*CartridgeOutline[5][RADIUS];

CylinderBase = CartridgeOutline[17][HEIGHT];

BodyOD = 2*CartridgeOutline[17][RADIUS];
BodyOAL = CartridgeOutline[19][HEIGHT];

//-------
// Fin dimensions

FinThick = 1.5*ThreadWidth; // outer square
StrutThick = 2.0*ThreadWidth; // diagonal struts

FinSquare = 1.25*BodyOD;
FinTaperLength = sqrt(2)*FinSquare/2 - sqrt(2)*FinThick - ThreadWidth;

FinBaseLength = 0.7 * CylinderBase;
FinTop = 0.9*CylinderBase;

//-------

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);

}

//-------
// CO2 cartridge outline

module Cartridge() {

 rotate_extrude($fn=CartridgeSides)
 polygon(points=CartridgeOutline);

}

//-------
// Diagonal fin strut

module FinStrut() {
 intersection() {
 rotate([90,0,45])
 translate([0,0,-StrutThick/2])
 linear_extrude(height=StrutThick)
 polygon(points=[
 [0,0],
 [FinTaperLength,0],
 [FinTaperLength,FinBaseLength],
 [0,(FinBaseLength + FinTaperLength)]
 ]);
 translate([0,0,FinTop/2])
 cube([2*FinSquare,2*FinSquare,FinTop], center=true);
 }
}

//-------
// Fin outline

module FinBlock() {
 
$fn=12;
 render(convexity = 4)
 union() {
 translate([0,0,FinBaseLength/2])
 difference() {
 intersection() {
 minkowski() {
 cube([FinSquare - 2*ThreadWidth,
 FinSquare - 2*ThreadWidth,
 FinBaseLength],center=true);
 cylinder(r=FinThick,h=Protrusion,$fn=8);
 }
 cube([2*FinSquare,2*FinSquare,FinBaseLength],center=true);
 }
 difference() {
 cube([(FinSquare - 2*FinThick),
 (FinSquare - 2*FinThick),
 (FinBaseLength + 2*Protrusion)],center=true);
 for (Index = [0:3])
 rotate(Index*90)
 translate([(FinSquare/2 - FinThick),(FinSquare/2 - FinThick),0])
 cylinder(r=2*StrutThick,h=(FinBaseLength + 2*Protrusion),center=true,$fn=16);
 }
 }
 
 for (Index = [0:3])
 rotate(Index*90)
 FinStrut();
 
 rotate(180/12)
 cylinder(d=IntegerMultiple(TipOD + 6*ThreadWidth,ThreadWidth),h=TipLength);
 }
}

//-------
// Fins

module FinAssembly() {

 difference() {
 FinBlock();
 translate([0,0,2*ThreadThick]) // add two layers to close base cylinder
 Cartridge();
 }

}

module FinFit() {

 translate([0,0.75*BodyBaseLength,2*ThreadThick])
 rotate([90,0,0])
 difference() {
 translate([-FinSquare/2,-2*ThreadThick,0])
 cube([IntegerMultiple(FinSquare,ThreadWidth),
 4*ThreadThick,
 1.5*BodyBaseLength]);
 translate([0,0,5*ThreadWidth])
 Cartridge();
 }


}

//-------
// Build it!

ShowPegGrid();

if (Layout == "FinStrut")
 FinStrut();

if (Layout == "FinBlock")
 FinBlock();

if (Layout == "Cartridge")
 Cartridge();

if (Layout == "Show") {
 FinAssembly();
 color("LightYellow") Cartridge();
}

if (Layout == "Fit")
 FinFit();

if (Layout == "Build")
 FinAssembly();
Advertisements

,

  1. #1 by Daniel B Martin on 2015-10-09 - 08:40

    Have you taken to huffing this stuff? ;-O

    • #2 by Vedran on 2015-10-09 - 09:38

      I usually take the picture, do a perspective correction if needed and then import it into SketchUp (or whatever tool I’m using for the project), scale it in place and trace the outline directly. Works a charm, and no trees need to be harmed by printing it out… well unless it’s a woodworking project :)
      I tried using OpenSCAD for non trivial objects, but it turned out much slower then using a point and click CAD package. I even tried that OpenSCAD front-end but it doesn’t really add anything to the party – or more likely, I was using it wrong :)

    • #3 by Ed on 2015-10-09 - 10:25

      I salvaged those from the guy doing whipped cream at a Locust Grove Sunset Sensations fundraiser and, for sure, he didn’t have time for huffing!