-
HQ Sixteen: Grip Angle Caps
The stock Handi-Quilter HQ Sixteen has serviceable black rubber caps covering the holes for the grips:

HQ Sixteen – original front handlebar mount Because we live in the future, I can do better than that:

HQ Sixteen – grip cap left In truth, the plastic grip plug now sticks up into the hole just beyond the top setscrews, leaving not enough room for the black plugs, so I had to make new covers.
They’re a multi-material print using white PETG to kinda-sorta match the machine and blue PETG-CF to match the other plastic parts. The colors in the solid model just distinguish the two materials:

Handlebar Grip Mount – plug caps – solid model The white covers have recesses exactly fitting the text:

Handlebar Grip Mount – cap text recess – solid model In some cases that’s not needed, but I’m unsure how PrusaSlicer knows what I intend and chopping the text out was easy, so that’s how I did it.
I did not realize applying a transformation, like
translate()or BOSL2’s syntactic sugarleft(), to both the cover and the text implicitly joins them into a single “object”, so the slicer can’t distinguish them as separate materials. As a result, the OpenSCAD code must move the pieces separately:if (Layout == "Covers") { left(Plug[OD]) GripCover(LEFT,"Cover"); left(Plug[OD]) GripCover(LEFT,"Text"); right(Plug[OD]) GripCover(RIGHT,"Cover"); right(Plug[OD]) GripCover(RIGHT,"Text"); }Which is awkward, but not insurmountable.
Export the model as a
3mffile, import it into PrusaSlicer, and you get separate objects for the cover and the text. Assign different materials and slice to produce a multi-material result, with the Wipe Tower in the background:
Handlebar Grip Mount – cap first layer – PrusaSlicer They must print face down to merge the two colors into a single flat surface with a nubbly texture from the steel sheet’s coating.
Disks of adhesive sheet will eventually stick them atop the plugs, but for now they’re just dropped into the holes.
The OpenSCAD source code as a GitHub Gist:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters// Handiquilter HQ Sixteen front handlebar grip angle mount // Ed Nisley – KE4ZNU // 2024-11-29 include <BOSL2/std.scad> Layout = "Show"; // [Show,Build,Plug,Block,Covers,Cover] Material = "All"; // [All,Cover,Text] // Angle w.r.t. base GripAngle = 20; // [10:30] // Plug glued, not screwed PlugGlue = true; // Square nuts, not inserts SquareNuts = true; // Additional length of bottom AddLength = 0; // [0:20] // Separation in Show display Gap = 5; // [0:20] /* [Hidden] */ HoleWindage = 0.1; Protrusion = 0.1; NumSides = 2*3*4; ID = 0; OD = 1; LENGTH = 2; Grip = [19.7,22.4,20.0]; // (7/8)*INCH = 22.2 mm + roughness, LENGTH=OEM insertion depth GripRadius = Grip[OD]/2; // used everywhere Plug = [15.0,Grip[OD],45.0]; // inserts into handlebar base PlugRim = [Plug[ID],25.0,10.0]; // … sits against handlebar base BaseScrewPositions = [[11.0,12.0],[27.0,29.0]]; // setscrew offsets from rim top: side,rear BaseCutout = [Plug[OD]/2,Plug[ID],10]; // cable cutout into base BaseCutoutOffset = 18.0; // … centerline position w.r.t. rim WallThick = 7.0; // should at least fit insert length SupportSag = 0.4; // vertical sag over support structure MidLength = AddLength + 3.0; // total length allowing for grip tube stop TopOD = PlugRim[OD] + 2*WallThick; BotOD = Grip[OD] + 2*WallThick; BaseScrew = [4.0,4.8 + HoleWindage,1.0]; // HQ 10-32 screws, LENGTH=capture dent Insert = [5.4,6.0,6.0]; // M4 inserts in plug rim //Insert = [4.0,5.0,5.0]; // M4 inserts in plug rim Screw = [3.5,4.0,1]; // M4 screws through angle block to inserts ScrewHeadOD = 7.4 + 0.4; // M4 BHCS head + comfort SquareNut = [4.0,7.0,3.0 + 0.4]; // M4 square nut LENGTH + inset allowance NutInset = GripRadius – sqrt(pow(GripRadius,2) – pow(SquareNut[OD],2)/4); PinOD = 1.2; // plug reinforcing pins NumPins = 5; CoverThick = [3.5,9.5]; // low and high sides of grip covers CoverAngle = atan((CoverThick[1] – CoverThick[0])/Plug[OD]); LogoText = ["Sew","Fine"]; LogoFont = "Fira Sans Condensed:style=SemiBold"; LogoSize = 7.5; LogoColor = "Red"; LogoThick = 0.8; //———- // Simulator for aluminum plug replacing handlebar in base module BasePlug() { difference() { union() { tube(Plug[LENGTH],(Plug[OD] – HoleWindage)/2,Plug[ID]/2,anchor=DOWN); tube(PlugRim[LENGTH],PlugRim[OD]/2,PlugRim[ID]/2,anchor=DOWN); } up(BaseCutoutOffset + PlugRim[LENGTH]) left(Plug[OD]/4) resize(BaseCutout) yrot(90) zrot(180/8) cylinder(d=1,h=1,$fn=8,center=true); up(PlugRim[LENGTH]) right(PlugRim[OD]/2 – 1.0) cube([2.0,1.0,1.0],center=true); for (i = [0:NumPins – 1]) zrot(i*360/NumPins + 180/NumPins) down(Protrusion) right((Plug[OD] + Plug[ID])/4) zrot(180/6) cylinder(d=PinOD,h=2*PlugRim[LENGTH],$fn=6); for (k = [0:1]) // recesses in plug to capture base setscrews for (a = [0:1]) up(PlugRim[LENGTH] + BaseScrewPositions[k][a]) zrot(a*90) right(Plug[OD]/2) yrot(90) zrot(180/8) cylinder(d=BaseScrew[OD],h=2*BaseScrew[LENGTH],$fn=8,center=true); if (!PlugGlue) for (a = [0:1]) // inserts for angle block screws up(PlugRim[LENGTH]/2) zrot(a*90) yrot(90) zrot(180/8) cylinder(d=Insert[OD],h=2*PlugRim[OD],$fn=8,center=true); } } //———- // Block fitting against handlebar base with handlebar angle module AngleBlock() { difference() { hull() { up((TopOD/2)*sin(GripAngle)) xrot(GripAngle) cylinder(d=TopOD,h=PlugRim[LENGTH],$fn=NumSides); for (a = [1:2:GripAngle+1]) up((TopOD/2)*sin(a-1)) hull() { xrot(a) cylinder(d=TopOD,h=0.1,$fn=NumSides); xrot(a-1) cylinder(d=TopOD,h=0.1,$fn=NumSides); } down(Grip[LENGTH] + MidLength) cylinder(d=(Grip[OD] + 2*WallThick),h=0.1,$fn=NumSides); } up((TopOD/2)*sin(GripAngle)) xrot(GripAngle) down(SupportSag) cylinder(d=(PlugRim[OD] + HoleWindage), h=PlugRim[LENGTH] + SupportSag + Protrusion, $fn=NumSides); up((TopOD/2)*sin(GripAngle)) sphere(d=PlugRim[ID],$fn=NumSides); cylinder(d=PlugRim[ID],h=(TopOD/2)*sin(GripAngle),$fn=NumSides); down(MidLength + Protrusion) cylinder(d=(Grip[ID] – 2.0),h=(MidLength + 2*Protrusion),$fn=NumSides); down(Grip[LENGTH] + MidLength + Protrusion) cylinder(d=(Grip[OD] + HoleWindage),h=(Grip[LENGTH] + Protrusion),$fn=NumSides); up((TopOD/2)*sin(GripAngle)) xrot(GripAngle) up(PlugRim[LENGTH]) right(PlugRim[OD]/2 + 0.9) cube([2.0,1.0,1.0],center=true); if (!PlugGlue) { for (a = [0:1]) up((TopOD/2)*sin(GripAngle)) xrot(GripAngle) up(PlugRim[LENGTH]/2) zrot(a*90) yrot(90) zrot(180/8) cylinder(d=Screw[OD],h=3*PlugRim[OD],$fn=8,center=true); for (a = [0:3]) up((TopOD/2)*sin(GripAngle)) xrot(GripAngle) up(PlugRim[LENGTH]/2) zrot(a*90) right(TopOD/2 – 2.0) yrot(90) zrot(180/8) cylinder(d=ScrewHeadOD,h=TopOD,$fn=8,center=false); } if (SquareNuts) { for (a = [0:1]) for (k = [1,3]) down(k*Grip[LENGTH]/4 + MidLength) zrot(a*90) right(BotOD/2) yrot(90) zrot(180/8) cylinder(d=SquareNut[ID],h=BotOD,$fn=8,center=true); for (a = [0:1]) for (k = [1,3]) down(k*Grip[LENGTH]/4 + MidLength) zrot(a*90) right(GripRadius + SquareNut[LENGTH]/2 – NutInset/2) yrot(90) cube([SquareNut[OD],SquareNut[OD],SquareNut[LENGTH] + NutInset],center=true); } else { for (a = [0:1]) for (k = [1,3]) down(k*Grip[LENGTH]/4 + MidLength) zrot(a*90) right(BotOD/2) yrot(90) zrot(180/8) cylinder(d=Insert[OD],h=BotOD,$fn=8,center=true); } } } //———- // Chip fitting against handlebar base matching top angle // Text will be invisible until sliced module GripCover(loc=LEFT,matl="Cover") { if (matl == "Text" || matl == "All") color(LogoColor) down(matl == "All" ? 0.01 : 0.0) text3d(LogoText[loc == LEFT ? 0 : 1],LogoThick,LogoSize,LogoFont, orient=DOWN,anchor=TOP,atype="ycenter"); if (matl == "Cover" || matl == "All") difference() { intersection() { yrot(loc == RIGHT ? -CoverAngle : CoverAngle) cylinder(d=Plug[OD],h=(CoverThick[0] + CoverThick[1]),anchor=CENTER); cube(2*Plug[OD],anchor=BOTTOM); } text3d(LogoText[loc == LEFT ? 0 : 1],LogoThick,LogoSize,LogoFont, orient=DOWN,anchor=TOP,atype="ycenter"); } } //———- // Build things if (Layout == "Cover") { GripCover(LEFT,Material); } if (Layout == "Covers") { left(Plug[OD]) GripCover(LEFT,"Cover"); left(Plug[OD]) GripCover(LEFT,"Text"); right(Plug[OD]) GripCover(RIGHT,"Cover"); right(Plug[OD]) GripCover(RIGHT,"Text"); } if (Layout == "Plug") BasePlug(); if (Layout == "Block") AngleBlock(); if (Layout == "Show") { up((TopOD/2)*sin(GripAngle) + Protrusion) xrot(GripAngle) up(Plug[LENGTH] + CoverThick[1] + Gap) yrot(180 + CoverAngle) GripCover(RIGHT,"All"); up((TopOD/2)*sin(GripAngle) + Protrusion) xrot(GripAngle) up(Gap) color("Lime",0.75) BasePlug(); render() difference() { AngleBlock(); back(50) right(50) cube(100,center=true); } color("Silver",0.5) down(MidLength + Gap) tube(3*Grip[LENGTH],GripRadius,Grip[ID]/2,anchor=TOP); } if (Layout == "Build") { mirror_copy([1,0,0]) { right(BotOD) { up((TopOD/2)*sin(GripAngle) + PlugRim[LENGTH]*cos(GripAngle) + Protrusion) xrot(180 – GripAngle) AngleBlock(); back(1.5*max(TopOD,BotOD)) BasePlug(); } } fwd(60) { left(Plug[OD]) GripCover(LEFT,"Cover"); right(Plug[OD]) GripCover(RIGHT,"Cover"); } fwd(60) { left(Plug[OD]) GripCover(LEFT,"Text"); right(Plug[OD]) GripCover(RIGHT,"Text"); } }