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.

Tag: Improvements

Making the world a better place, one piece at a time

  • Tour Easy Front Fender Clip: Longer and Stronger

    We negotiated the Belmar Bridge connection stairway from the Allegheny River Trail to the Sandy Creek trail:

    Belmar Bridge Stairs - Overview
    Belmar Bridge Stairs – Overview

    We’re maneuvering Mary’s bike, but you get the general idea. Our bikes aren’t built for stairways, particularly ones with low overheads:

    Belmar Bridge Stairs - Low Overhead
    Belmar Bridge Stairs – Low Overhead

    The front fender clip on my Tour Easy snapped (at the expected spots) when the mudflap snagged on one of the angles:

    Belmar Bridge Stairs - First Turn
    Belmar Bridge Stairs – First Turn

    For some inexplicable reason, I didn’t have a roll of duct tape in my packs, so the temporary repair required a strip of tape from a battery pack, two snippets of hook-and-loop tape, and considerable muttering:

    Tour Easy front fender clip - expedient repair
    Tour Easy front fender clip – expedient repair

    It was good for two dozen more miles to the end of our vacation, so I’d say that was Good Enough.

    The new version has holes in the ferrules ten stay diameters deep, instead of six, which might eliminate the need for heatstink tubing. I added a small hole at the joint between the curved hooks and the ferrules to force more plastic into those spots:

    Front Fender Clip - Slic3r
    Front Fender Clip – Slic3r

    I also bent the hanger extension to put the fender’s neutral position closer to the wheel.

    We’ll see how long this one lasts. By now, I now have black double-sticky foam tape!

    The OpenSCAD source code as a GitHub Gist:

    // Tour Easy front fender clip
    // Ed Nisley KE4ZNU July 2017
    Layout = "Build"; // Build Profile Ferrule Clip
    //– Extrusion parameters must match reality!
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    HoleWindage = 0.2;
    Protrusion = 0.1; // make holes end cleanly
    inch = 25.4;
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    //———————-
    // Dimensions
    // special case: fender is exactly half a circle!
    FenderC = 51.0; // fender outside width = chord
    FenderM = 21.0; // height of chord
    FenderR = (pow(FenderM,2) + pow(FenderC,2)/4) / (2 * FenderM); // radius
    echo(str("Fender radius: ", FenderR));
    FenderD = 2*FenderR;
    FenderA = 2 * asin(FenderC / (2*FenderR));
    echo(str(" … Arc: ",FenderA," deg"));
    FenderThick = 2.5; // fender thickness, assume dia of edge
    ClipHeight = 15.0; // top to bottom, ignoring rakish tilt
    ClipThick = IntegerMultiple(2.5,ThreadWidth); // thickness of clip around fender
    ClipD = FenderD; // ID of clip against fender
    ClipSides = 4 * 8; // polygon sides around clip circle
    BendReliefD = 2.5; // bend arch diameter
    BendReliefA = 2/3 * FenderA/2; // … angle from dead ahead
    BendReliefCut = 1.5; // factor to thin outside of bend
    ID = 0;
    OD = 1;
    LENGTH = 2;
    StayDia = 3.3; // fender stay rod diameter
    StayOffset = 15.0; // stay-to-fender distance
    StayPitch = 5; // angle from stay to fender arch
    DropoutSpace = 120; // stay spacing at wheel hub
    StayLength = 235; // stay length: hub to fender
    StaySplay = asin((DropoutSpace FenderC)/(2*StayLength)); // outward angle to hub
    echo(str(" … Pitch: ",StayPitch," deg"));
    echo(str(" … Splay: ",StaySplay," deg"));
    FerruleSides = 2*4;
    Ferrule = [StayDia,3*FenderThick/cos(180/FerruleSides),10*StayDia + StayOffset]; // ID = stay rod OD
    FerruleHoleD = 0.1; // small hole to create solid plastic at ferrule joint
    //———————-
    // 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);
    }
    //———————-
    // Clip profile around fender
    // Centered on fender arc
    module Profile(HeightScale = 1) {
    linear_extrude(height=HeightScale*ClipHeight,convexity=5) {
    difference() {
    offset(r=ClipThick) // outside of clip
    union() {
    circle(d=ClipD,$fn=ClipSides);
    for (i=[1,1])
    rotate(i*BendReliefA) {
    translate([ClipD/2 + BendReliefD/2,0,0])
    circle(d=BendReliefD,$fn=6);
    }
    }
    union() { // inside of clip
    circle(d=ClipD,$fn=ClipSides);
    for (i=[1,1])
    rotate(i*BendReliefA) {
    translate([ClipD/2 + BendReliefCut*BendReliefD/2,0,0])
    circle(d=BendReliefD/cos(180/6),$fn=6);
    translate([ClipD/2,0,0])
    square([BendReliefCut*BendReliefD,BendReliefD],center=true);
    }
    }
    translate([(FenderR FenderM FenderD/2),0]) // trim ends
    square([FenderD,2*FenderD],center=true);
    }
    for (a=[1,1]) // hooks around fender
    rotate(a*(FenderA/2))
    translate([FenderR FenderThick/2,0]) {
    difference() {
    rotate(1*180/12)
    circle(d=FenderThick + 2*ClipThick,$fn=12);
    rotate(1*180/8)
    circle(d=FenderThick,$fn=8);
    rotate(a * 90)
    translate([0,2*FenderThick,0])
    square(4*FenderThick,center=false);
    }
    }
    }
    }
    //———————-
    // Ferrule body
    module FerruleBody() {
    translate([0,0,Ferrule[OD]/2 * cos(180/FerruleSides)])
    rotate([0,90,0]) rotate(180/FerruleSides)
    difference() {
    cylinder(d=Ferrule[OD],h=Ferrule[LENGTH],$fn=FerruleSides,center=false);
    translate([0,0,StayOffset + Protrusion])
    PolyCyl(Ferrule[ID],Ferrule[LENGTH] StayOffset + Protrusion,FerruleSides);
    }
    }
    //———————-
    // Generate entire clip at mounting angle
    module FenderClip() {
    difference() {
    union() {
    translate([FenderR,0,0])
    difference() { // angle and trim clip
    rotate([0,StayPitch,0])
    translate([(FenderR + ClipThick),0,0])
    Profile(2); // scale upward for trimming
    translate([0,0,ClipHeight]) // trim bottom
    cube(2*[FenderD,FenderD,ClipHeight],center=true);
    translate([0,0,ClipHeight*cos(StayPitch)+ClipHeight]) // trim top
    cube(2*[FenderD,FenderD,ClipHeight],center=true);
    }
    for (j = [1,1]) // place ferrules
    translate([Ferrule[OD]*sin(StayPitch) + (Ferrule[OD]/2)*sin(StaySplay),j*(FenderR FenderThick/2),0])
    rotate(j*StaySplay)
    FerruleBody();
    }
    for (i=[1,1]) // punch stiffening holes
    translate([FenderThick/2,i*(FenderR FenderThick/2),Ferrule[OD]/2])
    rotate([0,90,i*StaySplay])
    PolyCyl(FerruleHoleD,Ferrule[OD],FerruleSides);
    }
    }
    //———————-
    // Build it
    if (Layout == "Profile") {
    Profile();
    }
    if (Layout == "Ferrule") {
    FerruleBody();
    }
    if (Layout == "Clip") {
    FenderClip();
    }
    if (Layout == "Build") {
    FenderClip();
    }

    As a bonus for paging all the way to the end, here’s the descent on the same stairway:

    Belmar Bridge Stairs - Descent
    Belmar Bridge Stairs – Descent

    No, I wasn’t even tempted …

  • Mint Extract: Results

    Six weeks later, the mint seemed about as extracted as it was going to get and I now have nearly a liter of decidedly green mint extract:

    Mint Extract - liquid color
    Mint Extract – liquid color

    Correspondingly, the leaves turned from bright green to dull brown:

    Mint Extract - spent leaf colors
    Mint Extract – spent leaf colors

    The smaller and darker pile in the rightmost bowl came from the smaller jar (on the left) with a higher alcohol-to-leaf ratio:

    Mint Extract - start - 2018-05-29
    Mint Extract – start – 2018-05-29

    Perhaps packing the jars before pouring in the alcohol doesn’t extract as efficiently. Or maybe, as in so many things, it doesn’t really matter.

    A liter of mint extract may not be a lifetime supply, but it’ll suffice for quite a while!

  • Tek A6302 Current Probe: Reason for Being

    The question occasionally comes up as to why one would want a Tektronix A6302 Hall effect current probe and AM503 amplifier. The answer is simple: non-contact, essentially non-invasive current monitoring.

    I used the venerable dead-battery Astable Multivibrator to check out the rebalanced A6302 probe:

    Tek A6302 Current Probe vs Astable Multivibrator
    Tek A6302 Current Probe vs Astable Multivibrator

    The scope screen in the background shows the two base voltages at the top, plus the overall battery current along the bottom:

    Tek A6302 - Astable multivibrator - LED current 1 mA-div
    Tek A6302 – Astable multivibrator – LED current 1 mA-div

    The current at 1 mA/div shows plenty of noise, but the 200 ms LED pulse is barely 1 mA tall. The two AA alkaline cells have faded to 2.5 V, so the “wearable” white-LED-with-dyed-overcoat runs far under its nominal 3.6-ish V spec.

    There’s basically no other way to get that result, because inserting a current-sense resistor into the circuit will alter the results, plus be intractably difficult to measure, particularly if you need the current in a non-ground-referenced branch of the circuit.

    The AM503 has terrible thermal drift, by contemporary standards, but after the first half-hour or so it’s manageable for short durations. I’m thinking of epoxying a small knob to the screwdriver-adjustable twiddlepot to simplify the baseline adjustment.

    Alas, even non-working probes and amps have become eBay collectables. You could, of course, buy new.

  • Ortlieb Backroller Pack Drop

    Although the pair of Ortlieb Back-Roller packs on Mary’s bike make her look like a long-distance tourist, we’re actually on our way to her garden plot:

    AS30V-0285
    AS30V-0285

    The left-side pack suddenly seemed unusually floppy:

    AS30V-0300
    AS30V-0300

    One second later:

    AS30V-0360
    AS30V-0360

    Another second and it’s visible under my right hand:

    AS30V-0420
    AS30V-0420

    The view from her bike at about the same time:

    Ortlieb-0158
    Ortlieb-0158

    I’m expecting to fall to my right, but it’d have been better if I hadn’t kicked the bag:

    Ortlieb-0169
    Ortlieb-0169

    The pack went under the rear wheel and out the far side:

    Ortlieb-0185
    Ortlieb-0185

    Where it came to rest in the middle of the trail:

    Ortlib pack drop - aftermath
    Ortlib pack drop – aftermath

    Elapsed time from the first picture: just under 5 s.

    Did you notice the other cyclist in the other pictures? She’s why I veered so hard to my right!

    A pair of these latches hold the pack onto the rear rack:

    Ortlieb pack drop - QL latch detail
    Ortlieb pack drop – QL latch detail

    When they’re properly engaged, they look like this:

    Ortlieb pack drop - QL latch - secure
    Ortlieb pack drop – QL latch – secure

    When they’re not, they look like this:

    Ortlieb pack drop - QL latch - whoopsie
    Ortlieb pack drop – QL latch – whoopsie

    Which is obvious in the picture and inconspicuous in real life.

    The strap emerging from the top of the latch serves as both a carrying handle and latch release: pull upward to open the latches and release them from the bar, lift to remove the pack, and carry it away as you go. Installing the pack proceeds in reverse: lower the pack onto the rack bar, release the handle, and the latches engage.

    Unless the pack is empty enough to not quite fully open the latches as you carry it, in which case the closed latches simply rest on the bar. We’ve both made that mistake and I generally give her packs a quick glance to ensure sure they’re latched. In this case, the plastic drawer atop the racks (carrying seedling pots on their way to the garden) completely concealed the pack latches.

    Tree roots have been creasing the asphalt along that section of the rail trail: the bike finally bounced hard enough to lift the drawer and fall off the rack rod.

    Memo to Self: In addition to the visual check, lift the packs using the strap across the middle holding the rolled-down top in place. Remember, don’t check by lifting the carrying handle, because it just releases the latches; another easy mistake to make.

    Whew!

  • Copying Action Camera Video: Now With UUIDs

    Having tired of manually decoding UDEV’s essentially random device names produced for the various USB action cameras and card readers, I put the device UUIDs in /etc/fstab and let the device names fall where they may:

    UUID=B40C6DD40C6D9262	/mnt/video	ntfs	noauto,uid=ed 0 0
    UUID=0FC4-01AB	/mnt/Fly6	vfat	noauto,nodiratime,uid=ed	0	0
    UUID=0000-0001	/mnt/M20	vfat	noauto,nodiratime,uid=ed	0	0
    LABEL=AS30V	/mnt/AS30V	exfat	noauto,nodiratime,uid=ed	0	0
    

    You get those by plugging everything in, running blkid, and sorting out the results.

    The 64 GB MicroSD card from the Sony AS30V camera uses Microsoft’s proprietary exfat file system, which apparently doesn’t associate a UUID/GUID with the entire device, so you must use a partition label. The Official SD Card Formatter doesn’t (let you) set one, so:

    exfatlabel /dev/sdd1 AS30V
    

    It turns out you can include spaces in the partition label, but there’s no way to escape them (that I know of) in /etc/fstab, so being succinct counts for more than being explanatory.

    One could name the partition in the Windows device properties pane, which would make sense if one knew it was necessary while the Token Windows Laptop was booted with the card in place.

    I think this is easier then trying to persuade UDEV to create known device names based on the USB hardware characteristics, because those will depend on which USB card / device / reader I use. I can force the UUIDs to be whatever I want, because they’re just bits in the disk image.

    With all that in place, you plug in All. The. Gadgets. and run the script (as seen below). The general idea is to verify the bulk video drive mounted OK, attempt to mount each memory card and fire off a corresponding rsync copy, wait until they’re all done, tidy the target filenames, then delete all the source files to get ready for the next ride.

    Funneling all three copies to a single USB hard drive probably isn’t the smartest thing, but the overall write ticks along at 18 MB/s, which is Good Enough for my simple needs. If the drive thrashes itself to death, I won’t do it again; I expect it won’t fail until well outside the 1 year limited warranty.

    If any of the rsync copies fail, then nothing gets deleted. I’m a little queasy about automagically deleting files, but it’s really just video with very little value. Should something horrible happen, I’d do the copies by hand, taking great care to not screw up.

    After all, how many pictures like this do we need?

    Ed signalling on Raymond
    Ed signalling on Raymond

    The Bash script as a GitHub Gist:

    UUID=B40C6DD40C6D9262 /mnt/video ntfs noauto,uid=ed 0 0
    UUID=0FC4-01AB /mnt/Fly6 vfat noauto,nodiratime,uid=ed 0 0
    UUID=0000-0001 /mnt/M20 vfat noauto,nodiratime,uid=ed 0 0
    LABEL=AS30V /mnt/AS30V exfat noauto,nodiratime,uid=ed 0 0
    view raw fstab hosted with ❤ by GitHub
    #!/bin/bash
    # This uses too many bashisms for dash
    thisdate=$(date –rfc-3339=date)
    echo Date is $thisdate
    date
    # MicroSD / readers / USB drive defined in fstab
    # … with UUID or PARTID as appropriate
    echo Mounting bulk video drive
    sudo mount /mnt/video
    if [ $? -ne 0 ]; then
    echo '** Cannot mount video storage drive'
    exit
    fi
    # Show starting space available
    df -h /mnt/video
    #– Sony AS30V
    printf "\n— AS30V\n"
    as30v=/mnt/AS30V
    sudo mount $as30v
    if [ $? -eq 0 ]; then
    echo " start AS30V transfer on $as30v"
    mkdir /mnt/video/AS30V/$thisdate
    rsync -ahu –progress –exclude "*THM" $as30v/MP_ROOT/100ANV01/ /mnt/video/AS30V/$thisdate &
    pid1=$!
    echo " PID is $pid1"
    else
    echo " skipping"
    as30v=
    fi
    #– Cycliq Fly6
    printf "\n— Fly6\n"
    fly6=/mnt/Fly6
    sudo mount $fly6
    if [ $? -eq 0 ]; then
    echo " start Fly6 transfer on $fly6"
    rsync -ahu –progress $fly6 /mnt/video &
    pid2=$!
    echo " PID is $pid2"
    else
    echo " skipping"
    fly6=
    fi
    #– SJCAM M20
    printf "\n— M20\n"
    m20=/mnt/M20
    sudo mount $m20
    if [ $? -eq 0 ]; then
    echo " start M20 transfer on $m20"
    mkdir /mnt/video/M20/$thisdate
    # See if any still images exist to avoid error messages
    n=$( ls $m20/DCIM/Photo/* 2> /dev/null | wc -l )
    if [ $n -gt 0 ] ; then
    echo " copy M20 photos first"
    rsync -ahu –progress $m20/DCIM/Photo/ /mnt/video/M20/$thisdate
    fi
    rsync -ahu –progress $m20/DCIM/Movie/ /mnt/video/M20/$thisdate &
    pid3=$!
    echo " PID is $pid3"
    else
    echo " skipping"
    m20=
    fi
    printf "\n—– Waiting for all rsync terminations\n"
    rc=0
    for p in $pid1 $pid2 $pid3 ; do
    wait -n
    rc=$(( rc+$? ))
    echo RC so far: $rc
    done
    date
    if [ $rc -eq 0 ] ; then
    echo '—– Final cleanups'
    echo Fix capitalized extensions
    find /mnt/video -name \*AVI -print0 | xargs -0 rename -v -f 's/AVI/avi/'
    find /mnt/video -name \*MP4 -print0 | xargs -0 rename -v -f 's/MP4/mp4/'
    if [ "$as30v" ]; then
    echo Remove files on $as30v
    rm $as30v/MP_ROOT/100ANV01/*
    sudo umount $as30v
    fi
    if [ "$fly6" ]; then
    echo Remove files on $fly6
    rm -rf $fly6/DCIM/*
    sudo umount $fly6
    fi
    if [ "$m20" ]; then
    echo Remove files on $m20
    rm $m20/DCIM/Movie/* $m20/DCIM/Photo/*
    sudo umount $m20
    fi
    echo '—– Space remaining on video drive'
    df -h /mnt/video
    sudo umount /mnt/video
    echo Done!
    else
    echo Whoopsie! Total RC: $rc
    fi
    view raw savevideo.sh hosted with ❤ by GitHub
  • Siglent SDS2304X Oscilloscope: Homebrew Front Cover

    Both my Tek 2215A and HP 54602 oscilloscopes came with snap-on front covers to protect all those delicate knobs and connectors. Not so the Siglent SDS2304X, which is basically a flat shoebox with a handle: the case has no features for a cover to snap onto, Siglent doesn’t offer a padded carrying case, and it’s too thick big for any of the laptop bags around here.

    I’ve been lugging it to Squidwrench meetings and can easily visualize a gash across the LCD panel or a knob rammed against a door frame.

    So I trimmed a pair of foam angles, punched holes to fit around the knobs along the right edge, cut up a cardboard tray from the heap, and duct-taped the whole mess together:

    Siglent SDS2304X Oscilloscope - crude front cover - interior
    Siglent SDS2304X Oscilloscope – crude front cover – interior

    The cover is equally ugly from the outside:

    Siglent SDS2304X Oscilloscope - crude front cover - installed
    Siglent SDS2304X Oscilloscope – crude front cover – installed

    A Velcro bellyband around the whole affair / through the handle holds it together.

    I considered 3D printing a set of corners and screwing them to a flat plastic plate, but came to my senses just in time.

  • Bypass Lopper

    Some surreptitious brush clearing called for a tool larger than our wonderful Fiskars PowerGear pruner, so I unearthed a long-disused bypass lopper in the garage (it may have Come With The House). Alas, the pivot bolt lost its jam nut long ago:

    Bypass loppers - OEM 10 mm bolt
    Bypass loppers – OEM 10 mm bolt

    That’s an M10x1.5 bolt, for which I lack a corresponding nut.

    But 3/8-16 is approximately M10x1.5, for small values of thread engagement, and I do have an assortment of inch-sized stainless steel fasteners:

    Bypass loppers - 0.375 inch bolt
    Bypass loppers – 0.375 inch bolt

    The nylon lock nut jams the bolt against the left blade, with the split washer applying pressure to the tapered blade. Slobbering oil in the sliding joints restored it to perfect working order.

    The weird round dingus on the far side of the pivot, up against the handles, is a bumper cushioning the fully closed position. It’s a nice touch and might work better if its rubber pad hadn’t aged out over the decades spent in the garage waiting for this very day.

    It’s my kind of yard work: “What do you need killed next?”