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

  • What Free Shipping Means

    It really is free:

    China Post postage label
    China Post postage label

    Yeah, I’m sure that’s not what it means, but, still…

    I don’t understand how the total cost of a nontrivial something shipped halfway around the planet can be less than the price I’d pay to return it. I’m certain it involves massive subsidies and mysterious cash flows that never break the surface of the eBay “Buy It Now!” pond.

  • StirlingTEK NP-BX1 Batteries

    Because the first pair of Wasabi NP-BX1 batteries for the Sony HDR-AS30V camera faded to the point where they weren’t useful for a typical bike ride, I bought a pair of SterlingTEK (a.k.a. STK) NP-BX1 batteries that, like the Wasabi batteries, claimed to have a 1600 mA·h capacity. These are “second tier” batteries, not the cheap eBay crap I’ve already dismissed, and run a bit under $10 apiece.

    Here’s the picture from their product description:

    SterlingTEK - STK NP-BX1 battery - as advertised
    SterlingTEK – STK NP-BX1 battery – as advertised

    Here’s what arrived:

    STK NP-BX1 batteries
    STK NP-BX1 batteries

    Huh.

    That’s  a red flag, right there. It’s remarkably tempting to ship a good product for a while, then swap in much cheaper junk that can ride on the good reviews. Not saying that’s what happened, but it’s a possibility.

    Here’s how they performed:

    Sony NP-BX1 - Sony Wasabi STK - as received
    Sony NP-BX1 – Sony Wasabi STK – as received

    The red and blue curves show that the STK batteries produced less than 1000 mA·h in their first two charges, with the blue battery (I labeled it B) showing considerable variation that suggests it’ll suffer early failure. The green curve shows one of those Wasabi batteries and the purple curve is the OEM Sony battery, both in as-received condition.

    SterlingTEK will send two more batteries, in the belief that I received two sub-standard samples. We shall see…

  • Disabling Windows 10 Upgrade Nagware

    If you’re running Windows, then you have more experience than I do, but it seems Microsoft, for reasons best known to it, really really really wants you to upgrade to Windows 10, has been forcing nagware onto every Windows box in existence, and actively working to defeat efforts to remove said nagware.

    Our Token Windows Box, an off-lease Dell Optiplex 780 that arrived bearing Windows 7 Professional, will never, ever get upgraded, because it’s running a bunch of ancient Windows programs that interface with specific bits of hardware, none of which (most likely) will work with Windows 10. In any event, I see no reason to go through the hassle of “upgrading” an old machine, (maybe) resolving all the inevitable compatibility problems, and (maybe) having no way to roll back the upgrade, all for a few programs run, at most, monthly.

    Continually declining Windows 10 upgrade prompts isn’t my idea of a Good User Experience, but I’m also tired of manually inspecting and killing updates that re-re-re-install the nagware.

    The GWX Control Panel (“GWX” = “Get Windows 10” in MS-speak) seems to be the least awful way of dealing with this mess. It’s not offered by Microsoft, for obvious reasons, but is offered free-of-charge.

    Just do it…

  • Tiny Cylinder Test Object

    A discussion on the M2 forums prompted this test object:

    Tiny Cylinder - 0.9x9.0 mm
    Tiny Cylinder – 0.9×9.0 mm

    Sliced with Slic3r for PETG at 1 mm/s, with fans in full effect. It sits amid a 5 mm brim, inside a skirt that uses 15 mm of filament, giving it a Washington Monument aspect.

    The challenge was to print a 0.7x9.0 cylinder, which doesn’t work well with a 0.35 mm nozzle. Instead, I went with 0.9 mm diameter. The result measures 1.1 mm over all the obvious bumps, so it’s surprisingly close. The “nail head” at the bottom most likely comes from the hot end depressurizing as it suddenly transitions from 15 mm/s in the brim to 1 mm/s for the cylinder.

    Fairly obviously, you can’t print something like that at full speed (50 mm/s was claimed for a Rep 2 and I don’t believe that for an instant). Indeed, it’s such a pathological model that Slic3r’s minimum layer time and small perimeter settings had no effect; I had to manually set the extrusion speed to 1 mm/s in order to make it work. Plus adding that brim, because I knew it wouldn’t stand by itself.

    Other than that, printing it was no big deal.

    A picture from that M2 forum discussion suggests you can go crazy with this stuff:

    20 mm, 40 mm, 60 mm and 120 mm
    20 mm, 40 mm, 60 mm and 120 mm

    The OpenSCAD source code for my version:

    cylinder(d=0.9,h=9,$fn=8);
    

    There, now, that wasn’t so hard, was it?

  • Sony and Wasabi NP-BX1 Li-Ion Battery Life

    Using the Sony HDR-AS30V helmet camera more-or-less daily during the bicycling season chews up batteries as well as MicroSD cards:

    Sony NP-BX1 - OEM Wasabi - 2015-10-25
    Sony NP-BX1 – OEM Wasabi – 2015-10-25

    The dotted traces show the most recent status and the solid traces are from almost exactly one year ago:

    • Red = Genuine Sony
    • Blue = Wasabi Power: cell D, August 2014
    • Green = Wasabi Power: cell B, January 2014

    All the tests are at 500 mA, approximately half the camera’s load. Oddly, the numeric values along the mA·h axis work out pretty close to the actual runtime in hours:

    • Sony – 1:30
    • Wasabi D – 1:15
    • Wasabi B – 0:40

    Given that a typical bike ride takes an hour, the two year old Wasabi B battery’s 40 minute runtime isn’t useful. The Wasabi D battery is a bit over a year old and looks very much like the B battery did last year.

    The Wasabi batteries march through the camera and charger in order, so each one gets used about once a week. The Sony battery gets used once every half-dozen complete cycles, just so I have a standard “good” battery.

    The Sony and Wasabi B cells over the course of two years:

    Sony NP-BX1 - OEM Wasabi - 2015-10 2014-10 2014-01
    Sony NP-BX1 – OEM Wasabi – 2015-10 2014-10 2014-01

    Much to my surprise, the Wasabi batteries started out slightly better than the Sony OEM battery, at least as measured by the available voltage and energy. The camera runs from an internal switching power supply, so the area under the curve (basically equal to energy in W·h) above the cutoff voltage is all that matters.

    In round numbers, I can expect 100 cycles out of each battery before the run time drops below the ride time; at $10/battery, that’s a dime a ride. Any claims that the batteries can be recharged “1000 times!” may be true, but they’ll have a useless fraction of their original capacity by then.

    Time to buy a few more batteries…

  • HP 7475A Plotter: One-Button Demo Madness

    Back in the day, you could install a Genuine HP 09872-60066 Digitizing Sight in your Genuine HP 7475A plotter, maneuver the sight to an interesting point on the paper, press the Enter button, send the point’s coordinates through the serial port to the computer, then do whatever you like with the numbers.

    Here in the future, I twiddled the demo code that draws Superformula patterns to send a digitization command and await the response at the end of each plot. I can then change the paper, press the Enter button, and get the next plot: exactly what I need for the upcoming Poughkeepsie Mini Maker Faire.

    The only gotcha turns out to be that, having hacked the Chiplotle interface to use hardware handshaking, there’s no way to tell when the outgoing buffer has drained. Until that happens, the plotter can’t respond to the digitizing command and, eventually, Chiplotle kvetches about not hearing anything.

    The least awful solution seems to be sleeping for 40 seconds (!) while the plotter trudges through the last line of the legend (!!), then continuing apace:

            print "Waiting for plotter... ignore timeout errors!"
            sleep(40)
            while NoneType is type(plt.status):
                sleep(5)
    
            print "Load more paper, then ..."
            print "  ... Press ENTER on the plotter to continue"
            plt.clear_digitizer()
            plt.digitize_point()
            
            plotstatus = plt.status
            while (NoneType is type(plotstatus)) or (0 == int(plotstatus) & 0x04):
                plotstatus = plt.status
                
            print "Digitized: " + str(plt.digitized_point)
    

    When the interface times out, Chiplotle doesn’t set the status code to anything in particular (which makes sense), so you can’t do anything useful with it. Therefore, the operand order in the last while statement matters: you can’t convert a value of type NoneType into anything else.

    The other change wraps the entire plotting loop with an always-and-forever loop: hit Ctrl-C to break out at the end of the day.

    You can’t change the new plot’s paper size, because the digitizing command preempts the Enter button that’s part of the Enter+Size combination. That makes perfect sense, even in retrospect.

    Testing that gave me the opportunity to run all the pens, refilled and OEM, through their paces:

    HP 7475A - Superformula demo
    HP 7475A – Superformula demo

    The Sakura pens in their adapters continue to work well:

    HP 7475A - Superformula - Sakura pens
    HP 7475A – Superformula – Sakura pens

    They’re such unique snowflakes…

    The complete Python source code:

    from chiplotle import *
    from math import *
    from datetime import *
    from time import *
    from types import *
    import random
    
    
    def superformula_polar(a, b, m, n1, n2, n3, phi):
        ''' Computes the position of the point on a
        superformula curve.
        Superformula has first been proposed by Johan Gielis
        and is a generalization of superellipse.
        see: http://en.wikipedia.org/wiki/Superformula
        Tweaked to return polar coordinates
        '''
    
        t1 = cos(m * phi / 4.0) / a
        t1 = abs(t1)
        t1 = pow(t1, n2)
    
        t2 = sin(m * phi / 4.0) / b
        t2 = abs(t2)
        t2 = pow(t2, n3)
    
        t3 = -1 / float(n1)
        r = pow(t1 + t2, t3)
        if abs(r) == 0:
            return (0, 0)
        else:
          #     return (r * cos(phi), r * sin(phi))
            return (r, phi)
    
    
    def supershape(width, height, m, n1, n2, n3,
                   point_count=10 * 1000, percentage=1.0, a=1.0, b=1.0, travel=None):
        '''Supershape, generated using the superformula first proposed 
        by Johan Gielis.
    
        - `points_count` is the total number of points to compute.
        - `travel` is the length of the outline drawn in radians. 
           3.1416 * 2 is a complete cycle.
        '''
        travel = travel or (10 * 2 * pi)
    
        # compute points...
        phis = [i * travel / point_count
                for i in range(1 + int(point_count * percentage))]
        points = [superformula_polar(a, b, m, n1, n2, n3, x) for x in phis]
    
        # scale and transpose...
        path = []
        for r, a in points:
            x = width * r * cos(a)
            y = height * r * sin(a)
            path.append(Coordinate(x, y))
    
        return Path(path)
    
    
    # RUN DEMO CODE
    
    if __name__ == '__main__':
    
        override = False
    
        plt = instantiate_plotters()[0]
    #   plt.write('IN;')
    
        if plt.margins.soft.width < 11000:               # A=10365 B=16640
            maxplotx = (plt.margins.soft.width / 2) - 100
            maxploty = (plt.margins.soft.height / 2) - 150
            legendx = maxplotx - 2600
            legendy = -(maxploty - 650)
            tscale = 0.45
            numpens = 4
            # prime/10 = number of spikes
            m_values = [n / 10.0 for n in [11, 13, 17, 19, 23]]
            # ring-ness 0.1 to 2.0, higher is larger
            n1_values = [
                n / 100.0 for n in range(55, 75, 2) + range(80, 120, 5) + range(120, 200, 10)]
        else:
            maxplotx = plt.margins.soft.width / 2
            maxploty = plt.margins.soft.height / 2
            legendx = maxplotx - 3000
            legendy = -(maxploty - 700)
            tscale = 0.45
            numpens = 6
            m_values = [n / 10.0 for n in [11, 13, 17, 19, 23, 29, 31,
                                           37, 41, 43, 47, 53, 59]]   # prime/10 = number of spikes
            # ring-ness 0.1 to 2.0, higher is larger
            n1_values = [
                n / 100.0 for n in range(15, 75, 2) + range(80, 120, 5) + range(120, 200, 10)]
    
        print "   Max: ({},{})".format(maxplotx, maxploty)
    
        # spiky-ness 0.1 to 2.0, lower is spiky-er
        n2_values = [
            n / 100.0 for n in range(10, 60, 2) + range(65, 100, 5) + range(110, 200, 10)]
    
        plt.write(chr(27) + '.H200:')   # set hardware handshake block size
        plt.set_origin_center()
        # scale based on B size characters
        plt.write(hpgl.SI(tscale * 0.285, tscale * 0.375))
        # slow speed for those abrupt spikes
        plt.write(hpgl.VS(10))
        
        while True:
            
            # standard loadout has pen 1 = fine black
            plt.write(hpgl.PA([(legendx, legendy)]))
            plt.select_pen(1)
            plt.write(hpgl.LB("Started " + str(datetime.today())))
    
            if override:
                m = 4.1
                n1_list = [1.15, 0.90, 0.25, 0.59, 0.51, 0.23]
                n2_list = [0.70, 0.58, 0.32, 0.28, 0.56, 0.26]
            else:
                m = random.choice(m_values)
                n1_list = random.sample(n1_values, numpens)
                n2_list = random.sample(n2_values, numpens)
    
            pen = 1
            for n1, n2 in zip(n1_list, n2_list):
                n3 = n2
                print "{0} - m: {1:.1f}, n1: {2:.2f}, n2=n3: {3:.2f}".format(pen, m, n1, n2)
                plt.select_pen(pen)
                plt.write(hpgl.PA([(legendx, legendy - 100 * pen)]))
                plt.write(
                    hpgl.LB("Pen {0}: m={1:.1f} n1={2:.2f} n2=n3={3:.2f}".format(pen, m, n1, n2)))
                e = supershape(maxplotx, maxploty, m, n1, n2, n3)
                plt.write(e)
                pen = pen + 1 if (pen % numpens) else 1
    
            plt.select_pen(1)
            plt.write(hpgl.PA([(legendx, legendy - 100 * (numpens + 1))]))
            plt.write(hpgl.LB("Ended   " + str(datetime.today())))
            plt.select_pen(0)
            plt.write(hpgl.PA([(-maxplotx,maxploty)]))
            
            print "Waiting for plotter... ignore timeout errors!"
            sleep(40)
            while NoneType is type(plt.status):
                sleep(5)
    
            print "Load more paper, then ..."
            print "  ... Press ENTER on the plotter to continue"
            plt.clear_digitizer()
            plt.digitize_point()
            
            plotstatus = plt.status
            while (NoneType is type(plotstatus)) or (0 == int(plotstatus) & 0x04):
                plotstatus = plt.status
                
            print "Digitized: " + str(plt.digitized_point)
    
  • Monthly Science: Dehumidification by Rice

    As part of a discussion on the M2 forums about using rice to dehumidify 3D printer filament, I replaced the 500 g bag of silica gel in the basement safe with a bowl containing 200 g of long-grain brown rice from our rice supply and let it sit for a while:

    Basement Safe Humidity - Rice vs. Silica Gel - 2015-10-31
    Basement Safe Humidity – Rice vs. Silica Gel – 2015-10-31

    The abrupt drop in humidity from 52% to the logger’s minimum 15% marks the point where I replaced the rice with a fresh bag of silica gel, with a door opening shortly thereafter. The basement air outside the safe varied between 52% and 54% during that time, so the air inside the safe trended upward toward that goal.

    The rice still weighed exactly 200 g after its stay in the safe, so we can conclude it hadn’t absorbed or released any water.

    Conclusion: nope, rice doesn’t work as a dehumidifier…