The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

3D Printed 20×102mm Cartridge

Having accumulated a box of empty 12 gram CO₂ capsules and having already done Too Many bomb fins:

20x102mm cartridges
20x102mm cartridges

The capsule is obviously the wrong shape, too short, and only 19 mm diameter, but it’s the thought that counts.

Apply the contour gauge to a genuine slightly battered 20×102mm cartridge:

20x102mm cartridge tracing
20x102mm cartridge tracing

Scan the sketch, import into Inkscape, rotate the image to correct the case taper angle vs. the page, lay lines & curves around the perimeter, align half of it at the page origin to work with OpenSCAD, export as SVG:

Cartridge - 20x102mm outline - Inkscape layout
Cartridge – 20x102mm outline – Inkscape layout

Import into OpenSCAD, let rotate_extrude do the heavy lifting, and remove some pieces:

Cartridge Case - build view solid model
Cartridge Case – build view solid model

The little disk represents a fired primer you’d print separately in a different color and glue into the pocket shown in this cutaway view:

Cartridge Case - cutaway solid model
Cartridge Case – cutaway solid model

The interior void could hold sand for additional heft, as the whole thing is obviously nose-heavy; that’s certainly in the nature of fine tuning. Obviously, we are not dealing with anything that could go bang.

It builds just like you’d expect:

20x102mm cartridge - printing
20x102mm cartridge – printing

Dab some adhesive on the capsule tip, ditto for the primer, stick them in place, and it’s all good.

I like the gray PETG-CF version:

20x102mm cartridges - blue gray PETG-CF
20x102mm cartridges – blue gray PETG-CF

Maybe not such a good idea in this day & age. Print responsibly, as they say.

Update

Print a sabot to fit a CO₂ capsule into a genuine steel cartridge.

The solid model:

Cartridge Case - sabot solid model
Cartridge Case – sabot solid model

The OpenSCAD making it happen:

module Sabot() {
tube(SabotOA[LENGTH],id=SabotOA[ID],od=SabotOA[OD],anchor=BOTTOM)
    position(BOTTOM)
      tube(SabotOA[LENGTH]/2,id=SabotOA[ID],od=CartridgeOA[ID],anchor=BOTTOM);
}

The result:

20x102mm cartridges
20x102mm cartridges

The OpenSCAD source code (minus the sabot) and outline as a GitHub Gist:

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
// 20x102mm cartridge
// Ed Nisley – KE4ZNU
// 2025-05-18
include <BOSL2/std.scad>
Layout = "Show"; // [Show,Build]
Powder = true; // build internal void
/* [Hidden] */
ID = 0;
OD = 1;
LENGTH = 2;
HoleWindage = 0.2;
Protrusion = 0.1;
NumSides = 3*3*4;
$fn = NumSides;
CartridgeOA = [21.0,29.5,101.4]; // must match SVG pretty closely
PrimerOA = [2.0,8.0,2.0];
CapsuleTip = [7.5,7.5,5.0];
Capsule = [7.5,18.8 + HoleWindage,83];
SeatingDepth = 25.0;
Void = [CartridgeOA[ID]- 4.0,CartridgeOA[OD]- 4.0,CartridgeOA[LENGTH] – SeatingDepth – 4*PrimerOA[LENGTH]];
//———-
// Define shapes
module Cartridge() {
difference() {
rotate_extrude()
import("Cartridge – 20x102mm outline.svg",layer="Cartridge Aligned Half");
up(PrimerOA[LENGTH])
cyl(PrimerOA[LENGTH] + Protrusion,d=PrimerOA[OD],anchor=TOP);
up(CartridgeOA[LENGTH] + CapsuleTip[LENGTH])
cyl(SeatingDepth,d=Capsule[OD],anchor=TOP);
up(CartridgeOA[LENGTH] – SeatingDepth)
cyl(Void[LENGTH],d=CapsuleTip[OD],anchor=BOTTOM);
if (Powder) {
up(Void[LENGTH]/2)
cyl(Void[LENGTH],d=CapsuleTip[OD],anchor=BOTTOM);
up(2*PrimerOA[LENGTH])
cyl(Void[LENGTH],d=Void[OD],rounding=Void[OD]/2,anchor=BOTTOM);
down(Protrusion)
cyl(Void[LENGTH],d=PrimerOA[ID],anchor=BOTTOM);
}
}
}
module Primer() {
difference() {
cyl(PrimerOA[LENGTH] – Protrusion,d=PrimerOA[OD] – HoleWindage,anchor=BOTTOM);
up(PrimerOA[LENGTH])
spheroid(d=PrimerOA[ID]);
}
}
//———-
// Build things
if (Layout == "Show")
//render()
difference() {
Cartridge();
cuboid(3*CartridgeOA[LENGTH],anchor=LEFT+BACK);
}
if (Layout == "Build") {
Cartridge();
right(CartridgeOA[OD])
Primer();
}