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

  • RAMPS 1.4: Configuration for Generic Motor Control

    Configuring the knockoff RAMPS 1.4 board went reasonably smoothly:

    RAMPS 1.4 - First Light
    RAMPS 1.4 – First Light

    The DC (n.b., not an AC) solid state relay in the foreground switches the 20 V laptop supply brick to the RAMPS shield atop the knockoff Arduino Mega 2560, controlled by the PS_ON pin (black wire), with +5 V from a pin in the AUX header (yellow wire). The SSR includes a ballast resistor limiting the current to 12 mA, with an inconspicuous red LED behind the black dot showing when the output is turned on.

    Because it’s a DC SSR, polarity matters: the supply goes to the + terminal, the RAMPS power inputs to the – terminal.

    I haven’t applied much of a load to to the SSR, but it works as expected. Define POWER_SUPPLY 1 and PS_DEFAULT_OFF so the boards starts up with the SSR turned off, then use M80 / M81 to turn it on / off as needed.

    Remove D1 on the RAMPS board to isolate the Mega power from the +20 V supply. Stuffed as shown, the Mega draws 70 mA from the USB port, although an external 8 V (-ish) supply is always a good idea.

    The stepper is a random NEMA 17 from the heap in a mount intended for a DIY plotter. I adjusted the tiny trimpots on all the boards for 400 mA peak = 250 mA RMS into the windings, after finding 250 mApk didn’t produce nearly enough mojo, even for a demonstration:

    X Axis Stepper Drive
    X Axis Stepper Drive

    Just to get it running, I used DEFAULT_AXIS_STEPS_PER_UNIT = 100 step/mm, MAX_FEEDRATE 100 mm/s, and (for lack of anything better)
    DEFAULT_*_ACCELERATION 1000. Those all depend the torque produced by the motor current, which is still way too low.

    The endstops require X_???_ENDSTOP_INVERTING true.

    I set the ?_BED_SIZE parameters to a generous 2000, with ?_MIN_POS equal to -SIZE/2 to put the origin in the middle where I prefer it, with a similar setting for the Z axis. Obviously, those numbers don’t correspond to any physical reality.

    Three little 100 kΩ thermistors sprout from their header and produce reasonable temperatures, although (being cheap eBay parts) they may not match the Type 4 curve. I don’t have any heaters connected. All the over / under temperature lockouts are disabled, because I don’t care right now.

    The G-Code parser wants uppercase command letters, which means I get to press the Caps Lock key for the first time in nearly forever!

    The header along the right edge of the board connects to the LCD control board, which is another story.

    The diffs for the Configuration.h and Configuration_adv.h files as a GitHub Gist:

    77c77
    < #define STRING_CONFIG_H_AUTHOR "(none, default config)" // Who made the changes.
    > #define STRING_CONFIG_H_AUTHOR "(Ed Nisley – KE4ZNU)" // Who made the changes.
    113c113
    < #define BAUDRATE 250000
    > #define BAUDRATE 115200
    126c126
    < //#define CUSTOM_MACHINE_NAME "3D Printer"
    > #define CUSTOM_MACHINE_NAME "Not a 3D Printer"
    130c130
    < //#define MACHINE_UUID "00000000-0000-0000-0000-000000000000"
    > #define MACHINE_UUID "89647f7b-2575-4809-bc90-5396f4376e02"
    225c225
    < #define POWER_SUPPLY 0
    > #define POWER_SUPPLY 1
    230c230
    < //#define PS_DEFAULT_OFF
    > #define PS_DEFAULT_OFF
    285c285
    < #define TEMP_SENSOR_0 1
    > #define TEMP_SENSOR_0 4
    290c290
    < #define TEMP_SENSOR_BED 0
    > #define TEMP_SENSOR_BED 4
    304c304
    < #define TEMP_WINDOW 1 // (degC) Window around target to start the residency timer x degC early.
    > #define TEMP_WINDOW 2 // (degC) Window around target to start the residency timer x degC early.
    309c309
    < #define TEMP_BED_WINDOW 1 // (degC) Window around target to start the residency timer x degC early.
    > #define TEMP_BED_WINDOW 2 // (degC) Window around target to start the residency timer x degC early.
    324,325c324,325
    < #define HEATER_0_MAXTEMP 275
    < #define HEATER_1_MAXTEMP 275
    > #define HEATER_0_MAXTEMP 75
    > #define HEATER_1_MAXTEMP 75
    329c329
    < #define BED_MAXTEMP 150
    > #define BED_MAXTEMP 75
    417,418c417,418
    < #define PREVENT_COLD_EXTRUSION
    < #define EXTRUDE_MINTEMP 170
    > //#define PREVENT_COLD_EXTRUSION
    > #define EXTRUDE_MINTEMP 50
    422c422
    < #define PREVENT_LENGTHY_EXTRUDE
    > //#define PREVENT_LENGTHY_EXTRUDE
    441,442c441,442
    < #define THERMAL_PROTECTION_HOTENDS // Enable thermal protection for all extruders
    < #define THERMAL_PROTECTION_BED // Enable thermal protection for the heated bed
    > //#define THERMAL_PROTECTION_HOTENDS // Enable thermal protection for all extruders
    > //#define THERMAL_PROTECTION_BED // Enable thermal protection for the heated bed
    476c476
    < #define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors
    > //#define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors
    490,495c490,495
    < #define X_MIN_ENDSTOP_INVERTING false // set to true to invert the logic of the endstop.
    < #define Y_MIN_ENDSTOP_INVERTING false // set to true to invert the logic of the endstop.
    < #define Z_MIN_ENDSTOP_INVERTING false // set to true to invert the logic of the endstop.
    < #define X_MAX_ENDSTOP_INVERTING false // set to true to invert the logic of the endstop.
    < #define Y_MAX_ENDSTOP_INVERTING false // set to true to invert the logic of the endstop.
    < #define Z_MAX_ENDSTOP_INVERTING false // set to true to invert the logic of the endstop.
    > #define X_MIN_ENDSTOP_INVERTING true // set to true to invert the logic of the endstop.
    > #define Y_MIN_ENDSTOP_INVERTING true // set to true to invert the logic of the endstop.
    > #define Z_MIN_ENDSTOP_INVERTING true // set to true to invert the logic of the endstop.
    > #define X_MAX_ENDSTOP_INVERTING true // set to true to invert the logic of the endstop.
    > #define Y_MAX_ENDSTOP_INVERTING true // set to true to invert the logic of the endstop.
    > #define Z_MAX_ENDSTOP_INVERTING true // set to true to invert the logic of the endstop.
    527c527
    < #define DEFAULT_AXIS_STEPS_PER_UNIT { 80, 80, 4000, 500 }
    > #define DEFAULT_AXIS_STEPS_PER_UNIT { 100, 100, 100, 100 }
    534c534
    < #define DEFAULT_MAX_FEEDRATE { 300, 300, 5, 25 }
    > #define DEFAULT_MAX_FEEDRATE { 100, 100, 100, 100 }
    542c542
    < #define DEFAULT_MAX_ACCELERATION { 3000, 3000, 100, 10000 }
    > #define DEFAULT_MAX_ACCELERATION { 1000, 1000, 1000, 1000 }
    552,554c552,554
    < #define DEFAULT_ACCELERATION 3000 // X, Y, Z and E acceleration for printing moves
    < #define DEFAULT_RETRACT_ACCELERATION 3000 // E acceleration for retracts
    < #define DEFAULT_TRAVEL_ACCELERATION 3000 // X, Y, Z acceleration for travel (non printing) moves
    > #define DEFAULT_ACCELERATION 1000 // X, Y, Z and E acceleration for printing moves
    > #define DEFAULT_RETRACT_ACCELERATION 1000 // E acceleration for retracts
    > #define DEFAULT_TRAVEL_ACCELERATION 1000 // X, Y, Z acceleration for travel (non printing) moves
    566,567c566,567
    < #define DEFAULT_ZJERK 0.4
    < #define DEFAULT_EJERK 5.0
    > #define DEFAULT_ZJERK 20.0
    > #define DEFAULT_EJERK 20.0
    744c744
    < #define INVERT_X_DIR false
    > #define INVERT_X_DIR true
    746c746
    < #define INVERT_Z_DIR false
    > #define INVERT_Z_DIR true
    774,775c774,775
    < #define X_BED_SIZE 200
    < #define Y_BED_SIZE 200
    > #define X_BED_SIZE 2000
    > #define Y_BED_SIZE 2000
    778,783c778,783
    < #define X_MIN_POS 0
    < #define Y_MIN_POS 0
    < #define Z_MIN_POS 0
    < #define X_MAX_POS X_BED_SIZE
    < #define Y_MAX_POS Y_BED_SIZE
    < #define Z_MAX_POS 200
    > #define X_MIN_POS -X_BED_SIZE/2
    > #define Y_MIN_POS -Y_BED_SIZE/2
    > #define Z_MIN_POS -1000
    > #define X_MAX_POS X_BED_SIZE/2
    > #define Y_MAX_POS Y_BED_SIZE/2
    > #define Z_MAX_POS 1000
    1013c1013
    < //#define EEPROM_SETTINGS // Enable for M500 and M501 commands
    > #define EEPROM_SETTINGS // Enable for M500 and M501 commands
    1023c1023
    < #define HOST_KEEPALIVE_FEATURE // Disable this if your host doesn't like keepalive messages
    > //#define HOST_KEEPALIVE_FEATURE // Disable this if your host doesn't like keepalive messages
    1046,1047c1046,1047
    < #define PREHEAT_1_TEMP_BED 70
    < #define PREHEAT_1_FAN_SPEED 0 // Value from 0 to 255
    > #define PREHEAT_1_TEMP_BED 60
    > #define PREHEAT_1_FAN_SPEED 255 // Value from 0 to 255
    1050,1051c1050,1051
    < #define PREHEAT_2_TEMP_BED 110
    < #define PREHEAT_2_FAN_SPEED 0 // Value from 0 to 255
    > #define PREHEAT_2_TEMP_BED 90
    > #define PREHEAT_2_FAN_SPEED 255 // Value from 0 to 255
    1275c1275
    < //#define REVERSE_ENCODER_DIRECTION
    > #define REVERSE_ENCODER_DIRECTION
    1290c1290
    < //#define INDIVIDUAL_AXIS_HOMING_MENU
    > #define INDIVIDUAL_AXIS_HOMING_MENU
    1307,1308c1307,1308
    < //#define LCD_FEEDBACK_FREQUENCY_DURATION_MS 100
    < //#define LCD_FEEDBACK_FREQUENCY_HZ 1000
    > #define LCD_FEEDBACK_FREQUENCY_DURATION_MS 50
    > #define LCD_FEEDBACK_FREQUENCY_HZ 700
    1379c1379
    < //#define REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER
    > #define REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER
    65,66c65,66
    < #define THERMAL_PROTECTION_PERIOD 40 // Seconds
    < #define THERMAL_PROTECTION_HYSTERESIS 4 // Degrees Celsius
    > #define THERMAL_PROTECTION_PERIOD 100 // Seconds
    > #define THERMAL_PROTECTION_HYSTERESIS 5 // Degrees Celsius
    77c77
    < #define WATCH_TEMP_PERIOD 20 // Seconds
    > #define WATCH_TEMP_PERIOD 60 // Seconds
    85c85
    < #define THERMAL_PROTECTION_BED_PERIOD 20 // Seconds
    > #define THERMAL_PROTECTION_BED_PERIOD 120 // Seconds
    97c97
    < #define WATCH_BED_TEMP_PERIOD 60 // Seconds
    > #define WATCH_BED_TEMP_PERIOD 120 // Seconds
    225c225
    < *
    > *
    352c352
    < #define HOMING_BUMP_DIVISOR {2, 2, 4} // Re-Bump Speed Divisor (Divides the Homing Feedrate)
    > #define HOMING_BUMP_DIVISOR {4, 4, 4} // Re-Bump Speed Divisor (Divides the Homing Feedrate)
    374c374
    < #define DEFAULT_STEPPER_DEACTIVE_TIME 120
    > #define DEFAULT_STEPPER_DEACTIVE_TIME 0
    458c458
    < //#define LCD_INFO_MENU
    > #define LCD_INFO_MENU
    461c461
    < //#define STATUS_MESSAGE_SCROLLING
    > #define STATUS_MESSAGE_SCROLLING
    464c464
    < //#define LCD_DECIMAL_SMALL_XY
    > #define LCD_DECIMAL_SMALL_XY
    467c467
    < //#define LCD_TIMEOUT_TO_STATUS 15000
    > #define LCD_TIMEOUT_TO_STATUS 10000
    562c562
    < #define XYZ_HOLLOW_FRAME
    > //#define XYZ_HOLLOW_FRAME
    565c565
    < #define MENU_HOLLOW_FRAME
    > //#define MENU_HOLLOW_FRAME
    573c573
    < //#define USE_SMALL_INFOFONT
    > #define USE_SMALL_INFOFONT
    752c752
    < #define TX_BUFFER_SIZE 0
    > #define TX_BUFFER_SIZE 128
  • Streaming Radio Player: OLED SPI Speed Fix

    The OLED displays on the streaming radio players have SH1106 controllers supported by the Luma library, which works just fine. Digging into the source shows the default SH1106 setup (see the class spi() at the bottom) uses an 8 MHz clock:

        def __init__(self, spi=None, gpio=None, port=0, device=0,
                     bus_speed_hz=8000000, transfer_size=4096,
                     gpio_DC=24, gpio_RST=25):
    assert(bus_speed_hz in [mhz * 1000000 for mhz in [0.5, 1, 2, 4, 8, 16, 32]])
    

    Alas, the SH1106 doc suggests a maximum SPI clock of 2 to 4 MHz, the latter only with fair skies, a tailwind, and a stiff power supply:

    SH1106 OLED Controller - SPI timing
    SH1106 OLED Controller – SPI timing

    The display doesn’t get updated all that often, so there’s no point in rushing things:

    serial = spi(device=0,port=0,bus_speed_hz=1000000)
    device = sh1106(serial)
    

    They’ve been ticking along without mysterious blanking or mirroring for a bit over two weeks, so I’ll call it a fix.

  • Google Pixel vs. USB Mounting

    For reasons undoubtedly making sense at the time, the Google Pixel (and, most likely, current Android devices) don’t support the USB Mass Storage protocol. A bit of poking around suggests the jmtpfs utility supplies the other end of the Pixel’s Media Transfer Protocol and the process goes a little something like this:

    • Once upon a time, create a mountpoint: mkdir /mnt/pixel
    • Unlock the phone
    • Plug in the USB cable
    • Pull down the top menu, tap USB charging this device
    • Select Transfer Files
    • sudo jmtpfs /mnt/pixel -o allow_other,fsname="Pixel"

    The allow_other parameter sets the directory / file permissions so ordinary users can access the files. The fsname is just for pretty.

    The Pixel’s storage then appears as the awkwardly named /mnt/pixel/Internal\ shared\ storage/ directory.

    Despite being somewhat Linuxy under the hood, the mapped storage doesn’t support the usual filesystem attributes, so don’t try to transfer them with, say, rsync -a:

    rsync -rhu --progress /mnt/music/Music\ for\ Programming /mnt/pixel/Internal\ shared\ storage/Music/
    

    When you’re done: sudo umount /mnt/pixel

    This may not be a win over bankshotting off Dropbox or Google Drive, except for sensitive bits like private keys and suchlike.

    Thunar apparently knows how to detect and mount mtp devices automagically and I suppose GUI-fied drag-n-drop works as you’d expect.

  • Hooker Avenue at Raymond: Left Turn on Red

    T=0: You can’t tell, but the signals for Hooker Avenue have been yellow for several seconds and are about to turn red:

    Raymond - Left on Red - 2017-10-11 - 1
    Raymond – Left on Red – 2017-10-11 – 1

    T+3: The opposing signals have been red for a while, but nobody much cares about that:

    Raymond - Left on Red - 2017-10-11 - 2
    Raymond – Left on Red – 2017-10-11 – 2

    T+11: Right-turning traffic (with a green arrow) blocks his path, so he just drops to a dead stop in the middle of the intersection:

    Raymond - Left on Red - 2017-10-11 - 3
    Raymond – Left on Red – 2017-10-11 – 3

    T+14: Finally! All clear for a left on red:

    Raymond - Left on Red - 2017-10-11 - 4
    Raymond – Left on Red – 2017-10-11 – 4

    When a cyclist delays a driver for two, maybe three, seconds, even while riding legally, outrage occurs.

    And, yeah, I’ve made mistakes, too. Happens to everybody. Cyclists seem to arouse disproportionate outrage, so I try very hard to ride within the rules and the lines.

  • Honeybee for Supper

    We often have supper on the patio, with a fly swatter at the ready, but honeybees get special treatment:

    Honeybee on cooked squash
    Honeybee on cooked squash

    She surveyed both our plates, landed on my cooked squash, and probed into the crevices as she would to extract nectar from a flower. The weather has been dry for the last few days and we think she was looking for anything providing a bit of moisture.

    I splashed some water on the table and plopped that part of the squash nearby, in the hopes she’d find what she needs. We’ll never know the end of the story.

  • Shortening a 2MT-to-1MT Morse Taper Sleeve

    The hulking 1/2 inch Jacobs chuck is grossly oversized for most of the holes I poke in things spinning in the lathe. I already have several smaller Jacobs chucks for the Sherline’s 1 MT spindle, so I got some Morse Taper Sleeve Adapters for the mini-lathe’s 2MT tailstock. They’re longer than the “short” 2MT dead center:

    1MT to 2MT adapter - vs 2MT dead center
    1MT to 2MT adapter – vs 2MT dead center

    Because they’re longer, the tailstock ram loses nearly an inch of travel it can’t afford.

    So I hacksawed the taper just beyond the opening at the tang and faced off the ragged end:

    1MT to 2MT adapter - facing
    1MT to 2MT adapter – facing

    The steady rest jaws don’t match the Morse taper angle, but they’re way better than assuming the nose of the Jacob chuck can hold such an ungainly affair.

    The short 1MT taper on the drill chuck doesn’t extend to the opening: when it’s firmly pushed into the socket, there’s no simple way to eject it. So, drill a small hole for a pin punch to pop it out:

    1MT to 2MT adapter - center drilling
    1MT to 2MT adapter – center drilling

    I hate hammering on tooling, which means I must eventually enlarge the hole to clear a 5 mm bolt, make a square-ish nut to fit inside the slot, and gimmick up a plug for the 1/4-20 socket in the 1MT taper (used by the Sherline mill drawbar). More work than I want to take on right now, but it’ll provide some Quality Shop Time.

    If the truth be known, I also got a 3/8-16 thread to 2MT adapter for the mid-size Jacobs chuck seen in the pictures, thus eliminating the thread-to-1MT adapter and plugging the chuck directly into the tailstock. The 1MT adapter will come in handy for the least Jacobs chuck; although LMS has a 0JT-to-2MT adapter, the less I monkey with that tiny taper, the better off we’ll both be.

  • Plotter Grit Wheel Bushings

    As part of recommissioning the lathe tailstock, I made some bushings to adapt Dremel sanding drums bands to an 8 mm shaft (in imitation of the grit drive wheels on the HP plotter):

    Plotter Y bushing - samples
    Plotter Y bushing – samples

    They’re not all the same because the lad who’s building the plotter got to turn out his own bushings. We think the knurled version, with a setscrew to lock it on the shaft, will work better than adhesive-bonding the drum to the bushing.

    The overall process starts with a rough 1/2 inch aluminum rod. Skim-cut to get a concentric surface and face the end smooth:

    Plotter Y bushing - facing
    Plotter Y bushing – facing

    Then knurl it:

    Plotter Y bushing - knurling
    Plotter Y bushing – knurling

    The skim cut makes the aluminum rod a loose fit inside the sanding band, but the knurling enlarges the diameter enough to make it a firm press fit and I think it’ll have enough traction to stay in place.

    FWIW, the wheels in the LittleMachineShop knurling tool seem pretty bad: the central holes aren’t quite concentric with the cutting edge, the bores are a loose fit on the mounting screws, the wheels are much narrower than the slots they ride in, so they wobble uncontrollably. It’s not a fatal flaw, but they definitely produce a sub-par knurl.

    Face off the front, cut the knurling down at each end, then part it off:

    Plotter Y bushing - cutoff
    Plotter Y bushing – cutoff

    Clamp it in the Sherline mill, laser-spot the edges, set the origin in the middle, and center drill:

    Plotter Y bushing - center drill
    Plotter Y bushing – center drill

    Drill and tap for a teeny M3 setscrew:

    Plotter Y bushing - tapping
    Plotter Y bushing – tapping

    Clean out the chips, debur the hole, install the setscrew, and you’re half-done: do it again to get the second drive roller!