40mm NATO to Honeywell North adapter

Posted 05/20/25 #gasmask #project

Low quality article but better than never posting it.

I have a MSA Millenium full-face respirator. My primary purpose in owning it is that it is drip, and also I love equipment. For those keeping score at home, no, I don't have the sun-shade outsert. However despite being drip on it's own, it would be nice to be able to use it for it's intended purpose (respiratory protection.)

Certainly 40mm NATO cartridges are an option, but most of them are intended for CW agents and are big, heavy, and chemically active with limited shelf life. I'm primarily interested in particle filtration (i.e. the same thing you wear a facemask for) not filtering out CS gas or whatever. The relevant spec for this is usually "P100" or "P99" filtration; as opposed to the term for filtering out chemical warfare agents which is usually "Enforcement." Such filters exist, but they seem weird/rare (and still big.)

Plenty of cartridge-based P100 filters exist for various other equipment, such as these 3M cartridge P100 filters. For that kind of filter, 3M sells an OEM adapter to 40mm NATO for a reasonable price. Unfortunately, the actual cartridges are grey and square and fuck the drip.

The Honeywell North line of respirators has some nice cartridge options from very cheap P100 filters (easily colorable to black) to organic vapor (interesting to a friend of mine with her own FFR + black to start with). Unfortunately, they don't offer an OEM adapter to 40mm NATO. Some helpful character on Thingiverse designed and posted such an adapter. Awesome! Unfortunately, it's really freaking long. So long that it sticks way out of the FFR and also kinda fucks the drip.

So I decided to look at CAD for the first time since high school and try to make my own go at it. I briefly looked at FreeCAD but it kept crashing on my laptop and the thread tool was scaring me :P. So instead I regressed to my base FOSSHead instincts and started mucking around in OpenSCAD.

Wow! OpenSCAD is cool as hell, and I quickly found someone that had a Bezier and thread library published for OpenSCAD that made quite quick work of figuring out how to model the threading. I ended up approximating the 40mm threading with a Bezier curve...

nato_pitch = 3.629;
nato_r = 1.225;

pi = 3.1415;
piscale = nato_pitch / (2*pi);

rscale = 2;

bezccpoints = [
    [-nato_r/rscale, 0, ],
    [-nato_r/rscale, (pi-2)*piscale, ],
    [nato_r/rscale, 2*piscale, ],
    [nato_r/rscale, pi*piscale, ],
    
    [nato_r/rscale, (pi+(pi-2))*piscale, ],
    [-nato_r/rscale, (pi+2)*piscale, ],
    [-nato_r/rscale, (2*pi)*piscale, ]
];

bezpoints = Bezier(bezccpoints);

polygon(bezpoints);

...which produces...

which is about right. Then instead of just extruding the profile with polygon() we can instead revolve it with the thread library...

nato_d1 = 40;
nato_d2 = 38.4;
nato_dd = nato_d2 - nato_d1;
nato_length = 7;
cowl_length = 3.125; // little less than 1/8"

rawThread(bezpoints, d=nato_d1 + nato_dd, adjustRadius=true, h=nato_length+cowl_length);

...to produce...

which fits!

(Later I would discover this article about doing the exact same thing that includes some better dimensional drawings. Probably should redo this at some point to be a better hemispherical thread. Aside: check out that person's username. EITSP.)

The Honeywell North threading is a published normal thread standard which is really easy to do with the thread library.

north_d1 = 25.5 * north_dscale;
north_pitch = 1.5;
north_length = 6;
isoThread(d=north_d1, h=north_length, pitch=north_pitch, internal=false, $fn=60);

We can then combine them (and so some trickery I may write at more length about later) to produce an adapter that is as flush as possible:

difference() {
    union() {
        difference() {
            rawThread(bezpoints, d=nato_d1 + nato_dd, adjustRadius=true, h=nato_length+cowl_length);
            translate([0, 0, nato_length]) cylinder(cowl_length+nudge, d=nato_d1 - cowl_wall);
        }
        translate([0, 0, nato_length]) isoThread(d=north_d1, h=north_length, pitch=north_pitch, internal=false, $fn=60);
    }
    translate([0, 0, -nudge]) cylinder(nato_length+north_length+nudge2, d=north_id);
};

...which looks like...

This nests the length of the North threading inside the length of the 40MM threading, making the filter stick out as little as possible.

It could be made even a tighter fit, but then you wouldn't be able to remove the outsert without removing the filter.

Download the OpenSCAD source or STL if you'd like, licensed under the NPL. Contact me for alternative licensing arrangements.