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

  • Micro-Mark Mini Bandsaw

    Unlike their craptastic Mini Miter/Cut-off saw, the Micro-Mark Variable Speed Mini Bandsaw seems like a solid improvement over the corresponding Harbor Freight offering:

    Micro-Mark Bandsaw - mostly ready
    Micro-Mark Bandsaw – mostly ready

    That’s the tank for the water-cooling option atop the housing, with the collection tray underneath. It’s screwed to a big wood plank; I’ll probably bench-mount the thing, but that’s stable enough for now.

    The right-rear mounting screw hides below the dust collection vacuum port:

    Micro-Mark Bandsaw - vacuum fitting
    Micro-Mark Bandsaw – vacuum fitting

    You must remove the metal fitting that’s screwed to the frame in the obvious manner:

    Micro-Mark Bandsaw - right rear screw - installed
    Micro-Mark Bandsaw – right rear screw – installed

    The slowest speed runs a bit faster than I’d like, but I admit to being a sissy.

    The 14 tpi blade cuts wood just fine:

    Micro-Mark Bandsaw - first cut
    Micro-Mark Bandsaw – first cut

    The 24 tpi blades should chop up the smaller chunks I generally work with around here.

    Bonus: the blade guide just barely clears my huge block of machinable wax.

     

  • Micro-Mark Mini Miter / Cut-off Saw

    I bought a 2 inch Micro-Mark Mini Miter / Cut-off Saw to cut screws & brass tubing, in the hopes that it would be somewhat better than the essentially equivalent Harbor Freight offering. I think that’s true, but it’s a near thing.

    Apparently, the saws all come from the same factory with the same bass-ackwards vise:

    Micro-Mark Cutoff Saw - vise side view
    Micro-Mark Cutoff Saw – vise side view

    The V-groove should be on the fixed jaw, where it would more-or-less precisely align rods / cylinders with the blade. The moveable jaw isn’t dovetailed to the base of the vise, so it ends up wherever it stops and, somehow, they managed to machine the end of the screw shaft off-center from the shaft, so the moveable jaw moves in a small circle as you tighten it.

    A small punch mark locks the jaw to the screw; you can pull the disk on the shaft past the indentation by turning the knob with sufficient enthusiasm:

    Micro-Mark Cutoff Saw - clamp jaw detail
    Micro-Mark Cutoff Saw – clamp jaw detail

    The hole in the vise, just under the disk, lets somebody whack the jaw with a punch.

    Some machining or an entirely new vise setup lies in the future of this thing.

    I mounted it on a scrap of countertop by transfer-punching the base holes, only to discover that the punch didn’t leave a mark for one hole, even though a dent was clearly visible at the bottom of the hole with the saw on the countertop.

    A bit of headscratching later:

    Micro-Mark Cutoff Saw - unfinished casting hole
    Micro-Mark Cutoff Saw – unfinished casting hole

    Apparently the core for that hole in the injection mold didn’t seat quite right. The layer was thin enough to drill out easily.

    The blade is identical with the Harbor Freight blades I’m using on the Sherline, right down to the printed legend declaring it fits saws with non-Micro-Mark part numbers:

    2 inch blades - Micro-Mark vs Harbor Freight
    2 inch blades – Micro-Mark vs Harbor Freight

    Granted, the Micro-Mark blade on the left has nicer printing, but MM blades run $15 each and HF offers a three-pack for ten bucks. Note the carefully positioned thumb in the Micro-Mark picture.

    Beware of cheap imitations!” says Micro-Mark.

  • APRS/GPS + Voice Interface: Improved PTT Button Cap

    Long ago, Mary picked out a PTT switch with a raised, square post that provided a distinct shape and positive tactile feedback:

    PTT Button - bare post
    PTT Button – bare post

    Time passes, she dinged her thumb in the garden, and asked for a more rounded button. I have some switches with rounded caps, but replacing the existing switch looked a lot like work, sooooo:

    PTT Button Cap - Slic3r preview
    PTT Button Cap – Slic3r preview

    As with all small objects, building them four at a time gives the plastic in each one time to cool before slapping the next layer on top:

    PTT Button - on platform
    PTT Button – on platform

    The hole in the cap is 0.2 mm oversize, which results in a snug press fit on the small ridges barely visible around the post in the first image:

    PTT Button - rounded cap
    PTT Button – rounded cap

    Rather than compute the chord covering the surface, I just resized a sphere to twice the desired dome height (picked as 6 threads, just for convenience) and plunked it atop a cylinder. Remember to expand the sphere diameter by 1/cos(180/sides) to make it match the cylinder and force both to have the same number of sides.

    If it falls off, I have three backups.

    The OpenSCAD source code as a GitHub Gist:

    // PTT Button cap
    // Ed Nisley KE4ZNU – June 2016
    //- Extrusion parameters – must match reality!
    ThreadThick = 0.20;
    ThreadWidth = 0.40;
    Protrusion = 0.1;
    HoleWindage = 0.2;
    //——
    // Dimensions
    Post = [3.8,3.8,3.0];
    OD = 0;
    HEIGHT = 1;
    DOMEHEIGHT = 2;
    Button = [12,0+Post[2],6*ThreadThick];
    NumSides = 8*4;
    //———————-
    //- Build it
    difference() {
    union() {
    translate([0,0,Button[HEIGHT]])
    resize([0,0,2*Button[DOMEHEIGHT]])
    sphere(d=Button[OD]/cos(180/NumSides),$fn=NumSides);
    cylinder(d=Button[OD],h=Button[HEIGHT],$fn=NumSides);
    }
    translate([0,0,Post[2]/2 – Protrusion])
    cube(Post + [HoleWindage,HoleWindage,Protrusion],center=true);
    }
  • Protecting The Sony HDR-AS30V Lens: First Drop

    After a year and a half, I finally found out whether flipping the AS-30V camera upside-down would protect its lens:

    Sony HDR-AS30V - flip mode vs ground contact
    Sony HDR-AS30V – flip mode vs ground contact

    Yes. Yes, it does, at least from a grass-like ground cover.

    I’d leaned the bike against a Blue Loo, turned my back, took four steps, and wham down it went.

    The upper front rim of the skeleton case ended up firmly pressed against the ground, with the lens safe. A slight smear from the greenery wiped off easily, with dirt embedded between the fake fur and the case, exactly where the lens would stick out in its normal orientation.

    Whew!

    I love it when a plan works out …

  • Nothing Exceeds Like Excess: Tektronix CT-5 Current Transformer Probe

    When a 100 A current probe won’t do the job, another order of magnitude can make all the difference:

    Tek CT-5 A6302 Current Probe - 500 W bulb
    Tek CT-5 A6302 Current Probe – 500 W bulb

    That’s a Tektronix CT-5 current transformer, rated for 1 kA between -3 dB points at 0.5 Hz and 20 MHz, with an A6302 20 A probe snapped around its 1000:1 output winding.

    The eBay deal didn’t include the 015-0190-00 1000:1 bucking coil that lets you measure small AC signals against high DC current; if you happen to find one for considerably less than the $100 I was unwilling to pay, let me know. I doubt I’ll ever need it, but ya never know.

    Lacking a calibrated current source with sufficient moxie to exercise the thing, I settled for a 500 W incandescent bulb: 514 W and 4.38 A rms, according to a Kill-A-Watt meter off to the left.

    The 1000:1 output, seen through the A6302 probe at 2 mA/div = 2 A/div:

    Tek CT-5 A6302 - 2 mA div 1000 ratio - 514 W 4.38 A
    Tek CT-5 A6302 – 2 mA div 1000 ratio – 514 W 4.38 A

    The 22.22 mVrms corresponds to 4.4 A = (22.22 / 10) * 0.002 * 1000.

    Moving the probe to the 20:1 output at 100 mA/div = 2 A/div:

    Tek CT-5 A6302 - 100 mA div 20 ratio - 514 W 4.38 A
    Tek CT-5 A6302 – 100 mA div 20 ratio – 514 W 4.38 A

    Again, the scope’s 21.67 mVrms works out to 4.3 A = (21.67 / 10) * 0.1 A * 20.

    Close enough, methinks.

     

     

  • Tektronix AM503, A6302, and A6303 In Full Effect

    Over the past few months I picked up a pair of Tektronix AM503 Current Probe Amplifiers, plus A6302 20 A and A6303 100 A Hall effect probes. The proper calibration procedures require rather specialized (and, in some cases, custom-built) equipment that I don’t have, but I’ll mostly use these things for non-contact / isolated current measurements where just seeing what’s going on counts for more than absolute accuracy.

    For a quick check, I set up a pair of 100 W incandescent bulbs with a plug/socket that breaks out the line conductor into a widowmaker zip cord intended for a foot switch, but I’m not fussy:

    Tektronix A6302 A6303 Current Probes - test load
    Tektronix A6302 A6303 Current Probes – test load

    That’s an old (pronounced “vintage” in eBay-speak) Radio Shack (“Micronta”) clamp-on AC ammeter that, for my present purposes, I can regard as the Gold Standard for current measurement. The 200 W resistive load reads 1.6 A, which is pretty close to the 1.7 A you’d expect.

    The big A6303 probe loafs along at the low end of its range:

    Tek A6303 probe - 200 W incandescent
    Tek A6303 probe – 200 W incandescent

    The scope says 17.78 mV RMS, which translates to 1.8 A with the AM503 set to 1 A/div. A bit hot, perhaps, but not off by too much.

    The two AM503 amps produce slightly different results when switching the probes back and forth, but this arrangement looks consistent:

    Tek A6303 A6302 probes - 1.6 A rms
    Tek A6303 A6302 probes – 1.6 A rms

    With the AM503 amps set to 2 A/div, 7.546 mV = 1.5 A and 7.994 mV = 1.6 A. The last few digits of those RMS calculations absolutely don’t matter.

    The overall error (at least for low-range AC) looks to be around 10%, which is certainly good enough for my immediate needs. I doubt that I can gimmick up a square wave current calibration fixture that I’d trust.

    Labeling the amps improves the odds that I’ll plug the probes in correctly:

    Tektronix TM502 Mainframe with AM503 Current Probe Amps
    Tektronix TM502 Mainframe with AM503 Current Probe Amps

    The A6303 amp lights the “high range” indicator, the A6302 lights the “low range” indicator. Newer (but still obsolete) AM503A and AM503B amps have an LED readout showing the current/division, but …

  • Raspberry Pi Streaming Radio Player: Mostly Viable Product

    The latest version of my simpleminded streaming radio player includes:

    • More durable parsing for track titles with embedded quotes and semicolons
    • Muting during empty / non-music Radionomy tracks
    • The Dutchess County E911 service

    Audionomy’s empty / non-music tracks include a remarkable number of mis-encoded MP3 sections triggering decoding problems; those problems don’t occur during music tracks. Some tracks come through as advertisements, which would be mostly OK apart from the garbled / high-volume gibberish, but on the whole they’re un-listenable:

    ICY Info: StreamTitle='';
    A:1271.0 (21:10.9) of 0.0 (00.0)  4.0% 44%
    [mp3float @ 0x7623e080]overread, skip -7 enddists: -5 -5
    [mp3float @ 0x7623e080]overread, skip -9 enddists: -6 -6
    A:1271.2 (21:11.2) of 0.0 (00.0)  4.0% 45%
    [mp3float @ 0x7623e080]overread, skip -7 enddists: -5 -5
    A:1309.1 (21:49.1) of 0.0 (00.0)  4.0% 42%
    ICY Info: StreamTitle='Targetspot - TargetSpot';
    A:1316.4 (21:56.4) of 0.0 (00.0)  4.0% 40%
    [mp3float @ 0x7623e080]overread, skip -5 enddists: -4 -4
    [mp3float @ 0x7623e080]overread, skip -5 enddists: -2 -2
    

    Muting happens in the mixer, because that seems easier than messing with mplayer in mid-flight. Rather than attempt to control the muted state with specific timeouts, I just un-mute after a new track title arrives; that has no effect if it’s already un-muted. The delays depend on the buffer fill level and avoid the worst of the gibberish.

    The player still falls over dead / jams solid on occasion, generally because the incoming data has stopped streaming or delivered severe encoding problems. Other than that, it runs pretty much all day, every day, on at least one of the Raspberry Pi streamers.

    Still no track display. Mostly, we still don’t miss it.

    The Python source code as a GitHub Gist:

    from evdev import InputDevice,ecodes,KeyEvent
    import subprocess32 as subprocess
    import select
    import re
    import sys
    import time
    Media = {'KEY_KP7' : ['Classical',['mplayer','-playlist','http://stream2137.init7.net/listen.pls'%5D%5D,
    'KEY_KP8' : ['Jazz',['mplayer','-playlist','http://stream2138.init7.net/listen.pls'%5D%5D,
    'KEY_KP9' : ['WMHT',['mplayer','http://live.str3am.com:2070/wmht1'%5D%5D,
    'KEY_KP4' : ['Classic 1000',['mplayer','-playlist','http://listen.radionomy.com/1000classicalhits.m3u'%5D%5D,
    'KEY_KP5' : ['DCNY 911',['mplayer','-playlist','http://www.broadcastify.com/scripts/playlists/1/12305/-5857889408.m3u'%5D%5D,
    'KEY_KP6' : ['WAMC',['mplayer','http://pubint.ic.llnwd.net/stream/pubint_wamc'%5D%5D,
    'KEY_KP1' : ['60s',['mplayer','-playlist','http://listen.radionomy.com/all60sallthetime-keepfreemusiccom.m3u'%5D%5D,
    'KEY_KP2' : ['50-70s',['mplayer','-playlist','http://listen.radionomy.com/golden-50-70s-hits.m3u'%5D%5D,
    'KEY_KP3' : ['Soft Rock',['mplayer','-playlist','http://listen.radionomy.com/softrockradio.m3u'%5D%5D,
    'KEY_KP0' : ['Zen',['mplayer','-playlist','http://listen.radionomy.com/zen-for-you.m3u'%5D%5D
    }
    CurrentKC = 'KEY_KP7'
    Controls = {'KEY_KPSLASH' : '//////',
    'KEY_KPASTERISK' : '******',
    'KEY_KPENTER' : ' ',
    'KEY_KPMINUS' : '<',
    'KEY_KPPLUS' : '>',
    'KEY_VOLUMEUP' : '*',
    'KEY_VOLUMEDOWN' : '/'
    }
    MuteDelay = 5.5 # delay before non-music track; varies with buffering
    UnMuteDelay = 7.3 # delay after non-music track
    MixerChannel = 'PCM' # which amixer thing to use
    # set up event inputs and polling objects
    # This requires some udev magic to create the symlinks
    k = InputDevice('/dev/input/keypad')
    k.grab()
    kp = select.poll()
    kp.register(k.fileno(),select.POLLIN + select.POLLPRI + select.POLLERR)
    v = InputDevice('/dev/input/volume')
    v.grab()
    vp = select.poll()
    vp.register(v.fileno(),select.POLLIN + select.POLLPRI + select.POLLERR)
    # set up files for mplayer pipes
    lw = open('/tmp/mp.log','w') # mplayer piped output
    lr = open('/tmp/mp.log','r') # … reading that output
    # set the mixer output low enough that the initial stream won't wake the dead
    subprocess.call(['amixer','sset',MixerChannel,'10'])
    # Start the player with the default stream
    print 'Starting mplayer on',Media[CurrentKC][0],' -> ',Media[CurrentKC][-1][-1]
    p = subprocess.Popen(Media[CurrentKC][-1],
    stdin=subprocess.PIPE,stdout=lw,stderr=subprocess.STDOUT)
    print ' … running'
    #——————–
    #— Play the streams
    while True:
    # pluck next line from mplayer and decode it
    text = lr.readline()
    if 'ICY Info: ' in text: # these lines may contain track names
    trkinfo = text.split(';') # also splits at semicolon embedded in track name
    for ln in trkinfo:
    if 'StreamTitle' in ln: # this part contains a track name
    if 2 == ln.count("'"): # exactly two single quotes = probably none embedded in track name
    trkhit = re.search(r"StreamTitle='(.*)'",ln)
    if trkhit: # true for valid search results
    TrackName = trkhit.group(1) # the string between the two quotes
    print 'Track name: ', TrackName
    if ('' == TrackName or 'TargetSpot' in TrackName) and 'radionomy' in Media[CurrentKC][-1][-1]:
    print ' … muting empty Radionomy track'
    time.sleep(MuteDelay)
    subprocess.call(['amixer','-q','sset',MixerChannel,'mute'])
    else:
    print ' … unmuting'
    time.sleep(UnMuteDelay)
    subprocess.call(['amixer','-q','sset',MixerChannel,'unmute'])
    else:
    print ' … semicolon in track name: ', ln
    else:
    print ' … quotes in track name: ', ln
    elif 'Exiting…' in text:
    print 'Got EOF / stream cutoff'
    print ' … killing dead mplayer'
    p.kill()
    print ' … flushing pipes'
    lw.truncate(0)
    print ' … discarding keys'
    while [] != kp.poll(0):
    kev = k.read
    print ' … restarting mplayer: ',Media[CurrentKC][0]
    p = subprocess.Popen(Media[CurrentKC][-1],
    stdin=subprocess.PIPE,stdout=lw,stderr=subprocess.STDOUT)
    print ' … running'
    continue
    # accept pending events from volume control knob
    if [] != vp.poll(10):
    vev = v.read()
    for e in vev:
    if e.type == ecodes.EV_KEY:
    kc = KeyEvent(e).keycode
    # print 'Volume kc: ',kc
    if kc in Controls:
    print 'Vol Control: ',kc
    try:
    p.stdin.write(Controls[kc])
    except Exception as e:
    print "Can't send control: ",e
    print ' … restarting player: ',Media[CurrentKC][0]
    p = subprocess.Popen(Media[CurrentKC][-1],
    stdin=subprocess.PIPE,stdout=lw,stderr=subprocess.STDOUT)
    print ' … running'
    # accept pending events from keypad
    if [] != kp.poll(10):
    kev = k.read()
    for e in kev:
    if e.type == ecodes.EV_KEY:
    kc = KeyEvent(e).keycode
    if kc == 'KEY_NUMLOCK':
    continue
    # print 'Got: ',kc
    if (kc == 'KEY_BACKSPACE') and (KeyEvent(e).keystate == KeyEvent.key_hold):
    if True:
    print 'Backspace = shutdown!'
    p = subprocess.call(['sudo','shutdown','-HP','now'])
    else:
    print 'BS = bail from main, ssh to restart!'
    sys.exit(0)
    if KeyEvent(e).keystate != KeyEvent.key_down:
    continue
    if kc in Controls:
    print 'Control:', kc
    try:
    p.stdin.write(Controls[kc])
    except Exception as e:
    print "Can't send control: ",e
    print ' … restarting player: ',Media[CurrentKC][0]
    p = subprocess.Popen(Media[CurrentKC][-1],
    stdin=subprocess.PIPE,stdout=lw,stderr=subprocess.STDOUT)
    print ' … running'
    if kc in Media:
    print 'Switching stream to ',Media[kc][0],' -> ',Media[kc][-1][-1]
    CurrentKC = kc
    print ' … halting player'
    try:
    p.communicate(input='q')
    except Exception as e:
    print 'Perhaps mplayer died?',e
    print ' … killing it for sure'
    p.kill()
    print ' … flushing pipes'
    lw.truncate(0)
    print ' … restarting player: ',Media[CurrentKC][0]
    p = subprocess.Popen(Media[CurrentKC][-1],
    stdin=subprocess.PIPE,stdout=lw,stderr=subprocess.STDOUT)
    print ' … running'
    print 'Out of loop!'
    view raw Streamer.py hosted with ❤ by GitHub