
After a bit of OpenSCAD twiddling, those doodles turned into a printable model. This view shows what it looks like all neatly assembled:
The tiny hole on the top of the Elevation Body accepts a 2-56 setscrew that grabs the arc protruding from the Elevation Plate and locks the up-and-down setting. The Azimuth Mount pivots on the 3-48 screw holding it to the Elevation Mount.
Both of those pivots must be loose enough to move when you bump the mirror and tight enough to stay put in normal use. It’s a delicate balance and I’m not convinced this will work for the long term, but it’s a brassboard.
The 2-56 stud on the end of the mirror shaft screws into a socket in the rear side of the Az Mount. Another 2-56 setscrew in the Az Mount (facing the El Body), grabs the side of the shaft and prevents it from rotating.
All the parts lay out on their backs for printing, with a grid to show how they fit on the build platform:

The mirror shaft shoulder on the Az Mount (front center) sticks out in mid air and requires a little bit of support.
The El Mount (left rear) builds surprisingly well with its curved top surface downward. If it’s rotated 90 degrees with the curve facing to the left, Skeinforge grumps about not being able to do something or another and generates totally bogus G-Code.
The Helmet Plate has a 3 mm deep depression that more-or-less corresponds to the helmet’s surface. It’s gouged out by a huge sphere sitting on the plate, with a radius calculated from the measured helmet curvature.
The OpenSCAD source code has two useful parameters near the top:
- Layout selects the overall appearance: Fit, Show, or Build
- Examine selects a single part for inspection & tweakage
You’ll need the MCAD and Visibone libraries to make this work. It’s the original code, without the tweaks to the grid mentioned in the comments there:
// Helmet mirror mount
// Ed Nisley KE4ZNU June 2011
include </home/ed/Thing-O-Matic/lib/MCAD/units.scad>
include </home/ed/Thing-O-Matic/lib/MCAD/boxes.scad>
include </home/ed/Thing-O-Matic/lib/visibone_colors.scad>
//-- Layout Control
Layout = "Show"; // Build Fit Show None
Examine = "None"; // AzMount ElMount ElBody ElPlate HelmetPlate None
//-- Extrusion parameters
ThreadThick = 0.33;
ThreadWT = 2.0;
ThreadWidth = ThreadThick * ThreadWT;
HoleWindage = 0; // enlarge hole dia by this amount
//-- Useful sizes
Tap2_56 = 0.070 * inch;
Clear2_56 = 0.082 * inch;
Head2_56 = 0.156 * inch;
Head2_56Thick = 0.055 * inch;
Nut2_56Dia = 0.204 * inch;
Nut2_56Thick = 0.065 * inch;
Tap3_48 = 0.079 * inch;
Clear3_48 = 0.096 * inch;
Head3_48 = 0.184 * inch;
Head3_48Thick = 0.058 * inch;
Nut3_48Dia = 0.201 * inch;
Nut3_48Thick = 0.073 * inch;
Tap4_40 = 0.089 * inch;
Clear4_40 = 0.110 * inch;
Head4_40 = 0.211 * inch;
Head4_40Thick = 0.065 * inch;
Nut4_40Dia = 0.228 * inch;
Nut4_40Thick = 0.086 * inch;
//-- Azimuth Mount
AzMountDia = 12.0;
AzMountLength = 14.0;
AzFacets = 30;
echo(str("Azmuth mount dia: ",AzMountDia," length: ",AzMountLength));
//-- Mirror sizes
MirrorShaftDia = 3.60;
MirrorShaftOffset = -1.5; // vertical offset from center of AzMountBody
MirrorShoulderLen = 3*MirrorShaftDia;
MirrorShoulderDia = min(AzMountDia,MirrorShaftDia + 6*ThreadWidth);
MirrorStudDia = Tap3_48;
MirrorStudLen = 2.0;
//-- Elevation Mount / Body / Plate
ElMountDia = AzMountDia;
ElMountLength = 2.0 + ElMountDia;
ElMountBase = 2.0;
ElMountRounding = 2.0;
ElMountFacets = AzFacets;
ElBodyWidth = ElMountDia;
ElBodyBlockLength = ElMountLength + AzMountLength/2 - MirrorShaftOffset;
ElBodyThick = 8.0;
echo(str("Elevation body overall: ",(ElBodyBlockLength + ElBodyWidth/2)," width: ",ElBodyWidth));
ElPlateTall = ElBodyBlockLength + 0.70*ElBodyWidth;
ElPlateWidth = 1.25 * ElPlateTall;
ElPlateThick = ceil(4.0 / ThreadThick) * ThreadThick;
ElPlatePlusX = ElPlateThick + (ElMountDia/2 + ElMountBase) + ElBodyThick;
echo(str("Elevation plate tall: ",ElPlateTall," width: ",ElPlateWidth));
ElArcRadius = (3/4) * ElBodyBlockLength;
ElArcThick = 4*ThreadWidth;
ElArcHeight = (1/2) * ElBodyThick;
ElArcAngle = 35;
ElArcFacets = 32;
ElPlateFacets = 52;
//-- Helmet Interface Plate
HelmetCX = 60.0;
HelmetMX = 4.0;
HelmetRX = (pow(HelmetMX,2) + pow(HelmetCX,2)/4)/(2*HelmetMX);
HelmetPlateC = max(ElPlateTall,ElPlateWidth);
HelmetPlateTheta = atan(HelmetPlateC/HelmetRX);
HelmetPlateM = 2*HelmetRX*pow(sin(HelmetPlateTheta/4),2);
HelmetPlateThick = ThreadThick*(ceil(HelmetPlateM/ThreadThick) + 1);
//-- Bearing Interfaces
BearingWidth = 3*ThreadWidth;
BearingOverlap = 3*ThreadThick;
BearingClearance = 1*ThreadThick;
BearingStudDia = min(AzMountDia,ElBodyWidth) - 2*BearingWidth;
//-- Convenience values
Protrusion = 0.1; // make holes look good
PegSize = 1.0;
//----------------------
// Useful routines
module PolyCyl(Dia,Height) { // based on nophead's polyholes
Sides = ceil(Dia) + 2;
FixDia = Dia / cos(180/Sides);
cylinder(r=(FixDia + HoleWindage)/2,
h=Height,
$fn=Sides);
}
module ShowPegGrid(Size) {
for (x=[-5:5])
for (y=[-5:5])
translate([x*10,y*10,Size/2])
cube(Size,center=true);
}
//----------------------
// Azimuth Mount
module AzMount() {
difference() {
union() {
cylinder(r=AzMountDia/2,h=AzMountLength,$fn=AzFacets); // body
translate([0,0,AzMountLength/2 + MirrorShaftOffset])
rotate([-90,0,0])
cylinder(r=MirrorShoulderDia/2,
h=MirrorShoulderLen,$fn=AzFacets); // mirror shaft shoulder
if (Layout != "Fit")
for (y=[0:1]) // shoulder support
translate([-AzMountDia/2,(4*y + AzMountDia/2 + ThreadWidth),0])
difference() {
cube([AzMountDia,2*ThreadWidth,AzMountLength/6]);
translate([AzMountDia/2,-Protrusion,AzMountLength/2 + MirrorShaftOffset])
rotate([-90,0,0])
cylinder(r=MirrorShoulderDia/2,h=ThreadWidth + 2*Protrusion);
}
}
translate([0,-Head3_48/2,AzMountLength/2 + MirrorShaftOffset])
rotate([-90,0,0])
PolyCyl(MirrorShaftDia,(AzMountDia + MirrorShoulderLen)); // mirror shaft
translate([0,-(Head3_48/2 - Protrusion),AzMountLength/2 + MirrorShaftOffset])
rotate([90,0,0])
PolyCyl(MirrorStudDia,MirrorStudLen+Protrusion); // mirror stud
translate([0,0,
Head3_48Thick - (AzMountLength - MirrorShaftDia)/2 + MirrorShaftOffset - Protrusion])
PolyCyl(Head3_48,AzMountLength + Protrusion); // mounting screw head
translate([0,0,-Protrusion])
cylinder(r=(Clear3_48 + HoleWindage)/2,
h=(AzMountLength + 2*Protrusion),
$fn=ceil(Clear3_48)+2); // mounting screw clearance
translate([0,0,AzMountLength/2 + Head3_48Thick + MirrorShaftDia/2 + MirrorShaftOffset - Protrusion])
cylinder(r1=(Head3_48/cos(180/7) + HoleWindage)/2,
r2=Clear3_48/2,
h=(3*ThreadThick + Protrusion),
$fn=7); // overhang support
translate([0,0,AzMountLength/2 + MirrorShaftOffset])
rotate([0,90,0])
PolyCyl(Tap2_56,AzMountDia/2 + Protrusion); // setscrew hole
translate([0,0,AzMountLength - (BearingOverlap + BearingClearance)])
PolyCyl(BearingStudDia,
BearingOverlap + BearingClearance + Protrusion); // bearing surface
}
}
//----------------------
// Elevation Mount
module ElMount() {
difference() {
union() {
translate([(ElMountDia/4 + ElMountBase/2),0,(ElMountLength/2 + BearingOverlap)])
rotate([0,90,0])
cube([ElMountLength,ElMountDia,(ElMountDia/2 + ElMountBase)],
center=true); // mounting block
translate([0,0,BearingOverlap]) {
// color([0.4,0.3,0.3,0.7])
cylinder(r=ElMountDia/2,
h=ElMountLength - ElMountDia/2,
$fn=ElMountFacets); // cylinder to Az
// color([0.3,0.4,0.3,0.7])
translate([0,0,ElMountLength - ElMountDia/2]) { // curved interface
intersection() {
cylinder(r=ElMountDia/2,h=ElMountDia/2,$fn=ElMountFacets);
translate([0,ElMountDia/2,0])
rotate([90,0,0])
cylinder(r=ElMountDia/2,h=ElMountDia,$fn=ElMountFacets);
}
}
}
cylinder(r=(BearingStudDia - HoleWindage)/2,h=BearingOverlap); // bearing stud
}
translate([0,0,-Protrusion])
PolyCyl(Tap3_48,(3/4)*ElMountLength + BearingOverlap + Protrusion); // AzMount screw
}
}
//----------------------
// Elevation Body
module ElBody() {
difference() {
union() {
translate([-ElBodyBlockLength,-ElBodyWidth/2,0])
cube([ElBodyBlockLength,ElBodyWidth,ElBodyThick]);
translate([0,0,ElBodyThick])
cylinder(r=(ElBodyWidth - 2*BearingWidth)/2,h=BearingOverlap);
cylinder(r=ElBodyWidth/2,h=ElBodyThick,$fn=ElMountFacets);
}
PolyCyl(Clear3_48,ElBodyThick + BearingOverlap + Protrusion);
translate([0,0,-Protrusion])
PolyCyl(Head3_48,Head3_48Thick);
translate([-ElArcRadius,0,ElBodyThick - ElArcHeight/2])
rotate([0,-90,0])
PolyCyl(Tap2_56,ElBodyBlockLength - ElArcRadius + Protrusion);
translate([0,0,ElBodyThick - (ElArcHeight + BearingClearance)])
difference() {
cylinder(r=ElArcRadius + (ElArcThick/2 + BearingClearance),
h=ElArcHeight + BearingClearance + Protrusion,
$fn=ElArcFacets);
cylinder(r=ElArcRadius - (ElArcThick/2 + BearingClearance),
h=ElArcHeight + BearingClearance + Protrusion,
$fn=ElArcFacets);
}
}
}
//----------------------
// Elevation Plate
module ElPlate() {
union() {
difference() {
translate([ElBodyWidth/2 - ElPlateTall/2,0,0])
scale([ElPlateTall,ElPlateWidth,1.0])
cylinder(r=0.5,h=ElPlateThick,$fn=ElPlateFacets);
translate([0,0,-Protrusion])
PolyCyl(Tap3_48,ElPlateThick + 2*Protrusion);
translate([0,0,ElPlateThick - (BearingOverlap + BearingClearance)])
PolyCyl(BearingStudDia,(BearingOverlap + BearingClearance) + Protrusion);
translate([0,0,-Protrusion])
cylinder(r=Nut3_48Dia/2,h=(1.1*Nut3_48Thick + Protrusion),$fn=6);
}
translate([0,0,ElPlateThick])
difference() {
cylinder(r=ElArcRadius + ElArcThick/2,
h=ElArcHeight,
$fn=ElArcFacets);
cylinder(r=ElArcRadius - ElArcThick/2,
h=ElArcHeight + Protrusion,
$fn=ElArcFacets);
rotate([0,0,90 - ElArcAngle])
translate([ElArcRadius + ElArcThick,0,ElArcHeight/2])
cube([2*ElArcRadius + ElArcThick,
2*ElArcRadius + ElArcThick,
ElArcHeight + Protrusion],
center=true);
rotate([0,0,-(90 - ElArcAngle)])
translate([ElArcRadius + ElArcThick,0,ElArcHeight/2])
cube([2*ElArcRadius + ElArcThick,
2*ElArcRadius + ElArcThick,
ElArcHeight + Protrusion],
center=true);
}
}
}
//----------------------
// Helmet Interface Plate
module HelmetPlate() {
difference() {
scale([ElPlateTall,ElPlateWidth,1.0])
cylinder(r=0.5,h=HelmetPlateThick,$fn=ElPlateFacets);
translate([0,0,HelmetRX + HelmetPlateThick - HelmetPlateM])
sphere(r=HelmetRX,$fn=256,$fs=0.1);
}
}
//----------------------
// Lash it together
if (Examine == "AzMount")
AzMount();
if (Examine == "ElMount")
ElMount();
if (Examine == "ElBody")
ElBody();
if (Examine == "ElPlate")
ElPlate();
if (Examine == "HelmetPlate")
HelmetPlate();
if ((Layout == "Build" || Layout == "Show") && Examine == "None") {
translate([-10,-20,0])
rotate([0,0,90]) // mis-align top fill from ElMount
AzMount();
translate([-10,20,ElMountLength + BearingOverlap])
rotate([0,180,-90])
ElMount();
translate([0,0,0])
rotate([0,0,0])
ElBody();
translate([10,15,0])
rotate([0,0,215]) // mis-align top fill from ElBody
ElPlate();
translate([20,-20,0])
rotate([0,0,-45])
HelmetPlate();
if (Layout == "Show")
ShowPegGrid(PegSize);
}
if ((Layout == "Fit") && Examine == "None") {
translate([0,0,-(AzMountLength/2 + MirrorShaftOffset)])
color(MFG) AzMount();
translate([0,0,AzMountLength/2 - MirrorShaftOffset - BearingOverlap])
color(DHC) ElMount();
// color([ 0/255, 204/255, 204/255,0.5]) ElMount();
translate([ElMountDia/2 + ElMountBase,0,0])
rotate([0,90,0])
color(DFC) ElBody();
translate([ElPlatePlusX,0,0])
rotate([180,90,0])
color(LHC) ElPlate();
translate([ElPlatePlusX,0,ElPlateTall/2 - ElBodyWidth/2])
rotate([0,90,0])
color(LWM) HelmetPlate();
}
Comments
3 responses to “Helmet Mirror Mount: Solid Model”
> loose enough to move when you bump the mirror and tight enough to stay put in normal use
Maybe put a compression spring under the heads of the tension screws (concealed in a square countersink), combined with cork or thin rubber at the friction point.
Along those lines, this may be another good place for rubberdraulics: a dab of silicone rubber in the hole, compressed by the setscrew. I’ve never done anything quite that small, but it should be OK. The first two mounts work OK; I may just be borrowing trouble…
[…] radius will come out crazy large for very shallow dents. Here’s the helmet plate for my Bicycle Helmet Mirror Mount, which has an indentation (roughly) matching the curve on the side of my bike […]