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.

Category: Recumbent Bicycling

Cruisin’ the streets

  • Sandisk 64 GB High Endurance MicroSD Card: End of Life

    Sandisk 64 GB High Endurance MicroSD Card: End of Life

    After about 7.5 years (!) the 64 GB card in my Sony HDR-AS30V helmet camera breathed its last:

    SanDisk 64 GB MicroSD card - end of life
    SanDisk 64 GB MicroSD card – end of life

    Over the course of several rides I noticed many video files ended prematurely or would not play. I gave up attempting to reformat the card in overwrite mode using the Official SD Card formatter after four hours, which says the wear leveler in the card has no spare capacity.

    In round numbers, I ride 1700 miles a year at 12 mph, so the card recorded 1000 hours of 1920×1080 video at 60 frame/s, storing one 4.3 GB file every 22.75 minutes for a grand total of 12 TB of data.

    Although that’s 188 times the capacity of the card, it rarely held more than an hour or two of data at any one time, because I copy the camera video files to a 3 TB USB hard drive after each ride. I don’t know how the exFAT file system interacts with the card’s wear leveling, but overall it’s much better than the non-high-endurance cards I’d been using way back when.

    A new Sandisk 128 GB High Endurance card cost a third of what the 64 GB card did and, after setting the partition label to AS30V, it’s off to a good start:

    Street Lamp Pole - Rombout House Ln - 2025-05-07
    Street Lamp Pole – Rombout House Ln – 2025-05-07

    That’s the street lamp pole installed on the replaced base at the corner of Rt 376 and Rombout House Lane, with the barrels gradually being pushed closer and closer to the pole by turning traffic on the newly paved lane.

    That pole is not going to see the end of this year.

    Update: The barrels vanished this morning:

    Street Lamp Pole - Rombout House Ln - 2025-05-08
    Street Lamp Pole – Rombout House Ln – 2025-05-08

    Definitely the triumph of hope over experience.

  • Tour Easy: Broken Seat Parts

    Tour Easy: Broken Seat Parts

    So hardened socket head cap screws survive fifteen years of hard service on my Tour Easy’s seat stay:

    Tour Easy - broken seat stay screw
    Tour Easy – broken seat stay screw

    I replaced both screws with stainless steel 1-½ 10-32 socket head screws, with a reshaped head on the drive side, and we’ll see how long these last.

    A few days later the continuing creak led to finding a broken gear clamp on the left side of the seat back:

    Tour Easy - replacement seat frame clamp
    Tour Easy – replacement seat frame clamp

    Apart from the atypical lack of grime, you couldn’t tell that’s the replacement clamp, because the broken one looked exactly the same way. The clamp strap broke where it bent around the bottom edge of the seat pan bracket, probably due to the flexing caused by the broken seat stay screw.

    Riding season is in full effect!

  • Cycling Shoe Sole Carving

    Cycling Shoe Sole Carving

    As before, the sole & lugs on Mary’s new Specialized cycling shoes requires too much torque to release the cleat, so I once again carved off everything that got in the way:

    Cycling shoe sole carving
    Cycling shoe sole carving

    A field test prompted a little more carving, but you get the general idea.

    This surely affects the shoes’ lateral stability, but getting her feet out of the cleats when & where needed outweighs everything else.

  • Royal Carting Truck: Squeeze Play

    Royal Carting Truck: Squeeze Play

    I’m riding downhill from Red Oaks Mill toward the bridge across the Wappinger Creek, pedaling a bit over 24 mph = 37 feet/sec, far enough into the lane to avoid trash along the curb on the right:

    Royal front 2024-09-13 - 078
    Royal front 2024-09-13 – 078

    Although you can barely see the vehicle passing on my left, I’ve just realized I am in one heap of trouble.

    Half a second later (the frame number in the caption ticks along at 60 fps) I’m caught in the slipstream:

    Royal front 2024-09-13 - 108
    Royal front 2024-09-13 – 108

    Another half second and I’m leaning slightly to the right:

    Royal front 2024-09-13 - 138
    Royal front 2024-09-13 – 138

    Make that wobbling:

    Royal front 2024-09-13 - 158
    Royal front 2024-09-13 – 158

    Well, that’s a relief:

    Royal front 2024-09-13 - 178
    Royal front 2024-09-13 – 178

    The truck is now completely within our lane and I’m further to the right, so our paths really were converging:

    Royal front 2024-09-13 - 208
    Royal front 2024-09-13 – 208

    Elapsed time: 2.2 seconds.

    The view from the rear shows the driver started with reasonable clearance (these frames tick at 30 fps):

    Royal rear 2024-09-13 - 090
    Royal rear 2024-09-13 – 090

    A second later, the dumpster grabber is about even with my handlebars, corresponding to the first helmet camera picture:

    Royal rear 2024-09-13 - 120
    Royal rear 2024-09-13 – 120

    A third of a second later:

    Royal rear 2024-09-13 - 130
    Royal rear 2024-09-13 – 130

    The rear wheels passed much closer:

    Royal rear 2024-09-13 - 180
    Royal rear 2024-09-13 – 180

    In general, Royal’s drivers give us plenty of clearance.

    In this case, I think he badly misjudged how fast I was moving and figured he would be well past by the time he had to be completely in the right lane to avoid vehicles in the left-turn lane on the bridge.

    However, intent wouldn’t make me any less dead after a trip around those tires …

  • Sting-Kill: Everyday Carry Tube

    Sting-Kill: Everyday Carry Tube

    One of Mary’s gardening cronies suggested Sting-Kill might reduce her dramatic swelling [^1] after a bee / wasp / insect sting. Because it must be applied immediately after the sting, the swab must be on hand in the garden or on a bike ride, but the glass vial inside seem entirely too fragile to survive amid the usual clutter of a purse / pocketbook / belt pack / bike pack.

    Well, I can fix that:

    Pill tube - PETG default
    Pill tube – PETG default

    It’s a KeyChain Pill Tube from Printables, enlarged 20% in the XY plane to fit the Sting-Kill swab, with the white applicator end fitting neatly into the domed screw-on lid for a bit of cushioning.

    The solid model looks about like you’d expect:

    Pill Tube - slicer preview
    Pill Tube – slicer preview

    Despite that preview, I printed it with a brim. PETG sticks tenaciously to the Textured PEI steel sheet and a brim wasn’t really needed; just pop the parts off the platform when cool.

    Somewhat to my astonishment, the threads screwed together easily, smoothed out after a few on-and-off cycles, and it’s ready for a moment we both hope will never occur.

    [^1] Mary did tote an EpiPen back in the day, but a few near misses indicated she’s no longer quite as sensitized. She does swell up something powerful and we’re hoping immediately applying a Sting-Kill will help knock it down.

  • Anker A1215 PowerCore 13000 Power Banks: Five Years

    Anker A1215 PowerCore 13000 Power Banks: Five Years

    After five years of powering the action cameras on our Tour Easy recumbents, the pair of Anker A1215 PowerCore 13000 USB power banks have about 8 A·hr of capacity with a 2 A load after a full charge:

    Anker PowerCore 13000 - 20204-07-26
    Anker PowerCore 13000 – 20204-07-26

    It seems I did not test them on arrival, so I have no idea what their original capacity might have been, but I’m certain it wasn’t the 13 A·hr implied by their name.

    The sawtooth voltage output looks like the internal controller picks a constant boost (or buck) ratio based on the battery voltage, then adjusts it when the output voltage falls below the lower limit. You can imagine it desperately boosting the ratio as the battery voltage falls off a cliff near the end of the curve.

    I have no idea why the two packs behave so differently, although the voltages are certainly within ordinary USB limits.

    They’ll continue powering the camera on my bike for a while, after which I’m sure they’ll come in handy for something …

  • Tour Easy: Anker 20K V2 USB Power Bank

    Tour Easy: Anker 20K V2 USB Power Bank

    After five years, it’s time to replace the Anker 13000 mA·hr USB power banks / chargers I used with the M20 cameras and then the C100 cameras:

    SJCAM M20 Mount - Tour Easy side view
    SJCAM M20 Mount – Tour Easy side view

    The Anker 325 20K V2 power bank is considerably chunkier, as befits its 20,000 mA·hr cell capacity (although the fine print says 12,500 mA·hr output):

    Anker 20K V2 Power Bank - installed
    Anker 20K V2 Power Bank – installed

    The white tape stripe on the top marks the USB port on the end to reduce the fumbling involved in an out-of-sight socket. There’s also a USB-C port on that end for both charging the pack and powering other devices.

    The new mounting cradle descends directly from the 13000 cradle:

    Anker 325 20KV2 Power Bank - slicer preview
    Anker 325 20KV2 Power Bank – slicer preview

    The model includes a projection of the battery on the XY plane for export to an SVG file suitable for laser-cutting an EVA foam pad to cushion the bumps.

    The OpenSCAD source code as a GitHub Gist:

    // Anker PowerCore 325 20K V2 Power Bank
    // Ed Nisley – KE4ZNU
    // 2024-07
    /* [Layout Options] */
    Layout = "Show"; // [Show,Build]
    Part = "Cradle"; // [Cradle,Battery,Pad]
    /* [Extrusion Parameters] */
    ThreadWidth = 0.40;
    ThreadThick = 0.25;
    HoleWindage = 0.2;
    Protrusion = 0.1;
    //—–
    // Dimensions
    /* [Hidden] */
    ID = 0;
    OD = 1;
    LENGTH = 2;
    EmbossDepth = 2*ThreadThick + Protrusion; // recess depth + Protrusion beyond surface
    DebossHeight = EmbossDepth; // text height + Protrusion into part
    Projection = 10; // stick-out to punch through shell sides & suchlike
    FadeColor = "Green";
    FadeAlpha = 0.25;
    //—–
    // Useful routines
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    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);
    }
    //—–
    // Battery
    // Based on Anker PowerCore 325, simplified shapes
    // Includes port punchouts
    Battery = [162.0+0.5,81.5+0.5,24.0]; // X=length, Y=max, Z=max
    module BatteryShape(Jacks = true) {
    USB = [[Projection,20,12],[Projection,18,10]]; // clearance around USB output jacks
    USBOffset = [[0,20.0,0],[0,62.5,0]]; // from -Y edge to center of jack, Z centered
    BatteryRad = 7.0; // corner rounding radius
    BatterySides = 2*3*4;
    hull()
    for (i=[-1,1], j=[-1,1])
    translate([i*(Battery.x/2 – BatteryRad),
    j*(Battery.y/2 – BatteryRad),
    0])
    cylinder(r=BatteryRad,h=Battery.z,$fn=BatterySides,center=true);
    if (Jacks)
    for (i=[0,len(USB)-1])
    translate([(Battery.x + USB[i].x)/2 – Protrusion,-Battery.y/2 + USBOffset[i].y,0])
    cube(USB[i],center=true);
    }
    //—–
    // Battery cradle
    RackWidth = 90.0; // flat width between rack rails
    CradleWall = [4.0,4.0,3.0]; // wall thickness
    CradleRadius = 2.0; // corner rounding
    CradlePad = 1.0; // cushion on battery bottom
    BatteryBase = CradleWall.z + CradlePad; // actual bottom surface of battery
    CradleOA = [Battery.x + 2*CradleWall.x,
    min((Battery.y + 2*CradleWall.y),RackWidth),
    BatteryBase + Battery.z/2];
    echo(str("Cradle OA: ",CradleOA));
    module Cradle() {
    difference() {
    hull()
    for (i=[-1,1], j=[-1,1]) { // box with tidy rounded corners
    translate([i*(CradleOA.x/2 – CradleRadius),
    j*(CradleOA.y/2 – CradleRadius),
    1*(CradleOA.z – CradleRadius)])
    sphere(r=CradleRadius,$fn=6);
    translate([i*(CradleOA.x/2 – CradleRadius),
    j*(CradleOA.y/2 – CradleRadius),
    0*(CradleOA.z/2 – CradleRadius)])
    cylinder(r=CradleRadius,h=CradleOA.z/2,$fn=6);
    }
    translate([0,0,Battery.z/2 + BatteryBase]) // minus the battery
    minkowski(convexity=3) { // … slightly embiggened
    BatteryShape();
    cube(2*CradlePad,center=true);
    }
    translate([0,0,CradleWall.z – ThreadThick + Protrusion/2]) // recess top legend
    cube([55,20,EmbossDepth],center=true);
    translate([0,0,(EmbossDepth – Protrusion)/2]) // recess bottom legend
    cube([70,15,EmbossDepth],center=true);
    }
    translate([0,4.0,CradleWall.z – DebossHeight – Protrusion])
    linear_extrude(height=DebossHeight,convexity=20)
    text(text="PowerCore",size=6,spacing=1.20,
    font="Arial:style:Bold",halign="center",valign="center");
    translate([0,-4.0,CradleWall.z – DebossHeight – Protrusion])
    linear_extrude(height=DebossHeight,convexity=20)
    text(text="20K V2",size=6,spacing=1.20,
    font="Arial:style:Bold",halign="center",valign="center");
    linear_extrude(height=DebossHeight,convexity=20)
    mirror([0,1,0])
    text(text="KE4ZNU",size=10,spacing=1.20,
    font="Arial:style:Bold",halign="center",valign="center");
    }
    //—–
    // Build things
    // Layouts for design & tweaking
    if (Layout == "Show")
    if (Part == "Battery")
    BatteryShape();
    else if (Part == "Cradle") {
    Cradle();
    translate([0,0,Battery.z/2 + CradleWall.z])
    color(FadeColor,FadeAlpha)
    BatteryShape();
    }
    else if (Part == "Pad")
    linear_extrude(height=CradlePad)
    projection(cut=true)
    BatteryShape(Jacks = false);
    // Build layouts for top-level parts
    if (Layout == "Build") {
    if (Part == "Cradle")
    Cradle();
    if (Part == "Pad")
    projection(cut=true)
    BatteryShape(Jacks = false);
    }