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.

The New Hotness

  • Drive Wheelchair Brake Knob

    The bent-steel brake levers on our Drive Blue Streak wheelchair present themselves edge-on to the rider:

    Drive Wheelchair Brake
    Drive Wheelchair Brake

    There are good mechanical reasons for shaping and orienting the steel like that, but the handle concentrates the considerable force required to push the brake tab into the rubberoid tire on your (well, my) palms. After a couple of weeks, I decided I didn’t need two more sore spots and conjured a palm-filling knob from the vasty digital deep:

    Wheelchair Brake Knob - installed
    Wheelchair Brake Knob – installed

    Bonus part: the little octagon near the wheel prevents the leg rest (seen in the first picture) from smashing into the end of the brake tab and chipping the lovely blue powder coat. The brown fuzzy felt foot seemed like a good idea at the time, but isn’t strictly necessary.

    A cylindrical handle on Thingiverse apparently fits on the bare steel underneath the rubberish “cushion”, but cutting a perfectly good, albeit uncomfortable, cushion off seemed like a step in the wrong direction. My knob thus descends from a doodle of the OEM dimensions:

    Drive Wheelchair Brake Handle - dimensions
    Drive Wheelchair Brake Handle – dimensions

    The knob builds in two halves adjoining the bonus octagon, which stands on edge to eliminate support inside its slot:

    Wheelchair Brake Mods - solid model - build layout
    Wheelchair Brake Mods – solid model – build layout

    You (probably) need two of all those shapes, a job your slicer is ready to perform. At three hours for each knob, I just printed the same G-Code twice.

    You can customize the knob width to fit your palm, with the other two dimensions fitting themselves around the cushion. Mary and I settled on a knob size that fits both our hands reasonably well, so it’s probably not critical.

    I tried building the knob halves without support for the first prototype, but the sloped upper surface produced awful bridging:

    Wheelchair Brake Knob - unsupported interior
    Wheelchair Brake Knob – unsupported interior

    It’s easy enough to design a customized support structure:

    Wheelchair Brake Mods - cross section
    Wheelchair Brake Mods – cross section

    I oriented the knob to put the split on the narrow sides of the brake handle in order to not have a seam facing my palm:

    Wheelchair Brake Knob - rear half installed
    Wheelchair Brake Knob – rear half installed

    The quartet of M3×20 mm socket-head cap screws thread into brass inserts epoxied into the rear half. I recessed their heads deeply into the front half and avoided thinking too hard about plugs matching the surface curvature:

    Wheelchair Brake Knob - front view
    Wheelchair Brake Knob – front view

    The low-vertex-count polygonal shape is a stylin’ thing and produces a nice feel during a firm shove, at least to my paws. Although I’d rather not need a wheelchair at all, setting the brakes now seems authoritative instead of annoying.

    The OpenSCAD source code as a GitHub gist:

    // Pride wheelchair brake lever mods
    // Ed Nisley KE4ZNU 2020-11
    /* [Layout options] */
    Layout = "Build"; // [Build, Show, Fit, TabCap, Handle, Knob, Support]
    // Hold up the knob's inside
    Support = true;
    /* [Extrusion parameters] */
    /* [Hidden] */
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    HoleWindage = 0.2;
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    function IntegerLessMultiple(Size,Unit) = Unit * floor(Size / Unit);
    Protrusion = 0.1; // make holes end cleanly
    inch = 25.4;
    ID = 0;
    OD = 1;
    LENGTH = 2;
    //———————-
    // Useful routines
    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);
    }
    //* [Basic dimensions] */
    WallThick = 4.0; // min wall thickness
    Screw = [3.0,5.5,20.0]; // thread, head, length under head
    Insert = [3.0,4.1,8.0]; // thread, knurl, length
    //———————-
    // Brake tab cap
    BrakeTab = [15,21,3.1]; // length to wheel, width, thickness
    BrakeTabSagitta = 8.0; // height of curved endcap
    CapOAL = [BrakeTab.y + 2*WallThick,BrakeTab.y + 2*WallThick,BrakeTab.z + 2*WallThick];
    module TabCap() {
    difference() {
    rotate(180/8)
    cylinder(d=CapOAL.y,h=CapOAL.z,center=true,$fn=8);
    translate([BrakeTab.x/2,0,0])
    cube(BrakeTab,center=true);
    rotate(180/8)
    cylinder(d=BrakeTab.y/cos(180/8),h=BrakeTab.z,center=true,$fn=8);
    }
    }
    //———————-
    // Brake lever handle
    // Soft covering with rounded sides that we square off for simplicity
    HandleRibs = [15,34,14]; // ignoring slight taper from end
    HandleCore = [50.0,24.0,12.0]; // straight section of lever to top of ribs
    HandleTipWidth = 30.0; // ignoring actual sector height
    module Handle() {
    union() {
    hull() {
    rotate(180/8)
    cylinder(d=HandleTipWidth/cos(180/8),h=HandleCore.z,center=true,$fn=8);
    translate([-HandleCore.x/2,0,0])
    cube(HandleCore,center=true);
    }
    translate([-(3*HandleCore.x/2 – Protrusion),0,0]) // extend base for ball trimming
    cube(HandleCore,center=true);
    translate([-HandleRibs.x/2,0,0])
    cube(HandleRibs,center=true);
    }
    }
    //———————-
    // Support structure for handle cavity inside knob
    // Totally ad-hoc tweakage
    // Remember it's lying on its side to match the handle
    NumRibs = 2 + 1; // must be odd
    RibSpace = floor(HandleCore.z/(NumRibs + 1));
    module KnobSupport() {
    color("Yellow") { // support overlaps in the middle
    render(convexity=3)
    intersection() {
    for (k=[-1,1])
    translate([0,k*ThreadThick,0]) // shrink inward to break adhesion
    Handle();
    translate([(HandleCore.x – HandleRibs.x)/2 – HandleCore.x – Protrusion,0,0])
    cube([HandleCore.x – HandleRibs.x,HandleRibs.y,HandleCore.z],center=true);
    union()
    for (k=[-floor(NumRibs/2):floor(NumRibs/2)])
    translate([0,0,k* RibSpace])
    cube([2*HandleCore.x,HandleRibs.y,2*ThreadWidth],center=true);
    }
    translate([(HandleCore.x – HandleRibs.x)/2 – HandleCore.x,0,0])
    cube([HandleCore.x – HandleRibs.x,4*ThreadWidth,NumRibs*RibSpace],center=true);
    }
    }
    //———————-
    // Brake handle knob
    // Largely built with magic numbers
    // Includes support because it's not really optional
    KnobOD = 55.0;
    KnobOffset = HandleRibs.x/1;
    KnobSides = 2*4*3;
    module Knob() {
    difference() {
    hull() {
    resize([0,HandleRibs.y + 4*WallThick,HandleCore.x + HandleTipWidth/2 + WallThick])
    sphere(d=KnobOD,$fn=KnobSides);
    }
    translate([0,0,KnobOffset])
    rotate([0,-90,0])
    Handle();
    for (i=[-1,1],k=[-1,1])
    translate([i*KnobOD/4,0,k*KnobOD/4]) {
    rotate([90,0,0])
    PolyCyl(Insert[OD],1.5*Insert[LENGTH],6);
    translate([0,-Screw[LENGTH]/2,0])
    rotate([-90,0,0])
    PolyCyl(Screw[ID],KnobOD,6);
    translate([0,Screw[LENGTH] – Insert[LENGTH],0])
    rotate([-90,0,0])
    PolyCyl(Screw[OD],KnobOD,6);
    }
    }
    if (Support)
    translate([0,0,KnobOffset])
    rotate([0,-90,0])
    KnobSupport();
    }
    //———————-
    // Lash it together
    if (Layout == "TabCap") {
    TabCap();
    }
    if (Layout == "Handle") {
    Handle();
    }
    if (Layout == "Support") {
    KnobSupport();
    }
    if (Layout == "Knob") {
    Knob();
    }
    if (Layout == "Show") {
    translate([60,0,0])
    TabCap();
    Knob();
    }
    if (Layout == "Fit") {
    translate([60,0,0])
    difference() {
    TabCap();
    translate([0,0,CapOAL.z/2])
    cube(CapOAL,center=true);
    }
    difference() {
    Knob();
    translate([KnobOD + KnobOD/4,0*KnobOD,0])
    cube(2*KnobOD,center=true);
    translate([-KnobOD,-KnobOD,0])
    cube(2*KnobOD,center=true);
    }
    }
    if (Layout == "Build") {
    translate([KnobOD/2,0,(CapOAL.y*cos(180/8))/2])
    rotate([0,-90,90])
    TabCap();
    for (j=[-1,1])
    translate([0,-j*0.75*HandleCore.x,0])
    difference() {
    rotate([j*90,0,0])
    Knob();
    translate([0,0,-KnobOD])
    cube(2*KnobOD,center=true);
    }
    }

    A doodle with dimensions of other parts:

    Drive Wheelchair - brake footrest tab dimensions
    Drive Wheelchair – brake footrest tab dimensions

    The angled tab on the middle left is for the leg rest release latch, but I decided not to silk-purse-ize the thing.