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.

Author: Ed

  • 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 …

  • Squidwrench Power Wheels Racer: Motor Current

    With a new motor and controller in the reconfigured SqWr Power Wheels chassis, I made a few measurements under somewhat less than controlled conditions, with the butt end of the chassis on jack stands. The general idea was to find out what the “lightly loaded” condition looked like in terms of motor current; after some mechanical and electrical improvements, we’ll be in a better position to determine the battery load & suchlike.

    Preliminary measurements:

    • Motor DC resistance: 0.7 Ω (meter lead resistance 0.2 Ω, so don’t trust it)
    • Motor winding inductance: 128 µH
    • Motor shaft key: 1/8 inch (keyway chewed by pulley setscrews, needs matching shaft flats)
    • Twist-grip throttle applies nonzero voltage when released: possibly damaged

    With everything in position and the Tek 6303 probe set for 10 A/div, this is what happens when you push the deadman switch:

    Out V I 10 A - start transient
    Out V I 10 A – start transient

    Obviously, the motor controller takes much too long to wake up & sense the current.

    The initial slope of that current waveform looks like 80 A/360 µs = 220 kA/s. The upper trace gives the motor voltage, so 23 V / (220 kA/s) = 104 µH, surprisingly close to the measured 128 µH.

    Deploying the mighty Tek CT-5 (with an enclosed A6302), cranking the gain to 50 A/div, and poking the deadman again:

    Out V I 50 A - start transient full
    Out V I 50 A – start transient full

    During that initial pulse, the controller connects the battery directly to the motor, so you’re looking directly at 200 A of battery current. For reasons that aren’t relevant here, the mandatory 60 A safety fuse isn’t present, although it should be able to withstand a millisecond or two of moderate overload without blowing.

    With that out of the way and the motor running at a few hundred RPM, due to the nonzero twist-grip output voltage with no throttle applied, the controller actually does PWM pretty much as you’d expect:

    Out V I 10 A - run low speed
    Out V I 10 A – run low speed

    It’s not clear what caused the small dent just before the middle pulse; perhaps the motor commutator switched from one winding to the next.

    The battery current will be much lower than the motor current in this mode, roughly (motor current) * (PWM fraction). We haven’t verified that, but for 30% PWM it should be around 5 A = 15 A * 0.30. The actual battery current looks smoother than I expected, although I have no traces to show for it; more study is needed.

    Eks once again graciously loaned me his Tek current probes; this whole Power Wheels mess motivated me to get off my ass and accumulate my own collection, about which more later.

  • Video Overlays

    There’s nothing like a little unexpected video overlay action to spice up a high-production-value image:

    RIT Commencement - video status display
    RIT Commencement – video status display

    Spotted overhead at the RIT Commencement, about which more later…

  • Chipmunk Gibbage

    Mary found the north end of a southbound chipmunk just outside the garden gate, at the foot of the utility pole that often serves as a hawk perch:

    Chipmunk tail tip
    Chipmunk tail tip

    Shortly thereafter, she found piles of gibbage atop the retaining wall by the basement door:

    Raptor vs. Rodent gibbage
    Raptor vs. Rodent gibbage

    It looks too loose for an owl pellet, but hawks also blurp up the indigestible bits. We have definitely have a pair of Cooper’s Hawks nesting in the area again; most likely, this is what’s left of the south end of that chipmunk.

    The next morning, we had a feeding frenzy out there:

    Raptor vs. Rodent gibbage - feeding frenzy
    Raptor vs. Rodent gibbage – feeding frenzy

    I’m not sure if the snail over on the right is a participant or a bystander. It’s certainly outclassed by the slugs, which are basically soft-shell snails.

    As dBm points out, nothing goes to waste in Nature:

    Raptor vs. Rodent gibbage - cleanup squad
    Raptor vs. Rodent gibbage – cleanup squad

    After the crowd left and the remains dried out a bit, one chunk had a tuft of brown-tipped fur with gray roots that definitely looks like it came from a chipmunk.

    Good work, hawks: go, go, go!

  • M2 Platform Alignment Check

    As part of setting the Makergear M2 up after The Great Cleanout, I ran off a set of thinwall calibration squares that showed the left rear corner was high by 0.12 mm: the square in that corner measured 2.88 mm, rather than the intended 3.0 mm. The walls were 0.43 mm, about 10% above the nominal 0.40 mm.

    That’s similar in both absolute values and alignment to the measurements from two months back.

    I tightened the rear platform screw by a bit under 1/12 turn, less than half a flat on the hex nut, and dialed the Extrusion Multiplier back by 10%. The next set of squares, set up for walls made of three parallel threads, came out with heights within 0.08 mm of each other and 1.15 mm thick (rather than the nominal 1.20 mm).

    They’re 40 mm on a side, mostly to produce bigger handouts for the next show-n-tell:

    Thinwall open box - array on platform - 3w 40 3.0
    Thinwall open box – array on platform – 3w 40 3.0

    Letting it sit for a few days and running the same G-Code produced heights within 0.07 mm and wall thickness at 1.18, which I defined to be Good Enough.

    Recent versions of Slic3r have been adjusting the various thread widths on the fly, as I’ve let everything except the basic extrusion width go with the default values. As a result, setting the wall width to 2 threads (0.80 mm) can produce an extremely thin third thread between the two perimeter threads that doesn’t extrude well. Making the wall three threads wide works much better:

    Calibration Box - open - 3w 40 3.0
    Calibration Box – open – 3w 40 3.0

    The slicing algorithms may be smart enough to make all the tricks I’ve learned completely obsolete; that’s fine with me!

    The raw measurements:

    Calibration box measurements - 2016-06
    Calibration box measurements – 2016-06

  • 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